refactor: rename the theme brand and every identifier from AKSRT to Jio
Full-project rename. `git grep -i aksrt` is now empty apart from the
DBMigrator 3.3.0 changelog note that documents the rename itself.
Code identifiers
- PHP namespace AKSRT\ -> Jio\ (composer PSR-4 + 378 declarations)
- global constants AKSRT_* -> JIO_* (VERSION/DIR/URI, PAY_TYPE_*, CAPTCHA_*)
- procedural functions, hooks, options, meta keys, table names,
cookies, query vars, ajax actions and nonces: aksrt_ -> jio_
- text domain aksrt -> jio; Theme Name -> Jio
- JS globals: aksrtData/aksrtAdminData/... -> jioData/jioAdminData/...,
window.AKSRTCaptcha & friends -> window.JioCaptcha, Aksrt* -> Jio*
- Vue components Aks*.vue -> Jio*.vue (15 files renamed + imports)
- CSS classes/data-attrs/custom properties: aksrt- -> jio-
- REST namespace aksrt/v1 -> jio/v1 (incl. payment gateway callbacks)
Storage layer
- DB tables {prefix}aksrt_* -> {prefix}jio_*; SCHEMA_VERSION 3.2.0 -> 3.3.0
so dbDelta creates the new names on install
- widget id_base aksrt_widget_* -> jio_widget_*
- uninstall.php drop list rebuilt from the actual migrator tables
(dropped 3 stale entries, added the 17 missing ones)
Removed
- hardcoded https://api.aksrt.com/version.json default update endpoint;
get_endpoint() now reads the 「更新端点」 setting and do_check() no-ops
when it is empty
Files renamed: inc/helpers/aksrt-*.php -> jio-*.php (54),
assets/admin/src/components/form/Aks*.vue -> Jio*.vue (15).
Build artifacts regenerated: assets/css/build, assets/js/runtime,
assets/admin/build.
Verified: audit-psr4-paths errors=0, audit-admin-contracts errors=0
(warnings=56, unchanged baseline), 813/813 widget-system tests,
44/44 phpunit, php -l clean across all PHP.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
5b16bc6e15
commit
35bb96e82f
997 files changed
+28216
-28188
No files matched your search
@@ -1,20 +1,20 @@
|
||||
<template>
|
||||
<div class="aksrt-page-container">
|
||||
<h2 class="aksrt-page-title">积分配置</h2>
|
||||
<p class="aksrt-page-desc">
|
||||
<div class="jio-page-container">
|
||||
<h2 class="jio-page-title">积分配置</h2>
|
||||
<p class="jio-page-desc">
|
||||
配置积分规则与发放策略。可自定义货币名称(如”金币”、”魔石”等)。用户余额与手工调整在 WordPress 原生”用户”菜单中管理。
|
||||
</p>
|
||||
|
||||
<n-card class="aksrt-section-card">
|
||||
<div class="aksrt-section-header"><h3>主开关 + 基础设置</h3></div>
|
||||
<n-form :model="cfg" label-placement="left" label-width="200" class="aksrt-form">
|
||||
<n-card class="jio-section-card">
|
||||
<div class="jio-section-header"><h3>主开关 + 基础设置</h3></div>
|
||||
<n-form :model="cfg" label-placement="left" label-width="200" class="jio-form">
|
||||
<n-form-item label="启用积分系统">
|
||||
<n-switch v-model:value="cfg.enabled" />
|
||||
</n-form-item>
|
||||
<n-form-item label="自定义货币名称">
|
||||
<n-input v-model:value="cfg.currency_name" placeholder="积分" maxlength="20" />
|
||||
<template #feedback>
|
||||
<span class="aksrt-hint-text">自定义货币显示名称,如"金币"、"魔石"等。留空则使用默认名称"积分"。</span>
|
||||
<span class="jio-hint-text">自定义货币显示名称,如"金币"、"魔石"等。留空则使用默认名称"积分"。</span>
|
||||
</template>
|
||||
</n-form-item>
|
||||
<n-form-item label="注册赠送积分">
|
||||
@@ -23,9 +23,9 @@
|
||||
</n-form>
|
||||
</n-card>
|
||||
|
||||
<n-card class="aksrt-section-card">
|
||||
<div class="aksrt-section-header"><h3>每日签到</h3></div>
|
||||
<n-form :model="cfg.daily_signin" label-placement="left" label-width="200" class="aksrt-form">
|
||||
<n-card class="jio-section-card">
|
||||
<div class="jio-section-header"><h3>每日签到</h3></div>
|
||||
<n-form :model="cfg.daily_signin" label-placement="left" label-width="200" class="jio-form">
|
||||
<n-form-item label="启用">
|
||||
<n-switch v-model:value="cfg.daily_signin.enabled" />
|
||||
</n-form-item>
|
||||
@@ -40,15 +40,15 @@
|
||||
:autosize="{ minRows: 2 }"
|
||||
/>
|
||||
<template #feedback>
|
||||
<span class="aksrt-hint-text">连续 N 天时额外发放的积分。</span>
|
||||
<span class="jio-hint-text">连续 N 天时额外发放的积分。</span>
|
||||
</template>
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
</n-card>
|
||||
|
||||
<n-card class="aksrt-section-card">
|
||||
<div class="aksrt-section-header"><h3>评论奖励</h3></div>
|
||||
<n-form :model="cfg.comment_reward" label-placement="left" label-width="200" class="aksrt-form">
|
||||
<n-card class="jio-section-card">
|
||||
<div class="jio-section-header"><h3>评论奖励</h3></div>
|
||||
<n-form :model="cfg.comment_reward" label-placement="left" label-width="200" class="jio-form">
|
||||
<n-form-item label="启用">
|
||||
<n-switch v-model:value="cfg.comment_reward.enabled" />
|
||||
</n-form-item>
|
||||
@@ -67,9 +67,9 @@
|
||||
</n-form>
|
||||
</n-card>
|
||||
|
||||
<n-card class="aksrt-section-card">
|
||||
<div class="aksrt-section-header"><h3>Ref 推广奖励</h3></div>
|
||||
<n-form :model="cfg.referral_reward" label-placement="left" label-width="200" class="aksrt-form">
|
||||
<n-card class="jio-section-card">
|
||||
<div class="jio-section-header"><h3>Ref 推广奖励</h3></div>
|
||||
<n-form :model="cfg.referral_reward" label-placement="left" label-width="200" class="jio-form">
|
||||
<n-form-item label="启用">
|
||||
<n-switch v-model:value="cfg.referral_reward.enabled" />
|
||||
</n-form-item>
|
||||
@@ -91,19 +91,19 @@
|
||||
</n-form>
|
||||
</n-card>
|
||||
|
||||
<n-card class="aksrt-section-card">
|
||||
<div class="aksrt-section-header"><h3>下载消费(参考)</h3></div>
|
||||
<n-form :model="cfg" label-placement="left" label-width="200" class="aksrt-form">
|
||||
<n-card class="jio-section-card">
|
||||
<div class="jio-section-header"><h3>下载消费(参考)</h3></div>
|
||||
<n-form :model="cfg" label-placement="left" label-width="200" class="jio-form">
|
||||
<n-form-item :label="`默认积分价参考(${cfg.currency_name || '积分'})`">
|
||||
<n-input-number v-model:value="cfg.download_default_cost" :min="0" :max="100000" />
|
||||
<template #feedback>
|
||||
<span class="aksrt-hint-text">实际价格以文章「付费内容设置」的积分价或现金价为准;下载解锁走收银台订单,不按次扣费。</span>
|
||||
<span class="jio-hint-text">实际价格以文章「付费内容设置」的积分价或现金价为准;下载解锁走收银台订单,不按次扣费。</span>
|
||||
</template>
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
</n-card>
|
||||
|
||||
<div class="aksrt-form-footer">
|
||||
<div class="jio-form-footer">
|
||||
<n-button type="primary" :loading="saving" @click="saveCfg">保存配置</n-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="aksrt-schema-page">
|
||||
<AksFormRenderer
|
||||
<div class="jio-schema-page">
|
||||
<JioFormRenderer
|
||||
:title="pageMeta.title"
|
||||
:description="pageMeta.description"
|
||||
:icon="pageMeta.icon"
|
||||
@@ -24,7 +24,7 @@
|
||||
v-model:value="captchaProviderTab"
|
||||
type="segment"
|
||||
animated
|
||||
class="aksrt-tabs aksrt-captcha-provider-tabs"
|
||||
class="jio-tabs jio-captcha-provider-tabs"
|
||||
>
|
||||
<n-tab-pane
|
||||
v-for="provider in captchaProviders"
|
||||
@@ -48,18 +48,18 @@
|
||||
#field-geoip_block_countries="{ value, setValue }"
|
||||
>
|
||||
<n-dynamic-tags :value="Array.isArray(value) ? value : []" @update:value="setValue" />
|
||||
<p class="aksrt-schema-page__field-hint">使用 ISO 国家代码,如 CN / US / RU。</p>
|
||||
<p class="jio-schema-page__field-hint">使用 ISO 国家代码,如 CN / US / RU。</p>
|
||||
</template>
|
||||
|
||||
<!-- Slot for custom group content (override per page if needed) -->
|
||||
<template v-for="(_, name) in $slots" #[name]="slotData">
|
||||
<slot :name="name" v-bind="slotData" />
|
||||
</template>
|
||||
</AksFormRenderer>
|
||||
</JioFormRenderer>
|
||||
|
||||
<div
|
||||
v-if="isPermissionsLogin && !loading"
|
||||
class="aksrt-schema-page__tool-actions"
|
||||
class="jio-schema-page__tool-actions"
|
||||
>
|
||||
<n-button
|
||||
:disabled="!formData?.enabled || !formData?.active_provider"
|
||||
@@ -80,7 +80,7 @@
|
||||
<n-spin />
|
||||
<p style="margin-top:10px;color:#999;">加载中...</p>
|
||||
</div>
|
||||
<div v-if="testResult && !testLoading" :style="{color: testResult.success ? 'var(--aksrt-color-primary)' : '#d03050', textAlign:'center', padding:'20px'}">
|
||||
<div v-if="testResult && !testLoading" :style="{color: testResult.success ? 'var(--jio-color-primary)' : '#d03050', textAlign:'center', padding:'20px'}">
|
||||
<p style="font-size:16px;margin:0;">{{ testResult.message }}</p>
|
||||
</div>
|
||||
<div v-if="!testLoading && !testResult" id="captcha-test-box" style="min-height:150px;"></div>
|
||||
@@ -95,7 +95,7 @@
|
||||
* SchemaPage — generic Schema-driven settings page.
|
||||
*
|
||||
* Reads the schema from the Vue-side schema registry, fetches/saves settings
|
||||
* via the API client, and renders using AksFormRenderer.
|
||||
* via the API client, and renders using JioFormRenderer.
|
||||
*
|
||||
* Usage (in router or parent):
|
||||
* <SchemaPage domain="global" section="logo" />
|
||||
@@ -106,7 +106,7 @@
|
||||
import { computed, watch, ref, nextTick, onBeforeUnmount } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { useMessage } from 'naive-ui'
|
||||
import AksFormRenderer from '@/components/form/AksFormRenderer.vue'
|
||||
import JioFormRenderer from '@/components/form/JioFormRenderer.vue'
|
||||
import { useSectionForm } from '@/composables/useSectionForm'
|
||||
import { getSchema, normalizeSchemaDomain } from '@/schema/index.js'
|
||||
import api from '@/api/index.js'
|
||||
@@ -221,7 +221,7 @@ const {
|
||||
const payload = { ...data }
|
||||
const clearSecrets = []
|
||||
Object.keys(payload).forEach((key) => {
|
||||
if (payload[key] === '__AKSRT_CLEAR_SECRET__') {
|
||||
if (payload[key] === '__JIO_CLEAR_SECRET__') {
|
||||
clearSecrets.push(key)
|
||||
delete payload[key]
|
||||
}
|
||||
@@ -417,7 +417,7 @@ function loadProviderSDK(provider, cfg) {
|
||||
sitekey: cfg.site_key,
|
||||
theme: cfg.theme || 'auto',
|
||||
size: cfg.size || 'normal',
|
||||
action: 'aksrt-admin-test',
|
||||
action: 'jio-admin-test',
|
||||
cdata: 'admin-captcha-test',
|
||||
callback: function(token) {
|
||||
submitCaptchaTest('cloudflare', { cf_turnstile_response: token })
|
||||
@@ -539,21 +539,21 @@ onBeforeUnmount(() => {
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.aksrt-schema-page {
|
||||
.jio-schema-page {
|
||||
max-width: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.aksrt-schema-page__tool-actions {
|
||||
.jio-schema-page__tool-actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.aksrt-schema-page__field-hint {
|
||||
.jio-schema-page__field-hint {
|
||||
margin: 8px 0 0;
|
||||
font-size: 12px;
|
||||
color: var(--aksrt-color-muted);
|
||||
color: var(--jio-color-muted);
|
||||
}
|
||||
|
||||
.captcha-test-overlay {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="aksrt-page-container content-page">
|
||||
<div class="jio-page-container content-page">
|
||||
<PageHeader title="右侧悬浮按钮" desc="显示在页面右侧的悬浮按钮,支持排序及添加自定义按钮。" />
|
||||
|
||||
<n-spin :show="loading" style="width: 100%; min-height: 200px;">
|
||||
@@ -7,8 +7,8 @@
|
||||
<b>全局悬浮按钮:</b>显示在页面右侧的悬浮按钮,支持排序及添加自定义按钮
|
||||
</n-alert>
|
||||
|
||||
<n-card class="aksrt-section-card">
|
||||
<n-form :model="form" label-placement="left" label-width="160" class="aksrt-form">
|
||||
<n-card class="jio-section-card">
|
||||
<n-form :model="form" label-placement="left" label-width="160" class="jio-form">
|
||||
<n-form-item label="按钮样式">
|
||||
<n-radio-group v-model:value="form.style">
|
||||
<n-space>
|
||||
@@ -53,7 +53,7 @@
|
||||
v-model="form.items"
|
||||
v-bind="SORTABLE_LIST_ATTRS"
|
||||
item-key="type"
|
||||
class="aksrt-sortable"
|
||||
class="jio-sortable"
|
||||
>
|
||||
<template #item="{ element, index }">
|
||||
<FloatBtnItemPanel :model-value="element" @update:model-value="updateItem(index, $event)" />
|
||||
@@ -63,7 +63,7 @@
|
||||
</n-card>
|
||||
</n-spin>
|
||||
|
||||
<AksSaveBar :dirty="dirty" :saving="saving" @save="handleSave" @reload="loadSettings" />
|
||||
<JioSaveBar :dirty="dirty" :saving="saving" @save="handleSave" @reload="loadSettings" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -73,7 +73,7 @@ import { useMessage } from 'naive-ui'
|
||||
import draggable from 'vuedraggable'
|
||||
import api from '@/api'
|
||||
import PageHeader from '@/components/PageHeader.vue'
|
||||
import AksSaveBar from '@/components/form/AksSaveBar.vue'
|
||||
import JioSaveBar from '@/components/form/JioSaveBar.vue'
|
||||
import { SORTABLE_LIST_ATTRS } from '@/components/form/sortable-options.js'
|
||||
import FloatBtnItemPanel from '@/components/floating/FloatBtnItemPanel.vue'
|
||||
import { defaultSettings, normalizeItems } from '@/components/floating/floating-defaults.js'
|
||||
@@ -162,13 +162,13 @@ onMounted(loadSettings)
|
||||
|
||||
.float-settings__desc {
|
||||
font-size: 12px;
|
||||
color: var(--aksrt-color-muted, #6F7A72);
|
||||
color: var(--jio-color-muted, #6F7A72);
|
||||
}
|
||||
|
||||
.float-settings__label {
|
||||
margin-left: 12px;
|
||||
font-size: 13px;
|
||||
color: var(--aksrt-color-muted, #6F7A72);
|
||||
color: var(--jio-color-muted, #6F7A72);
|
||||
}
|
||||
|
||||
.float-settings__section {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="aksrt-page-container content-page">
|
||||
<div class="jio-page-container content-page">
|
||||
<PageHeader title="底部Tab配置" desc="自定义移动端底部导航栏的按钮,支持排序、图标配置和返回顶部功能。">
|
||||
<template #actions>
|
||||
<n-button type="primary" :loading="saving" @click="handleSave">保存</n-button>
|
||||
@@ -8,24 +8,24 @@
|
||||
|
||||
<n-spin :show="loading" style="width: 100%; min-height: 200px;">
|
||||
<!-- 基础设置 -->
|
||||
<n-card class="aksrt-section-card">
|
||||
<n-card class="jio-section-card">
|
||||
<template #header>
|
||||
<div class="aksrt-card-header-row">
|
||||
<div class="aksrt-card-header-row__left">
|
||||
<div class="jio-card-header-row">
|
||||
<div class="jio-card-header-row__left">
|
||||
<span class="header-icon"><i class="fa fas fa-cog"></i></span>
|
||||
<strong class="aksrt-card-header-row__title">基础设置</strong>
|
||||
<strong class="jio-card-header-row__title">基础设置</strong>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<n-form :model="form" label-placement="left" label-width="140" class="aksrt-form">
|
||||
<n-form :model="form" label-placement="left" label-width="140" class="jio-form">
|
||||
<n-form-item label="启用底部Tab">
|
||||
<n-switch v-model:value="form.enabled" />
|
||||
<span class="aksrt-hint-text" style="margin-left: 12px;">移动端底部导航栏总开关</span>
|
||||
<span class="jio-hint-text" style="margin-left: 12px;">移动端底部导航栏总开关</span>
|
||||
</n-form-item>
|
||||
<n-form-item label="向下滚动隐藏">
|
||||
<n-switch v-model:value="form.scroll_down_hide" />
|
||||
<span class="aksrt-hint-text" style="margin-left: 12px;">页面向下滚动时隐藏,向上滚动时显示</span>
|
||||
<span class="jio-hint-text" style="margin-left: 12px;">页面向下滚动时隐藏,向上滚动时显示</span>
|
||||
</n-form-item>
|
||||
<n-form-item label="文章页专属Tab">
|
||||
<n-select
|
||||
@@ -36,18 +36,18 @@
|
||||
]"
|
||||
style="width: 240px;"
|
||||
/>
|
||||
<span class="aksrt-hint-text" style="margin-left: 12px;">文章详情页底部显示的Tab按钮类型</span>
|
||||
<span class="jio-hint-text" style="margin-left: 12px;">文章详情页底部显示的Tab按钮类型</span>
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
</n-card>
|
||||
|
||||
<!-- Tab按钮配置 -->
|
||||
<n-card class="aksrt-section-card">
|
||||
<n-card class="jio-section-card">
|
||||
<template #header>
|
||||
<div class="aksrt-card-header-row">
|
||||
<div class="aksrt-card-header-row__left">
|
||||
<div class="jio-card-header-row">
|
||||
<div class="jio-card-header-row__left">
|
||||
<span class="header-icon"><i class="fa fas fa-list-ul"></i></span>
|
||||
<strong class="aksrt-card-header-row__title">Tab按钮配置 ({{ form.items.length }})</strong>
|
||||
<strong class="jio-card-header-row__title">Tab按钮配置 ({{ form.items.length }})</strong>
|
||||
</div>
|
||||
<n-button type="primary" size="small" @click="addItem">
|
||||
<template #icon><i class="fa fas fa-plus"></i></template>
|
||||
@@ -63,27 +63,27 @@
|
||||
v-model="form.items"
|
||||
v-bind="SORTABLE_LIST_ATTRS"
|
||||
item-key="id"
|
||||
class="aksrt-sortable"
|
||||
class="jio-sortable"
|
||||
@end="resetSortOrder"
|
||||
>
|
||||
<template #item="{ element, index }">
|
||||
<div class="aksrt-sortable__item">
|
||||
<div class="aksrt-sortable__head">
|
||||
<AksSortHandle />
|
||||
<span class="aksrt-sortable__icon">
|
||||
<div class="jio-sortable__item">
|
||||
<div class="jio-sortable__head">
|
||||
<JioSortHandle />
|
||||
<span class="jio-sortable__icon">
|
||||
<IconValue v-if="element.icon" :value="element.icon" />
|
||||
</span>
|
||||
<div class="aksrt-sortable__main">
|
||||
<div class="aksrt-sortable__title-row">
|
||||
<span class="aksrt-sortable__title">{{ element.text || '按钮' }}</span>
|
||||
<div class="jio-sortable__main">
|
||||
<div class="jio-sortable__title-row">
|
||||
<span class="jio-sortable__title">{{ element.text || '按钮' }}</span>
|
||||
<n-tag size="small" :bordered="false">{{ typeLabelMap[element.type] || element.type }}</n-tag>
|
||||
<n-tag v-if="element.badge" size="small" type="error" :bordered="false">徽标 {{ element.badge }}</n-tag>
|
||||
<n-tag v-if="element.type === 'home' && element.ontop" size="small" type="success" :bordered="false">返回顶部</n-tag>
|
||||
<n-tag size="small" :type="element.enabled ? 'success' : 'default'" :bordered="false">{{ element.enabled ? '启用' : '禁用' }}</n-tag>
|
||||
</div>
|
||||
<div class="aksrt-sortable__desc">{{ getItemSummary(element) }}</div>
|
||||
<div class="jio-sortable__desc">{{ getItemSummary(element) }}</div>
|
||||
</div>
|
||||
<div class="aksrt-sortable__actions">
|
||||
<div class="jio-sortable__actions">
|
||||
<n-button size="tiny" quaternary type="primary" @click="editItem(index)">
|
||||
<template #icon><i class="fa fas fa-edit" style="font-size:12px;" /></template>
|
||||
编辑
|
||||
@@ -100,7 +100,7 @@
|
||||
<n-empty v-else description="暂无Tab按钮,请点击上方按钮添加" />
|
||||
</n-card>
|
||||
|
||||
<div class="aksrt-form-actions">
|
||||
<div class="jio-form-actions">
|
||||
<n-button type="primary" :loading="saving" @click="handleSave">保存底部Tab配置</n-button>
|
||||
</div>
|
||||
</n-spin>
|
||||
@@ -111,10 +111,10 @@
|
||||
:mask-closable="false"
|
||||
preset="card"
|
||||
:title="editingIndex >= 0 ? '编辑Tab按钮' : '添加Tab按钮'"
|
||||
class="aksrt-modal-card"
|
||||
class="jio-modal-card"
|
||||
style="max-width: 520px;"
|
||||
>
|
||||
<n-form :model="editingItem" label-placement="top" class="aksrt-form">
|
||||
<n-form :model="editingItem" label-placement="top" class="jio-form">
|
||||
<n-form-item label="按钮类型">
|
||||
<n-select
|
||||
v-model:value="editingItem.type"
|
||||
@@ -214,12 +214,12 @@
|
||||
v-model="editingItem.add_items"
|
||||
v-bind="SORTABLE_LIST_ATTRS"
|
||||
item-key="id"
|
||||
class="aksrt-sortable aksrt-sortable--compact"
|
||||
class="jio-sortable jio-sortable--compact"
|
||||
>
|
||||
<template #item="{ element, index: subIndex }">
|
||||
<div class="aksrt-sortable__item">
|
||||
<div class="aksrt-sortable__head add-items-editor__row">
|
||||
<AksSortHandle />
|
||||
<div class="jio-sortable__item">
|
||||
<div class="jio-sortable__head add-items-editor__row">
|
||||
<JioSortHandle />
|
||||
<n-input v-model:value="element.label" placeholder="名称,例如:写文章" />
|
||||
<FaIconPicker v-model="element.icon" placeholder="选择图标" />
|
||||
<n-input v-model:value="element.url" placeholder="链接,例如:/wp-admin/post-new.php" />
|
||||
@@ -236,7 +236,7 @@
|
||||
|
||||
<n-form-item v-if="editingItem.type === 'home'" label="返回顶部功能">
|
||||
<n-switch v-model:value="editingItem.ontop" />
|
||||
<span class="aksrt-hint-text" style="margin-left: 12px;">页面滚动后切换为返回顶部按钮</span>
|
||||
<span class="jio-hint-text" style="margin-left: 12px;">页面滚动后切换为返回顶部按钮</span>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="启用状态">
|
||||
@@ -245,7 +245,7 @@
|
||||
</n-form>
|
||||
|
||||
<template #footer>
|
||||
<div class="aksrt-modal-footer">
|
||||
<div class="jio-modal-footer">
|
||||
<n-button @click="showModal = false">取消</n-button>
|
||||
<n-button type="primary" @click="saveItem">保存</n-button>
|
||||
</div>
|
||||
@@ -262,7 +262,7 @@ import api from '@/api'
|
||||
import PageHeader from '@/components/PageHeader.vue'
|
||||
import FaIconPicker from '@/components/form/FaIconPicker.vue'
|
||||
import IconValue from '@/components/form/IconValue.vue'
|
||||
import AksSortHandle from '@/components/form/AksSortHandle.vue'
|
||||
import JioSortHandle from '@/components/form/JioSortHandle.vue'
|
||||
import { SORTABLE_LIST_ATTRS } from '@/components/form/sortable-options.js'
|
||||
|
||||
const message = useMessage()
|
||||
@@ -606,7 +606,7 @@ onMounted(loadSettings)
|
||||
}
|
||||
|
||||
.icon-preview-row a {
|
||||
color: var(--aksrt-color-primary, #18A058);
|
||||
color: var(--jio-color-primary, #18A058);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
@@ -615,12 +615,12 @@ onMounted(loadSettings)
|
||||
}
|
||||
|
||||
.muted-text {
|
||||
color: var(--aksrt-color-muted, #6F7A72);
|
||||
color: var(--jio-color-muted, #6F7A72);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.section-desc {
|
||||
color: var(--aksrt-color-muted, #6F7A72);
|
||||
color: var(--jio-color-muted, #6F7A72);
|
||||
font-size: 13px;
|
||||
margin: 0 0 16px;
|
||||
}
|
||||
@@ -650,7 +650,7 @@ onMounted(loadSettings)
|
||||
|
||||
.add-items-editor__presets-label {
|
||||
font-size: 12px;
|
||||
color: var(--aksrt-color-muted, #6F7A72);
|
||||
color: var(--jio-color-muted, #6F7A72);
|
||||
}
|
||||
|
||||
.add-items-editor__row {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="aksrt-page-container content-page">
|
||||
<div class="jio-page-container content-page">
|
||||
<PageHeader title="通知管理" desc="管理通知内容开关、user 徽标统计口径和自动清理策略。">
|
||||
<template #actions>
|
||||
<n-space>
|
||||
@@ -10,7 +10,7 @@
|
||||
</PageHeader>
|
||||
|
||||
<n-spin :show="loading" style="width: 100%; min-height: 200px;">
|
||||
<n-card title="通知内容开关" class="aksrt-section-card">
|
||||
<n-card title="通知内容开关" class="jio-section-card">
|
||||
<n-form :model="settings" label-placement="left" label-width="180">
|
||||
<n-form-item label="评论回复通知">
|
||||
<n-switch v-model:value="settings.enabled_types.comment_reply" />
|
||||
@@ -35,21 +35,21 @@
|
||||
|
||||
<n-grid :cols="2" :x-gap="16" responsive="screen" item-responsive style="margin-top: 16px;">
|
||||
<n-grid-item span="24 l:10">
|
||||
<n-card title="user 徽标规则" class="aksrt-section-card">
|
||||
<n-card title="user 徽标规则" class="jio-section-card">
|
||||
<n-form :model="settings" label-placement="left" label-width="180">
|
||||
<n-form-item label="启用 user 动态徽标">
|
||||
<n-switch v-model:value="settings.user_badge_enabled" />
|
||||
</n-form-item>
|
||||
<n-form-item label="徽标包含状态提醒">
|
||||
<n-switch v-model:value="settings.badge_include_stateful" />
|
||||
<span class="aksrt-hint-text" style="margin-left: 12px;">未读持久化通知之外,叠加邮箱待验证、待审核评论等即时提醒</span>
|
||||
<span class="jio-hint-text" style="margin-left: 12px;">未读持久化通知之外,叠加邮箱待验证、待审核评论等即时提醒</span>
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
</n-card>
|
||||
</n-grid-item>
|
||||
|
||||
<n-grid-item span="24 l:14">
|
||||
<n-card title="通知清理策略" class="aksrt-section-card">
|
||||
<n-card title="通知清理策略" class="jio-section-card">
|
||||
<n-form :model="settings" label-placement="left" label-width="180">
|
||||
<n-form-item label="已读通知保留天数">
|
||||
<n-input-number v-model:value="settings.read_retention_days" :min="1" :max="365" style="width: 180px;" />
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<template>
|
||||
<div class="aksrt-page-container">
|
||||
<div class="jio-page-container">
|
||||
<PageHeader title="文档中心" desc="主题使用文档、开发指南、迁移说明和更新日志。" />
|
||||
|
||||
<!-- Quick Actions -->
|
||||
<n-card title="常用操作" size="small" class="aksrt-docs__section">
|
||||
<n-card title="常用操作" size="small" class="jio-docs__section">
|
||||
<n-grid :cols="2" :x-gap="12" :y-gap="12">
|
||||
<n-grid-item>
|
||||
<div class="aksrt-docs__action">
|
||||
<div class="jio-docs__action">
|
||||
<FaIcon icon="fa fas fa-paint-brush" :size="16" />
|
||||
<div>
|
||||
<strong>全局设置</strong>
|
||||
@@ -16,7 +16,7 @@
|
||||
</div>
|
||||
</n-grid-item>
|
||||
<n-grid-item>
|
||||
<div class="aksrt-docs__action">
|
||||
<div class="jio-docs__action">
|
||||
<FaIcon icon="fa fas fa-home" :size="16" />
|
||||
<div>
|
||||
<strong>首页配置</strong>
|
||||
@@ -26,7 +26,7 @@
|
||||
</div>
|
||||
</n-grid-item>
|
||||
<n-grid-item>
|
||||
<div class="aksrt-docs__action">
|
||||
<div class="jio-docs__action">
|
||||
<FaIcon icon="fa fas fa-users" :size="16" />
|
||||
<div>
|
||||
<strong>用户管理</strong>
|
||||
@@ -36,7 +36,7 @@
|
||||
</div>
|
||||
</n-grid-item>
|
||||
<n-grid-item>
|
||||
<div class="aksrt-docs__action">
|
||||
<div class="jio-docs__action">
|
||||
<FaIcon icon="fa fas fa-wrench" :size="16" />
|
||||
<div>
|
||||
<strong>工具</strong>
|
||||
@@ -49,30 +49,30 @@
|
||||
</n-card>
|
||||
|
||||
<!-- Reference Docs -->
|
||||
<div class="aksrt-docs__grid">
|
||||
<div class="jio-docs__grid">
|
||||
<n-card
|
||||
v-for="doc in docs"
|
||||
:key="doc.key"
|
||||
class="aksrt-docs__card"
|
||||
class="jio-docs__card"
|
||||
size="small"
|
||||
hoverable
|
||||
@click="openDoc(doc)"
|
||||
>
|
||||
<div class="aksrt-docs__card-inner">
|
||||
<div class="aksrt-docs__card-icon" :style="{ background: doc.color }">
|
||||
<div class="jio-docs__card-inner">
|
||||
<div class="jio-docs__card-icon" :style="{ background: doc.color }">
|
||||
<FaIcon :icon="doc.icon" :size="20" color="#fff" />
|
||||
</div>
|
||||
<div class="aksrt-docs__card-body">
|
||||
<h4 class="aksrt-docs__card-title">{{ doc.title }}</h4>
|
||||
<p class="aksrt-docs__card-desc">{{ doc.description }}</p>
|
||||
<div class="jio-docs__card-body">
|
||||
<h4 class="jio-docs__card-title">{{ doc.title }}</h4>
|
||||
<p class="jio-docs__card-desc">{{ doc.description }}</p>
|
||||
</div>
|
||||
<FaIcon icon="fa fas fa-external-link-alt" :size="12" class="aksrt-docs__card-arrow" />
|
||||
<FaIcon icon="fa fas fa-external-link-alt" :size="12" class="jio-docs__card-arrow" />
|
||||
</div>
|
||||
</n-card>
|
||||
</div>
|
||||
|
||||
<!-- Version Info -->
|
||||
<n-card title="当前版本" size="small" class="aksrt-docs__section">
|
||||
<n-card title="当前版本" size="small" class="jio-docs__section">
|
||||
<n-descriptions :column="2" bordered label-placement="left" size="small">
|
||||
<n-descriptions-item label="主题版本">
|
||||
<n-tag type="success" size="small">{{ themeVersion }}</n-tag>
|
||||
@@ -91,12 +91,12 @@ import PageHeader from '@/components/PageHeader.vue'
|
||||
import FaIcon from '@/components/form/FaIcon.vue'
|
||||
import api from '@/api/index.js'
|
||||
|
||||
const themeVersion = ref(window.aksrtAdminData?.themeVersion || '3.4.0-dev')
|
||||
const themeVersion = ref(window.jioAdminData?.themeVersion || '3.4.0-dev')
|
||||
const dbSchemaVersion = ref('—')
|
||||
|
||||
const docs = ref([
|
||||
{ key: 'admin-ia-map', title: '后台 IA 蓝图', description: '完整的后台信息架构映射,12 个顶级分区及子页面清单。', icon: 'fa fas fa-sitemap', color: 'var(--aksrt-color-primary)', file: 'admin-ia-map.md' },
|
||||
{ key: 'legacy-gap-matrix', title: '对标差异矩阵', description: 'AKSRT 当前 → 原主题参考 → AKSRT 目标三层对照表。', icon: 'fa fas fa-columns', color: '#722ed1', file: 'legacy-gap-matrix.md' },
|
||||
{ key: 'admin-ia-map', title: '后台 IA 蓝图', description: '完整的后台信息架构映射,12 个顶级分区及子页面清单。', icon: 'fa fas fa-sitemap', color: 'var(--jio-color-primary)', file: 'admin-ia-map.md' },
|
||||
{ key: 'legacy-gap-matrix', title: '对标差异矩阵', description: 'Jio 当前 → 原主题参考 → Jio 目标三层对照表。', icon: 'fa fas fa-columns', color: '#722ed1', file: 'legacy-gap-matrix.md' },
|
||||
{ key: 'frontend-page-matrix', title: '前端页面矩阵', description: '前端模板、CSS、JS 资产映射与覆盖范围。', icon: 'fa fas fa-desktop', color: '#13c2c2', file: 'frontend-page-matrix.md' },
|
||||
{ key: 'manual-acceptance-baseline', title: '验收基线', description: '每个 Phase 的人工验收标准和检查清单。', icon: 'fa fas fa-clipboard', color: '#52c41a', file: 'manual-acceptance-baseline.md' },
|
||||
{ key: 'feature-domain-map', title: '功能域地图', description: '业务域划分、依赖关系和模块边界说明。', icon: 'fa fas fa-map', color: '#fa8c16', file: 'feature-domain-map.md' },
|
||||
@@ -117,35 +117,35 @@ onMounted(async () => {
|
||||
|
||||
function openDoc(doc) {
|
||||
// Link to local docs directory (admin can open in new tab)
|
||||
const base = window.aksrtAdminData?.siteUrl || window.location.origin
|
||||
window.open(`${base}/wp-content/themes/AKSRT-theme/docs/${doc.file}`, '_blank')
|
||||
const base = window.jioAdminData?.siteUrl || window.location.origin
|
||||
window.open(`${base}/wp-content/themes/Jio-theme/docs/${doc.file}`, '_blank')
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.aksrt-docs__grid {
|
||||
.jio-docs__grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(340px, 1fr));
|
||||
gap: 12px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.aksrt-docs__card {
|
||||
.jio-docs__card {
|
||||
cursor: pointer;
|
||||
transition: box-shadow 0.2s;
|
||||
}
|
||||
|
||||
.aksrt-docs__card:hover {
|
||||
.jio-docs__card:hover {
|
||||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
.aksrt-docs__card-inner {
|
||||
.jio-docs__card-inner {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.aksrt-docs__card-icon {
|
||||
.jio-docs__card-icon {
|
||||
flex-shrink: 0;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
@@ -155,38 +155,38 @@ function openDoc(doc) {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.aksrt-docs__card-body {
|
||||
.jio-docs__card-body {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.aksrt-docs__card-title {
|
||||
.jio-docs__card-title {
|
||||
margin: 0 0 2px;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: var(--aksrt-color-text);
|
||||
color: var(--jio-color-text);
|
||||
}
|
||||
|
||||
.aksrt-docs__card-desc {
|
||||
.jio-docs__card-desc {
|
||||
margin: 0;
|
||||
font-size: 12px;
|
||||
color: var(--aksrt-color-muted);
|
||||
color: var(--jio-color-muted);
|
||||
line-height: 1.5;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.aksrt-docs__card-arrow {
|
||||
.jio-docs__card-arrow {
|
||||
flex-shrink: 0;
|
||||
color: #c0c4cc;
|
||||
}
|
||||
|
||||
.aksrt-docs__section {
|
||||
.jio-docs__section {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.aksrt-docs__action {
|
||||
.jio-docs__action {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
align-items: flex-start;
|
||||
@@ -195,31 +195,31 @@ function openDoc(doc) {
|
||||
background: #fafafa;
|
||||
}
|
||||
|
||||
.aksrt-docs__action i {
|
||||
color: var(--aksrt-color-primary);
|
||||
.jio-docs__action i {
|
||||
color: var(--jio-color-primary);
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.aksrt-docs__action strong {
|
||||
.jio-docs__action strong {
|
||||
display: block;
|
||||
font-size: 14px;
|
||||
color: var(--aksrt-color-text);
|
||||
color: var(--jio-color-text);
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
.aksrt-docs__action p {
|
||||
.jio-docs__action p {
|
||||
margin: 0 0 4px;
|
||||
font-size: 12px;
|
||||
color: var(--aksrt-color-muted);
|
||||
color: var(--jio-color-muted);
|
||||
}
|
||||
|
||||
.aksrt-docs__action a {
|
||||
.jio-docs__action a {
|
||||
font-size: 12px;
|
||||
color: var(--aksrt-color-primary);
|
||||
color: var(--jio-color-primary);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.aksrt-docs__action a:hover {
|
||||
.jio-docs__action a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
</style>
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="aksrt-page-container">
|
||||
<div class="jio-page-container">
|
||||
<PageHeader :title="title" :desc="desc">
|
||||
<template #actions>
|
||||
<n-space v-if="links.length">
|
||||
@@ -10,7 +10,7 @@
|
||||
</template>
|
||||
</PageHeader>
|
||||
|
||||
<n-card v-if="note" class="aksrt-section-card">
|
||||
<n-card v-if="note" class="jio-section-card">
|
||||
<n-alert type="info" :show-icon="false">
|
||||
{{ note }}
|
||||
</n-alert>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="aksrt-page-container">
|
||||
<div class="jio-page-container">
|
||||
<PageHeader
|
||||
title="基本权限 / 能力矩阵"
|
||||
desc="统一管理用户治理、投稿和评论的角色能力矩阵。"
|
||||
@@ -17,8 +17,8 @@
|
||||
|
||||
|
||||
<n-spin :show="loading" style="width: 100%; min-height: 240px;">
|
||||
<n-card class="aksrt-section-card" v-if="summary.cap_count">
|
||||
<div class="aksrt-section-header">
|
||||
<n-card class="jio-section-card" v-if="summary.cap_count">
|
||||
<div class="jio-section-header">
|
||||
<h3>矩阵概览</h3>
|
||||
</div>
|
||||
<n-space>
|
||||
@@ -28,12 +28,12 @@
|
||||
</n-space>
|
||||
</n-card>
|
||||
|
||||
<n-card v-for="group in groups" :key="group.key" class="aksrt-section-card">
|
||||
<n-card v-for="group in groups" :key="group.key" class="jio-section-card">
|
||||
<template #header>
|
||||
<div class="aksrt-cap-matrix__header">
|
||||
<div class="jio-cap-matrix__header">
|
||||
<div>
|
||||
<h3 class="aksrt-cap-matrix__title">{{ group.title }}</h3>
|
||||
<p class="aksrt-cap-matrix__desc">共 {{ group.items.length }} 项能力</p>
|
||||
<h3 class="jio-cap-matrix__title">{{ group.title }}</h3>
|
||||
<p class="jio-cap-matrix__desc">共 {{ group.items.length }} 项能力</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -48,7 +48,7 @@
|
||||
/>
|
||||
</n-card>
|
||||
|
||||
<div class="aksrt-form-actions">
|
||||
<div class="jio-form-actions">
|
||||
<n-button type="primary" :loading="saving" @click="handleSave">保存能力矩阵</n-button>
|
||||
</div>
|
||||
</n-spin>
|
||||
@@ -117,7 +117,7 @@ function buildColumns(group) {
|
||||
key: 'label',
|
||||
fixed: 'left',
|
||||
width: 280,
|
||||
render: (row) => h('div', { class: 'aksrt-cap-matrix__cap' }, [
|
||||
render: (row) => h('div', { class: 'jio-cap-matrix__cap' }, [
|
||||
h('strong', row.label),
|
||||
h('code', row.cap_id),
|
||||
]),
|
||||
@@ -148,7 +148,7 @@ function buildColumns(group) {
|
||||
function renderCapCell(row, col) {
|
||||
const hidden = !(row.visible_columns || []).includes(col)
|
||||
if (hidden) {
|
||||
return h('span', { class: 'aksrt-cap-matrix__empty' }, '—')
|
||||
return h('span', { class: 'jio-cap-matrix__empty' }, '—')
|
||||
}
|
||||
|
||||
if (!userCaps[row.cap_id]) {
|
||||
@@ -209,40 +209,40 @@ async function handleSave() {
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.aksrt-cap-matrix__header {
|
||||
.jio-cap-matrix__header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.aksrt-cap-matrix__title {
|
||||
.jio-cap-matrix__title {
|
||||
margin: 0;
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.aksrt-cap-matrix__desc {
|
||||
.jio-cap-matrix__desc {
|
||||
margin: 4px 0 0;
|
||||
font-size: 12px;
|
||||
color: var(--aksrt-color-muted);
|
||||
color: var(--jio-color-muted);
|
||||
}
|
||||
|
||||
.aksrt-cap-matrix__cap {
|
||||
.jio-cap-matrix__cap {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.aksrt-cap-matrix__cap code {
|
||||
.jio-cap-matrix__cap code {
|
||||
font-size: 11px;
|
||||
color: #667085;
|
||||
}
|
||||
|
||||
.aksrt-cap-matrix__empty {
|
||||
.jio-cap-matrix__empty {
|
||||
color: #c0c4cc;
|
||||
}
|
||||
|
||||
.aksrt-form-actions {
|
||||
.jio-form-actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin-top: 16px;
|
||||
|
||||
@@ -21,7 +21,7 @@ const title = computed(() => route.meta?.title || '运营功能已迁移')
|
||||
const nativeUrl = computed(() => {
|
||||
const path = route.meta?.nativeAdminPath || ''
|
||||
if (!path) return ''
|
||||
const base = (window.aksrtAdminData?.adminUrl || '/wp-admin/').replace(/\/?$/, '/')
|
||||
const base = (window.jioAdminData?.adminUrl || '/wp-admin/').replace(/\/?$/, '/')
|
||||
return base + path.replace(/^\//, '')
|
||||
})
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="aksrt-page-container">
|
||||
<div class="jio-page-container">
|
||||
<PageHeader
|
||||
title="主题授权"
|
||||
desc="当前版本按产品决策不实现在线授权/撤销授权,仅保留主题信息与更新能力。"
|
||||
@@ -12,14 +12,14 @@
|
||||
</template>
|
||||
</PageHeader>
|
||||
|
||||
<n-card class="aksrt-section-card">
|
||||
<n-card class="jio-section-card">
|
||||
<n-alert type="info" title="按设计省略" :show-icon="true">
|
||||
本主题当前不实现 原主题风格的授权码校验、域名绑定、撤销授权、本地免授权等机制。
|
||||
`AKSRT_Update_Checker` 仅负责匿名版本检测与更新提示,不与授权系统耦合。
|
||||
`JIO_Update_Checker` 仅负责匿名版本检测与更新提示,不与授权系统耦合。
|
||||
</n-alert>
|
||||
</n-card>
|
||||
|
||||
<n-card class="aksrt-section-card" title="当前策略" size="small">
|
||||
<n-card class="jio-section-card" title="当前策略" size="small">
|
||||
<n-list bordered>
|
||||
<n-list-item>不提供授权码输入框或“立即授权”按钮</n-list-item>
|
||||
<n-list-item>不提供“已授权 / 未授权 / 本地免授权”三态逻辑</n-list-item>
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
<template>
|
||||
<div class="aksrt-page-container">
|
||||
<div class="jio-page-container">
|
||||
<PageHeader title="主题信息" desc="主题版本、运行环境、已启用模块和关键系统信息。" />
|
||||
|
||||
<div v-if="loading" class="aksrt-theme-info__loading">
|
||||
<div v-if="loading" class="jio-theme-info__loading">
|
||||
<n-spin size="medium" />
|
||||
</div>
|
||||
|
||||
<template v-else>
|
||||
<!-- Version Card -->
|
||||
<n-card class="aksrt-theme-info__card" title="版本信息" size="small">
|
||||
<n-card class="jio-theme-info__card" title="版本信息" size="small">
|
||||
<n-descriptions :column="2" bordered label-placement="left" size="small">
|
||||
<n-descriptions-item label="主题版本">
|
||||
<n-tag type="success" size="small">{{ info.themeVersion }}</n-tag>
|
||||
@@ -33,7 +33,7 @@
|
||||
</n-card>
|
||||
|
||||
<!-- Environment Card -->
|
||||
<n-card class="aksrt-theme-info__card" title="运行环境" size="small">
|
||||
<n-card class="jio-theme-info__card" title="运行环境" size="small">
|
||||
<n-descriptions :column="2" bordered label-placement="left" size="small">
|
||||
<n-descriptions-item label="站点地址">
|
||||
<n-text code>{{ info.siteUrl }}</n-text>
|
||||
@@ -61,14 +61,14 @@
|
||||
</n-card>
|
||||
|
||||
<!-- Modules Card -->
|
||||
<n-card class="aksrt-theme-info__card" title="已启用模块" size="small">
|
||||
<div class="aksrt-theme-info__modules">
|
||||
<n-card class="jio-theme-info__card" title="已启用模块" size="small">
|
||||
<div class="jio-theme-info__modules">
|
||||
<n-tag
|
||||
v-for="mod in info.modules"
|
||||
:key="mod.key"
|
||||
:type="mod.enabled ? 'success' : 'default'"
|
||||
size="small"
|
||||
class="aksrt-theme-info__module-tag"
|
||||
class="jio-theme-info__module-tag"
|
||||
>
|
||||
<FaIcon :icon="mod.enabled ? 'fa fas fa-check-circle' : 'fa fas fa-circle'" :size="10" />
|
||||
{{ mod.label }}
|
||||
@@ -80,7 +80,7 @@
|
||||
</n-card>
|
||||
|
||||
<!-- Data Tables Card -->
|
||||
<n-card class="aksrt-theme-info__card" title="数据表状态" size="small">
|
||||
<n-card class="jio-theme-info__card" title="数据表状态" size="small">
|
||||
<n-data-table
|
||||
:columns="tableColumns"
|
||||
:data="info.tables"
|
||||
@@ -91,25 +91,25 @@
|
||||
</n-card>
|
||||
|
||||
<!-- Docs Links Card -->
|
||||
<n-card class="aksrt-theme-info__card" title="快速入口" size="small">
|
||||
<div class="aksrt-theme-info__links">
|
||||
<router-link to="/docs" class="aksrt-theme-info__link">
|
||||
<n-card class="jio-theme-info__card" title="快速入口" size="small">
|
||||
<div class="jio-theme-info__links">
|
||||
<router-link to="/docs" class="jio-theme-info__link">
|
||||
<FaIcon icon="fa fas fa-book" :size="16" />
|
||||
<span>文档中心</span>
|
||||
</router-link>
|
||||
<router-link to="/tools/update" class="aksrt-theme-info__link">
|
||||
<router-link to="/tools/update" class="jio-theme-info__link">
|
||||
<FaIcon icon="fa fas fa-cloud-download-alt" :size="16" />
|
||||
<span>更新中心</span>
|
||||
</router-link>
|
||||
<router-link to="/tools/backup" class="aksrt-theme-info__link">
|
||||
<router-link to="/tools/backup" class="jio-theme-info__link">
|
||||
<FaIcon icon="fa fas fa-archive" :size="16" />
|
||||
<span>数据备份</span>
|
||||
</router-link>
|
||||
<router-link to="/tools/health" class="aksrt-theme-info__link">
|
||||
<router-link to="/tools/health" class="jio-theme-info__link">
|
||||
<FaIcon icon="fa fas fa-heartbeat" :size="16" />
|
||||
<span>健康检查</span>
|
||||
</router-link>
|
||||
<router-link to="/tools/import-export" class="aksrt-theme-info__link">
|
||||
<router-link to="/tools/import-export" class="jio-theme-info__link">
|
||||
<FaIcon icon="fa fas fa-exchange-alt" :size="16" />
|
||||
<span>导入导出</span>
|
||||
</router-link>
|
||||
@@ -173,13 +173,13 @@ onMounted(async () => {
|
||||
const data = res?.data || res || {}
|
||||
|
||||
info.value = {
|
||||
themeVersion: window.aksrtAdminData?.themeVersion || data.theme_version || '3.4.0-dev',
|
||||
themeVersion: window.jioAdminData?.themeVersion || data.theme_version || '3.4.0-dev',
|
||||
wpVersion: data.wp_version || '',
|
||||
phpVersion: data.php_version || '',
|
||||
dbSchemaVersion: data.db_schema_version || '',
|
||||
emailBackfillDone: !!data.email_backfill_done,
|
||||
siteUrl: data.site_url || window.aksrtAdminData?.siteUrl || '',
|
||||
apiUrl: data.api_url || window.aksrtAdminData?.apiUrl || '',
|
||||
siteUrl: data.site_url || window.jioAdminData?.siteUrl || '',
|
||||
apiUrl: data.api_url || window.jioAdminData?.apiUrl || '',
|
||||
themeDir: data.theme_dir || '',
|
||||
uploadDir: data.upload_dir || '',
|
||||
isMultisite: !!data.is_multisite,
|
||||
@@ -191,8 +191,8 @@ onMounted(async () => {
|
||||
console.error('[ThemeInfo] Failed to load health data:', err)
|
||||
// Fallback with minimal info
|
||||
info.value.themeVersion = '3.4.0-dev'
|
||||
info.value.siteUrl = window.aksrtAdminData?.siteUrl || ''
|
||||
info.value.apiUrl = window.aksrtAdminData?.apiUrl || ''
|
||||
info.value.siteUrl = window.jioAdminData?.siteUrl || ''
|
||||
info.value.apiUrl = window.jioAdminData?.apiUrl || ''
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
@@ -218,35 +218,35 @@ function normalizeTables(raw) {
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.aksrt-theme-info__loading {
|
||||
.jio-theme-info__loading {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 60px 0;
|
||||
}
|
||||
|
||||
.aksrt-theme-info__card {
|
||||
.jio-theme-info__card {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.aksrt-theme-info__modules {
|
||||
.jio-theme-info__modules {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.aksrt-theme-info__module-tag {
|
||||
.jio-theme-info__module-tag {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.aksrt-theme-info__links {
|
||||
.jio-theme-info__links {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.aksrt-theme-info__link {
|
||||
.jio-theme-info__link {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
@@ -259,7 +259,7 @@ function normalizeTables(raw) {
|
||||
transition: background 0.2s;
|
||||
}
|
||||
|
||||
.aksrt-theme-info__link:hover {
|
||||
.jio-theme-info__link:hover {
|
||||
background: #e8eaed;
|
||||
}
|
||||
</style>
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="aksrt-page-container">
|
||||
<div class="jio-page-container">
|
||||
<PageHeader
|
||||
title="数据备份"
|
||||
desc="管理设置快照、创建手动备份,并执行恢复或删除。"
|
||||
@@ -12,8 +12,8 @@
|
||||
</PageHeader>
|
||||
|
||||
<n-spin :show="loading" style="width: 100%; min-height: 200px;">
|
||||
<n-card class="aksrt-section-card">
|
||||
<div class="aksrt-section-header">
|
||||
<n-card class="jio-section-card">
|
||||
<div class="jio-section-header">
|
||||
<h3>备份策略</h3>
|
||||
</div>
|
||||
<n-space vertical size="small" style="width: 100%;">
|
||||
@@ -26,19 +26,19 @@
|
||||
<n-tag round :type="backups.length ? 'success' : 'default'">现有快照:{{ backups.length }} 份</n-tag>
|
||||
</n-space>
|
||||
<n-space align="center" wrap>
|
||||
<span class="aksrt-backup__label">自动备份</span>
|
||||
<span class="jio-backup__label">自动备份</span>
|
||||
<n-switch v-model:value="settings.backup_auto" />
|
||||
<span class="aksrt-backup__label">频率</span>
|
||||
<span class="jio-backup__label">频率</span>
|
||||
<n-select v-model:value="settings.backup_frequency" :options="frequencyOptions" style="width: 140px;" />
|
||||
<span class="aksrt-backup__label">保留</span>
|
||||
<span class="jio-backup__label">保留</span>
|
||||
<n-input-number v-model:value="settings.backup_retain" :min="3" :max="20" style="width: 140px;" />
|
||||
<n-button type="primary" :loading="savingPolicy" @click="handleSavePolicy">保存策略</n-button>
|
||||
</n-space>
|
||||
</n-space>
|
||||
</n-card>
|
||||
|
||||
<n-card class="aksrt-section-card">
|
||||
<div class="aksrt-section-header">
|
||||
<n-card class="jio-section-card">
|
||||
<div class="jio-section-header">
|
||||
<h3>手动创建快照</h3>
|
||||
</div>
|
||||
<n-space vertical size="small" style="width: 100%;">
|
||||
@@ -50,8 +50,8 @@
|
||||
</n-space>
|
||||
</n-card>
|
||||
|
||||
<n-card class="aksrt-section-card">
|
||||
<div class="aksrt-section-header">
|
||||
<n-card class="jio-section-card">
|
||||
<div class="jio-section-header">
|
||||
<h3>快照列表</h3>
|
||||
</div>
|
||||
<n-empty v-if="!backups.length" description="暂无设置快照" />
|
||||
@@ -64,7 +64,7 @@
|
||||
:single-line="false"
|
||||
:scroll-x="900"
|
||||
/>
|
||||
<p class="aksrt-backup__hint">
|
||||
<p class="jio-backup__hint">
|
||||
恢复非当前网站 / 非当前版本的快照可能导致配置异常,恢复前请确认站点环境一致。
|
||||
</p>
|
||||
</n-card>
|
||||
@@ -264,14 +264,14 @@ async function handleDelete(row) {
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.aksrt-backup__hint {
|
||||
.jio-backup__hint {
|
||||
margin: 12px 0 0;
|
||||
color: #667085;
|
||||
font-size: 12px;
|
||||
line-height: 1.7;
|
||||
}
|
||||
|
||||
.aksrt-backup__label {
|
||||
.jio-backup__label {
|
||||
color: #344054;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="aksrt-page-container">
|
||||
<div class="jio-page-container">
|
||||
<PageHeader
|
||||
title="健康检查"
|
||||
desc="集中查看运行环境、数据库表和系统诊断状态。"
|
||||
@@ -12,9 +12,9 @@
|
||||
</PageHeader>
|
||||
|
||||
<n-spin :show="loading" style="width: 100%; min-height: 200px;">
|
||||
<div class="aksrt-health-grid">
|
||||
<n-card v-for="check in checkItems" :key="check.key" class="aksrt-section-card">
|
||||
<div class="aksrt-section-header">
|
||||
<div class="jio-health-grid">
|
||||
<n-card v-for="check in checkItems" :key="check.key" class="jio-section-card">
|
||||
<div class="jio-section-header">
|
||||
<h3>{{ check.label }}</h3>
|
||||
<n-tag round :type="statusToTag(check.status)">{{ check.status }}</n-tag>
|
||||
</div>
|
||||
@@ -76,7 +76,7 @@ onMounted(load)
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.aksrt-health-grid {
|
||||
.jio-health-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
|
||||
gap: 16px;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="aksrt-page-container">
|
||||
<div class="jio-page-container">
|
||||
<PageHeader
|
||||
title="导入导出"
|
||||
desc="导出当前设置快照、执行 dry-run 导入校验,并支持按域重置到 schema 默认值。"
|
||||
@@ -12,8 +12,8 @@
|
||||
</template>
|
||||
</PageHeader>
|
||||
|
||||
<n-card class="aksrt-section-card">
|
||||
<div class="aksrt-section-header">
|
||||
<n-card class="jio-section-card">
|
||||
<div class="jio-section-header">
|
||||
<h3>导出与导入</h3>
|
||||
</div>
|
||||
<n-space style="margin-bottom: 16px;">
|
||||
@@ -27,13 +27,13 @@
|
||||
:autosize="{ minRows: 12, maxRows: 20 }"
|
||||
placeholder="导出的 JSON 会出现在这里,也可以直接粘贴导入。"
|
||||
/>
|
||||
<p class="aksrt-tools-hint">
|
||||
<p class="jio-tools-hint">
|
||||
正式导入前会自动创建一份“导入前自动快照”,与“数据备份”页的快照体系共用,便于回滚。
|
||||
</p>
|
||||
</n-card>
|
||||
|
||||
<n-card class="aksrt-section-card">
|
||||
<div class="aksrt-section-header">
|
||||
<n-card class="jio-section-card">
|
||||
<div class="jio-section-header">
|
||||
<h3>按域重置</h3>
|
||||
</div>
|
||||
<n-space align="center" wrap>
|
||||
@@ -41,14 +41,14 @@
|
||||
<n-button :loading="resetting" @click="handleReset">重置所选域</n-button>
|
||||
<n-button type="error" tertiary :loading="resettingAll" @click="handleResetAll">重置全部</n-button>
|
||||
</n-space>
|
||||
<p class="aksrt-tools-hint">仅支持重置 schema 托管的业务域。健康检查和迁移状态属于运维面板,不参与按域回滚。</p>
|
||||
<p class="jio-tools-hint">仅支持重置 schema 托管的业务域。健康检查和迁移状态属于运维面板,不参与按域回滚。</p>
|
||||
</n-card>
|
||||
|
||||
<n-card class="aksrt-section-card">
|
||||
<div class="aksrt-section-header">
|
||||
<n-card class="jio-section-card">
|
||||
<div class="jio-section-header">
|
||||
<h3>最近结果</h3>
|
||||
</div>
|
||||
<pre class="aksrt-tools-output">{{ resultText || '尚未执行操作。' }}</pre>
|
||||
<pre class="jio-tools-output">{{ resultText || '尚未执行操作。' }}</pre>
|
||||
</n-card>
|
||||
</div>
|
||||
</template>
|
||||
@@ -169,7 +169,7 @@ async function handleResetAll() {
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.aksrt-tools-output {
|
||||
.jio-tools-output {
|
||||
margin: 0;
|
||||
padding: 14px;
|
||||
border-radius: 12px;
|
||||
@@ -181,7 +181,7 @@ async function handleResetAll() {
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.aksrt-tools-hint {
|
||||
.jio-tools-hint {
|
||||
margin: 12px 0 0;
|
||||
color: #667085;
|
||||
font-size: 12px;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="aksrt-page-container">
|
||||
<div class="jio-page-container">
|
||||
<PageHeader
|
||||
title="更新中心"
|
||||
desc="查看版本状态、检测更新并浏览更新日志与教程入口。"
|
||||
@@ -13,8 +13,8 @@
|
||||
</PageHeader>
|
||||
|
||||
<n-spin :show="loading" style="width: 100%; min-height: 220px;">
|
||||
<n-card class="aksrt-section-card">
|
||||
<div class="aksrt-section-header">
|
||||
<n-card class="jio-section-card">
|
||||
<div class="jio-section-header">
|
||||
<h3>版本状态</h3>
|
||||
</div>
|
||||
<n-space>
|
||||
@@ -26,8 +26,8 @@
|
||||
</n-space>
|
||||
</n-card>
|
||||
|
||||
<n-card class="aksrt-section-card" v-if="updateInfo.update_available">
|
||||
<div class="aksrt-section-header">
|
||||
<n-card class="jio-section-card" v-if="updateInfo.update_available">
|
||||
<div class="jio-section-header">
|
||||
<h3>可用更新</h3>
|
||||
</div>
|
||||
<n-alert type="warning" style="margin-bottom: 12px;">
|
||||
@@ -39,18 +39,18 @@
|
||||
</n-button>
|
||||
<n-button @click="handleDismiss" :loading="dismissing">忽略此版本</n-button>
|
||||
</n-space>
|
||||
<div v-if="updateInfo.changelog" class="aksrt-update__changelog">
|
||||
<div v-if="updateInfo.changelog" class="jio-update__changelog">
|
||||
<h4>更新日志</h4>
|
||||
<pre>{{ updateInfo.changelog }}</pre>
|
||||
</div>
|
||||
</n-card>
|
||||
|
||||
<n-card class="aksrt-section-card">
|
||||
<div class="aksrt-section-header">
|
||||
<n-card class="jio-section-card">
|
||||
<div class="jio-section-header">
|
||||
<h3>常用教程入口</h3>
|
||||
</div>
|
||||
<div class="aksrt-update__grid">
|
||||
<a v-for="item in guides" :key="item.key" class="aksrt-update__guide" :href="item.url" target="_blank" rel="noreferrer">
|
||||
<div class="jio-update__grid">
|
||||
<a v-for="item in guides" :key="item.key" class="jio-update__guide" :href="item.url" target="_blank" rel="noreferrer">
|
||||
<strong>{{ item.title }}</strong>
|
||||
<span>{{ item.desc }}</span>
|
||||
</a>
|
||||
@@ -152,11 +152,11 @@ async function handleDismiss() {
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.aksrt-update__changelog {
|
||||
.jio-update__changelog {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.aksrt-update__changelog pre {
|
||||
.jio-update__changelog pre {
|
||||
margin: 8px 0 0;
|
||||
padding: 12px 14px;
|
||||
border-radius: 12px;
|
||||
@@ -168,30 +168,30 @@ async function handleDismiss() {
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.aksrt-update__grid {
|
||||
.jio-update__grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.aksrt-update__guide {
|
||||
.jio-update__guide {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
padding: 14px;
|
||||
border: 1px solid var(--aksrt-color-border);
|
||||
border: 1px solid var(--jio-color-border);
|
||||
border-radius: 12px;
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
background: #fafafa;
|
||||
}
|
||||
|
||||
.aksrt-update__guide:hover {
|
||||
border-color: var(--aksrt-color-primary);
|
||||
.jio-update__guide:hover {
|
||||
border-color: var(--jio-color-primary);
|
||||
background: #f5faff;
|
||||
}
|
||||
|
||||
.aksrt-update__guide span {
|
||||
.jio-update__guide span {
|
||||
font-size: 12px;
|
||||
color: #667085;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="aksrt-page-container">
|
||||
<div class="jio-page-container">
|
||||
<PageHeader title="用户徽章" desc="配置勋章分类、自动授予条件与前台公开展示。">
|
||||
<template #actions>
|
||||
<n-space>
|
||||
@@ -10,11 +10,11 @@
|
||||
</PageHeader>
|
||||
|
||||
<n-spin :show="loading" style="width: 100%; min-height: 200px;">
|
||||
<n-card class="aksrt-section-card">
|
||||
<div class="aksrt-section-header">
|
||||
<n-card class="jio-section-card">
|
||||
<div class="jio-section-header">
|
||||
<h3>徽章展示</h3>
|
||||
</div>
|
||||
<n-form :model="form" label-placement="left" label-width="180" class="aksrt-form">
|
||||
<n-form :model="form" label-placement="left" label-width="180" class="jio-form">
|
||||
<n-form-item label="启用徽章/勋章系统">
|
||||
<n-switch v-model:value="form.user_medal_s" />
|
||||
</n-form-item>
|
||||
@@ -31,8 +31,8 @@
|
||||
</n-form>
|
||||
</n-card>
|
||||
|
||||
<n-card v-if="form.user_medal_s" class="aksrt-section-card">
|
||||
<div class="aksrt-section-header users-badge__header">
|
||||
<n-card v-if="form.user_medal_s" class="jio-section-card">
|
||||
<div class="jio-section-header users-badge__header">
|
||||
<h3>徽章明细</h3>
|
||||
<span class="users-badge__stats">{{ form.user_medal_args.length }} 个分类 · {{ itemCount }} 枚徽章</span>
|
||||
</div>
|
||||
@@ -40,7 +40,7 @@
|
||||
拖动手柄调整分类与条目顺序,点击行头展开编辑。获取条件选择「仅手动授予」时不自动发放。
|
||||
</p>
|
||||
|
||||
<div v-if="!form.user_medal_args.length" class="aksrt-sortable__empty">
|
||||
<div v-if="!form.user_medal_args.length" class="jio-sortable__empty">
|
||||
<i class="fa fas fa-trophy" aria-hidden="true" />
|
||||
<span>暂无分类,请添加</span>
|
||||
</div>
|
||||
@@ -49,7 +49,7 @@
|
||||
v-model="form.user_medal_args"
|
||||
v-bind="SORTABLE_LIST_ATTRS"
|
||||
:item-key="rowKey"
|
||||
class="aksrt-sortable"
|
||||
class="jio-sortable"
|
||||
>
|
||||
<template #item="{ element, index }">
|
||||
<MedalCategoryCard
|
||||
@@ -68,7 +68,7 @@
|
||||
</n-card>
|
||||
</n-spin>
|
||||
|
||||
<AksSaveBar :dirty="dirty" :saving="saving" @save="handleSave" @reload="load" />
|
||||
<JioSaveBar :dirty="dirty" :saving="saving" @save="handleSave" @reload="load" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -79,7 +79,7 @@ import { useMessage } from 'naive-ui'
|
||||
import draggable from 'vuedraggable'
|
||||
import api from '@/api'
|
||||
import PageHeader from '@/components/PageHeader.vue'
|
||||
import AksSaveBar from '@/components/form/AksSaveBar.vue'
|
||||
import JioSaveBar from '@/components/form/JioSaveBar.vue'
|
||||
import { SORTABLE_LIST_ATTRS } from '@/components/form/sortable-options.js'
|
||||
import { useCollapsibleItems } from '@/components/form/useCollapsibleItems.js'
|
||||
import { defaultMedalArgs } from '@/schema/sections/users/badge.js'
|
||||
@@ -176,13 +176,13 @@ onMounted(load)
|
||||
}
|
||||
|
||||
.users-badge__stats {
|
||||
color: var(--aksrt-color-muted, #6F7A72);
|
||||
color: var(--jio-color-muted, #6F7A72);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.users-badge__hint {
|
||||
margin: 0 0 12px;
|
||||
color: var(--aksrt-color-muted, #6F7A72);
|
||||
color: var(--jio-color-muted, #6F7A72);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="aksrt-page-container">
|
||||
<div class="jio-page-container">
|
||||
<PageHeader
|
||||
title="用户等级"
|
||||
desc="配置等级开关、最高等级、升级经验阈值与经验获取矩阵(对齐 legacy 用户等级 / 经验值)。"
|
||||
@@ -13,8 +13,8 @@
|
||||
</PageHeader>
|
||||
|
||||
<n-spin :show="loading" style="width: 100%; min-height: 200px;">
|
||||
<n-card class="aksrt-section-card">
|
||||
<div class="aksrt-section-header"><h3>当前摘要</h3></div>
|
||||
<n-card class="jio-section-card">
|
||||
<div class="jio-section-header"><h3>当前摘要</h3></div>
|
||||
<n-space>
|
||||
<n-tag round :type="form.user_level_s ? 'success' : 'default'">
|
||||
等级系统:{{ form.user_level_s ? '已启用' : '已关闭' }}
|
||||
@@ -24,9 +24,9 @@
|
||||
</n-space>
|
||||
</n-card>
|
||||
|
||||
<n-card class="aksrt-section-card">
|
||||
<div class="aksrt-section-header"><h3>等级显示</h3></div>
|
||||
<n-form :model="form" label-placement="left" label-width="180" class="aksrt-form">
|
||||
<n-card class="jio-section-card">
|
||||
<div class="jio-section-header"><h3>等级显示</h3></div>
|
||||
<n-form :model="form" label-placement="left" label-width="180" class="jio-form">
|
||||
<n-form-item label="启用用户等级">
|
||||
<n-switch v-model:value="form.user_level_s" />
|
||||
</n-form-item>
|
||||
@@ -42,17 +42,17 @@
|
||||
</n-form>
|
||||
</n-card>
|
||||
|
||||
<n-card v-if="form.user_level_s" class="aksrt-section-card">
|
||||
<div class="aksrt-section-header"><h3>升级所需经验(累计)</h3></div>
|
||||
<n-card v-if="form.user_level_s" class="jio-section-card">
|
||||
<div class="jio-section-header"><h3>升级所需经验(累计)</h3></div>
|
||||
<n-alert type="info" :show-icon="false" style="margin-bottom: 12px;">
|
||||
Lv.1 通常为 0。数值为升到该级所需的累计经验。修改最高等级后会自动补齐/截断行。
|
||||
</n-alert>
|
||||
<n-data-table :columns="levelColumns" :data="levelRows" :bordered="false" size="small" />
|
||||
</n-card>
|
||||
|
||||
<n-card v-if="form.user_level_s" class="aksrt-section-card">
|
||||
<div class="aksrt-section-header"><h3>经验值得分</h3></div>
|
||||
<n-form :model="form" label-placement="left" label-width="180" class="aksrt-form">
|
||||
<n-card v-if="form.user_level_s" class="jio-section-card">
|
||||
<div class="jio-section-header"><h3>经验值得分</h3></div>
|
||||
<n-form :model="form" label-placement="left" label-width="180" class="jio-form">
|
||||
<n-form-item label="每日上限">
|
||||
<n-input-number v-model:value="form.user_integral_opt.day_max" :min="0" :max="10000" style="width: 180px;" />
|
||||
</n-form-item>
|
||||
@@ -71,7 +71,7 @@
|
||||
</div>
|
||||
</n-card>
|
||||
|
||||
<div class="aksrt-form-actions">
|
||||
<div class="jio-form-actions">
|
||||
<n-button type="primary" :loading="saving" @click="handleSave">保存配置</n-button>
|
||||
</div>
|
||||
</n-spin>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="aksrt-page-container">
|
||||
<div class="jio-page-container">
|
||||
<PageHeader
|
||||
title="工单中心"
|
||||
desc="工单功能开关、提交公告与提交表单配置,以及部门、状态、预设回复三块字典维护。工单的日常处理在 WordPress 用户菜单的「工单管理」中完成。"
|
||||
@@ -11,7 +11,7 @@
|
||||
</template>
|
||||
</PageHeader>
|
||||
|
||||
<n-tabs v-model:value="activeTab" type="segment" animated class="aksrt-ticket-tabs">
|
||||
<n-tabs v-model:value="activeTab" type="segment" animated class="jio-ticket-tabs">
|
||||
<n-tab-pane name="settings" tab="基础配置">
|
||||
<SchemaPage domain="users" section="ticket" />
|
||||
</n-tab-pane>
|
||||
@@ -57,13 +57,13 @@ watch(activeTab, (name) => {
|
||||
})
|
||||
|
||||
function openNativeList() {
|
||||
const base = (window.aksrtAdminData?.adminUrl || '/wp-admin/').replace(/\/?$/, '/')
|
||||
window.location.href = base + 'users.php?page=aksrt_tickets'
|
||||
const base = (window.jioAdminData?.adminUrl || '/wp-admin/').replace(/\/?$/, '/')
|
||||
window.location.href = base + 'users.php?page=jio_tickets'
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.aksrt-ticket-tabs {
|
||||
.jio-ticket-tabs {
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,8 +1,8 @@
|
||||
<template>
|
||||
<div class="aksrt-page-container">
|
||||
<div class="jio-page-container">
|
||||
<PageHeader title="身份认证" desc="配置通用认证申请规则;申请审核和用户认证资料管理位于 WordPress 用户菜单。" />
|
||||
<n-spin :show="loading" style="width: 100%; min-height: 240px">
|
||||
<n-card class="aksrt-section-card" title="认证申请设置">
|
||||
<n-card class="jio-section-card" title="认证申请设置">
|
||||
<n-form :model="form" label-placement="left" label-width="190">
|
||||
<n-form-item label="启用身份认证"><n-switch v-model:value="form.user_auth_s" /></n-form-item>
|
||||
<n-form-item label="允许用户前台申请"><n-switch v-model:value="form.user_auth_apply_s" :disabled="!form.user_auth_s" /></n-form-item>
|
||||
@@ -18,7 +18,7 @@
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
</n-card>
|
||||
<div class="aksrt-form-actions">
|
||||
<div class="jio-form-actions">
|
||||
<n-button :disabled="!dirty || saving" @click="load">放弃更改</n-button>
|
||||
<n-button type="primary" :disabled="!dirty" :loading="saving" @click="save">保存设置</n-button>
|
||||
</div>
|
||||
|
||||
@@ -1,80 +1,80 @@
|
||||
<template>
|
||||
<div class="aksrt-page-container">
|
||||
<div class="jio-page-container">
|
||||
<PageHeader title="微信模板消息" desc="配置微信公众号模板消息推送。" />
|
||||
|
||||
<!-- 状态卡片 -->
|
||||
<div class="aksrt-wechat__status">
|
||||
<div class="aksrt-wechat__status-card">
|
||||
<div class="aksrt-wechat__status-icon" :class="status.configured ? 'aksrt-wechat__status-icon--ok' : 'aksrt-wechat__status-icon--warn'">
|
||||
<div class="jio-wechat__status">
|
||||
<div class="jio-wechat__status-card">
|
||||
<div class="jio-wechat__status-icon" :class="status.configured ? 'jio-wechat__status-icon--ok' : 'jio-wechat__status-icon--warn'">
|
||||
<i :class="status.configured ? 'fa fas fa-check' : 'fa fas fa-exclamation'"></i>
|
||||
</div>
|
||||
<div class="aksrt-wechat__status-info">
|
||||
<div class="aksrt-wechat__status-label">配置状态</div>
|
||||
<div class="aksrt-wechat__status-value">{{ status.configured ? '已配置' : '未配置' }}</div>
|
||||
<div class="jio-wechat__status-info">
|
||||
<div class="jio-wechat__status-label">配置状态</div>
|
||||
<div class="jio-wechat__status-value">{{ status.configured ? '已配置' : '未配置' }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="aksrt-wechat__status-card">
|
||||
<div class="aksrt-wechat__status-icon" :class="status.has_token ? 'aksrt-wechat__status-icon--ok' : 'aksrt-wechat__status-icon--warn'">
|
||||
<div class="jio-wechat__status-card">
|
||||
<div class="jio-wechat__status-icon" :class="status.has_token ? 'jio-wechat__status-icon--ok' : 'jio-wechat__status-icon--warn'">
|
||||
<i :class="status.has_token ? 'fa fas fa-key' : 'fa fas fa-key'"></i>
|
||||
</div>
|
||||
<div class="aksrt-wechat__status-info">
|
||||
<div class="aksrt-wechat__status-label">Access Token</div>
|
||||
<div class="aksrt-wechat__status-value">{{ status.has_token ? '已获取' : '未获取' }}</div>
|
||||
<div class="jio-wechat__status-info">
|
||||
<div class="jio-wechat__status-label">Access Token</div>
|
||||
<div class="jio-wechat__status-value">{{ status.has_token ? '已获取' : '未获取' }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="aksrt-wechat__status-card">
|
||||
<div class="aksrt-wechat__status-icon" :class="status.has_template ? 'aksrt-wechat__status-icon--ok' : 'aksrt-wechat__status-icon--warn'">
|
||||
<div class="jio-wechat__status-card">
|
||||
<div class="jio-wechat__status-icon" :class="status.has_template ? 'jio-wechat__status-icon--ok' : 'jio-wechat__status-icon--warn'">
|
||||
<i :class="status.has_template ? 'fa fas fa-file-alt' : 'fa fas fa-file-alt'"></i>
|
||||
</div>
|
||||
<div class="aksrt-wechat__status-info">
|
||||
<div class="aksrt-wechat__status-label">模板 ID</div>
|
||||
<div class="aksrt-wechat__status-value">{{ status.has_template ? '已配置' : '未配置' }}</div>
|
||||
<div class="jio-wechat__status-info">
|
||||
<div class="jio-wechat__status-label">模板 ID</div>
|
||||
<div class="jio-wechat__status-value">{{ status.has_template ? '已配置' : '未配置' }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="aksrt-wechat__status-card">
|
||||
<div class="aksrt-wechat__status-icon aksrt-wechat__status-icon--info">
|
||||
<div class="jio-wechat__status-card">
|
||||
<div class="jio-wechat__status-icon jio-wechat__status-icon--info">
|
||||
<i class="fa fas fa-users"></i>
|
||||
</div>
|
||||
<div class="aksrt-wechat__status-info">
|
||||
<div class="aksrt-wechat__status-label">绑定用户</div>
|
||||
<div class="aksrt-wechat__status-value">{{ status.bound_users || 0 }} 人</div>
|
||||
<div class="jio-wechat__status-info">
|
||||
<div class="jio-wechat__status-label">绑定用户</div>
|
||||
<div class="jio-wechat__status-value">{{ status.bound_users || 0 }} 人</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 配置表单 -->
|
||||
<div class="aksrt-wechat__form-card">
|
||||
<div class="jio-wechat__form-card">
|
||||
<h3>基本配置</h3>
|
||||
<div class="aksrt-form-group">
|
||||
<div class="jio-form-group">
|
||||
<label>
|
||||
<input type="checkbox" v-model="form.enabled"> 启用微信模板消息
|
||||
</label>
|
||||
</div>
|
||||
<div class="aksrt-form-group">
|
||||
<div class="jio-form-group">
|
||||
<label>AppID</label>
|
||||
<input v-model="form.app_id" type="text" class="aksrt-input" placeholder="微信公众号 AppID">
|
||||
<input v-model="form.app_id" type="text" class="jio-input" placeholder="微信公众号 AppID">
|
||||
</div>
|
||||
<div class="aksrt-form-group">
|
||||
<div class="jio-form-group">
|
||||
<label>AppSecret</label>
|
||||
<input v-model="form.app_secret" type="password" class="aksrt-input" placeholder="微信公众号 AppSecret">
|
||||
<p class="aksrt-form-hint">保存后不会回显完整密钥</p>
|
||||
<input v-model="form.app_secret" type="password" class="jio-input" placeholder="微信公众号 AppSecret">
|
||||
<p class="jio-form-hint">保存后不会回显完整密钥</p>
|
||||
</div>
|
||||
<div class="aksrt-form-group">
|
||||
<div class="jio-form-group">
|
||||
<label>模板 ID</label>
|
||||
<input v-model="form.template_id" type="text" class="aksrt-input" placeholder="微信模板消息模板 ID">
|
||||
<input v-model="form.template_id" type="text" class="jio-input" placeholder="微信模板消息模板 ID">
|
||||
</div>
|
||||
<div class="aksrt-form-actions">
|
||||
<button class="aksrt-button aksrt-button--primary" :disabled="saving" @click="saveSettings">
|
||||
<div class="jio-form-actions">
|
||||
<button class="jio-button jio-button--primary" :disabled="saving" @click="saveSettings">
|
||||
{{ saving ? '保存中...' : '保存设置' }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 通知类型 -->
|
||||
<div class="aksrt-wechat__form-card">
|
||||
<div class="jio-wechat__form-card">
|
||||
<h3>支持的通知类型</h3>
|
||||
<p class="aksrt-form-hint">以下事件类型可触发微信模板消息推送(需用户绑定微信且开启对应订阅):</p>
|
||||
<table class="aksrt-table aksrt-table--sm">
|
||||
<p class="jio-form-hint">以下事件类型可触发微信模板消息推送(需用户绑定微信且开启对应订阅):</p>
|
||||
<table class="jio-table jio-table--sm">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>事件类型</th>
|
||||
@@ -87,7 +87,7 @@
|
||||
<td><code>{{ evt.key }}</code></td>
|
||||
<td>{{ evt.desc }}</td>
|
||||
<td>
|
||||
<span class="aksrt-badge" :class="evt.ready ? 'aksrt-badge--success' : 'aksrt-badge--warning'">
|
||||
<span class="jio-badge" :class="evt.ready ? 'jio-badge--success' : 'jio-badge--warning'">
|
||||
{{ evt.ready ? '可用' : '待接入' }}
|
||||
</span>
|
||||
</td>
|
||||
@@ -192,13 +192,13 @@ export default {
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.aksrt-wechat__status {
|
||||
.jio-wechat__status {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: 16px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
.aksrt-wechat__status-card {
|
||||
.jio-wechat__status-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
@@ -207,7 +207,7 @@ export default {
|
||||
border-radius: 8px;
|
||||
border: 1px solid #e8e8e8;
|
||||
}
|
||||
.aksrt-wechat__status-icon {
|
||||
.jio-wechat__status-icon {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 8px;
|
||||
@@ -216,40 +216,40 @@ export default {
|
||||
justify-content: center;
|
||||
font-size: 16px;
|
||||
}
|
||||
.aksrt-wechat__status-icon--ok {
|
||||
.jio-wechat__status-icon--ok {
|
||||
background: #d4edda;
|
||||
color: #155724;
|
||||
}
|
||||
.aksrt-wechat__status-icon--warn {
|
||||
.jio-wechat__status-icon--warn {
|
||||
background: #fff3cd;
|
||||
color: #856404;
|
||||
}
|
||||
.aksrt-wechat__status-icon--info {
|
||||
.jio-wechat__status-icon--info {
|
||||
background: #d1ecf1;
|
||||
color: #0c5460;
|
||||
}
|
||||
.aksrt-wechat__status-value {
|
||||
.jio-wechat__status-value {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: var(--aksrt-color-text);
|
||||
color: var(--jio-color-text);
|
||||
}
|
||||
.aksrt-wechat__status-label {
|
||||
.jio-wechat__status-label {
|
||||
font-size: 12px;
|
||||
color: #888;
|
||||
}
|
||||
.aksrt-wechat__form-card {
|
||||
.jio-wechat__form-card {
|
||||
background: #fff;
|
||||
border: 1px solid #e8e8e8;
|
||||
border-radius: 8px;
|
||||
padding: 24px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
.aksrt-wechat__form-card h3 {
|
||||
.jio-wechat__form-card h3 {
|
||||
margin: 0 0 16px;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
}
|
||||
.aksrt-form-hint {
|
||||
.jio-form-hint {
|
||||
font-size: 12px;
|
||||
color: #888;
|
||||
margin-top: 4px;
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
<template>
|
||||
<div class="aksrt-sortable__item">
|
||||
<div class="aksrt-sortable__head" v-bind="headAttrs">
|
||||
<AksSortHandle @click.stop />
|
||||
<span class="aksrt-sortable__index">{{ index + 1 }}</span>
|
||||
<div class="aksrt-sortable__main">
|
||||
<div class="aksrt-sortable__title-row">
|
||||
<span class="aksrt-sortable__title">{{ category.cat_name || '未命名分类' }}</span>
|
||||
<div class="jio-sortable__item">
|
||||
<div class="jio-sortable__head" v-bind="headAttrs">
|
||||
<JioSortHandle @click.stop />
|
||||
<span class="jio-sortable__index">{{ index + 1 }}</span>
|
||||
<div class="jio-sortable__main">
|
||||
<div class="jio-sortable__title-row">
|
||||
<span class="jio-sortable__title">{{ category.cat_name || '未命名分类' }}</span>
|
||||
<n-tag size="small" :bordered="false">{{ category.items.length }} 枚</n-tag>
|
||||
</div>
|
||||
<span class="aksrt-sortable__desc">{{ previewNames || '该分类暂无条目' }}</span>
|
||||
<span class="jio-sortable__desc">{{ previewNames || '该分类暂无条目' }}</span>
|
||||
</div>
|
||||
<div class="aksrt-sortable__actions">
|
||||
<div class="jio-sortable__actions">
|
||||
<n-popconfirm @positive-click="emit('remove')">
|
||||
<template #trigger>
|
||||
<n-button size="tiny" quaternary type="error" title="删除分类" @click.stop>
|
||||
@@ -20,17 +20,17 @@
|
||||
删除分类「{{ category.cat_name || '未命名分类' }}」及其全部条目?
|
||||
</n-popconfirm>
|
||||
</div>
|
||||
<i class="fa fas aksrt-sortable__toggle" :class="open ? 'fa-chevron-down' : 'fa-chevron-right'" aria-hidden="true" />
|
||||
<i class="fa fas jio-sortable__toggle" :class="open ? 'fa-chevron-down' : 'fa-chevron-right'" aria-hidden="true" />
|
||||
</div>
|
||||
|
||||
<div v-if="open" class="aksrt-sortable__body">
|
||||
<n-form label-placement="left" label-width="96" class="aksrt-form">
|
||||
<div v-if="open" class="jio-sortable__body">
|
||||
<n-form label-placement="left" label-width="96" class="jio-form">
|
||||
<n-form-item label="分类名称">
|
||||
<n-input v-model:value="category.cat_name" placeholder="如:成长" style="max-width: 320px;" />
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
|
||||
<div v-if="!category.items.length" class="aksrt-sortable__empty">
|
||||
<div v-if="!category.items.length" class="jio-sortable__empty">
|
||||
<i class="fa fas fa-medal" aria-hidden="true" />
|
||||
<span>该分类暂无条目</span>
|
||||
</div>
|
||||
@@ -39,7 +39,7 @@
|
||||
v-model="category.items"
|
||||
v-bind="SORTABLE_LIST_ATTRS"
|
||||
:item-key="rowKey"
|
||||
class="aksrt-sortable aksrt-sortable--compact"
|
||||
class="jio-sortable jio-sortable--compact"
|
||||
>
|
||||
<template #item="{ element, index: ii }">
|
||||
<MedalItemCard
|
||||
@@ -62,7 +62,7 @@
|
||||
/** 徽章分类卡片:行头显示条目数与名称预览,展开后编辑分类名并拖拽排序条目。 */
|
||||
import { computed } from 'vue'
|
||||
import draggable from 'vuedraggable'
|
||||
import AksSortHandle from '@/components/form/AksSortHandle.vue'
|
||||
import JioSortHandle from '@/components/form/JioSortHandle.vue'
|
||||
import { SORTABLE_LIST_ATTRS } from '@/components/form/sortable-options.js'
|
||||
import { useCollapsibleItems } from '@/components/form/useCollapsibleItems.js'
|
||||
import { emptyItem, rowKey } from './badge-model.js'
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<img :src="src" :alt="`预设图标 ${i + 1}`" />
|
||||
</button>
|
||||
</div>
|
||||
<AksMediaField
|
||||
<JioMediaField
|
||||
:model-value="modelValue"
|
||||
placeholder="或从媒体库选择自定义图标"
|
||||
@update:model-value="emit('update:modelValue', $event)"
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
<script setup>
|
||||
/** 勋章图标选择:主题预设 SVG 一键选用,或走媒体库 / 直接填 URL。 */
|
||||
import AksMediaField from '@/components/form/AksMediaField.vue'
|
||||
import JioMediaField from '@/components/form/JioMediaField.vue'
|
||||
import { MEDAL_PRESET_ICONS } from '@/schema/sections/users/badge.js'
|
||||
|
||||
defineProps({
|
||||
@@ -55,9 +55,9 @@ const emit = defineEmits(['update:modelValue'])
|
||||
justify-content: center;
|
||||
height: 36px;
|
||||
padding: 0;
|
||||
border: 1px solid var(--aksrt-color-border, #E2E8E3);
|
||||
border: 1px solid var(--jio-color-border, #E2E8E3);
|
||||
border-radius: 8px;
|
||||
background: var(--aksrt-color-surface, #fff);
|
||||
background: var(--jio-color-surface, #fff);
|
||||
cursor: pointer;
|
||||
transition: border-color .15s ease, background-color .15s ease;
|
||||
}
|
||||
@@ -70,13 +70,13 @@ const emit = defineEmits(['update:modelValue'])
|
||||
|
||||
.medal-icon-picker__preset:hover,
|
||||
.medal-icon-picker__preset:focus-visible {
|
||||
border-color: var(--aksrt-color-primary, #18A058);
|
||||
border-color: var(--jio-color-primary, #18A058);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.medal-icon-picker__preset.is-active {
|
||||
border-color: var(--aksrt-color-primary, #18A058);
|
||||
background: var(--aksrt-color-primary-soft, #EAF7EF);
|
||||
box-shadow: 0 0 0 1px var(--aksrt-color-primary, #18A058);
|
||||
border-color: var(--jio-color-primary, #18A058);
|
||||
background: var(--jio-color-primary-soft, #EAF7EF);
|
||||
box-shadow: 0 0 0 1px var(--jio-color-primary, #18A058);
|
||||
}
|
||||
</style>
|
||||
@@ -1,31 +1,31 @@
|
||||
<template>
|
||||
<div class="aksrt-sortable__item">
|
||||
<div class="aksrt-sortable__head" v-bind="headAttrs">
|
||||
<AksSortHandle @click.stop />
|
||||
<span class="aksrt-sortable__icon">
|
||||
<div class="jio-sortable__item">
|
||||
<div class="jio-sortable__head" v-bind="headAttrs">
|
||||
<JioSortHandle @click.stop />
|
||||
<span class="jio-sortable__icon">
|
||||
<img v-if="item.icon" :src="item.icon" alt="" />
|
||||
<i v-else class="fa fas fa-medal" aria-hidden="true" />
|
||||
</span>
|
||||
<div class="aksrt-sortable__main">
|
||||
<div class="aksrt-sortable__title-row">
|
||||
<span class="aksrt-sortable__title">{{ item.name || '未命名徽章' }}</span>
|
||||
<div class="jio-sortable__main">
|
||||
<div class="jio-sortable__title-row">
|
||||
<span class="jio-sortable__title">{{ item.name || '未命名徽章' }}</span>
|
||||
<n-tag size="small" :bordered="false" :type="item.get_type === 'manually_add' ? 'default' : 'info'">
|
||||
{{ conditionSummary(item) }}
|
||||
</n-tag>
|
||||
<n-tag v-if="!item.slug" size="small" type="warning" :bordered="false">缺少 slug</n-tag>
|
||||
</div>
|
||||
<span class="aksrt-sortable__desc">{{ item.slug || '—' }}{{ item.desc ? ` · ${item.desc}` : '' }}</span>
|
||||
<span class="jio-sortable__desc">{{ item.slug || '—' }}{{ item.desc ? ` · ${item.desc}` : '' }}</span>
|
||||
</div>
|
||||
<div class="aksrt-sortable__actions">
|
||||
<div class="jio-sortable__actions">
|
||||
<n-button size="tiny" quaternary type="error" title="删除条目" @click.stop="emit('remove')">
|
||||
<i class="fa fas fa-trash-alt" aria-hidden="true" />
|
||||
</n-button>
|
||||
</div>
|
||||
<i class="fa fas aksrt-sortable__toggle" :class="open ? 'fa-chevron-down' : 'fa-chevron-right'" aria-hidden="true" />
|
||||
<i class="fa fas jio-sortable__toggle" :class="open ? 'fa-chevron-down' : 'fa-chevron-right'" aria-hidden="true" />
|
||||
</div>
|
||||
|
||||
<div v-if="open" class="aksrt-sortable__body">
|
||||
<n-form label-placement="left" label-width="96" class="aksrt-form medal-item-card__form">
|
||||
<div v-if="open" class="jio-sortable__body">
|
||||
<n-form label-placement="left" label-width="96" class="jio-form medal-item-card__form">
|
||||
<n-grid cols="1 m:2" :x-gap="16" responsive="screen">
|
||||
<n-form-item-gi label="名称">
|
||||
<n-input v-model:value="item.name" placeholder="如:签到达人" />
|
||||
@@ -59,7 +59,7 @@
|
||||
|
||||
<script setup>
|
||||
/** 徽章条目卡片:行头摘要(图标 / 名称 / 条件),展开后编辑字段。条目对象由父级直接持有并原地修改。 */
|
||||
import AksSortHandle from '@/components/form/AksSortHandle.vue'
|
||||
import JioSortHandle from '@/components/form/JioSortHandle.vue'
|
||||
import { MEDAL_GET_TYPES } from '@/schema/sections/users/badge.js'
|
||||
import { conditionSummary } from './badge-model.js'
|
||||
import MedalIconPicker from './MedalIconPicker.vue'
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<n-card class="aksrt-section-card">
|
||||
<div class="aksrt-section-header">
|
||||
<n-card class="jio-section-card">
|
||||
<div class="jio-section-header">
|
||||
<h3>预设回复</h3>
|
||||
<n-space>
|
||||
<n-button size="small" :disabled="saving || !reorderable" :loading="savingOrder" @click="saveOrder">
|
||||
@@ -21,17 +21,17 @@
|
||||
v-model="rows"
|
||||
v-bind="SORTABLE_LIST_ATTRS"
|
||||
item-key="id"
|
||||
class="aksrt-sortable"
|
||||
class="jio-sortable"
|
||||
>
|
||||
<template #item="{ element, index }">
|
||||
<div class="aksrt-sortable__item">
|
||||
<div class="aksrt-sortable__head">
|
||||
<AksSortHandle />
|
||||
<span class="aksrt-sortable__index">{{ index + 1 }}</span>
|
||||
<div class="aksrt-sortable__main">
|
||||
<span class="aksrt-ticket-prereply__content">{{ element.content }}</span>
|
||||
<div class="jio-sortable__item">
|
||||
<div class="jio-sortable__head">
|
||||
<JioSortHandle />
|
||||
<span class="jio-sortable__index">{{ index + 1 }}</span>
|
||||
<div class="jio-sortable__main">
|
||||
<span class="jio-ticket-prereply__content">{{ element.content }}</span>
|
||||
</div>
|
||||
<div class="aksrt-sortable__actions">
|
||||
<div class="jio-sortable__actions">
|
||||
<n-button size="tiny" type="primary" quaternary @click="openEdit(element)">编辑</n-button>
|
||||
<n-button size="tiny" type="error" quaternary @click="handleDelete(element)">删除</n-button>
|
||||
</div>
|
||||
@@ -74,7 +74,7 @@ import { computed, onMounted, ref } from 'vue'
|
||||
import { NButton, NSpace, useDialog, useMessage } from 'naive-ui'
|
||||
import draggable from 'vuedraggable'
|
||||
import api from '@/api'
|
||||
import AksSortHandle from '@/components/form/AksSortHandle.vue'
|
||||
import JioSortHandle from '@/components/form/JioSortHandle.vue'
|
||||
import { SORTABLE_LIST_ATTRS } from '@/components/form/sortable-options.js'
|
||||
|
||||
const message = useMessage()
|
||||
@@ -193,8 +193,8 @@ defineExpose({ reload: load })
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.aksrt-ticket-prereply__content {
|
||||
color: var(--aksrt-color-text, #1F2923);
|
||||
.jio-ticket-prereply__content {
|
||||
color: var(--jio-color-text, #1F2923);
|
||||
font-size: 13px;
|
||||
line-height: 1.6;
|
||||
white-space: pre-wrap;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<n-card class="aksrt-section-card aksrt-ticket-status-panel">
|
||||
<div class="aksrt-section-header">
|
||||
<n-card class="jio-section-card jio-ticket-status-panel">
|
||||
<div class="jio-section-header">
|
||||
<h3>工单状态</h3>
|
||||
<n-button size="small" type="primary" :disabled="saving" @click="openCreate">新增状态</n-button>
|
||||
</div>
|
||||
@@ -24,13 +24,13 @@
|
||||
v-model:show="visible"
|
||||
:title="editing ? '编辑状态' : '新增状态'"
|
||||
preset="card"
|
||||
class="aksrt-status-modal"
|
||||
class="jio-status-modal"
|
||||
style="width: 460px; max-width: 92vw;"
|
||||
:mask-closable="false"
|
||||
>
|
||||
<div class="aksrt-status-preview" aria-live="polite">
|
||||
<span class="aksrt-status-preview__label">预览</span>
|
||||
<span class="aksrt-ticket-badge" :style="{ '--aksrt-ticket-color': previewColor }">
|
||||
<div class="jio-status-preview" aria-live="polite">
|
||||
<span class="jio-status-preview__label">预览</span>
|
||||
<span class="jio-ticket-badge" :style="{ '--jio-ticket-color': previewColor }">
|
||||
{{ form.name.trim() || '状态名称' }}
|
||||
</span>
|
||||
</div>
|
||||
@@ -40,30 +40,30 @@
|
||||
<n-input v-model:value="form.name" placeholder="如:处理中" maxlength="60" show-count />
|
||||
</n-form-item>
|
||||
<n-form-item label="标识" path="status_key">
|
||||
<div class="aksrt-status-key">
|
||||
<div class="jio-status-key">
|
||||
<n-input
|
||||
v-model:value="form.status_key"
|
||||
class="aksrt-status-key__input"
|
||||
class="jio-status-key__input"
|
||||
:placeholder="editing ? '' : '留空则按名称自动生成'"
|
||||
maxlength="24"
|
||||
show-count
|
||||
:input-props="{ autocomplete: 'off', spellcheck: false }"
|
||||
@blur="form.status_key = normalizeKey(form.status_key)"
|
||||
/>
|
||||
<span class="aksrt-ticket-status__hint">
|
||||
<span class="jio-ticket-status__hint">
|
||||
小写字母开头,仅含小写字母、数字与下划线(2–24 位)。修改后,使用该状态的工单会同步改为新标识。
|
||||
</span>
|
||||
</div>
|
||||
</n-form-item>
|
||||
<n-form-item label="状态颜色" path="color">
|
||||
<div class="aksrt-status-color">
|
||||
<div class="aksrt-status-color__swatches" role="radiogroup" aria-label="状态颜色">
|
||||
<div class="jio-status-color">
|
||||
<div class="jio-status-color__swatches" role="radiogroup" aria-label="状态颜色">
|
||||
<button
|
||||
v-for="swatch in SWATCHES"
|
||||
:key="swatch"
|
||||
type="button"
|
||||
role="radio"
|
||||
class="aksrt-status-color__swatch"
|
||||
class="jio-status-color__swatch"
|
||||
:class="{ 'is-active': currentHex === swatch }"
|
||||
:style="{ '--swatch': swatch }"
|
||||
:aria-checked="currentHex === swatch"
|
||||
@@ -72,7 +72,7 @@
|
||||
@click="form.color = swatch"
|
||||
/>
|
||||
<!-- 自定义色:未选中时显示色环,选中后显示当前色并带选中环。 -->
|
||||
<AksColorPicker
|
||||
<JioColorPicker
|
||||
:model-value="previewColor"
|
||||
@update:model-value="setColor"
|
||||
>
|
||||
@@ -81,7 +81,7 @@
|
||||
:ref="setTriggerRef"
|
||||
type="button"
|
||||
role="radio"
|
||||
class="aksrt-status-color__swatch aksrt-status-color__swatch--custom"
|
||||
class="jio-status-color__swatch jio-status-color__swatch--custom"
|
||||
:class="{ 'is-active': isCustomColor }"
|
||||
:style="{ '--swatch': previewColor }"
|
||||
:aria-checked="isCustomColor"
|
||||
@@ -90,25 +90,25 @@
|
||||
@click="onClick"
|
||||
/>
|
||||
</template>
|
||||
</AksColorPicker>
|
||||
</JioColorPicker>
|
||||
</div>
|
||||
<n-input
|
||||
v-model:value="form.color"
|
||||
class="aksrt-status-color__hex"
|
||||
class="jio-status-color__hex"
|
||||
maxlength="7"
|
||||
placeholder="#6b7280"
|
||||
@blur="form.color = toHex(form.color) || form.color.trim()"
|
||||
>
|
||||
<template #prefix>
|
||||
<i class="aksrt-status-color__chip" :style="{ background: previewColor }" />
|
||||
<i class="jio-status-color__chip" :style="{ background: previewColor }" />
|
||||
</template>
|
||||
</n-input>
|
||||
</div>
|
||||
</n-form-item>
|
||||
<n-form-item label="完结状态" path="is_closed" :show-feedback="false">
|
||||
<div class="aksrt-status-closed">
|
||||
<div class="jio-status-closed">
|
||||
<n-switch v-model:value="form.is_closed" />
|
||||
<span class="aksrt-ticket-status__hint">开启后该状态视为终态,工单不可再流转</span>
|
||||
<span class="jio-ticket-status__hint">开启后该状态视为终态,工单不可再流转</span>
|
||||
</div>
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
@@ -126,7 +126,7 @@
|
||||
import { computed, h, onMounted, ref } from 'vue'
|
||||
import { NButton, NSpace, useDialog, useMessage } from 'naive-ui'
|
||||
import api from '@/api'
|
||||
import AksColorPicker from '@/components/form/AksColorPicker.vue'
|
||||
import JioColorPicker from '@/components/form/JioColorPicker.vue'
|
||||
import { toHex } from '@/utils/color.js'
|
||||
|
||||
const message = useMessage()
|
||||
@@ -194,7 +194,7 @@ const currentHex = computed(() => toHex(form.value.color))
|
||||
const previewColor = computed(() => currentHex.value || DEFAULT_COLOR)
|
||||
const isCustomColor = computed(() => currentHex.value !== '' && !SWATCHES.includes(currentHex.value))
|
||||
|
||||
/** AksColorPicker 已归一化为 hex;清空(空串)时保留当前色。 */
|
||||
/** JioColorPicker 已归一化为 hex;清空(空串)时保留当前色。 */
|
||||
function setColor(value) {
|
||||
const hex = toHex(value)
|
||||
if (hex) form.value.color = hex
|
||||
@@ -208,15 +208,15 @@ const columns = computed(() => [
|
||||
minWidth: 160,
|
||||
// 注意:原生元素用 h('span', ...) 时,文本必须作为 children 直接传入;
|
||||
// 写成 () => row.name 的插槽函数对原生元素不生效,单元格会是空的。
|
||||
render: (row) => h('span', { class: 'aksrt-ticket-badge', style: { '--aksrt-ticket-color': row.color } }, row.name),
|
||||
render: (row) => h('span', { class: 'jio-ticket-badge', style: { '--jio-ticket-color': row.color } }, row.name),
|
||||
},
|
||||
{
|
||||
title: '颜色',
|
||||
key: 'color',
|
||||
width: 140,
|
||||
render: (row) => h('span', { class: 'aksrt-ticket-color-cell' }, [
|
||||
h('i', { class: 'aksrt-ticket-color-dot', style: { background: row.color } }),
|
||||
h('span', { class: 'aksrt-ticket-color-value' }, row.color),
|
||||
render: (row) => h('span', { class: 'jio-ticket-color-cell' }, [
|
||||
h('i', { class: 'jio-ticket-color-dot', style: { background: row.color } }),
|
||||
h('span', { class: 'jio-ticket-color-value' }, row.color),
|
||||
]),
|
||||
},
|
||||
{
|
||||
@@ -235,7 +235,7 @@ const columns = computed(() => [
|
||||
title: '标识',
|
||||
key: 'status_key',
|
||||
minWidth: 140,
|
||||
render: (row) => h('span', { class: 'aksrt-ticket-key' }, row.status_key),
|
||||
render: (row) => h('span', { class: 'jio-ticket-key' }, row.status_key),
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
@@ -348,13 +348,13 @@ defineExpose({ reload: load })
|
||||
(此前色块 <i> 因此没有尺寸,颜色列只剩色值文本。)
|
||||
-->
|
||||
<style>
|
||||
.aksrt-ticket-status-panel .aksrt-ticket-color-cell {
|
||||
.jio-ticket-status-panel .jio-ticket-color-cell {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.aksrt-ticket-status-panel .aksrt-ticket-color-dot {
|
||||
.jio-ticket-status-panel .jio-ticket-color-dot {
|
||||
display: inline-block;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
@@ -363,21 +363,21 @@ defineExpose({ reload: load })
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.aksrt-ticket-status-panel .aksrt-ticket-color-value,
|
||||
.aksrt-ticket-status-panel .aksrt-ticket-key {
|
||||
.jio-ticket-status-panel .jio-ticket-color-value,
|
||||
.jio-ticket-status-panel .jio-ticket-key {
|
||||
font-family: var(--n-font-family-mono, ui-monospace, SFMono-Regular, Menlo, Consolas, monospace);
|
||||
font-size: 12px;
|
||||
color: var(--aksrt-color-muted);
|
||||
color: var(--jio-color-muted);
|
||||
}
|
||||
|
||||
/* 徽章与前台 assets/css/routes/tickets.css 的 .aksrt-ticket-badge 同构;表格与弹窗预览共用。 */
|
||||
.aksrt-ticket-status-panel .aksrt-ticket-badge,
|
||||
.aksrt-status-modal .aksrt-ticket-badge {
|
||||
/* 徽章与前台 assets/css/routes/tickets.css 的 .jio-ticket-badge 同构;表格与弹窗预览共用。 */
|
||||
.jio-ticket-status-panel .jio-ticket-badge,
|
||||
.jio-status-modal .jio-ticket-badge {
|
||||
display: inline-block;
|
||||
padding: 2px 10px;
|
||||
border-radius: 999px;
|
||||
background: color-mix(in srgb, var(--aksrt-ticket-color, #6b7280) 16%, transparent);
|
||||
color: var(--aksrt-ticket-color, #6b7280);
|
||||
background: color-mix(in srgb, var(--jio-ticket-color, #6b7280) 16%, transparent);
|
||||
color: var(--jio-ticket-color, #6b7280);
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
line-height: 1.6;
|
||||
@@ -387,24 +387,24 @@ defineExpose({ reload: load })
|
||||
|
||||
<style scoped>
|
||||
/* —— 弹窗:顶部实时预览 —— */
|
||||
.aksrt-status-preview {
|
||||
.jio-status-preview {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
margin-bottom: 18px;
|
||||
padding: 14px 16px;
|
||||
border: 1px dashed var(--aksrt-color-border);
|
||||
border: 1px dashed var(--jio-color-border);
|
||||
border-radius: 8px;
|
||||
background: rgba(0, 0, 0, 0.02);
|
||||
}
|
||||
|
||||
.aksrt-status-preview__label {
|
||||
color: var(--aksrt-color-muted);
|
||||
.jio-status-preview__label {
|
||||
color: var(--jio-color-muted);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.aksrt-status-preview .aksrt-ticket-badge {
|
||||
.jio-status-preview .jio-ticket-badge {
|
||||
max-width: 70%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
@@ -412,20 +412,20 @@ defineExpose({ reload: load })
|
||||
}
|
||||
|
||||
/* —— 弹窗:颜色选择(预设色板 + 自定义 + 十六进制输入) —— */
|
||||
.aksrt-status-color {
|
||||
.jio-status-color {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.aksrt-status-color__swatches {
|
||||
.jio-status-color__swatches {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.aksrt-status-color__swatch {
|
||||
.jio-status-color__swatch {
|
||||
position: relative;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
@@ -438,21 +438,21 @@ defineExpose({ reload: load })
|
||||
transition: transform 0.12s ease, box-shadow 0.12s ease;
|
||||
}
|
||||
|
||||
.aksrt-status-color__swatch:hover {
|
||||
.jio-status-color__swatch:hover {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
.aksrt-status-color__swatch:focus-visible {
|
||||
outline: 2px solid var(--aksrt-color-primary, #2271b1);
|
||||
.jio-status-color__swatch:focus-visible {
|
||||
outline: 2px solid var(--jio-color-primary, #2271b1);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
/* 选中态:白色内圈 + 同色外环,深浅主题都清晰。 */
|
||||
.aksrt-status-color__swatch.is-active {
|
||||
.jio-status-color__swatch.is-active {
|
||||
box-shadow: 0 0 0 2px #fff, 0 0 0 4px var(--swatch);
|
||||
}
|
||||
|
||||
.aksrt-status-color__swatch.is-active::after {
|
||||
.jio-status-color__swatch.is-active::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
@@ -465,11 +465,11 @@ defineExpose({ reload: load })
|
||||
}
|
||||
|
||||
/* 自定义:未选中时显示色环,提示「更多颜色」。 */
|
||||
.aksrt-status-color__swatch--custom:not(.is-active) {
|
||||
.jio-status-color__swatch--custom:not(.is-active) {
|
||||
background: conic-gradient(#ef4444, #f59e0b, #eab308, #22c55e, #06b6d4, #3b82f6, #8b5cf6, #ec4899, #ef4444);
|
||||
}
|
||||
|
||||
.aksrt-status-color__swatch--custom:not(.is-active)::after {
|
||||
.jio-status-color__swatch--custom:not(.is-active)::after {
|
||||
content: '+';
|
||||
position: absolute;
|
||||
inset: 5px;
|
||||
@@ -484,12 +484,12 @@ defineExpose({ reload: load })
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.aksrt-status-color__hex {
|
||||
.jio-status-color__hex {
|
||||
width: 160px;
|
||||
font-family: var(--n-font-family-mono, ui-monospace, SFMono-Regular, Menlo, Consolas, monospace);
|
||||
}
|
||||
|
||||
.aksrt-status-color__chip {
|
||||
.jio-status-color__chip {
|
||||
display: inline-block;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
@@ -498,26 +498,26 @@ defineExpose({ reload: load })
|
||||
}
|
||||
|
||||
/* —— 弹窗:标识 —— */
|
||||
.aksrt-status-key {
|
||||
.jio-status-key {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.aksrt-status-key__input {
|
||||
.jio-status-key__input {
|
||||
font-family: var(--n-font-family-mono, ui-monospace, SFMono-Regular, Menlo, Consolas, monospace);
|
||||
}
|
||||
|
||||
/* —— 弹窗:完结开关 —— */
|
||||
.aksrt-status-closed {
|
||||
.jio-status-closed {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.aksrt-ticket-status__hint {
|
||||
color: var(--aksrt-color-muted);
|
||||
.jio-ticket-status__hint {
|
||||
color: var(--jio-color-muted);
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<n-card class="aksrt-section-card">
|
||||
<div class="aksrt-section-header">
|
||||
<n-card class="jio-section-card">
|
||||
<div class="jio-section-header">
|
||||
<h3>工单部门</h3>
|
||||
<n-button size="small" type="primary" :disabled="saving" @click="openCreate">新增部门</n-button>
|
||||
</div>
|
||||
|
||||
Reference in new issue
Block a user