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:
kate522andClaude Opus 5 committed 2026-11-01 20:05:04 +08:00
1 parent 5b16bc6e15
commit 35bb96e82f
997 files changed
+28216 -28188

No files matched your search

+1 -1
View File
@@ -7,7 +7,7 @@
/.workbuddy/
# Project planning, internal docs, and local-only development files
/.aksrt-chrome-profile/
/.jio-chrome-profile/
/.specs/
/docs/
+15 -15
View File
@@ -2,15 +2,15 @@
/**
* 404 template.
*
* @package AKSRT
* @package Jio
*/
defined('ABSPATH') || exit;
get_header();
$search_placeholder = function_exists('aksrt_get_search_placeholder') ? aksrt_get_search_placeholder() : __('开启精彩搜索', 'aksrt');
$hot_keywords = function_exists('aksrt_get_search_hot_keywords') ? aksrt_get_search_hot_keywords() : [];
$search_placeholder = function_exists('jio_get_search_placeholder') ? jio_get_search_placeholder() : __('开启精彩搜索', 'jio');
$hot_keywords = function_exists('jio_get_search_hot_keywords') ? jio_get_search_hot_keywords() : [];
$hot_query = new WP_Query([
'post_type' => 'post',
@@ -39,33 +39,33 @@ $top_cats = get_terms([
<i class="fa fas fa-compass"></i>
</p>
<p class="error-hero__code" id="error-title">404</p>
<h1 class="error-hero__title"><?php esc_html_e('页面未找到', 'aksrt'); ?></h1>
<h1 class="error-hero__title"><?php esc_html_e('页面未找到', 'jio'); ?></h1>
<p class="error-hero__desc">
<?php esc_html_e('你访问的页面不存在或已被删除。试试搜索,或者从下方常用入口继续浏览。', 'aksrt'); ?>
<?php esc_html_e('你访问的页面不存在或已被删除。试试搜索,或者从下方常用入口继续浏览。', 'jio'); ?>
</p>
</div>
<?php if (function_exists('aksrt_render_admin_quick_link')) { aksrt_render_admin_quick_link('page-display/other', __('404 页设置', 'aksrt')); } ?>
<?php if (function_exists('jio_render_admin_quick_link')) { jio_render_admin_quick_link('page-display/other', __('404 页设置', 'jio')); } ?>
</div>
<form role="search" method="get" class="error-hero__search" action="<?php echo esc_url(home_url('/')); ?>">
<span class="error-hero__search-icon" aria-hidden="true">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/></svg>
</span>
<label class="screen-reader-text" for="error-search-input"><?php esc_html_e('搜索', 'aksrt'); ?></label>
<label class="screen-reader-text" for="error-search-input"><?php esc_html_e('搜索', 'jio'); ?></label>
<input type="search" id="error-search-input" name="s" placeholder="<?php echo esc_attr($search_placeholder); ?>" autocomplete="off">
<button type="submit" class="btn-primary btn-sm"><?php esc_html_e('搜索', 'aksrt'); ?></button>
<button type="submit" class="btn-primary btn-sm"><?php esc_html_e('搜索', 'jio'); ?></button>
</form>
<?php aksrt_render_search_hot_keywords($hot_keywords, 'aksrt-search-hot-keywords'); ?>
<?php jio_render_search_hot_keywords($hot_keywords, 'jio-search-hot-keywords'); ?>
<div class="error-hero__actions">
<a href="<?php echo esc_url(home_url('/')); ?>" class="btn-primary"><?php esc_html_e('返回首页', 'aksrt'); ?></a>
<a href="javascript:history.back()" class="btn-outline"><?php esc_html_e('返回上一页', 'aksrt'); ?></a>
<a href="<?php echo esc_url(home_url('/')); ?>" class="btn-primary"><?php esc_html_e('返回首页', 'jio'); ?></a>
<a href="javascript:history.back()" class="btn-outline"><?php esc_html_e('返回上一页', 'jio'); ?></a>
</div>
</section>
<?php if (!empty($top_cats) && !is_wp_error($top_cats)) : ?>
<section class="error-section" aria-label="<?php esc_attr_e('热门分类', 'aksrt'); ?>">
<h2 class="error-section__title"><?php esc_html_e('热门分类', 'aksrt'); ?></h2>
<section class="error-section" aria-label="<?php esc_attr_e('热门分类', 'jio'); ?>">
<h2 class="error-section__title"><?php esc_html_e('热门分类', 'jio'); ?></h2>
<div class="error-section__chips">
<?php foreach ($top_cats as $cat) : ?>
<a class="error-section__chip" href="<?php echo esc_url(get_category_link($cat->term_id)); ?>">
@@ -78,8 +78,8 @@ $top_cats = get_terms([
<?php endif; ?>
<?php if ($hot_query->have_posts()) : ?>
<section class="error-section" aria-label="<?php esc_attr_e('热门内容', 'aksrt'); ?>">
<h2 class="error-section__title"><?php esc_html_e('热门内容', 'aksrt'); ?></h2>
<section class="error-section" aria-label="<?php esc_attr_e('热门内容', 'jio'); ?>">
<h2 class="error-section__title"><?php esc_html_e('热门内容', 'jio'); ?></h2>
<ul class="error-section__list">
<?php while ($hot_query->have_posts()) : $hot_query->the_post(); ?>
<li>
+28 -28
View File
@@ -1,4 +1,4 @@
# AKSRT WordPress Theme
# Jio WordPress Theme
> **版本**: 3.4.0-dev | **架构**: 原生 PHP + WordPress (非 headless)
> **要求**: WordPress >= 6.4 | PHP >= 8.1
@@ -7,7 +7,7 @@
## 项目概述
AKSRT 是一款现代化的 WordPress 主题,采用**原生 WordPress 主题架构**开发(PHP + HTML + CSS + JavaScript),不依赖 REST API 进行前端渲染。
Jio 是一款现代化的 WordPress 主题,采用**原生 WordPress 主题架构**开发(PHP + HTML + CSS + JavaScript),不依赖 REST API 进行前端渲染。
### 核心特性
@@ -22,14 +22,14 @@ AKSRT 是一款现代化的 WordPress 主题,采用**原生 WordPress 主题
## 文件结构
```
AKSRT-theme/
Jio-theme/
├── functions.php # 入口:常量 + Composer autoload + bootstrap + 单例 init
├── style.css # WordPress 主题声明头
├── composer.json # 第三方依赖 + 主题 PSR-4(AKSRT\ → src/)
├── composer.json # 第三方依赖 + 主题 PSR-4(Jio\ → src/)
│
├── *.php # WP 核心模板保留根目录
│
├── src/ # Composer PSR-4 类型根(namespace AKSRT\)
├── src/ # Composer PSR-4 类型根(namespace Jio\)
│ ├── Admin/ # SPA 编排 + 域控制器 + Schema + Native ops
│ ├── Auth/ # 登录 / OAuth / 审核 / 邮箱
│ ├── Content/ # 下载 token / 付费内容 / VIP / 可见性
@@ -89,7 +89,7 @@ AKSRT-theme/
## 安装方式
主题类型(`AKSRT\…`)通过 Composer PSR-4 从 `src/` 自动加载;`vendor/` 不进 Git。**部署或更新主题后必须在主题根目录生成 autoload**,否则会出现 `Class "AKSRT\Core\DomainModel" not found` 等致命错误。
主题类型(`Jio\…`)通过 Composer PSR-4 从 `src/` 自动加载;`vendor/` 不进 Git。**部署或更新主题后必须在主题根目录生成 autoload**,否则会出现 `Class "Jio\Core\DomainModel" not found` 等致命错误。
### 前置:Composer(必做)
@@ -106,16 +106,16 @@ composer dump-autoload -o
确认:
```bash
php -r "require 'vendor/autoload.php'; echo class_exists('AKSRT\\\\Core\\\\DomainModel') ? \"ok\\n\" : \"missing\\n\";"
php -r "require 'vendor/autoload.php'; echo class_exists('Jio\\\\Core\\\\DomainModel') ? \"ok\\n\" : \"missing\\n\";"
```
应输出 `ok`。若 PHP 开启了 OPcache,重载 php-fpm / 重启 PHP 后再访问站点。
### 方式一:直接上传(推荐)
1. 将整个 `AKSRT-theme` 文件夹上传到 `wp-content/themes/`
1. 将整个 `Jio-theme` 文件夹上传到 `wp-content/themes/`
2. 在服务器主题目录执行上一节的 `composer install`(若打包时已带上完整 `vendor/` 且已 `dump-autoload`,可跳过)
3. WordPress 后台 → **外观** → **主题** → 找到 **AKSRT** → **激活**
3. WordPress 后台 → **外观** → **主题** → 找到 **Jio** → **激活**
### 方式二:ZIP 打包上传
@@ -126,7 +126,7 @@ php -r "require 'vendor/autoload.php'; echo class_exists('AKSRT\\\\Core\\\\Domai
SSH 进入主题目录后:
```bash
cd /path/to/wp-content/themes/AKsrt-theme # 以实际路径为准
cd /path/to/wp-content/themes/Jio-theme # 以实际路径为准
composer install --no-dev --optimize-autoloader
# 或仅刷新映射:composer dump-autoload -o
# 可选:reload php-fpm / 清 OPcache
@@ -150,9 +150,9 @@ composer install --no-dev --optimize-autoloader
### 2. 后台配置路径
WordPress 后台左侧 **Admin Bar** → ⚡ **AKSRT 主题设置**
WordPress 后台左侧 **Admin Bar** → ⚡ **Jio 主题设置**
或直接访问:`/wp-admin/admin.php?page=aksrt-settings`
或直接访问:`/wp-admin/admin.php?page=jio-settings`
### 3. 当前后台域
@@ -173,7 +173,7 @@ WordPress 后台左侧 **Admin Bar** → ⚡ **AKSRT 主题设置**
### 5. 部署注意事项
- **佣金结算时效**:结算依赖小时级 wp-cron,并有收益页访问触发的懒结算兜底。高流量站点建议禁用 `WP_CRON_LOCK` 场景下的默认 WP-Cron,改用系统 crontab 定时请求 `wp-cron.php`,保证结算与过期任务准时执行。
- **反代 / CDN 与 IP 风控**:主题默认按 Cloudflare → 通用代理头顺序识别真实 IP。若需收紧伪造风险,添加 `add_filter('aksrt_trusted_proxies', fn() => ['10.0.0.0/8', '173.245.48.0/20'])`(填入你的代理/CDN 网段);名单非空时仅当 `REMOTE_ADDR` 命中名单才采纳转发头,否则直接使用 `REMOTE_ADDR`(推广奖励的 IP 日上限、验证码等均依赖该函数)。
- **反代 / CDN 与 IP 风控**:主题默认按 Cloudflare → 通用代理头顺序识别真实 IP。若需收紧伪造风险,添加 `add_filter('jio_trusted_proxies', fn() => ['10.0.0.0/8', '173.245.48.0/20'])`(填入你的代理/CDN 网段);名单非空时仅当 `REMOTE_ADDR` 命中名单才采纳转发头,否则直接使用 `REMOTE_ADDR`(推广奖励的 IP 日上限、验证码等均依赖该函数)。
---
@@ -181,20 +181,20 @@ WordPress 后台左侧 **Admin Bar** → ⚡ **AKSRT 主题设置**
### Settings Facade 分层
- `AKSRT_Settings` 仍是主题设置的**唯一静态 facade**,外部调用方式保持 `AKSRT_Settings::*`
- `JIO_Settings` 仍是主题设置的**唯一静态 facade**,外部调用方式保持 `JIO_Settings::*`
- 具体运行时 getter 已按领域拆分到 `inc/classes/settings/`,例如:
- `class-aksrt-settings-theme-search.php`
- `class-aksrt-settings-post-display.php`
- `class-aksrt-settings-home-cms.php`
- `class-aksrt-settings-user-runtime.php`
- `class-aksrt-settings-integration.php`
- `class-aksrt-settings-display-runtime.php`
- `class-aksrt-settings-extension-runtime.php`
- `class-aksrt-settings-credits-runtime.php`
- `class-aksrt-settings-category-runtime.php`
- `class-aksrt-settings-capabilities.php`
- `inc/bootstrap.php` 会先加载 `settings/class-aksrt-settings.php`,再按领域加载这些 delegate 类
- 新增设置运行时逻辑时,优先放入对应 settings 子类;仅把聚合输出、统一入口和跨域装配保留在 `AKSRT_Settings`
- `class-jio-settings-theme-search.php`
- `class-jio-settings-post-display.php`
- `class-jio-settings-home-cms.php`
- `class-jio-settings-user-runtime.php`
- `class-jio-settings-integration.php`
- `class-jio-settings-display-runtime.php`
- `class-jio-settings-extension-runtime.php`
- `class-jio-settings-credits-runtime.php`
- `class-jio-settings-category-runtime.php`
- `class-jio-settings-capabilities.php`
- `inc/bootstrap.php` 会先加载 `settings/class-jio-settings.php`,再按领域加载这些 delegate 类
- 新增设置运行时逻辑时,优先放入对应 settings 子类;仅把聚合输出、统一入口和跨域装配保留在 `JIO_Settings`
### 添加新辅助函数
@@ -202,14 +202,14 @@ WordPress 后台左侧 **Admin Bar** → ⚡ **AKSRT 主题设置**
### 添加新页面模板
将 `page-{name}.php` 放入 `templates/pages/`,并在 `class-aksrt-templates.php` 中注册。
将 `page-{name}.php` 放入 `templates/pages/`,并在 `class-jio-templates.php` 中注册。
### CSS 组织规范
| 目录 | 用途 | 加载场景 |
|------|------|---------|
| `css/frontend/` | 前端公共样式 | 所有前台页面 |
| `css/admin/` | 后台管理样式 | 仅 AKSRT 设置页面 |
| `css/admin/` | 后台管理样式 | 仅 Jio 设置页面 |
| `css/shared/` | 共用组件样式 | 前后端按需加载(如验证码) |
---
+26 -26
View File
@@ -2,9 +2,9 @@
/**
* Resource Archive Template
*
* Virtual list at /resources/ — ordinary posts marked with _aksrt_is_resource.
* Virtual list at /resources/ — ordinary posts marked with _jio_is_resource.
*
* @package AKSRT
* @package Jio
*/
defined('ABSPATH') || exit;
@@ -25,18 +25,18 @@ if (!in_array($current_price, ['all', 'free', 'paid'], true)) {
$price_min = isset($_GET['price_min']) && $_GET['price_min'] !== '' ? (float) $_GET['price_min'] : '';
$price_max = isset($_GET['price_max']) && $_GET['price_max'] !== '' ? (float) $_GET['price_max'] : '';
$archive_url = function_exists('aksrt_resource_archive_url') ? aksrt_resource_archive_url() : home_url('/resources/');
$archive_url = function_exists('jio_resource_archive_url') ? jio_resource_archive_url() : home_url('/resources/');
$sort_options = [
'date' => __('最新', 'aksrt'),
'downloads' => __('热门下载', 'aksrt'),
'views' => __('阅读最多', 'aksrt'),
'date' => __('最新', 'jio'),
'downloads' => __('热门下载', 'jio'),
'views' => __('阅读最多', 'jio'),
];
$price_options = [
'all' => __('全部', 'aksrt'),
'free' => __('免费', 'aksrt'),
'paid' => __('付费', 'aksrt'),
'all' => __('全部', 'jio'),
'free' => __('免费', 'jio'),
'paid' => __('付费', 'jio'),
];
$preserve = [];
@@ -59,18 +59,18 @@ $has_filter = $current_orderby !== 'date' || $current_price !== 'all' || $price_
<main id="main-content" class="site-main container" tabindex="-1">
<header class="resource-archive-header page-cover">
<div class="container">
<?php if (function_exists('aksrt_breadcrumbs')) : ?>
<nav class="resource-archive-header__breadcrumbs" aria-label="<?php esc_attr_e('面包屑', 'aksrt'); ?>">
<?php aksrt_breadcrumbs(); ?>
<?php if (function_exists('jio_breadcrumbs')) : ?>
<nav class="resource-archive-header__breadcrumbs" aria-label="<?php esc_attr_e('面包屑', 'jio'); ?>">
<?php jio_breadcrumbs(); ?>
</nav>
<?php endif; ?>
<h1 class="resource-archive-header__title"><?php esc_html_e('资源', 'aksrt'); ?></h1>
<h1 class="resource-archive-header__title"><?php esc_html_e('资源', 'jio'); ?></h1>
<p class="resource-archive-header__sub">
<?php
global $wp_query;
/* translators: %s: resource count */
printf(esc_html__('共 %s 个资源', 'aksrt'), esc_html(number_format_i18n((int) $wp_query->found_posts)));
printf(esc_html__('共 %s 个资源', 'jio'), esc_html(number_format_i18n((int) $wp_query->found_posts)));
?>
</p>
</div>
@@ -79,9 +79,9 @@ $has_filter = $current_orderby !== 'date' || $current_price !== 'all' || $price_
<div class="content-wrap">
<div class="content-layout content-layout--no-sidebar">
<div class="content-layout__primary resource-archive">
<nav class="resource-archive__toolbar" aria-label="<?php esc_attr_e('筛选', 'aksrt'); ?>">
<nav class="resource-archive__toolbar" aria-label="<?php esc_attr_e('筛选', 'jio'); ?>">
<div class="resource-archive__filter-group">
<span class="resource-archive__filter-label"><?php esc_html_e('排序', 'aksrt'); ?></span>
<span class="resource-archive__filter-label"><?php esc_html_e('排序', 'jio'); ?></span>
<ul class="resource-archive__sort">
<?php foreach ($sort_options as $key => $label) :
$args = $preserve;
@@ -105,7 +105,7 @@ $has_filter = $current_orderby !== 'date' || $current_price !== 'all' || $price_
</div>
<div class="resource-archive__filter-group">
<span class="resource-archive__filter-label"><?php esc_html_e('价格', 'aksrt'); ?></span>
<span class="resource-archive__filter-label"><?php esc_html_e('价格', 'jio'); ?></span>
<ul class="resource-archive__sort">
<?php foreach ($price_options as $key => $label) :
$args = $preserve;
@@ -139,43 +139,43 @@ $has_filter = $current_orderby !== 'date' || $current_price !== 'all' || $price_
}
?>
<label class="resource-archive__price-input">
<span><?php esc_html_e('最低', 'aksrt'); ?></span>
<span><?php esc_html_e('最低', 'jio'); ?></span>
<input type="number" name="price_min" min="0" step="1" value="<?php echo esc_attr((string) $price_min); ?>">
</label>
<span class="resource-archive__price-sep">—</span>
<label class="resource-archive__price-input">
<span><?php esc_html_e('最高', 'aksrt'); ?></span>
<span><?php esc_html_e('最高', 'jio'); ?></span>
<input type="number" name="price_max" min="0" step="1" value="<?php echo esc_attr((string) $price_max); ?>">
</label>
<button type="submit" class="btn-primary btn-sm"><?php esc_html_e('应用', 'aksrt'); ?></button>
<button type="submit" class="btn-primary btn-sm"><?php esc_html_e('应用', 'jio'); ?></button>
</form>
<?php if ($has_filter) : ?>
<a class="resource-archive__reset" href="<?php echo esc_url($archive_url); ?>">
<i class="fa fas fa-times-circle" aria-hidden="true"></i>
<?php esc_html_e('清除筛选', 'aksrt'); ?>
<?php esc_html_e('清除筛选', 'jio'); ?>
</a>
<?php endif; ?>
</nav>
<?php if (have_posts()) : ?>
<?php
$render_config = aksrt_resolve_post_list_render_config([
$render_config = jio_resolve_post_list_render_config([
'context' => 'archive',
'overrides' => ['type' => 'card'],
]);
aksrt_render_post_list(array_merge($render_config, ['wrapper_class' => 'content-stream__list']));
aksrt_render_pagination(null, [
jio_render_post_list(array_merge($render_config, ['wrapper_class' => 'content-stream__list']));
jio_render_pagination(null, [
'query_context' => 'archive',
'render_config' => $render_config,
]);
?>
<?php else : ?>
<div class="no-results">
<p><?php esc_html_e('暂无资源。', 'aksrt'); ?></p>
<p><?php esc_html_e('暂无资源。', 'jio'); ?></p>
<?php if ($has_filter) : ?>
<p><a class="btn-outline btn-sm" href="<?php echo esc_url($archive_url); ?>"><?php esc_html_e('清除筛选条件', 'aksrt'); ?></a></p>
<p><a class="btn-outline btn-sm" href="<?php echo esc_url($archive_url); ?>"><?php esc_html_e('清除筛选条件', 'jio'); ?></a></p>
<?php endif; ?>
</div>
<?php endif; ?>
+19 -19
View File
@@ -2,7 +2,7 @@
/**
* Generic archive template.
*
* @package AKSRT
* @package Jio
*/
defined('ABSPATH') || exit;
@@ -11,31 +11,31 @@ get_header();
global $wp_query;
$render_config = function_exists('aksrt_archive_get_render_config')
? aksrt_archive_get_render_config(['context' => 'archive'])
$render_config = function_exists('jio_archive_get_render_config')
? jio_archive_get_render_config(['context' => 'archive'])
: ['context' => 'archive', 'mode' => 'list'];
$has_sidebar = function_exists('aksrt_archive_has_sidebar')
? aksrt_archive_has_sidebar()
: (function_exists('aksrt_is_show_sidebar') ? aksrt_is_show_sidebar() : false);
$has_sidebar = function_exists('jio_archive_has_sidebar')
? jio_archive_has_sidebar()
: (function_exists('jio_is_show_sidebar') ? jio_is_show_sidebar() : false);
$archive_description = trim(wp_strip_all_tags((string) get_the_archive_description()));
$archive_summary = '';
if (is_author()) {
$author = get_queried_object();
if ($author instanceof WP_User) {
$archive_summary = sprintf(__('作者:%s', 'aksrt'), $author->display_name);
$archive_summary = sprintf(__('作者:%s', 'jio'), $author->display_name);
}
} elseif ($archive_description !== '') {
$archive_summary = $archive_description;
} elseif (isset($wp_query->found_posts)) {
$archive_summary = sprintf(
esc_html(_n('共 %d 篇内容', '共 %d 篇内容', (int) $wp_query->found_posts, 'aksrt')),
esc_html(_n('共 %d 篇内容', '共 %d 篇内容', (int) $wp_query->found_posts, 'jio')),
(int) $wp_query->found_posts
);
}
if (function_exists('aksrt_archive_open_shell')) {
aksrt_archive_open_shell([
if (function_exists('jio_archive_open_shell')) {
jio_archive_open_shell([
'main_class' => 'site-main container',
'has_sidebar' => $has_sidebar,
'page_kind' => 'archive',
@@ -45,16 +45,16 @@ if (function_exists('aksrt_archive_open_shell')) {
}
?>
<div class="content-main content-main--archive">
<?php if (function_exists('aksrt_breadcrumbs')) { aksrt_breadcrumbs(); } ?>
<?php if (function_exists('jio_breadcrumbs')) { jio_breadcrumbs(); } ?>
<?php
ob_start();
if (function_exists('aksrt_render_admin_quick_link')) {
aksrt_render_admin_quick_link('post-list/list', __('列表样式设置', 'aksrt'));
if (function_exists('jio_render_admin_quick_link')) {
jio_render_admin_quick_link('post-list/list', __('列表样式设置', 'jio'));
}
$admin_link = trim((string) ob_get_clean());
get_template_part('templates/parts/page-header', null, [
'eyebrow' => __('内容归档', 'aksrt'),
'eyebrow' => __('内容归档', 'jio'),
'title' => get_the_archive_title(),
'desc' => $archive_summary,
'extra' => $admin_link,
@@ -62,19 +62,19 @@ if (function_exists('aksrt_archive_open_shell')) {
?>
<?php
if (function_exists('aksrt_archive_render_stream')) {
aksrt_archive_render_stream(null, $render_config, [
if (function_exists('jio_archive_render_stream')) {
jio_archive_render_stream(null, $render_config, [
'page_kind' => 'archive',
'query_context' => 'archive',
'stream_class' => 'content-stream--archive',
'empty_text' => __('暂无文章', 'aksrt'),
'empty_text' => __('暂无文章', 'jio'),
]);
}
?>
</div>
<?php
if (function_exists('aksrt_archive_close_shell')) {
aksrt_archive_close_shell(['has_sidebar' => $has_sidebar]);
if (function_exists('jio_archive_close_shell')) {
jio_archive_close_shell(['has_sidebar' => $has_sidebar]);
} else {
echo '</div></div>';
if ($has_sidebar) { get_sidebar(); }
+6 -6
View File
@@ -104,7 +104,7 @@ const COMPONENT_STYLES = [
]
async function extractStyles() {
console.log('\n[AKSRT] 开始提取 NaiveUI 组件样式...\n')
console.log('\n[Jio] 开始提取 NaiveUI 组件样式...\n')
const allCss = []
let successCount = 0
@@ -137,9 +137,9 @@ async function extractStyles() {
// 静默跳过的后果是组件样式整体缺失(取色器曾因此没有尺寸和边框,糊成一团),
// 而页面不报错,只能靠肉眼发现。
if (code === 'ERR_MODULE_NOT_FOUND' || code === 'MODULE_NOT_FOUND') {
console.error(`[AKSRT] 样式路径不存在,已跳过: ${componentPath}`)
console.error(`[Jio] 样式路径不存在,已跳过: ${componentPath}`)
} else {
console.error(`[AKSRT] 样式提取异常,已跳过: ${componentPath}: ${err && err.message}`)
console.error(`[Jio] 样式提取异常,已跳过: ${componentPath}: ${err && err.message}`)
}
failCount++
}
@@ -148,7 +148,7 @@ async function extractStyles() {
const cssOutput = allCss.join('\n\n')
if (!cssOutput.trim()) {
console.warn('[AKSRT] 警告:未提取到任何 NaiveUI 样式!')
console.warn('[Jio] 警告:未提取到任何 NaiveUI 样式!')
return null
}
@@ -165,7 +165,7 @@ ${cssOutput}`
await writeFile(cssFile, fullContent, 'utf-8')
console.log(`[AKSRT] NaiveUI 样式提取完成:`)
console.log(`[Jio] NaiveUI 样式提取完成:`)
console.log(` 成功: ${successCount} 个组件`)
console.log(` 跳过: ${failCount} 个组件`)
console.log(` 输出: ${cssFile}`)
@@ -176,6 +176,6 @@ ${cssOutput}`
// 执行
extractStyles().catch((err) => {
console.error('[AKSRT] 样式提取失败:', err)
console.error('[Jio] 样式提取失败:', err)
process.exit(1)
})
+2 -2
View File
@@ -3,10 +3,10 @@
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>AKSRT 主题设置</title>
<title>Jio 主题设置</title>
</head>
<body>
<div id="aksrt-admin-app"></div>
<div id="jio-admin-app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>
+2 -2
View File
@@ -1,11 +1,11 @@
{
"name": "aksrt-admin",
"name": "jio-admin",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "aksrt-admin",
"name": "jio-admin",
"version": "1.0.0",
"dependencies": {
"@codemirror/lang-css": "^6.3.1",
+1 -1
View File
@@ -1 +1 @@
{"name":"aksrt-admin","version":"1.0.0","private":true,"type":"module","scripts":{"dev":"vite","build":"vite build && node extract-naive-styles.mjs","build:public":"node ../../tools/build-public-assets.mjs","build:pay-charts":"node ../../tools/build-pay-charts.mjs","preview":"vite preview"},"dependencies":{"@codemirror/lang-css":"^6.3.1","@codemirror/lang-html":"^6.4.11","@codemirror/lang-javascript":"^6.2.5","@codemirror/theme-one-dark":"^6.1.3","codemirror":"^6.0.2","naive-ui":"^2.40.0","pinia":"^2.2.0","vue":"^3.5.0","vue-router":"^4.4.0","vuedraggable":"^4.1.0"},"devDependencies":{"@vitejs/plugin-vue":"^5.1.0","echarts":"^6.1.0","esbuild":"^0.25.12","vite":"^6.0.0"},"allowScripts":{"esbuild@0.25.12":true,"vue-demi@0.14.10":true}}
{"name":"jio-admin","version":"1.0.0","private":true,"type":"module","scripts":{"dev":"vite","build":"vite build && node extract-naive-styles.mjs","build:public":"node ../../tools/build-public-assets.mjs","build:pay-charts":"node ../../tools/build-pay-charts.mjs","preview":"vite preview"},"dependencies":{"@codemirror/lang-css":"^6.3.1","@codemirror/lang-html":"^6.4.11","@codemirror/lang-javascript":"^6.2.5","@codemirror/theme-one-dark":"^6.1.3","codemirror":"^6.0.2","naive-ui":"^2.40.0","pinia":"^2.2.0","vue":"^3.5.0","vue-router":"^4.4.0","vuedraggable":"^4.1.0"},"devDependencies":{"@vitejs/plugin-vue":"^5.1.0","echarts":"^6.1.0","esbuild":"^0.25.12","vite":"^6.0.0"},"allowScripts":{"esbuild@0.25.12":true,"vue-demi@0.14.10":true}}
+45 -45
View File
@@ -6,9 +6,9 @@
<n-message-provider>
<n-dialog-provider>
<n-notification-provider>
<n-layout v-if="!isMobile" class="aksrt-admin-layout" has-sider>
<n-layout v-if="!isMobile" class="jio-admin-layout" has-sider>
<n-layout-sider
class="aksrt-admin-sider"
class="jio-admin-sider"
bordered
collapse-mode="width"
:collapsed-width="64"
@@ -19,16 +19,16 @@
@collapse="collapsed = true"
@expand="collapsed = false"
>
<div class="aksrt-logo">
<div class="jio-logo">
<span class="logo-icon">AK</span>
<span v-if="!collapsed" class="aksrt-logo__copy">
<span class="logo-text">AKSRT</span>
<span class="aksrt-logo__version">v{{ themeVersion }}</span>
<span v-if="!collapsed" class="jio-logo__copy">
<span class="logo-text">Jio</span>
<span class="jio-logo__version">v{{ themeVersion }}</span>
</span>
</div>
<n-menu
class="aksrt-admin-menu"
class="jio-admin-menu"
:value="activeMenuKey"
:collapsed="collapsed"
:collapsed-width="64"
@@ -37,39 +37,39 @@
/>
</n-layout-sider>
<n-layout :native-scrollbar="false" class="aksrt-admin-content">
<div class="aksrt-admin-content__inner">
<n-layout :native-scrollbar="false" class="jio-admin-content">
<div class="jio-admin-content__inner">
<router-view v-slot="{ Component }">
<transition name="fade-slide" mode="out-in">
<div class="aksrt-page-wrapper" :key="route.fullPath">
<div class="jio-page-wrapper" :key="route.fullPath">
<component :is="Component" />
</div>
</transition>
</router-view>
<div v-if="pageError" class="aksrt-error-fallback">
<p class="aksrt-error-title">页面渲染异常</p>
<p class="aksrt-error-msg">{{ pageError }}</p>
<div v-if="pageError" class="jio-error-fallback">
<p class="jio-error-title">页面渲染异常</p>
<p class="jio-error-msg">{{ pageError }}</p>
<n-button size="small" @click="pageError = null">重试</n-button>
</div>
</div>
</n-layout>
</n-layout>
<div v-else class="aksrt-admin-mobile">
<div v-else class="jio-admin-mobile">
<MobileTopBar :title="currentPageTitle" @toggle="drawerActive = true" />
<n-drawer v-model:show="drawerActive" placement="left" :width="280">
<n-drawer-content :native-scrollbar="false" body-content-style="padding:0;">
<div class="aksrt-logo aksrt-logo--drawer">
<div class="jio-logo jio-logo--drawer">
<span class="logo-icon">AK</span>
<span class="aksrt-logo__copy">
<span class="logo-text">AKSRT</span>
<span class="aksrt-logo__version">v{{ themeVersion }}</span>
<span class="jio-logo__copy">
<span class="logo-text">Jio</span>
<span class="jio-logo__version">v{{ themeVersion }}</span>
</span>
</div>
<n-menu
class="aksrt-admin-menu"
class="jio-admin-menu"
:value="activeMenuKey"
:options="menuOptions"
@update:value="handleMenuClick"
@@ -77,18 +77,18 @@
</n-drawer-content>
</n-drawer>
<div class="aksrt-admin-mobile__body">
<div class="jio-admin-mobile__body">
<router-view v-slot="{ Component }">
<transition name="fade-slide" mode="out-in">
<div class="aksrt-page-wrapper" :key="route.fullPath">
<div class="jio-page-wrapper" :key="route.fullPath">
<component :is="Component" />
</div>
</transition>
</router-view>
<div v-if="pageError" class="aksrt-error-fallback">
<p class="aksrt-error-title">页面渲染异常</p>
<p class="aksrt-error-msg">{{ pageError }}</p>
<div v-if="pageError" class="jio-error-fallback">
<p class="jio-error-title">页面渲染异常</p>
<p class="jio-error-msg">{{ pageError }}</p>
<n-button size="small" @click="pageError = null">重试</n-button>
</div>
</div>
@@ -113,7 +113,7 @@ const collapsed = ref(false)
const pageError = ref(null)
const isMobile = ref(false)
const drawerActive = ref(false)
const themeVersion = window.aksrtAdminData?.themeVersion || window.aksrtAdminData?.version || '9.0'
const themeVersion = window.jioAdminData?.themeVersion || window.jioAdminData?.version || '9.0'
const MOBILE_BREAKPOINT = 960
const adminThemeOverrides = {
@@ -184,7 +184,7 @@ onBeforeUnmount(() => {
provide('collapsed', collapsed)
onErrorCaptured((err) => {
console.error('[AKSRT] 组件渲染错误:', err)
console.error('[Jio] 组件渲染错误:', err)
pageError.value = err?.message || String(err)
return false
})
@@ -224,7 +224,7 @@ const menuOptions = ADMIN_SECTIONS.filter((section) => !section.hidden).map((sec
children: section.children.map((child) => ({
label: child.secondaryEntry ? `${child.label} · 次级` : child.label,
key: child.key,
props: child.secondaryEntry ? { class: 'aksrt-menu-item--secondary' } : undefined,
props: child.secondaryEntry ? { class: 'jio-menu-item--secondary' } : undefined,
})),
}
})
@@ -254,7 +254,7 @@ const activeMenuKey = computed(() => {
return ADMIN_SECTIONS[0]?.children?.[0]?.key || 'global-common'
})
const currentPageTitle = computed(() => route.meta?.title || 'AKSRT')
const currentPageTitle = computed(() => route.meta?.title || 'Jio')
function handleMenuClick(key) {
if (keyToPath[key]) {
@@ -267,17 +267,17 @@ function handleMenuClick(key) {
</script>
<style scoped>
.aksrt-logo {
.jio-logo {
display: flex;
align-items: center;
justify-content: flex-start;
height: 64px;
gap: 11px;
padding: 0 18px;
border-bottom: 1px solid var(--aksrt-color-border);
border-bottom: 1px solid var(--jio-color-border);
}
.aksrt-logo--drawer {
.jio-logo--drawer {
height: 64px;
}
@@ -289,14 +289,14 @@ function handleMenuClick(key) {
height: 28px;
flex: 0 0 28px;
border-radius: 7px;
background: var(--aksrt-color-primary);
background: var(--jio-color-primary);
color: #fff;
font-size: 12px;
font-weight: 700;
letter-spacing: 0.08em;
}
.aksrt-logo__copy {
.jio-logo__copy {
display: flex;
align-items: baseline;
gap: 7px;
@@ -306,56 +306,56 @@ function handleMenuClick(key) {
.logo-text {
font-size: 17px;
font-weight: 700;
color: var(--aksrt-color-text);
color: var(--jio-color-text);
letter-spacing: .08em;
}
.aksrt-logo__version {
color: var(--aksrt-color-muted);
.jio-logo__version {
color: var(--jio-color-muted);
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
font-size: 10px;
letter-spacing: .02em;
}
.aksrt-admin-content__inner {
.jio-admin-content__inner {
width: 100%;
max-width: 1236px;
margin: 0 auto;
padding: 26px 28px 42px;
}
.aksrt-admin-mobile {
background: var(--aksrt-color-canvas);
.jio-admin-mobile {
background: var(--jio-color-canvas);
min-height: 100vh;
}
.aksrt-admin-mobile__body {
.jio-admin-mobile__body {
padding: 14px 12px 32px;
}
.aksrt-page-wrapper {
.jio-page-wrapper {
min-height: calc(100vh - 120px);
}
.aksrt-error-fallback {
.jio-error-fallback {
padding: 48px 20px;
text-align: center;
}
.aksrt-error-title {
.jio-error-title {
margin: 0 0 10px;
font-size: 16px;
color: #d03050;
}
.aksrt-error-msg {
.jio-error-msg {
margin: 0 0 16px;
font-size: 13px;
color: #777;
}
@media (max-width: 1100px) {
.aksrt-admin-content__inner {
.jio-admin-content__inner {
padding: 22px 20px 38px;
}
}
+17 -17
View File
@@ -1,16 +1,16 @@
/**
* AKSRT Admin API Client
* Jio Admin API Client
*
* Communicates with the WordPress REST API at /wp-json/aksrt/v1
* (or index.php?rest_route=/aksrt/v1 when pretty permalinks are off).
* Communicates with the WordPress REST API at /wp-json/jio/v1
* (or index.php?rest_route=/jio/v1 when pretty permalinks are off).
* Methods are organized into domain modules while the client keeps the shared
* request pipeline and schema-domain normalization contract.
*/
import { apiMethods } from './modules/index.js'
const API_ROOT = window.aksrtAdminData?.apiUrl || '/wp-json/aksrt/v1'
const NONCE = window.aksrtAdminData?.nonce || ''
const API_ROOT = window.jioAdminData?.apiUrl || '/wp-json/jio/v1'
const NONCE = window.jioAdminData?.nonce || ''
function createIdempotencyKey() {
if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {
@@ -34,11 +34,11 @@ function normalizeDomainKey(domain) {
/**
* Join REST base + endpoint correctly for both pretty and plain permalinks.
*
* Pretty: https://site/wp-json/aksrt/v1 + /settings/schema/global/common
* → https://site/wp-json/aksrt/v1/settings/schema/global/common
* Pretty: https://site/wp-json/jio/v1 + /settings/schema/global/common
* → https://site/wp-json/jio/v1/settings/schema/global/common
*
* Plain: https://site/index.php?rest_route=/aksrt/v1 + /settings/schema/global/common
* → https://site/index.php?rest_route=/aksrt/v1/settings/schema/global/common
* Plain: https://site/index.php?rest_route=/jio/v1 + /settings/schema/global/common
* → https://site/index.php?rest_route=/jio/v1/settings/schema/global/common
*
* @param {string} baseUrl
* @param {string} endpoint path starting with /, may include ?query
@@ -56,7 +56,7 @@ function joinRestUrl(baseUrl, endpoint) {
path = '/' + path
}
const base = String(baseUrl || '').trim() || '/wp-json/aksrt/v1'
const base = String(baseUrl || '').trim() || '/wp-json/jio/v1'
// Plain permalinks: rest_route query mode
if (base.includes('rest_route=')) {
@@ -68,11 +68,11 @@ function joinRestUrl(baseUrl, endpoint) {
return base.replace(/\/?$/, '') + path + (extraQuery ? (base.includes('?') ? '&' : '?') + extraQuery : '')
}
const baseRoute = (u.searchParams.get('rest_route') || '/aksrt/v1').replace(/\/$/, '') || '/aksrt/v1'
const baseRoute = (u.searchParams.get('rest_route') || '/jio/v1').replace(/\/$/, '') || '/jio/v1'
let fullRoute
if (path === '/') {
fullRoute = baseRoute
} else if (path.startsWith('/aksrt/')) {
} else if (path.startsWith('/jio/')) {
fullRoute = path
} else {
fullRoute = baseRoute + path
@@ -110,7 +110,7 @@ class ApiClient {
async request(endpointOrConfig, options = {}) {
// Dual-signature support:
// request('/users/1/restrictions')
// request({ url: '/aksrt/v1/users/1/restrictions', method: 'GET' })
// request({ url: '/jio/v1/users/1/restrictions', method: 'GET' })
let endpoint, method, headers, params, body, rest
if (typeof endpointOrConfig === 'object' && endpointOrConfig !== null) {
@@ -134,10 +134,10 @@ class ApiClient {
delete rest.data; delete rest.headers
}
if (endpoint.startsWith('/wp-json/aksrt/v1')) {
endpoint = endpoint.replace('/wp-json/aksrt/v1', '') || '/'
} else if (endpoint.startsWith('/aksrt/v1')) {
endpoint = endpoint.replace('/aksrt/v1', '') || '/'
if (endpoint.startsWith('/wp-json/jio/v1')) {
endpoint = endpoint.replace('/wp-json/jio/v1', '') || '/'
} else if (endpoint.startsWith('/jio/v1')) {
endpoint = endpoint.replace('/jio/v1', '') || '/'
}
let url = joinRestUrl(this.baseUrl, endpoint)
+5 -5
View File
@@ -1,13 +1,13 @@
/**
* 工单管理端 REST(命名空间 aksrt/v1/admin)。
* 工单管理端 REST(命名空间 jio/v1/admin)。
*
* TicketRestAdmin 把三块字典 CRUD(工单状态 / 部门 / 预设回复)挂在
* aksrt/v1/admin 下,全部要求 manage_options。api 客户端的 baseUrl 只到
* aksrt/v1,因此这里必须用 /aksrt/ 全路径形式(joinRestUrl 的
* startsWith('/aksrt/') 分支会原样拼接,不再追加 base 前缀)。
* jio/v1/admin 下,全部要求 manage_options。api 客户端的 baseUrl 只到
* jio/v1,因此这里必须用 /jio/ 全路径形式(joinRestUrl 的
* startsWith('/jio/') 分支会原样拼接,不再追加 base 前缀)。
*/
const ADMIN = '/aksrt/v1/admin/tickets'
const ADMIN = '/jio/v1/admin/tickets'
export const ticketsApiMethods = {
/* ---------------- 工单状态 ---------------- */
+32 -32
View File
@@ -1,35 +1,35 @@
<template>
<div class="aksrt-deferred-page">
<div class="aksrt-deferred-page__icon">
<div class="jio-deferred-page">
<div class="jio-deferred-page__icon">
<FaIcon :icon="resolvedIcon" :size="48" />
</div>
<h2 class="aksrt-deferred-page__title">{{ resolvedTitle }}</h2>
<p class="aksrt-deferred-page__desc">{{ resolvedDesc }}</p>
<div class="aksrt-deferred-page__meta">
<h2 class="jio-deferred-page__title">{{ resolvedTitle }}</h2>
<p class="jio-deferred-page__desc">{{ resolvedDesc }}</p>
<div class="jio-deferred-page__meta">
<n-tag size="small" type="info">{{ resolvedStatus }}</n-tag>
<n-tag v-if="resolvedPhase" size="small" type="warning">Phase {{ resolvedPhase }}</n-tag>
</div>
<div v-if="resolvedDependsOn.length" class="aksrt-deferred-page__depends">
<span class="aksrt-deferred-page__label">依赖</span>
<div class="aksrt-deferred-page__depends-list">
<div v-if="resolvedDependsOn.length" class="jio-deferred-page__depends">
<span class="jio-deferred-page__label">依赖</span>
<div class="jio-deferred-page__depends-list">
<n-tag v-for="item in resolvedDependsOn" :key="item" size="small" type="default">{{ item }}</n-tag>
</div>
</div>
<div v-if="resolvedReason" class="aksrt-deferred-page__reason">
<span class="aksrt-deferred-page__label">原因</span>
<div v-if="resolvedReason" class="jio-deferred-page__reason">
<span class="jio-deferred-page__label">原因</span>
<p>{{ resolvedReason }}</p>
</div>
<div v-if="resolvedFeatures && resolvedFeatures.length" class="aksrt-deferred-page__features">
<div v-if="resolvedFeatures && resolvedFeatures.length" class="jio-deferred-page__features">
<div
v-for="(feat, i) in resolvedFeatures"
:key="i"
class="aksrt-deferred-page__feature"
class="jio-deferred-page__feature"
>
<FaIcon icon="fa fas fa-check-circle" :size="14" />
<span>{{ feat }}</span>
</div>
</div>
<div class="aksrt-deferred-page__badge">
<div class="jio-deferred-page__badge">
<n-tag type="info" size="small">即将推出</n-tag>
</div>
</div>
@@ -78,7 +78,7 @@ const resolvedFeatures = computed(() => {
</script>
<style scoped>
.aksrt-deferred-page {
.jio-deferred-page {
display: flex;
flex-direction: column;
align-items: center;
@@ -88,75 +88,75 @@ const resolvedFeatures = computed(() => {
padding: 40px 20px;
}
.aksrt-deferred-page__icon {
color: var(--aksrt-color-border-strong);
.jio-deferred-page__icon {
color: var(--jio-color-border-strong);
margin-bottom: 20px;
}
.aksrt-deferred-page__title {
.jio-deferred-page__title {
margin: 0 0 10px;
font-size: 20px;
font-weight: 600;
color: var(--aksrt-color-text);
color: var(--jio-color-text);
}
.aksrt-deferred-page__desc {
.jio-deferred-page__desc {
margin: 0 0 20px;
font-size: 14px;
color: var(--aksrt-color-muted);
color: var(--jio-color-muted);
max-width: 400px;
line-height: 1.6;
}
.aksrt-deferred-page__meta {
.jio-deferred-page__meta {
display: flex;
gap: 10px;
margin-bottom: 18px;
}
.aksrt-deferred-page__depends,
.aksrt-deferred-page__reason {
.jio-deferred-page__depends,
.jio-deferred-page__reason {
width: min(520px, 100%);
margin-bottom: 18px;
text-align: left;
}
.aksrt-deferred-page__label {
.jio-deferred-page__label {
display: inline-block;
margin-bottom: 8px;
font-size: 12px;
font-weight: 600;
color: var(--aksrt-color-text-secondary);
color: var(--jio-color-text-secondary);
}
.aksrt-deferred-page__depends-list {
.jio-deferred-page__depends-list {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.aksrt-deferred-page__reason p {
.jio-deferred-page__reason p {
margin: 0;
color: var(--aksrt-color-muted);
color: var(--jio-color-muted);
line-height: 1.7;
}
.aksrt-deferred-page__features {
.jio-deferred-page__features {
display: flex;
flex-direction: column;
gap: 8px;
margin-bottom: 20px;
}
.aksrt-deferred-page__feature {
.jio-deferred-page__feature {
display: flex;
align-items: center;
gap: 8px;
font-size: 13px;
color: var(--aksrt-color-muted);
color: var(--jio-color-muted);
}
.aksrt-deferred-page__feature :deep(i) {
.jio-deferred-page__feature :deep(i) {
color: #52c41a;
}
</style>
+11 -11
View File
@@ -1,10 +1,10 @@
<template>
<div class="aksrt-empty-state">
<div class="aksrt-empty-state__icon">
<div class="jio-empty-state">
<div class="jio-empty-state__icon">
<i :class="icon" style="font-size: 48px;"></i>
</div>
<h3 class="aksrt-empty-state__title">{{ title }}</h3>
<p class="aksrt-empty-state__desc">{{ desc }}</p>
<h3 class="jio-empty-state__title">{{ title }}</h3>
<p class="jio-empty-state__desc">{{ desc }}</p>
</div>
</template>
@@ -17,7 +17,7 @@ defineProps({
</script>
<style scoped>
.aksrt-empty-state {
.jio-empty-state {
display: flex;
flex-direction: column;
align-items: center;
@@ -26,22 +26,22 @@ defineProps({
text-align: center;
}
.aksrt-empty-state__icon {
.jio-empty-state__icon {
margin-bottom: 20px;
color: var(--aksrt-color-border-strong);
color: var(--jio-color-border-strong);
}
.aksrt-empty-state__title {
.jio-empty-state__title {
margin: 0 0 8px;
font-size: 18px;
font-weight: 600;
color: var(--aksrt-color-text);
color: var(--jio-color-text);
}
.aksrt-empty-state__desc {
.jio-empty-state__desc {
margin: 0;
font-size: 13px;
color: var(--aksrt-color-muted);
color: var(--jio-color-muted);
max-width: 360px;
line-height: 1.65;
}
+16 -16
View File
@@ -1,7 +1,7 @@
<template>
<header class="aksrt-mobile-topbar">
<header class="jio-mobile-topbar">
<button
class="aksrt-mobile-topbar__menu"
class="jio-mobile-topbar__menu"
type="button"
aria-label="打开菜单"
@click="$emit('toggle')"
@@ -13,35 +13,35 @@
</svg>
</button>
<div class="aksrt-mobile-topbar__title">{{ title }}</div>
<div class="jio-mobile-topbar__title">{{ title }}</div>
<div class="aksrt-mobile-topbar__brand">AK</div>
<div class="jio-mobile-topbar__brand">AK</div>
</header>
</template>
<script setup>
defineProps({
title: { type: String, default: 'AKSRT' },
title: { type: String, default: 'Jio' },
})
defineEmits(['toggle'])
</script>
<style scoped>
.aksrt-mobile-topbar {
.jio-mobile-topbar {
display: flex;
align-items: center;
gap: 10px;
height: 48px;
padding: 0 14px;
background: var(--aksrt-color-surface);
border-bottom: 1px solid var(--aksrt-color-border);
background: var(--jio-color-surface);
border-bottom: 1px solid var(--jio-color-border);
position: sticky;
top: 0;
z-index: 50;
}
.aksrt-mobile-topbar__menu {
.jio-mobile-topbar__menu {
display: inline-flex;
align-items: center;
justify-content: center;
@@ -50,26 +50,26 @@ defineEmits(['toggle'])
border: none;
border-radius: 8px;
background: transparent;
color: var(--aksrt-color-text);
color: var(--jio-color-text);
cursor: pointer;
margin-left: -6px;
}
.aksrt-mobile-topbar__menu:hover {
background: var(--aksrt-color-primary-soft);
.jio-mobile-topbar__menu:hover {
background: var(--jio-color-primary-soft);
}
.aksrt-mobile-topbar__title {
.jio-mobile-topbar__title {
flex: 1 1 auto;
font-size: 15px;
font-weight: 600;
color: var(--aksrt-color-text);
color: var(--jio-color-text);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.aksrt-mobile-topbar__brand {
.jio-mobile-topbar__brand {
flex: 0 0 auto;
display: inline-flex;
align-items: center;
@@ -77,7 +77,7 @@ defineEmits(['toggle'])
width: 28px;
height: 28px;
border-radius: 8px;
background: var(--aksrt-color-primary);
background: var(--jio-color-primary);
color: #fff;
font-size: 11px;
font-weight: 700;
+17 -17
View File
@@ -1,15 +1,15 @@
<template>
<header class="aksrt-page-header">
<div class="aksrt-page-header__main">
<h2 class="aksrt-page-header__title">{{ title }}</h2>
<p v-if="desc" class="aksrt-page-header__desc">
<header class="jio-page-header">
<div class="jio-page-header__main">
<h2 class="jio-page-header__title">{{ title }}</h2>
<p v-if="desc" class="jio-page-header__desc">
<slot name="desc">{{ desc }}</slot>
</p>
<div v-else-if="$slots.desc" class="aksrt-page-header__desc">
<div v-else-if="$slots.desc" class="jio-page-header__desc">
<slot name="desc" />
</div>
</div>
<div v-if="$slots.actions" class="aksrt-page-header__actions">
<div v-if="$slots.actions" class="jio-page-header__actions">
<slot name="actions" />
</div>
</header>
@@ -23,7 +23,7 @@ defineProps({
</script>
<style scoped>
.aksrt-page-header {
.jio-page-header {
display: flex;
align-items: flex-start;
justify-content: space-between;
@@ -32,28 +32,28 @@ defineProps({
flex-wrap: wrap;
}
.aksrt-page-header__main {
.jio-page-header__main {
flex: 1 1 auto;
min-width: 0;
}
.aksrt-page-header__title {
.jio-page-header__title {
margin: 0 0 6px;
color: var(--aksrt-color-text);
color: var(--jio-color-text);
font-size: 22px;
font-weight: 700;
letter-spacing: -0.02em;
line-height: 1.3;
}
.aksrt-page-header__desc {
.jio-page-header__desc {
margin: 0;
color: var(--aksrt-color-muted);
color: var(--jio-color-muted);
font-size: 13px;
line-height: 1.65;
}
.aksrt-page-header__actions {
.jio-page-header__actions {
flex: 0 0 auto;
display: flex;
align-items: center;
@@ -61,20 +61,20 @@ defineProps({
}
@media (max-width: 768px) {
.aksrt-page-header {
.jio-page-header {
margin-bottom: 14px;
gap: 10px;
}
.aksrt-page-header__title {
.jio-page-header__title {
font-size: 18px;
}
.aksrt-page-header__desc {
.jio-page-header__desc {
font-size: 12px;
}
.aksrt-page-header__actions {
.jio-page-header__actions {
width: 100%;
}
}
@@ -1,5 +1,5 @@
<template>
<n-form label-placement="left" label-width="110" class="aksrt-form float-common-fields">
<n-form label-placement="left" label-width="110" class="jio-form float-common-fields">
<n-form-item label="PC端显示" :show-feedback="false">
<n-switch :value="!!modelValue.pc_s" @update:value="update('pc_s', $event)" />
</n-form-item>
@@ -10,7 +10,7 @@
<div class="float-common-fields__colors">
<div class="float-common-fields__color">
<span>自定义图标颜色</span>
<AksColorPicker
<JioColorPicker
:model-value="modelValue.color?.color || ''"
alpha
clearable
@@ -19,7 +19,7 @@
</div>
<div class="float-common-fields__color">
<span>自定义背景颜色</span>
<AksColorPicker
<JioColorPicker
:model-value="modelValue.color?.bg || ''"
alpha
clearable
@@ -33,7 +33,7 @@
</template>
<script setup>
import AksColorPicker from '@/components/form/AksColorPicker.vue'
import JioColorPicker from '@/components/form/JioColorPicker.vue'
const props = defineProps({
modelValue: { type: Object, required: true },
@@ -1,10 +1,10 @@
<template>
<div class="float-btn-panel">
<div class="aksrt-sortable__head" v-bind="headAttrs">
<AksSortHandle @click.stop />
<div class="aksrt-sortable__main">
<div class="aksrt-sortable__title-row">
<span class="aksrt-sortable__title">{{ meta.title }}</span>
<div class="jio-sortable__head" v-bind="headAttrs">
<JioSortHandle @click.stop />
<div class="jio-sortable__main">
<div class="jio-sortable__title-row">
<span class="jio-sortable__title">{{ meta.title }}</span>
<template v-if="modelValue.type !== 'more'">
<n-tag v-if="modelValue.pc_s" size="small" type="info" :bordered="false">PC</n-tag>
<n-tag v-if="modelValue.m_s" size="small" type="warning" :bordered="false">移动</n-tag>
@@ -12,18 +12,18 @@
</template>
<n-tag v-else size="small" :bordered="false">{{ modelValue.buttons.length }} 个</n-tag>
</div>
<span v-if="meta.warn" class="aksrt-sortable__desc float-btn-panel__warn">
<span v-if="meta.warn" class="jio-sortable__desc float-btn-panel__warn">
<i class="fa fas fa-info-circle" aria-hidden="true" /> {{ meta.warn }}
</span>
</div>
<i
class="fa fas aksrt-sortable__toggle"
class="fa fas jio-sortable__toggle"
:class="expanded ? 'fa-chevron-down' : 'fa-chevron-right'"
aria-hidden="true"
/>
</div>
<div v-show="expanded" class="aksrt-sortable__body">
<div v-show="expanded" class="jio-sortable__body">
<div class="float-btn-panel__subtitle">{{ meta.panel }}</div>
<FloatMoreButtonsEditor
@@ -35,7 +35,7 @@
<template v-else>
<FloatBtnCommonFields :model-value="modelValue" @update:model-value="emit('update:modelValue', $event)" />
<n-form label-placement="left" label-width="110" class="aksrt-form float-btn-panel__extra">
<n-form label-placement="left" label-width="110" class="jio-form float-btn-panel__extra">
<n-form-item v-if="modelValue.type === 'qrcode'" label="一句话简介">
<n-input :value="modelValue.desc" @update:value="patch({ desc: $event })" />
</n-form-item>
@@ -49,7 +49,7 @@
</n-form-item>
<n-form-item v-if="modelValue.type === 'service_wechat'" label="微信二维码">
<AksMediaField
<JioMediaField
:model-value="modelValue.wechat_img"
placeholder="选择二维码图片"
@update:model-value="patch({ wechat_img: $event })"
@@ -62,11 +62,11 @@
</template>
<script setup>
/** 悬浮按钮排序列表中的单个卡片;外层 .aksrt-sortable__item 由 FloatingButtonsSettings 提供。 */
/** 悬浮按钮排序列表中的单个卡片;外层 .jio-sortable__item 由 FloatingButtonsSettings 提供。 */
import { computed, ref } from 'vue'
import FaIconPicker from '@/components/form/FaIconPicker.vue'
import AksMediaField from '@/components/form/AksMediaField.vue'
import AksSortHandle from '@/components/form/AksSortHandle.vue'
import JioMediaField from '@/components/form/JioMediaField.vue'
import JioSortHandle from '@/components/form/JioSortHandle.vue'
import { collapseHeadAttrs } from '@/components/form/useCollapsibleItems.js'
import FloatBtnCommonFields from './FloatBtnCommonFields.vue'
import FloatMoreButtonsEditor from './FloatMoreButtonsEditor.vue'
@@ -93,12 +93,12 @@ function patch(partial) {
<style scoped>
.float-btn-panel__warn {
color: var(--aksrt-color-warning, #D97706);
color: var(--jio-color-warning, #D97706);
}
.float-btn-panel__subtitle {
margin-bottom: 12px;
color: var(--aksrt-color-text);
color: var(--jio-color-text);
font-size: 13px;
font-weight: 600;
}
@@ -24,7 +24,7 @@
</n-button>
</template>
<n-form label-placement="left" label-width="110" class="aksrt-form">
<n-form label-placement="left" label-width="110" class="jio-form">
<n-form-item label="按钮简介">
<n-input :value="btn.desc" @update:value="patch(index, { desc: $event })" />
</n-form-item>
@@ -16,7 +16,7 @@ export const FLOAT_BTN_META = {
more: { title: '更多按钮', panel: '添加更多自定义按钮' },
}
const themeUri = (window.aksrtAdminData?.themeUri || '').replace(/\/$/, '')
const themeUri = (window.jioAdminData?.themeUri || '').replace(/\/$/, '')
/** 「更多按钮」出厂默认项(对齐参考主题 float_btn.more 默认值)。 */
export function giftMoreButton() {
@@ -1,5 +1,5 @@
<template>
<div class="aksrt-fa-icon-picker">
<div class="jio-fa-icon-picker">
<n-popover v-model:show="popoverShow" trigger="click" placement="bottom-start" :width="460" :style="{ padding: 0 }">
<template #trigger>
<n-input
@@ -19,8 +19,8 @@
</n-input>
</template>
<div class="aksrt-icon-picker__panel" @click="onPanelClick">
<div class="aksrt-icon-picker__search">
<div class="jio-icon-picker__panel" @click="onPanelClick">
<div class="jio-icon-picker__search">
<n-input v-model:value="search" placeholder="搜索图标..." size="small" clearable>
<template #prefix>
<FaIcon icon="fa fas fa-search" :size="12" />
@@ -28,12 +28,12 @@
</n-input>
</div>
<div class="aksrt-icon-picker__tabs">
<div class="jio-icon-picker__tabs">
<button
v-for="tab in tabs"
:key="tab.id"
type="button"
class="aksrt-icon-picker__tab"
class="jio-icon-picker__tab"
:class="{ 'is-active': activeTab === tab.id }"
@click="activeTab = tab.id"
>
@@ -42,23 +42,23 @@
</div>
<!-- Custom SVG tab -->
<div v-if="activeTab === 'custom'" class="aksrt-icon-picker__custom">
<div v-if="activeTab === 'custom'" class="jio-icon-picker__custom">
<n-input v-model:value="customCode" type="textarea" placeholder='&lt;svg viewBox="0 0 1024 1024"&gt;&lt;path d="…"&gt;&lt;/path&gt;&lt;/svg&gt;' :rows="4" />
<div class="aksrt-icon-picker__custom-actions">
<span class="aksrt-icon-picker__custom-preview" v-html="customPreview"></span>
<div class="jio-icon-picker__custom-actions">
<span class="jio-icon-picker__custom-preview" v-html="customPreview"></span>
<n-button size="small" type="primary" :disabled="!customPreview" @click="insertCustom">
确认插入
</n-button>
</div>
<div
v-if="sessionCustom.length"
class="aksrt-icon-picker__grid aksrt-icon-picker__grid--session"
data-aksrt-icon-grid="custom"
class="jio-icon-picker__grid jio-icon-picker__grid--session"
data-jio-icon-grid="custom"
>
<div
v-for="(svg, i) in sessionCustom"
:key="i"
class="aksrt-icon-picker__item"
class="jio-icon-picker__item"
:class="{ 'is-active': modelValue === `customsvg-${svg}` }"
title="customsvg"
:data-icon="`customsvg-${svg}`"
@@ -68,11 +68,11 @@
</div>
<!-- Catalog tab -->
<div v-else class="aksrt-icon-picker__grid" data-aksrt-icon-grid="catalog">
<div v-else class="jio-icon-picker__grid" data-jio-icon-grid="catalog">
<div
v-for="icon in filteredIcons"
:key="icon"
class="aksrt-icon-picker__item"
class="jio-icon-picker__item"
:class="{ 'is-active': modelValue === composeIconValue(activeGroup, icon) }"
:title="icon"
:data-icon="composeIconValue(activeGroup, icon)"
@@ -80,11 +80,11 @@
<i v-if="activeGroup.type === 'fa'" :class="[activeTab, 'fa-' + icon]"></i>
<span
v-else
class="aksrt-icon-picker__preview-svg"
class="jio-icon-picker__preview-svg"
v-html="zibsvgMarkup(`zibsvg-${icon}`)"
></span>
</div>
<div v-if="filteredIcons.length === 0" class="aksrt-icon-picker__empty">
<div v-if="filteredIcons.length === 0" class="jio-icon-picker__empty">
未找到匹配图标
</div>
</div>
@@ -96,7 +96,7 @@
<script setup>
/**
* FaIconPicker — universal icon picker backed by the server catalog
* (GET /aksrt/v1/icons/catalog): full FA5 free set, the theme's built-in
* (GET /jio/v1/icons/catalog): full FA5 free set, the theme's built-in
* SVG sprite keys and inline custom SVG values.
*/
import { ref, computed, onMounted } from 'vue'
@@ -176,53 +176,53 @@ onMounted(async () => {
</script>
<style scoped>
.aksrt-icon-picker__panel {
/* The popover teleports to <body>, outside #aksrt-admin-app where the
.jio-icon-picker__panel {
/* The popover teleports to <body>, outside #jio-admin-app where the
palette is declared — re-declare every token the panel consumes. */
--aksrt-color-primary: #18A058;
--aksrt-color-primary-hover: #36AD6A;
--aksrt-color-primary-soft: rgba(24, 160, 88, 0.12);
--aksrt-color-text-secondary: #465149;
--aksrt-color-muted: #6F7A72;
--aksrt-color-border: #E2E8E3;
--jio-color-primary: #18A058;
--jio-color-primary-hover: #36AD6A;
--jio-color-primary-soft: rgba(24, 160, 88, 0.12);
--jio-color-text-secondary: #465149;
--jio-color-muted: #6F7A72;
--jio-color-border: #E2E8E3;
padding: 12px;
}
.aksrt-icon-picker__search {
.jio-icon-picker__search {
margin-bottom: 10px;
}
.aksrt-icon-picker__tabs {
.jio-icon-picker__tabs {
display: flex;
flex-wrap: wrap;
gap: 6px;
margin-bottom: 10px;
}
.aksrt-icon-picker__tab {
.jio-icon-picker__tab {
padding: 3px 10px;
font-size: 13px;
line-height: 20px;
border: 1px solid var(--aksrt-color-border);
border: 1px solid var(--jio-color-border);
border-radius: 4px;
background: transparent;
color: var(--aksrt-color-text-secondary);
color: var(--jio-color-text-secondary);
cursor: pointer;
transition: all 0.15s;
}
.aksrt-icon-picker__tab:hover {
border-color: var(--aksrt-color-primary);
color: var(--aksrt-color-primary);
.jio-icon-picker__tab:hover {
border-color: var(--jio-color-primary);
color: var(--jio-color-primary);
}
.aksrt-icon-picker__tab.is-active {
border-color: var(--aksrt-color-primary);
background: var(--aksrt-color-primary);
.jio-icon-picker__tab.is-active {
border-color: var(--jio-color-primary);
background: var(--jio-color-primary);
color: #fff;
}
.aksrt-icon-picker__grid {
.jio-icon-picker__grid {
display: grid;
grid-template-columns: repeat(8, 1fr);
gap: 4px;
@@ -230,7 +230,7 @@ onMounted(async () => {
overflow-y: auto;
}
.aksrt-icon-picker__item {
.jio-icon-picker__item {
display: flex;
align-items: center;
justify-content: center;
@@ -239,60 +239,60 @@ onMounted(async () => {
border-radius: 6px;
cursor: pointer;
font-size: 16px;
color: var(--aksrt-color-text-secondary);
color: var(--jio-color-text-secondary);
transition: all 0.15s;
}
.aksrt-icon-picker__item:hover {
background: var(--aksrt-color-primary-soft);
color: var(--aksrt-color-primary);
.jio-icon-picker__item:hover {
background: var(--jio-color-primary-soft);
color: var(--jio-color-primary);
}
.aksrt-icon-picker__item.is-active {
background: var(--aksrt-color-primary);
.jio-icon-picker__item.is-active {
background: var(--jio-color-primary);
color: #fff;
}
.aksrt-icon-picker__item :deep(svg),
.aksrt-icon-picker__preview-svg :deep(svg),
.aksrt-icon-picker__preview-svg svg {
.jio-icon-picker__item :deep(svg),
.jio-icon-picker__preview-svg :deep(svg),
.jio-icon-picker__preview-svg svg {
width: 18px;
height: 18px;
fill: currentColor;
}
.aksrt-icon-picker__preview-svg {
.jio-icon-picker__preview-svg {
display: inline-flex;
}
.aksrt-icon-picker__empty {
.jio-icon-picker__empty {
grid-column: 1 / -1;
text-align: center;
padding: 20px;
color: var(--aksrt-color-muted);
color: var(--jio-color-muted);
font-size: 13px;
}
.aksrt-icon-picker__custom-actions {
.jio-icon-picker__custom-actions {
display: flex;
align-items: center;
gap: 10px;
margin-top: 8px;
}
.aksrt-icon-picker__custom-preview {
.jio-icon-picker__custom-preview {
display: inline-flex;
align-items: center;
justify-content: center;
width: 32px;
height: 32px;
border: 1px dashed var(--aksrt-color-muted);
border: 1px dashed var(--jio-color-muted);
border-radius: 4px;
}
.aksrt-icon-picker__grid--session {
.jio-icon-picker__grid--session {
margin-top: 10px;
padding-top: 8px;
border-top: 1px solid var(--aksrt-color-muted);
border-top: 1px solid var(--jio-color-muted);
}
</style>
@@ -4,13 +4,13 @@
<!-- Built-in sprite value -->
<span
v-else-if="isZibsvgValue(value)"
class="aksrt-icon-value__svg"
class="jio-icon-value__svg"
v-html="zibsvgMarkup(value)"
></span>
<!-- Inline custom SVG value -->
<span
v-else-if="isCustomSvgValue(value)"
class="aksrt-icon-value__svg"
class="jio-icon-value__svg"
v-html="cleanSvg(value.slice(10))"
></span>
</template>
@@ -35,12 +35,12 @@ const faClass = computed(() => {
</script>
<style scoped>
.aksrt-icon-value__svg {
.jio-icon-value__svg {
display: inline-flex;
}
.aksrt-icon-value__svg :deep(svg),
.aksrt-icon-value__svg svg {
.jio-icon-value__svg :deep(svg),
.jio-icon-value__svg svg {
width: 1em;
height: 1em;
fill: currentColor;
@@ -17,7 +17,7 @@
<script setup>
/**
* 后台唯一取色器:所有颜色字段都经由此组件,输出与
* PHP `AKSRT\Core\Color::sanitize($value, $allow_alpha)` 同一规则的规范值。
* PHP `Jio\Core\Color::sanitize($value, $allow_alpha)` 同一规则的规范值。
* 清空 / 非法值统一回传空串。
*/
import { computed } from 'vue'
@@ -1,6 +1,6 @@
<template>
<!-- Between number (min/max pair) -->
<div class="aksrt-composite aksrt-composite--between">
<div class="jio-composite jio-composite--between">
<n-input-number
:value="betweenValue('min')"
:min="schema.min"
@@ -11,7 +11,7 @@
style="flex: 1"
@update:value="update('min', $event)"
/>
<span class="aksrt-composite__sep">—</span>
<span class="jio-composite__sep">—</span>
<n-input-number
:value="betweenValue('max')"
:min="schema.min"
@@ -22,7 +22,7 @@
style="flex: 1"
@update:value="update('max', $event)"
/>
<span v-if="schema.unit" class="aksrt-composite__unit">{{ schema.unit }}</span>
<span v-if="schema.unit" class="jio-composite__unit">{{ schema.unit }}</span>
</div>
</template>
@@ -52,23 +52,23 @@ function betweenValue(part) {
</script>
<style scoped>
.aksrt-composite {
.jio-composite {
display: flex;
align-items: center;
gap: 8px;
}
.aksrt-composite--between {
.jio-composite--between {
max-width: 360px;
}
.aksrt-composite__sep {
color: var(--aksrt-color-border-strong);
.jio-composite__sep {
color: var(--jio-color-border-strong);
font-size: 14px;
}
.aksrt-composite__unit {
color: var(--aksrt-color-muted);
.jio-composite__unit {
color: var(--jio-color-muted);
font-size: 13px;
white-space: nowrap;
}
@@ -1,19 +1,19 @@
<template>
<div class="aksrt-field" :class="fieldClasses">
<div v-if="schema.label" class="aksrt-field__label-row">
<label class="aksrt-field__label">
<div class="jio-field" :class="fieldClasses">
<div v-if="schema.label" class="jio-field__label-row">
<label class="jio-field__label">
{{ schema.label }}
<span v-if="schema.required" class="aksrt-field__required">*</span>
<span v-if="schema.required" class="jio-field__required">*</span>
</label>
<n-tooltip v-if="schema.help" trigger="hover">
<template #trigger>
<FaIcon icon="fa fas fa-question-circle" :size="13" class="aksrt-field__help-icon" />
<FaIcon icon="fa fas fa-question-circle" :size="13" class="jio-field__help-icon" />
</template>
{{ schema.help }}
</n-tooltip>
</div>
<p v-if="schema.description && !schema.help" class="aksrt-field__desc">
<p v-if="schema.description && !schema.help" class="jio-field__desc">
{{ schema.description }}
</p>
@@ -25,7 +25,7 @@
/>
<!-- Input (text, email, url, password) -->
<div v-else-if="schema.type === 'input' || schema.type === 'text' || schema.type === 'url'" class="aksrt-field__input-wrap">
<div v-else-if="schema.type === 'input' || schema.type === 'text' || schema.type === 'url'" class="jio-field__input-wrap">
<n-input
:value="secretDisplayValue"
:placeholder="schema.placeholder || ''"
@@ -36,11 +36,11 @@
<template v-if="schema.prefix" #prefix>{{ schema.prefix }}</template>
<template v-if="schema.suffix" #suffix>{{ schema.suffix }}</template>
</n-input>
<AksSecretClear :visible="secretClearVisible" :marked="secretMarkedForClear" @toggle="toggleSecretClear" />
<JioSecretClear :visible="secretClearVisible" :marked="secretMarkedForClear" @toggle="toggleSecretClear" />
</div>
<!-- Textarea(secret 时不回显已配置值,聚焦后输入新值即覆盖) -->
<div v-else-if="schema.type === 'textarea'" class="aksrt-field__input-wrap">
<div v-else-if="schema.type === 'textarea'" class="jio-field__input-wrap">
<n-input
:value="secretTextareaValue"
type="textarea"
@@ -49,11 +49,11 @@
:disabled="schema.disabled"
@update:value="emit('update:modelValue', $event)"
/>
<AksSecretClear :visible="secretClearVisible" :marked="secretMarkedForClear" @toggle="toggleSecretClear" />
<JioSecretClear :visible="secretClearVisible" :marked="secretMarkedForClear" @toggle="toggleSecretClear" />
</div>
<!-- Number -->
<div v-else-if="schema.type === 'number' || schema.type === 'spinner'" class="aksrt-field__number">
<div v-else-if="schema.type === 'number' || schema.type === 'spinner'" class="jio-field__number">
<n-input-number
:value="modelValue"
:min="schema.min"
@@ -64,11 +64,11 @@
style="width: 100%"
@update:value="emit('update:modelValue', $event)"
/>
<span v-if="schema.unit" class="aksrt-field__unit">{{ schema.unit }}</span>
<span v-if="schema.unit" class="jio-field__unit">{{ schema.unit }}</span>
</div>
<!-- Select -->
<div v-else-if="schema.type === 'select'" class="aksrt-field__ordered-select">
<div v-else-if="schema.type === 'select'" class="jio-field__ordered-select">
<n-select
:value="modelValue"
:options="normalizedOptions"
@@ -78,7 +78,7 @@
:disabled="schema.disabled"
@update:value="emit('update:modelValue', $event)"
/>
<AksSelectedOrder
<JioSelectedOrder
v-if="schema.multiple && schema.sortable && Array.isArray(modelValue)"
:model-value="modelValue"
:options="normalizedOptions"
@@ -87,7 +87,7 @@
/>
</div>
<div v-else-if="schema.type === 'async_select'" class="aksrt-field__ordered-select">
<div v-else-if="schema.type === 'async_select'" class="jio-field__ordered-select">
<n-select
:value="schema.multiple === true && !Array.isArray(modelValue) ? [] : modelValue"
:options="asyncOptions"
@@ -100,7 +100,7 @@
@search="handleAsyncSearch"
@update:value="emit('update:modelValue', $event)"
/>
<AksSelectedOrder
<JioSelectedOrder
v-if="schema.multiple && schema.sortable && Array.isArray(modelValue)"
:model-value="modelValue"
:options="asyncOptions"
@@ -199,7 +199,7 @@
</n-checkbox-group>
<!-- Color picker -->
<AksColorPicker
<JioColorPicker
v-else-if="schema.type === 'color'"
:model-value="typeof modelValue === 'string' ? modelValue : ''"
:alpha="!!schema.showAlpha"
@@ -208,12 +208,12 @@
@update:model-value="emit('update:modelValue', $event)"
/>
<div v-else-if="schema.type === 'palette'" class="aksrt-field__palette">
<div v-else-if="schema.type === 'palette'" class="jio-field__palette">
<button
v-for="opt in normalizedOptions"
:key="opt.value"
type="button"
class="aksrt-field__palette-item"
class="jio-field__palette-item"
:class="{ 'is-active': modelValue === opt.value }"
:style="{ background: opt.label }"
:title="opt.value"
@@ -230,7 +230,7 @@
/>
<!-- Media upload -->
<AksMediaField
<JioMediaField
v-else-if="schema.type === 'media' || schema.type === 'upload'"
:model-value="modelValue"
:accept="schema.accept"
@@ -239,7 +239,7 @@
/>
<!-- WordPress image gallery (attachment ID array) -->
<AksGalleryField
<JioGalleryField
v-else-if="schema.type === 'gallery'"
:model-value="Array.isArray(modelValue) ? modelValue : []"
:title="schema.label || '选择图片'"
@@ -259,7 +259,7 @@
/>
<!-- Code editor with syntax highlighting (CodeMirror 6) -->
<AksCodeEditor
<JioCodeEditor
v-else-if="schema.type === 'code'"
:model-value="modelValue"
:language="schema.language || 'html'"
@@ -281,7 +281,7 @@
<!-- Pure HTML content (no form field, just display) -->
<div
v-else-if="schema.type === 'content'"
class="aksrt-field__content"
class="jio-field__content"
v-html="schema.content || modelValue || ''"
/>
@@ -316,7 +316,7 @@
/>
<!-- Object composite: between_number (min/max pair) -->
<AksCompositeField
<JioCompositeField
v-else-if="schema.type === 'between_number'"
:schema="schema"
:model-value="modelValue"
@@ -324,7 +324,7 @@
/>
<!-- Image select (radio with image preview) -->
<AksImageSelectField
<JioImageSelectField
v-else-if="schema.type === 'image_select'"
:model-value="modelValue"
:options="normalizedOptions"
@@ -334,24 +334,24 @@
/>
<!-- Fieldset (single nested object) -->
<div v-else-if="schema.type === 'fieldset' || schema.type === 'accordion'" class="aksrt-field__fieldset">
<div v-else-if="schema.type === 'fieldset' || schema.type === 'accordion'" class="jio-field__fieldset">
<template v-if="fieldsetSections.length">
<div
v-for="(section, sIndex) in fieldsetSections"
:key="section.title"
class="aksrt-field__accordion-section"
class="jio-field__accordion-section"
:class="{ 'is-collapsed': !isFieldsetSectionOpen(sIndex) }"
>
<div class="aksrt-field__accordion-section-head" @click="toggleFieldsetSection(sIndex)">
<span class="aksrt-field__accordion-section-title">{{ section.title }}</span>
<div class="jio-field__accordion-section-head" @click="toggleFieldsetSection(sIndex)">
<span class="jio-field__accordion-section-title">{{ section.title }}</span>
<FaIcon
:icon="isFieldsetSectionOpen(sIndex) ? 'fa fas fa-chevron-down' : 'fa fas fa-chevron-right'"
:size="12"
class="aksrt-field__accordion-section-toggle"
class="jio-field__accordion-section-toggle"
/>
</div>
<div v-show="isFieldsetSectionOpen(sIndex)" class="aksrt-field__accordion-section-body">
<AksField
<div v-show="isFieldsetSectionOpen(sIndex)" class="jio-field__accordion-section-body">
<JioField
v-for="field in sectionFields(section)"
:key="field.key"
:schema="field"
@@ -363,7 +363,7 @@
</div>
</template>
<template v-if="!fieldsetSections.length">
<AksField
<JioField
v-for="field in visibleNestedFields"
:key="field.key"
:schema="field"
@@ -374,7 +374,7 @@
</template>
</div>
<div v-else-if="schema.type === 'link'" class="aksrt-field__link">
<div v-else-if="schema.type === 'link'" class="jio-field__link">
<n-input :value="modelValue?.url || ''" placeholder="https://" @update:value="updateLink('url', $event)" />
<n-select :value="modelValue?.target || ''" :options="linkTargetOptions" @update:value="updateLink('target', $event)" />
<n-input :value="modelValue?.text || ''" placeholder="链接文字(可选)" @update:value="updateLink('text', $event)" />
@@ -386,54 +386,54 @@
v-bind="SORTABLE_LIST_ATTRS"
item-key="key"
:disabled="schema.disabled"
class="aksrt-sortable"
class="jio-sortable"
>
<template #item="{ element: item, index }">
<div class="aksrt-sortable__item">
<div class="jio-sortable__item">
<div
class="aksrt-sortable__head"
class="jio-sortable__head"
v-bind="item.fields?.length ? listItemHeadAttrs(item.key) : {}"
>
<AksSortHandle @click.stop />
<span class="aksrt-sortable__index">{{ index + 1 }}</span>
<span class="aksrt-sortable__main">
<span class="aksrt-sortable__title">{{ item.label }}</span>
<JioSortHandle @click.stop />
<span class="jio-sortable__index">{{ index + 1 }}</span>
<span class="jio-sortable__main">
<span class="jio-sortable__title">{{ item.label }}</span>
</span>
<FaIcon
v-if="item.fields?.length"
:icon="isListItemOpen(item.key) ? 'fa fas fa-chevron-down' : 'fa fas fa-chevron-right'"
:size="12"
class="aksrt-sortable__toggle"
class="jio-sortable__toggle"
/>
</div>
<div v-if="item.fields?.length" v-show="isListItemOpen(item.key)" class="aksrt-sortable__body aksrt-field__sortable-body">
<AksField v-for="field in item.fields" :key="field.key" :schema="field" :model-value="modelValue?.[item.key]?.[field.key] ?? field.default" :form-data="formData" @update:model-value="updateSortable(item.key, field.key, $event)" />
<div v-if="item.fields?.length" v-show="isListItemOpen(item.key)" class="jio-sortable__body jio-field__sortable-body">
<JioField v-for="field in item.fields" :key="field.key" :schema="field" :model-value="modelValue?.[item.key]?.[field.key] ?? field.default" :form-data="formData" @update:model-value="updateSortable(item.key, field.key, $event)" />
</div>
</div>
</template>
</draggable>
<!-- Repeater (array of objects) — inline expand (default, draggable) -->
<div v-else-if="(schema.type === 'repeater' || schema.type === 'group') && schema.ui !== 'list-modal'" class="aksrt-field__repeater">
<div v-else-if="(schema.type === 'repeater' || schema.type === 'group') && schema.ui !== 'list-modal'" class="jio-field__repeater">
<draggable
v-if="repeaterDragList.length"
v-model="repeaterDragList"
v-bind="SORTABLE_LIST_ATTRS"
:item-key="repeaterDragKey"
:disabled="schema.disabled"
class="aksrt-sortable"
class="jio-sortable"
>
<template #item="{ element, index }">
<div class="aksrt-sortable__item">
<div class="aksrt-sortable__head" v-bind="repeaterHeadAttrs(repeaterDragKey(element))">
<AksSortHandle @click.stop />
<span class="aksrt-sortable__index">{{ index + 1 }}</span>
<span class="aksrt-sortable__main">
<span class="aksrt-sortable__title aksrt-field__repeater-summary">
<div class="jio-sortable__item">
<div class="jio-sortable__head" v-bind="repeaterHeadAttrs(repeaterDragKey(element))">
<JioSortHandle @click.stop />
<span class="jio-sortable__index">{{ index + 1 }}</span>
<span class="jio-sortable__main">
<span class="jio-sortable__title jio-field__repeater-summary">
{{ repeaterItemSummary(element) || '未填写' }}
</span>
</span>
<div class="aksrt-sortable__actions" @click.stop>
<div class="jio-sortable__actions" @click.stop>
<n-button
size="tiny"
type="error"
@@ -448,12 +448,12 @@
<FaIcon
:icon="isRepeaterItemOpen(repeaterDragKey(element)) ? 'fa fas fa-chevron-down' : 'fa fas fa-chevron-right'"
:size="12"
class="aksrt-sortable__toggle"
class="jio-sortable__toggle"
/>
</div>
<div v-show="isRepeaterItemOpen(repeaterDragKey(element))" class="aksrt-sortable__body aksrt-field__repeater-fields">
<div v-show="isRepeaterItemOpen(repeaterDragKey(element))" class="jio-sortable__body jio-field__repeater-fields">
<template v-for="field in (schema.fields || [])" :key="field.key">
<AksField
<JioField
v-if="matchDependency(field.dependsOn, element)"
:schema="field"
:model-value="element[field.key]"
@@ -466,7 +466,7 @@
</div>
</template>
</draggable>
<div v-else class="aksrt-sortable__empty">
<div v-else class="jio-sortable__empty">
<FaIcon icon="fa fas fa-inbox" :size="18" />
<span>{{ schema.emptyText || '暂无数据' }}</span>
</div>
@@ -483,7 +483,7 @@
</div>
<!-- Repeater list-modal: draggable card list + modal editor -->
<AksRepeaterListModal
<JioRepeaterListModal
v-else-if="(schema.type === 'repeater' || schema.type === 'group') && schema.ui === 'list-modal'"
:schema="schema"
:model-value="modelValue"
@@ -503,35 +503,35 @@
/>
<!-- Validation message -->
<p v-if="errorMessage" class="aksrt-field__error">{{ errorMessage }}</p>
<p v-if="errorMessage" class="jio-field__error">{{ errorMessage }}</p>
</div>
</template>
<script setup>
/**
* AksField — renders a single form field based on its schema definition.
* JioField — renders a single form field based on its schema definition.
*
* Supported types: switch, input/text, textarea, number, select, radio,
* checkbox, color, icon, media, gallery, slider, code, alert, fieldset, sortable,
* repeater (inline|list-modal), custom (slot).
*
* 所有可拖拽列表(sortable / 已选值排序 / repeater)共用 sortable-list.css +
* SORTABLE_LIST_ATTRS + AksSortHandle。
* SORTABLE_LIST_ATTRS + JioSortHandle。
*/
import { computed, ref } from 'vue'
import draggable from 'vuedraggable'
import FaIcon from './FaIcon.vue'
import FaIconPicker from './FaIconPicker.vue'
import AksMediaField from './AksMediaField.vue'
import AksGalleryField from './AksGalleryField.vue'
import AksCodeEditor from './AksCodeEditor.vue'
import AksCompositeField from './AksCompositeField.vue'
import AksColorPicker from './AksColorPicker.vue'
import AksImageSelectField from './AksImageSelectField.vue'
import AksSortHandle from './AksSortHandle.vue'
import AksSecretClear from './AksSecretClear.vue'
import AksSelectedOrder from './AksSelectedOrder.vue'
import AksRepeaterListModal from './AksRepeaterListModal.vue'
import JioMediaField from './JioMediaField.vue'
import JioGalleryField from './JioGalleryField.vue'
import JioCodeEditor from './JioCodeEditor.vue'
import JioCompositeField from './JioCompositeField.vue'
import JioColorPicker from './JioColorPicker.vue'
import JioImageSelectField from './JioImageSelectField.vue'
import JioSortHandle from './JioSortHandle.vue'
import JioSecretClear from './JioSecretClear.vue'
import JioSelectedOrder from './JioSelectedOrder.vue'
import JioRepeaterListModal from './JioRepeaterListModal.vue'
import { buildFieldsetSections } from './fieldset-sections.js'
import { matchDependency } from './field-dependency.js'
import { SORTABLE_LIST_ATTRS } from './sortable-options.js'
@@ -567,12 +567,12 @@ const {
} = useFieldRemoteOptions(props)
const fieldClasses = computed(() => ({
'aksrt-field--disabled': props.schema.disabled,
'aksrt-field--inline': props.schema.inline,
[`aksrt-field--${props.schema.type}`]: !!props.schema.type,
'jio-field--disabled': props.schema.disabled,
'jio-field--inline': props.schema.inline,
[`jio-field--${props.schema.type}`]: !!props.schema.type,
}))
const secretMarkedForClear = computed(() => props.schema.secret && props.modelValue === '__AKSRT_CLEAR_SECRET__')
const secretMarkedForClear = computed(() => props.schema.secret && props.modelValue === '__JIO_CLEAR_SECRET__')
const secretDisplayValue = computed(() => secretMarkedForClear.value ? '' : props.modelValue)
/** 已配置密钥(服务端回传 '***'):textarea 不回显掩码,留空即保持原值。 */
const secretConfigured = computed(() => props.schema.secret && props.modelValue === '***')
@@ -580,7 +580,7 @@ const secretClearVisible = computed(() => secretConfigured.value || secretMarked
const secretTextareaValue = computed(() => secretConfigured.value ? '' : secretDisplayValue.value)
function toggleSecretClear() {
emit('update:modelValue', secretMarkedForClear.value ? '***' : '__AKSRT_CLEAR_SECRET__')
emit('update:modelValue', secretMarkedForClear.value ? '***' : '__JIO_CLEAR_SECRET__')
}
/** Normalize options: support string[], {label, value}[], and dynamic formData-key references */
@@ -682,7 +682,7 @@ function updateSortable(itemKey, fieldKey, value) {
emit('update:modelValue', { ...current, [itemKey]: { ...(current[itemKey] || {}), [fieldKey]: value } })
}
// ============ Repeater(inline 展开;list-modal 见 AksRepeaterListModal) ============
// ============ Repeater(inline 展开;list-modal 见 JioRepeaterListModal) ============
const repeaterLength = computed(() => Array.isArray(props.modelValue) ? props.modelValue.length : 0)
const reachedRepeaterMinimum = computed(() => repeaterLength.value <= Number(props.schema.min || 0))
const reachedRepeaterMaximum = computed(() => Number(props.schema.max || 0) > 0 && repeaterLength.value >= Number(props.schema.max))
@@ -754,165 +754,165 @@ function updateRepeaterItem(index, fieldKey, value) {
</script>
<style scoped>
.aksrt-field {
.jio-field {
margin-bottom: 18px;
}
.aksrt-field:last-child {
.jio-field:last-child {
margin-bottom: 0;
}
/* 结构化分组(会员商品/续费商品/积分兑换/升级价格)与相邻字段之间留出更明确的间隔,
* 避免两个分组上下贴在一起,和参考主题的留白一致。 */
.aksrt-field--group,
.aksrt-field--repeater,
.aksrt-field--accordion,
.aksrt-field--fieldset {
.jio-field--group,
.jio-field--repeater,
.jio-field--accordion,
.jio-field--fieldset {
margin-bottom: 26px;
}
.aksrt-field__input-wrap {
.jio-field__input-wrap {
display: grid;
gap: 8px;
}
.aksrt-field__label-row {
.jio-field__label-row {
display: flex;
align-items: center;
gap: 6px;
margin-bottom: 6px;
}
.aksrt-field__label {
.jio-field__label {
font-size: 13px;
font-weight: 500;
color: var(--aksrt-color-text-secondary);
color: var(--jio-color-text-secondary);
}
.aksrt-field__required {
.jio-field__required {
color: #d03050;
margin-left: 2px;
}
.aksrt-field__help-icon {
color: var(--aksrt-color-border-strong);
.jio-field__help-icon {
color: var(--jio-color-border-strong);
cursor: help;
transition: color 0.15s;
}
.aksrt-field__help-icon:hover {
color: var(--aksrt-color-primary);
.jio-field__help-icon:hover {
color: var(--jio-color-primary);
}
.aksrt-field__desc {
.jio-field__desc {
margin: -2px 0 8px;
font-size: 12px;
color: var(--aksrt-color-muted);
color: var(--jio-color-muted);
line-height: 1.5;
}
.aksrt-field__error {
.jio-field__error {
margin: 4px 0 0;
font-size: 12px;
color: #d03050;
}
.aksrt-field--disabled {
.jio-field--disabled {
opacity: 0.6;
pointer-events: none;
}
.aksrt-field__number {
.jio-field__number {
display: flex;
align-items: center;
gap: 8px;
max-width: 360px;
}
.aksrt-field__unit {
color: var(--aksrt-color-muted);
.jio-field__unit {
color: var(--jio-color-muted);
font-size: 13px;
white-space: nowrap;
}
.aksrt-field__palette {
.jio-field__palette {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.aksrt-field__palette-item {
.jio-field__palette-item {
width: 34px;
height: 26px;
padding: 0;
border: 3px solid var(--aksrt-color-surface);
border: 3px solid var(--jio-color-surface);
border-radius: 3px;
box-shadow: 0 0 0 1px var(--aksrt-color-border-strong);
box-shadow: 0 0 0 1px var(--jio-color-border-strong);
cursor: pointer;
}
.aksrt-field__palette-item.is-active {
box-shadow: 0 0 0 2px var(--aksrt-color-primary);
.jio-field__palette-item.is-active {
box-shadow: 0 0 0 2px var(--jio-color-primary);
}
.aksrt-field__link {
.jio-field__link {
display: grid;
grid-template-columns: minmax(220px, 1fr) 120px minmax(140px, .5fr);
gap: 8px;
}
/* sortable 卡片展开区:两列字段栅格(卡片本身见 styles/sortable-list.css) */
.aksrt-field__sortable-body {
.jio-field__sortable-body {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 16px;
}
/* Fieldset / Accordion */
.aksrt-field__fieldset {
.jio-field__fieldset {
padding: 14px;
border: 1px solid var(--aksrt-color-border);
border: 1px solid var(--jio-color-border);
border-radius: 8px;
background: var(--aksrt-color-canvas);
background: var(--jio-color-canvas);
}
.aksrt-field__accordion-section + .aksrt-field__accordion-section {
.jio-field__accordion-section + .jio-field__accordion-section {
margin-top: 14px;
}
.aksrt-field__accordion-section-head {
.jio-field__accordion-section-head {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
padding: 8px 10px;
border: 1px solid var(--aksrt-color-border);
border: 1px solid var(--jio-color-border);
border-radius: 6px;
background: var(--aksrt-color-surface);
background: var(--jio-color-surface);
cursor: pointer;
user-select: none;
font-size: 13px;
font-weight: 600;
color: var(--aksrt-color-text);
color: var(--jio-color-text);
transition: border-color 0.15s, color 0.15s;
}
.aksrt-field__accordion-section-head:hover {
border-color: var(--aksrt-color-primary);
background: var(--aksrt-color-primary-soft);
color: var(--aksrt-color-primary);
.jio-field__accordion-section-head:hover {
border-color: var(--jio-color-primary);
background: var(--jio-color-primary-soft);
color: var(--jio-color-primary);
}
.aksrt-field__accordion-section-title {
.jio-field__accordion-section-title {
min-width: 0;
}
.aksrt-field__accordion-section-toggle {
.jio-field__accordion-section-toggle {
flex-shrink: 0;
color: var(--aksrt-color-text-secondary);
color: var(--jio-color-text-secondary);
}
.aksrt-field__accordion-section-body {
.jio-field__accordion-section-body {
display: flex;
flex-direction: column;
gap: 8px;
@@ -920,58 +920,58 @@ function updateRepeaterItem(index, fieldKey, value) {
}
/* Repeater inline(卡片 / 手柄 / 拖拽态见 styles/sortable-list.css) */
.aksrt-field__repeater {
.jio-field__repeater {
display: flex;
flex-direction: column;
gap: 10px;
}
.aksrt-field__repeater-fields {
.jio-field__repeater-fields {
display: flex;
flex-direction: column;
gap: 8px;
}
/* Content field */
.aksrt-field__content {
.jio-field__content {
font-size: 13px;
color: var(--aksrt-color-text-secondary);
color: var(--jio-color-text-secondary);
line-height: 1.6;
}
.aksrt-field__content :deep(p) {
.jio-field__content :deep(p) {
margin: 0;
}
.aksrt-field__content :deep(p + ul) {
.jio-field__content :deep(p + ul) {
margin-top: 6px;
}
.aksrt-field__content :deep(ul) {
.jio-field__content :deep(ul) {
margin: 0;
padding-left: 18px;
line-height: 1.9;
}
/* 说明文字的小号灰色段落与警示文字(schema content 里用 class 引用) */
.aksrt-field__content :deep(.aksrt-hint) {
color: var(--aksrt-color-muted);
.jio-field__content :deep(.jio-hint) {
color: var(--jio-color-muted);
font-size: 12px;
line-height: 1.7;
}
.aksrt-field__content :deep(.aksrt-hint + .aksrt-hint) {
.jio-field__content :deep(.jio-hint + .jio-hint) {
margin-top: 6px;
}
.aksrt-field__content :deep(.aksrt-warn) {
color: var(--aksrt-color-warning, #d97706);
.jio-field__content :deep(.jio-warn) {
color: var(--jio-color-warning, #d97706);
}
/* Mobile */
@media (max-width: 768px) {
.aksrt-field__link,
.aksrt-field__sortable-body {
.jio-field__link,
.jio-field__sortable-body {
grid-template-columns: 1fr;
}
}
@@ -1,26 +1,26 @@
<template>
<div class="aksrt-field-group" :class="{ 'is-collapsible': collapsible, 'is-collapsed': collapsible && collapsed }">
<div class="jio-field-group" :class="{ 'is-collapsible': collapsible, 'is-collapsed': collapsible && collapsed }">
<div
v-if="title"
class="aksrt-field-group__header"
class="jio-field-group__header"
:class="{ 'is-clickable': collapsible }"
@click="collapsible ? toggleCollapse() : undefined"
>
<div class="aksrt-field-group__header-left">
<FaIcon v-if="icon" :icon="icon" :size="16" class="aksrt-field-group__icon" />
<div class="jio-field-group__header-left">
<FaIcon v-if="icon" :icon="icon" :size="16" class="jio-field-group__icon" />
<div>
<h3 class="aksrt-field-group__title">{{ title }}</h3>
<p v-if="description" class="aksrt-field-group__desc">{{ description }}</p>
<h3 class="jio-field-group__title">{{ title }}</h3>
<p v-if="description" class="jio-field-group__desc">{{ description }}</p>
</div>
</div>
<div class="aksrt-field-group__header-right">
<div v-if="$slots.actions" class="aksrt-field-group__actions" @click.stop>
<div class="jio-field-group__header-right">
<div v-if="$slots.actions" class="jio-field-group__actions" @click.stop>
<slot name="actions" />
</div>
<button
v-if="collapsible"
type="button"
class="aksrt-field-group__collapse-btn"
class="jio-field-group__collapse-btn"
:aria-expanded="(!collapsed).toString()"
:title="collapsed ? '展开配置' : '收起配置'"
@click.stop="toggleCollapse"
@@ -34,8 +34,8 @@
</div>
</div>
<transition name="aksrt-collapse">
<div v-show="!collapsed" class="aksrt-field-group__body">
<transition name="jio-collapse">
<div v-show="!collapsed" class="jio-field-group__body">
<slot />
</div>
</transition>
@@ -44,7 +44,7 @@
<script setup>
/**
* AksFieldGroup — card-style container for grouping related form fields.
* JioFieldGroup — card-style container for grouping related form fields.
* Supports collapsible sections, icon headers, and description text.
*
* defaultCollapsed only seeds the initial state; afterwards the user toggles freely.
@@ -69,16 +69,16 @@ function toggleCollapse() {
</script>
<style scoped>
.aksrt-field-group {
.jio-field-group {
margin-bottom: 20px;
border: 1px solid var(--aksrt-color-border);
border: 1px solid var(--jio-color-border);
border-radius: 12px;
background: var(--aksrt-color-surface);
box-shadow: var(--aksrt-shadow-card);
background: var(--jio-color-surface);
box-shadow: var(--jio-shadow-card);
overflow: hidden;
}
.aksrt-field-group__header {
.jio-field-group__header {
display: flex;
align-items: flex-start;
justify-content: space-between;
@@ -86,66 +86,66 @@ function toggleCollapse() {
gap: 12px;
}
.aksrt-field-group__header.is-clickable {
.jio-field-group__header.is-clickable {
cursor: pointer;
user-select: none;
}
.aksrt-field-group__header.is-clickable:hover .aksrt-field-group__title {
color: var(--aksrt-color-primary);
.jio-field-group__header.is-clickable:hover .jio-field-group__title {
color: var(--jio-color-primary);
}
.aksrt-field-group.is-collapsed .aksrt-field-group__header {
.jio-field-group.is-collapsed .jio-field-group__header {
padding-bottom: 18px;
}
.aksrt-field-group__header-left {
.jio-field-group__header-left {
display: flex;
align-items: flex-start;
gap: 10px;
min-width: 0;
}
.aksrt-field-group__header-right {
.jio-field-group__header-right {
display: flex;
align-items: center;
gap: 10px;
flex-shrink: 0;
}
.aksrt-field-group__icon {
color: var(--aksrt-color-primary);
.jio-field-group__icon {
color: var(--jio-color-primary);
margin-top: 2px;
}
.aksrt-field-group__title {
.jio-field-group__title {
margin: 0;
font-size: 15px;
font-weight: 600;
color: var(--aksrt-color-text);
color: var(--jio-color-text);
transition: color 0.15s;
}
.aksrt-field-group__desc {
.jio-field-group__desc {
margin: 4px 0 0;
font-size: 12px;
color: var(--aksrt-color-muted);
color: var(--jio-color-muted);
line-height: 1.5;
}
.aksrt-field-group__actions {
.jio-field-group__actions {
display: flex;
align-items: center;
gap: 8px;
}
.aksrt-field-group__collapse-btn {
.jio-field-group__collapse-btn {
display: inline-flex;
align-items: center;
gap: 6px;
border: 1px solid var(--aksrt-color-border);
background: var(--aksrt-color-canvas);
color: var(--aksrt-color-text-secondary);
border: 1px solid var(--jio-color-border);
background: var(--jio-color-canvas);
color: var(--jio-color-text-secondary);
border-radius: 999px;
padding: 4px 10px;
font-size: 12px;
@@ -153,25 +153,25 @@ function toggleCollapse() {
transition: color 0.15s, border-color 0.15s, background 0.15s;
}
.aksrt-field-group__collapse-btn:hover {
color: var(--aksrt-color-primary);
border-color: var(--aksrt-color-primary);
background: var(--aksrt-color-primary-soft);
.jio-field-group__collapse-btn:hover {
color: var(--jio-color-primary);
border-color: var(--jio-color-primary);
background: var(--jio-color-primary-soft);
}
.aksrt-field-group__body {
.jio-field-group__body {
padding: 16px 20px 20px;
}
/* Collapse transition */
.aksrt-collapse-enter-active,
.aksrt-collapse-leave-active {
.jio-collapse-enter-active,
.jio-collapse-leave-active {
transition: all 0.2s ease;
overflow: hidden;
}
.aksrt-collapse-enter-from,
.aksrt-collapse-leave-to {
.jio-collapse-enter-from,
.jio-collapse-leave-to {
opacity: 0;
max-height: 0;
padding-top: 0;
@@ -1,15 +1,15 @@
<template>
<div class="aksrt-form-renderer">
<div class="jio-form-renderer">
<!-- Page header with title and description -->
<div v-if="title" class="aksrt-form-renderer__header">
<div class="aksrt-form-renderer__header-left">
<FaIcon v-if="icon" :icon="icon" :size="22" class="aksrt-form-renderer__header-icon" />
<div v-if="title" class="jio-form-renderer__header">
<div class="jio-form-renderer__header-left">
<FaIcon v-if="icon" :icon="icon" :size="22" class="jio-form-renderer__header-icon" />
<div>
<h1 class="aksrt-form-renderer__title">{{ title }}</h1>
<p v-if="description" class="aksrt-form-renderer__desc">{{ description }}</p>
<h1 class="jio-form-renderer__title">{{ title }}</h1>
<p v-if="description" class="jio-form-renderer__desc">{{ description }}</p>
</div>
</div>
<div v-if="showSearch" class="aksrt-form-renderer__search">
<div v-if="showSearch" class="jio-form-renderer__search">
<n-input
v-model:value="searchQuery"
placeholder="搜索设置项..."
@@ -24,7 +24,7 @@
</div>
<!-- Loading state -->
<div v-if="loading" class="aksrt-form-renderer__loading">
<div v-if="loading" class="jio-form-renderer__loading">
<n-spin size="medium" />
<span>加载中...</span>
</div>
@@ -45,7 +45,7 @@
<!-- Form content -->
<template v-else-if="schema && schema.length">
<template v-for="group in filteredSchema" :key="groupKey(group)">
<AksFieldGroup
<JioFieldGroup
v-if="isGroupVisible(group)"
:title="group.title"
:description="group.description"
@@ -59,7 +59,7 @@
<!-- Tabbed: renders tabs whose sub-fields are flat top-level keys -->
<div
v-if="field.type === 'tabbed' && (field.tabs || []).length"
class="aksrt-form-renderer__tabbed"
class="jio-form-renderer__tabbed"
>
<n-tabs type="line" animated>
<n-tab-pane
@@ -69,7 +69,7 @@
:tab="tabName(tab)"
>
<template v-for="sub in (tab.fields || [])" :key="sub.key">
<AksField
<JioField
v-if="isFieldVisible(sub)"
:schema="sub"
:model-value="getFieldValue(sub.key)"
@@ -82,7 +82,7 @@
</n-tab-pane>
</n-tabs>
</div>
<AksSorterField
<JioSorterField
v-else-if="field.type === 'custom' && field.renderer === 'sorter'"
:model-value="getFieldValue(field.key) || {}"
:options="field.options || []"
@@ -93,7 +93,7 @@
:name="`field-${field.key}`"
v-bind="{ field, value: getFieldValue(field.key), setValue: (value) => setFieldValue(field.key, value), formData }"
>
<AksField
<JioField
:schema="field"
:model-value="getFieldValue(field.key)"
:form-data="formData"
@@ -102,7 +102,7 @@
@action="emit('field-action', $event)"
/>
</slot>
<AksField
<JioField
v-else
:schema="field"
:model-value="getFieldValue(field.key)"
@@ -117,24 +117,24 @@
<!-- Custom group content slot -->
<slot :name="`group-${group.key}`" v-bind="{ group, formData }" />
</AksFieldGroup>
</JioFieldGroup>
</template>
</template>
<!-- Empty state -->
<div v-else class="aksrt-form-renderer__empty">
<div v-else class="jio-form-renderer__empty">
<FaIcon icon="fa fas fa-cog" :size="32" />
<p>暂无配置项</p>
</div>
<!-- Sticky save bar -->
<AksSaveBar :dirty="dirty" :saving="saving" @save="$emit('save')" @reload="$emit('reload')" />
<JioSaveBar :dirty="dirty" :saving="saving" @save="$emit('save')" @reload="$emit('reload')" />
</div>
</template>
<script setup>
/**
* AksFormRenderer — the core schema-driven form engine.
* JioFormRenderer — the core schema-driven form engine.
*
* Takes a schema definition (array of field groups) and a reactive form data object,
* and renders a complete settings page with:
@@ -146,10 +146,10 @@
*/
import { ref, computed, useSlots } from 'vue'
import FaIcon from './FaIcon.vue'
import AksSaveBar from './AksSaveBar.vue'
import AksFieldGroup from './AksFieldGroup.vue'
import AksField from './AksField.vue'
import AksSorterField from './AksSorterField.vue'
import JioSaveBar from './JioSaveBar.vue'
import JioFieldGroup from './JioFieldGroup.vue'
import JioField from './JioField.vue'
import JioSorterField from './JioSorterField.vue'
const props = defineProps({
/** Page title */
@@ -308,7 +308,7 @@ const filteredSchema = computed(() => {
</script>
<style scoped>
.aksrt-form-renderer__header {
.jio-form-renderer__header {
display: flex;
align-items: flex-start;
justify-content: space-between;
@@ -317,73 +317,73 @@ const filteredSchema = computed(() => {
flex-wrap: wrap;
}
.aksrt-form-renderer__header-left {
.jio-form-renderer__header-left {
display: flex;
align-items: flex-start;
gap: 12px;
}
.aksrt-form-renderer__header-icon {
color: var(--aksrt-color-primary);
.jio-form-renderer__header-icon {
color: var(--jio-color-primary);
margin-top: 4px;
}
.aksrt-form-renderer__title {
.jio-form-renderer__title {
margin: 0;
font-size: 22px;
font-weight: 700;
color: var(--aksrt-color-text);
color: var(--jio-color-text);
letter-spacing: -0.02em;
}
.aksrt-form-renderer__desc {
.jio-form-renderer__desc {
margin: 4px 0 0;
font-size: 13px;
color: var(--aksrt-color-muted);
color: var(--jio-color-muted);
line-height: 1.6;
}
.aksrt-form-renderer__tabbed {
.jio-form-renderer__tabbed {
margin-bottom: 8px;
}
.aksrt-form-renderer__search {
.jio-form-renderer__search {
min-width: 200px;
max-width: 280px;
}
.aksrt-form-renderer__loading {
.jio-form-renderer__loading {
display: flex;
flex-direction: column;
align-items: center;
gap: 12px;
padding: 60px 0;
color: var(--aksrt-color-muted);
color: var(--jio-color-muted);
font-size: 14px;
}
.aksrt-form-renderer__empty {
.jio-form-renderer__empty {
display: flex;
flex-direction: column;
align-items: center;
gap: 12px;
padding: 60px 0;
color: var(--aksrt-color-border-strong);
color: var(--jio-color-border-strong);
}
.aksrt-form-renderer__empty p {
.jio-form-renderer__empty p {
margin: 0;
font-size: 14px;
}
/* Mobile */
@media (max-width: 768px) {
.aksrt-form-renderer__header {
.jio-form-renderer__header {
flex-direction: column;
gap: 10px;
}
.aksrt-form-renderer__search {
.jio-form-renderer__search {
max-width: 100%;
width: 100%;
}
@@ -1,23 +1,23 @@
<template>
<div class="aksrt-gallery-field">
<div v-if="attachmentIds.length" class="aksrt-gallery-field__grid">
<div class="jio-gallery-field">
<div v-if="attachmentIds.length" class="jio-gallery-field__grid">
<article
v-for="(attachmentId, index) in attachmentIds"
:key="attachmentId"
class="aksrt-gallery-field__item"
class="jio-gallery-field__item"
>
<img
v-if="previews[attachmentId]?.url"
:src="previews[attachmentId].url"
:alt="previews[attachmentId].alt || `附件 ${attachmentId}`"
class="aksrt-gallery-field__image"
class="jio-gallery-field__image"
/>
<div v-else class="aksrt-gallery-field__placeholder">
<div v-else class="jio-gallery-field__placeholder">
<FaIcon icon="fa fas fa-image" :size="22" />
<span>#{{ attachmentId }}</span>
</div>
<div class="aksrt-gallery-field__actions">
<div class="jio-gallery-field__actions">
<n-button
size="tiny"
quaternary
@@ -49,12 +49,12 @@
</article>
</div>
<div v-else class="aksrt-gallery-field__empty">
<div v-else class="jio-gallery-field__empty">
<FaIcon icon="fa fas fa-images" :size="28" />
<span>尚未选择图片</span>
</div>
<div class="aksrt-gallery-field__buttons">
<div class="jio-gallery-field__buttons">
<n-button type="primary" secondary @click="openMediaLibrary">
<FaIcon icon="fa fas fa-plus" />
{{ attachmentIds.length ? '编辑图片' : '选择图片' }}
@@ -64,7 +64,7 @@
</n-button>
</div>
<p v-if="mediaError" class="aksrt-gallery-field__error">{{ mediaError }}</p>
<p v-if="mediaError" class="jio-gallery-field__error">{{ mediaError }}</p>
</div>
</template>
@@ -172,25 +172,25 @@ watch(attachmentIds, hydratePreviews, { immediate: true })
</script>
<style scoped>
.aksrt-gallery-field__grid {
.jio-gallery-field__grid {
display: flex;
flex-wrap: wrap;
align-items: flex-start;
gap: 8px;
}
.aksrt-gallery-field__item {
.jio-gallery-field__item {
display: inline-flex;
flex-direction: column;
max-width: 100%;
padding: 4px 4px 0;
overflow: hidden;
border: 1px solid var(--aksrt-color-border);
border: 1px solid var(--jio-color-border);
border-radius: 8px;
background: var(--aksrt-color-canvas);
background: var(--jio-color-canvas);
}
.aksrt-gallery-field__image {
.jio-gallery-field__image {
display: block;
width: auto;
height: auto;
@@ -199,7 +199,7 @@ watch(attachmentIds, hydratePreviews, { immediate: true })
border-radius: 4px;
}
.aksrt-gallery-field__placeholder {
.jio-gallery-field__placeholder {
display: flex;
flex-direction: column;
width: 90px;
@@ -207,35 +207,35 @@ watch(attachmentIds, hydratePreviews, { immediate: true })
align-items: center;
justify-content: center;
gap: 4px;
color: var(--aksrt-color-muted);
color: var(--jio-color-muted);
}
.aksrt-gallery-field__actions {
.jio-gallery-field__actions {
display: flex;
justify-content: center;
padding: 4px;
border-top: 1px solid var(--aksrt-color-border);
border-top: 1px solid var(--jio-color-border);
}
.aksrt-gallery-field__empty {
.jio-gallery-field__empty {
display: flex;
min-height: 116px;
align-items: center;
justify-content: center;
flex-direction: column;
gap: 8px;
border: 1px dashed var(--aksrt-color-border-strong);
border: 1px dashed var(--jio-color-border-strong);
border-radius: 8px;
color: var(--aksrt-color-muted);
color: var(--jio-color-muted);
}
.aksrt-gallery-field__buttons {
.jio-gallery-field__buttons {
display: flex;
gap: 8px;
margin-top: 10px;
}
.aksrt-gallery-field__error {
.jio-gallery-field__error {
margin: 8px 0 0;
color: #d03050;
font-size: 12px;
@@ -1,21 +1,21 @@
<template>
<div class="aksrt-image-select" role="radiogroup">
<div class="jio-image-select" role="radiogroup">
<button
v-for="opt in options"
:key="opt.value"
type="button"
role="radio"
class="aksrt-image-select__item"
class="jio-image-select__item"
:class="{ 'is-active': modelValue === opt.value }"
:aria-checked="modelValue === opt.value"
:disabled="disabled"
@click="emit('update:modelValue', opt.value)"
>
<img v-if="opt.image" :src="opt.image" :alt="opt.label" class="aksrt-image-select__img" :style="imgStyle(opt)" />
<span v-else class="aksrt-image-select__placeholder" :style="imgStyle(opt)">
<img v-if="opt.image" :src="opt.image" :alt="opt.label" class="jio-image-select__img" :style="imgStyle(opt)" />
<span v-else class="jio-image-select__placeholder" :style="imgStyle(opt)">
<FaIcon :icon="opt.icon || 'fa fas fa-image'" :size="20" />
</span>
<span class="aksrt-image-select__label">{{ opt.label }}</span>
<span class="jio-image-select__label">{{ opt.label }}</span>
</button>
</div>
</template>
@@ -37,78 +37,78 @@ const emit = defineEmits(['update:modelValue'])
// An option may override the group width via its own `width`.
function imgStyle(opt) {
const width = opt && opt.width ? opt.width : props.previewWidth
return { '--aksrt-image-select-max': typeof width === 'number' ? `${width}px` : width }
return { '--jio-image-select-max': typeof width === 'number' ? `${width}px` : width }
}
</script>
<style scoped>
.aksrt-image-select {
.jio-image-select {
display: flex;
flex-wrap: wrap;
gap: 12px;
}
.aksrt-image-select__item {
.jio-image-select__item {
display: flex;
flex-direction: column;
align-items: center;
gap: 6px;
min-width: 80px;
padding: 8px;
border: 2px solid var(--aksrt-color-border);
border: 2px solid var(--jio-color-border);
border-radius: 8px;
background: var(--aksrt-color-surface);
background: var(--jio-color-surface);
cursor: pointer;
transition: border-color .15s ease, background-color .15s ease;
}
.aksrt-image-select__item:hover,
.aksrt-image-select__item:focus-visible {
.jio-image-select__item:hover,
.jio-image-select__item:focus-visible {
outline: none;
border-color: var(--aksrt-color-primary);
border-color: var(--jio-color-primary);
}
.aksrt-image-select__item.is-active {
border-color: var(--aksrt-color-primary);
background: var(--aksrt-color-primary-soft);
.jio-image-select__item.is-active {
border-color: var(--jio-color-primary);
background: var(--jio-color-primary-soft);
}
.aksrt-image-select__item:disabled {
.jio-image-select__item:disabled {
cursor: not-allowed;
}
.aksrt-image-select__img {
.jio-image-select__img {
display: block;
/* Preview images are wide layout strips (header 597x57, footer 800x190, slide
align 200x101), so let them keep their own aspect ratio inside the card.
A fixed square box with object-fit:cover crops the layout to an
unrecognisable sliver — the width is capped instead and the height follows. */
width: 100%;
max-width: var(--aksrt-image-select-max, 140px);
max-width: var(--jio-image-select-max, 140px);
height: auto;
border-radius: 4px;
background: var(--aksrt-color-canvas);
background: var(--jio-color-canvas);
}
.aksrt-image-select__placeholder {
.jio-image-select__placeholder {
display: flex;
align-items: center;
justify-content: center;
width: var(--aksrt-image-select-max, 140px);
width: var(--jio-image-select-max, 140px);
height: 60px;
border-radius: 4px;
background: var(--aksrt-color-canvas);
color: var(--aksrt-color-border-strong);
background: var(--jio-color-canvas);
color: var(--jio-color-border-strong);
}
.aksrt-image-select__label {
color: var(--aksrt-color-text-secondary);
.jio-image-select__label {
color: var(--jio-color-text-secondary);
font-size: 11px;
text-align: center;
}
@media (prefers-reduced-motion: reduce) {
.aksrt-image-select__item {
.jio-image-select__item {
transition: none;
}
}
@@ -1,17 +1,17 @@
<template>
<div class="aksrt-media-field">
<div v-if="modelValue" class="aksrt-media-field__preview">
<div class="jio-media-field">
<div v-if="modelValue" class="jio-media-field__preview">
<img
v-if="isImage"
:src="modelValue"
:alt="placeholder"
class="aksrt-media-field__image"
class="jio-media-field__image"
/>
<div v-else class="aksrt-media-field__file">
<div v-else class="jio-media-field__file">
<FaIcon icon="fa fas fa-file" :size="24" />
<span class="aksrt-media-field__filename">{{ fileName }}</span>
<span class="jio-media-field__filename">{{ fileName }}</span>
</div>
<div class="aksrt-media-field__overlay">
<div class="jio-media-field__overlay">
<n-button size="tiny" secondary circle title="更换" @click="openMediaLibrary">
<FaIcon icon="fa fas fa-exchange-alt" />
</n-button>
@@ -21,7 +21,7 @@
</div>
</div>
<div v-else class="aksrt-media-field__empty" @click="openMediaLibrary">
<div v-else class="jio-media-field__empty" @click="openMediaLibrary">
<FaIcon icon="fa fas fa-cloud-upload-alt" :size="28" />
<span>{{ placeholder }}</span>
</div>
@@ -30,7 +30,7 @@
:value="modelValue"
:placeholder="'或直接输入 URL'"
size="small"
class="aksrt-media-field__url"
class="jio-media-field__url"
@update:value="emit('update:modelValue', $event)"
/>
</div>
@@ -38,7 +38,7 @@
<script setup>
/**
* AksMediaField — image/file selector with preview.
* JioMediaField — image/file selector with preview.
*
* In the WordPress admin context, this can open the WP Media Library.
* For now, it supports direct URL input with preview.
@@ -95,7 +95,7 @@ function clearMedia() {
</script>
<style scoped>
.aksrt-media-field__preview {
.jio-media-field__preview {
position: relative;
display: inline-flex;
max-width: 100%;
@@ -104,13 +104,13 @@ function clearMedia() {
padding: 4px;
border-radius: 8px;
overflow: hidden;
border: 1px solid var(--aksrt-color-border);
background: var(--aksrt-color-canvas);
border: 1px solid var(--jio-color-border);
background: var(--jio-color-canvas);
margin-bottom: 8px;
vertical-align: top;
}
.aksrt-media-field__image {
.jio-media-field__image {
display: block;
width: auto;
height: auto;
@@ -119,21 +119,21 @@ function clearMedia() {
border-radius: 4px;
}
.aksrt-media-field__file {
.jio-media-field__file {
display: flex;
align-items: center;
gap: 8px;
padding: 16px;
background: var(--aksrt-color-canvas);
background: var(--jio-color-canvas);
}
.aksrt-media-field__filename {
.jio-media-field__filename {
font-size: 13px;
color: var(--aksrt-color-text-secondary);
color: var(--jio-color-text-secondary);
word-break: break-all;
}
.aksrt-media-field__overlay {
.jio-media-field__overlay {
position: absolute;
top: 0;
right: 0;
@@ -144,33 +144,33 @@ function clearMedia() {
transition: opacity 0.2s;
}
.aksrt-media-field__preview:hover .aksrt-media-field__overlay {
.jio-media-field__preview:hover .jio-media-field__overlay {
opacity: 1;
}
.aksrt-media-field__empty {
.jio-media-field__empty {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 8px;
padding: 32px;
border: 2px dashed var(--aksrt-color-border-strong);
border: 2px dashed var(--jio-color-border-strong);
border-radius: 8px;
cursor: pointer;
color: var(--aksrt-color-muted);
color: var(--jio-color-muted);
font-size: 13px;
transition: all 0.2s;
margin-bottom: 8px;
}
.aksrt-media-field__empty:hover {
border-color: var(--aksrt-color-primary);
color: var(--aksrt-color-primary);
background: var(--aksrt-color-primary-soft);
.jio-media-field__empty:hover {
border-color: var(--jio-color-primary);
color: var(--jio-color-primary);
background: var(--jio-color-primary-soft);
}
.aksrt-media-field__url {
.jio-media-field__url {
margin-top: 4px;
}
</style>
@@ -1,27 +1,27 @@
<template>
<div class="aksrt-repeater-list">
<div class="jio-repeater-list">
<draggable
v-if="rows.length"
v-model="rows"
v-bind="SORTABLE_LIST_ATTRS"
:item-key="rowKey"
:disabled="schema.disabled"
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__icon" :class="preview(element).iconClass">
<span v-if="preview(element).customIcon" class="aksrt-repeater-list__icon-html" v-html="preview(element).customIcon" />
<div class="jio-sortable__item">
<div class="jio-sortable__head">
<JioSortHandle />
<span class="jio-sortable__icon" :class="preview(element).iconClass">
<span v-if="preview(element).customIcon" class="jio-repeater-list__icon-html" v-html="preview(element).customIcon" />
<i v-else-if="preview(element).icon" :class="preview(element).icon" aria-hidden="true" />
<FaIcon v-else icon="fa fas fa-star" :size="16" />
</span>
<div class="aksrt-sortable__main">
<span class="aksrt-sortable__title">{{ preview(element).title }}</span>
<span class="aksrt-sortable__desc">{{ preview(element).desc }}</span>
<div class="jio-sortable__main">
<span class="jio-sortable__title">{{ preview(element).title }}</span>
<span class="jio-sortable__desc">{{ preview(element).desc }}</span>
</div>
<div class="aksrt-sortable__actions">
<div class="jio-sortable__actions">
<n-button size="tiny" quaternary type="primary" :disabled="schema.disabled" @click="openModal(index)">
<template #icon><FaIcon icon="fa fas fa-edit" :size="12" /></template>
编辑
@@ -35,7 +35,7 @@
</div>
</template>
</draggable>
<div v-else class="aksrt-sortable__empty">
<div v-else class="jio-sortable__empty">
<FaIcon icon="fa fas fa-inbox" :size="18" />
<span>{{ schema.emptyText || '暂无数据' }}</span>
</div>
@@ -50,11 +50,11 @@
:mask-closable="false"
preset="card"
:title="editingIndex >= 0 ? (schema.editText || '编辑项目') : (schema.addText || '添加项目')"
class="aksrt-modal-card"
class="jio-modal-card"
style="max-width: 640px; width: 92vw;"
>
<div class="aksrt-repeater-list__modal-fields">
<AksField
<div class="jio-repeater-list__modal-fields">
<JioField
v-for="field in draftFields"
:key="field.key"
:schema="field"
@@ -63,7 +63,7 @@
@update:model-value="draft = { ...draft, [field.key]: $event }"
/>
</div>
<div class="aksrt-modal-footer">
<div class="jio-modal-footer">
<n-button @click="closeModal">取消</n-button>
<n-button type="primary" @click="confirmModal">确定</n-button>
</div>
@@ -76,8 +76,8 @@
import { computed, ref } from 'vue'
import draggable from 'vuedraggable'
import FaIcon from './FaIcon.vue'
import AksField from './AksField.vue'
import AksSortHandle from './AksSortHandle.vue'
import JioField from './JioField.vue'
import JioSortHandle from './JioSortHandle.vue'
import { matchDependency } from './field-dependency.js'
import { SORTABLE_LIST_ATTRS } from './sortable-options.js'
import { createRepeaterRow, createRepeaterRowId, repeaterRowPreview } from './repeater-rows.js'
@@ -151,13 +151,13 @@ function confirmModal() {
</script>
<style scoped>
.aksrt-repeater-list {
.jio-repeater-list {
display: flex;
flex-direction: column;
gap: 10px;
}
.aksrt-repeater-list__icon-html {
.jio-repeater-list__icon-html {
display: inline-flex;
align-items: center;
justify-content: center;
@@ -165,14 +165,14 @@ function confirmModal() {
height: 100%;
}
.aksrt-repeater-list__icon-html :deep(svg),
.aksrt-repeater-list__icon-html :deep(img) {
.jio-repeater-list__icon-html :deep(svg),
.jio-repeater-list__icon-html :deep(img) {
width: 20px;
height: 20px;
object-fit: contain;
}
.aksrt-repeater-list__modal-fields {
.jio-repeater-list__modal-fields {
display: flex;
flex-direction: column;
gap: 4px;
@@ -1,11 +1,11 @@
<template>
<div v-if="dirty" class="aksrt-form-renderer__save-bar">
<div class="aksrt-form-renderer__save-bar__inner">
<div class="aksrt-form-renderer__save-bar__info">
<div v-if="dirty" class="jio-form-renderer__save-bar">
<div class="jio-form-renderer__save-bar__inner">
<div class="jio-form-renderer__save-bar__info">
<FaIcon icon="fa fas fa-exclamation-circle" :size="14" />
<span>您有未保存的更改</span>
</div>
<div class="aksrt-form-renderer__save-bar__actions">
<div class="jio-form-renderer__save-bar__actions">
<n-button size="small" :disabled="saving" @click="emit('reload')">放弃更改</n-button>
<n-button
size="small"
@@ -23,8 +23,8 @@
<script setup>
/**
* AksSaveBar — the admin-wide sticky save bar (shown only when dirty).
* Shared by AksFormRenderer (schema pages) and custom settings pages.
* JioSaveBar — the admin-wide sticky save bar (shown only when dirty).
* Shared by JioFormRenderer (schema pages) and custom settings pages.
*/
import FaIcon from './FaIcon.vue'
@@ -37,19 +37,19 @@ const emit = defineEmits(['save', 'reload'])
</script>
<style scoped>
.aksrt-form-renderer__save-bar {
.jio-form-renderer__save-bar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
z-index: 1000;
background: var(--aksrt-color-surface);
border-top: 1px solid var(--aksrt-color-border);
box-shadow: var(--aksrt-shadow-floating);
background: var(--jio-color-surface);
border-top: 1px solid var(--jio-color-border);
box-shadow: var(--jio-shadow-floating);
animation: slideUp 0.2s ease;
}
.aksrt-form-renderer__save-bar__inner {
.jio-form-renderer__save-bar__inner {
display: flex;
align-items: center;
justify-content: space-between;
@@ -59,7 +59,7 @@ const emit = defineEmits(['save', 'reload'])
gap: 16px;
}
.aksrt-form-renderer__save-bar__info {
.jio-form-renderer__save-bar__info {
display: flex;
align-items: center;
gap: 8px;
@@ -67,7 +67,7 @@ const emit = defineEmits(['save', 'reload'])
font-size: 13px;
}
.aksrt-form-renderer__save-bar__actions {
.jio-form-renderer__save-bar__actions {
display: flex;
gap: 8px;
}
@@ -84,17 +84,17 @@ const emit = defineEmits(['save', 'reload'])
}
@media (max-width: 768px) {
.aksrt-form-renderer__save-bar__inner {
.jio-form-renderer__save-bar__inner {
flex-direction: column;
padding: 10px 14px;
gap: 8px;
}
.aksrt-form-renderer__save-bar__actions {
.jio-form-renderer__save-bar__actions {
width: 100%;
}
.aksrt-form-renderer__save-bar__actions .n-button {
.jio-form-renderer__save-bar__actions .n-button {
flex: 1;
}
}
@@ -1,9 +1,9 @@
<template>
<div v-if="visible" class="aksrt-secret-clear">
<div v-if="visible" class="jio-secret-clear">
<n-button size="small" secondary :type="marked ? 'warning' : 'error'" @click="$emit('toggle')">
{{ marked ? '取消清除' : '清除已配置密钥' }}
</n-button>
<span v-if="marked" class="aksrt-secret-clear__hint">保存后将删除此密钥</span>
<span v-if="marked" class="jio-secret-clear__hint">保存后将删除此密钥</span>
</div>
</template>
@@ -22,15 +22,15 @@ defineEmits(['toggle'])
</script>
<style scoped>
.aksrt-secret-clear {
.jio-secret-clear {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 8px;
}
.aksrt-secret-clear__hint {
color: var(--aksrt-color-warning, #d97706);
.jio-secret-clear__hint {
color: var(--jio-color-warning, #d97706);
font-size: 12px;
}
</style>
@@ -4,14 +4,14 @@
v-bind="SORTABLE_LIST_ATTRS"
:item-key="valueKey"
:disabled="disabled"
class="aksrt-sortable aksrt-sortable--compact aksrt-selected-order"
class="jio-sortable jio-sortable--compact jio-selected-order"
>
<template #item="{ element, index }">
<div class="aksrt-sortable__item">
<div class="aksrt-sortable__head">
<AksSortHandle />
<span class="aksrt-sortable__index">{{ index + 1 }}</span>
<span class="aksrt-sortable__title">{{ labelOf(element) }}</span>
<div class="jio-sortable__item">
<div class="jio-sortable__head">
<JioSortHandle />
<span class="jio-sortable__index">{{ index + 1 }}</span>
<span class="jio-sortable__title">{{ labelOf(element) }}</span>
</div>
</div>
</template>
@@ -22,7 +22,7 @@
/** 多选 + sortable 的已选值排序列表(select / async_select 下方)。 */
import { computed } from 'vue'
import draggable from 'vuedraggable'
import AksSortHandle from './AksSortHandle.vue'
import JioSortHandle from './JioSortHandle.vue'
import { SORTABLE_LIST_ATTRS } from './sortable-options.js'
const props = defineProps({
@@ -47,7 +47,7 @@ function labelOf(value) {
</script>
<style scoped>
.aksrt-selected-order {
.jio-selected-order {
margin-top: 8px;
}
</style>
@@ -1,5 +1,5 @@
<template>
<button type="button" class="aksrt-sortable__handle" :title="label" :aria-label="label">
<button type="button" class="jio-sortable__handle" :title="label" :aria-label="label">
<i class="fa fas fa-grip-vertical" aria-hidden="true"></i>
</button>
</template>
@@ -1,12 +1,12 @@
<template>
<div class="aksrt-sorter">
<div class="jio-sorter">
<div
v-for="column in COLUMNS"
:key="column.key"
class="aksrt-sorter__column"
:class="`aksrt-sorter__column--${column.key}`"
class="jio-sorter__column"
:class="`jio-sorter__column--${column.key}`"
>
<div class="aksrt-sorter__title">
<div class="jio-sorter__title">
<span>{{ column.title }}</span>
<n-tag size="small" :type="column.tagType" :bordered="false">{{ columns[column.key].length }}</n-tag>
</div>
@@ -14,21 +14,21 @@
v-model="columns[column.key]"
v-bind="SORTABLE_LIST_ATTRS"
item-key="value"
group="aksrt-sorter"
class="aksrt-sortable aksrt-sortable--compact aksrt-sorter__list"
group="jio-sorter"
class="jio-sortable jio-sortable--compact jio-sorter__list"
@change="commit"
>
<template #item="{ element }">
<div class="aksrt-sortable__item">
<div class="aksrt-sortable__head">
<AksSortHandle />
<i v-if="element.icon" :class="element.icon" class="aksrt-sorter__icon" aria-hidden="true"></i>
<span class="aksrt-sortable__title">{{ element.label }}</span>
<div class="jio-sortable__item">
<div class="jio-sortable__head">
<JioSortHandle />
<i v-if="element.icon" :class="element.icon" class="jio-sorter__icon" aria-hidden="true"></i>
<span class="jio-sortable__title">{{ element.label }}</span>
</div>
</div>
</template>
</draggable>
<div v-if="columns[column.key].length === 0" class="aksrt-sortable__empty aksrt-sorter__empty">
<div v-if="columns[column.key].length === 0" class="jio-sortable__empty jio-sorter__empty">
{{ column.empty }}
</div>
</div>
@@ -39,7 +39,7 @@
/** 启用 / 未启用两列拖拽排序器;样式见 styles/sortable-list.css。 */
import { reactive, watch } from 'vue'
import draggable from 'vuedraggable'
import AksSortHandle from './AksSortHandle.vue'
import JioSortHandle from './JioSortHandle.vue'
import { SORTABLE_LIST_ATTRS } from './sortable-options.js'
const COLUMNS = [
@@ -89,37 +89,37 @@ watch(() => [props.modelValue, props.options], syncColumns, { immediate: true, d
</script>
<style scoped>
.aksrt-sorter {
.jio-sorter {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 14px;
}
.aksrt-sorter__column {
.jio-sorter__column {
position: relative;
min-height: 210px;
padding: 12px;
border: 1px solid var(--aksrt-color-border);
border: 1px solid var(--jio-color-border);
border-radius: 8px;
background: var(--aksrt-color-canvas);
background: var(--jio-color-canvas);
}
.aksrt-sorter__title {
.jio-sorter__title {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 10px;
color: var(--aksrt-color-text);
color: var(--jio-color-text);
font-size: 13px;
font-weight: 600;
}
/* 空列也要留出可放置区域,拖拽目标不能塌成 0 高度。 */
.aksrt-sorter__list {
.jio-sorter__list {
min-height: 44px;
}
.aksrt-sorter__empty {
.jio-sorter__empty {
position: absolute;
right: 12px;
bottom: 12px;
@@ -128,15 +128,15 @@ watch(() => [props.modelValue, props.options], syncColumns, { immediate: true, d
pointer-events: none;
}
.aksrt-sorter__icon {
.jio-sorter__icon {
flex: 0 0 auto;
width: 16px;
color: var(--aksrt-color-primary);
color: var(--jio-color-primary);
text-align: center;
}
@media (max-width: 720px) {
.aksrt-sorter {
.jio-sorter {
grid-template-columns: 1fr;
}
}
@@ -1,15 +1,15 @@
/**
* 所有后台 vuedraggable 列表共用的 Sortable 选项(v-bind 到 <draggable>)。
* 配套样式见 src/styles/sortable-list.css,拖拽手柄统一用 AksSortHandle。
* 配套样式见 src/styles/sortable-list.css,拖拽手柄统一用 JioSortHandle。
*/
const prefersReducedMotion = typeof window !== 'undefined'
&& typeof window.matchMedia === 'function'
&& window.matchMedia('(prefers-reduced-motion: reduce)').matches
export const SORTABLE_LIST_ATTRS = Object.freeze({
handle: '.aksrt-sortable__handle',
ghostClass: 'aksrt-sortable__ghost',
chosenClass: 'aksrt-sortable__chosen',
dragClass: 'aksrt-sortable__drag',
handle: '.jio-sortable__handle',
ghostClass: 'jio-sortable__ghost',
chosenClass: 'jio-sortable__chosen',
dragClass: 'jio-sortable__drag',
animation: prefersReducedMotion ? 0 : 180,
})
@@ -2,7 +2,7 @@ import { onMounted, ref } from 'vue'
import api from '@/api'
/**
* AksField 的远程选项加载:async_select / taxonomy_select / user_select / page_select。
* JioField 的远程选项加载:async_select / taxonomy_select / user_select / page_select。
* 仅按 schema.type 在挂载时拉取对应数据源。
*/
export function useFieldRemoteOptions(props) {
@@ -47,7 +47,7 @@ export function useFieldRemoteOptions(props) {
value: t.term_id,
}))
} catch (e) {
console.warn('[AksField] taxonomy load failed:', e)
console.warn('[JioField] taxonomy load failed:', e)
taxonomyOptions.value = []
} finally {
taxonomyLoading.value = false
@@ -64,7 +64,7 @@ export function useFieldRemoteOptions(props) {
value: u.id,
}))
} catch (e) {
console.warn('[AksField] user load failed:', e)
console.warn('[JioField] user load failed:', e)
userOptions.value = []
} finally {
userLoading.value = false
@@ -84,7 +84,7 @@ export function useFieldRemoteOptions(props) {
const items = res?.data || res || []
pageOptions.value = Array.isArray(items) ? items : []
} catch (e) {
console.warn('[AksField] page load failed:', e)
console.warn('[JioField] page load failed:', e)
pageOptions.value = []
} finally {
pageLoading.value = false
+11 -11
View File
@@ -14,35 +14,35 @@ app.use(NaiveUI)
// 全局错误处理
app.config.errorHandler = (err, vm, info) => {
console.error('[AKSRT] 全局错误:', err, info)
console.error('[Jio] 全局错误:', err, info)
}
// 兜底:立即显示加载状态(防止白屏)
function showFallback(el) {
el.innerHTML = '<div style="padding:40px;text-align:center;color:#666;font-family:sans-serif;">'
+ '<p style="font-size:18px;margin-bottom:8px;">AKSRT 正在加载...</p>'
+ '<p style="font-size:18px;margin-bottom:8px;">Jio 正在加载...</p>'
+ '<p style="font-size:13px;color:#999;">如果长时间停留在此页面,请按 F12 查看控制台错误</p>'
+ '</div>'
}
showFallback(document.getElementById('aksrt-admin-app') || document.body.appendChild(
Object.assign(document.createElement('div'), { id: 'aksrt-admin-app' })
showFallback(document.getElementById('jio-admin-app') || document.body.appendChild(
Object.assign(document.createElement('div'), { id: 'jio-admin-app' })
))
/**
* 获取或创建一个干净的挂载容器
* 核心问题:WordPress 后台的 jQuery/脚本会在页面加载后持续操作 DOM,
* 导致 PHP 输出的 <div id="aksrt-admin-app"> 可能被外部修改或其兄弟节点被移除,
* 导致 PHP 输出的 <div id="jio-admin-app"> 可能被外部修改或其兄弟节点被移除,
* Vue patch 时遍历到 null 节点 → nextSibling 报错。
*
* 解决方案:在挂载前一刻,动态创建一个全新的容器元素替换旧的,
* 确保该节点及其父级在 Vue 接管前不被任何外部脚本污染。
*/
function getCleanContainer() {
const existing = document.getElementById('aksrt-admin-app')
const existing = document.getElementById('jio-admin-app')
if (!existing) {
// 极端情况:PHP 没有输出容器,手动创建
const fresh = document.createElement('div')
fresh.id = 'aksrt-admin-app'
fresh.id = 'jio-admin-app'
document.body.appendChild(fresh)
return fresh
}
@@ -53,13 +53,13 @@ function getCleanContainer() {
if (!parent) {
// 旧容器已脱离文档树,重新创建
const fresh = document.createElement('div')
fresh.id = 'aksrt-admin-app'
fresh.id = 'jio-admin-app'
document.body.appendChild(fresh)
return fresh
}
const fresh = document.createElement('div')
fresh.id = 'aksrt-admin-app'
fresh.id = 'jio-admin-app'
// 将旧容器的位置信息转移给新容器(保留 fallback 内容)
fresh.innerHTML = existing.innerHTML || ''
@@ -91,12 +91,12 @@ router.isReady().then(() => {
styleMountTarget.value = container
app.mount(container)
} catch (err) {
console.error('[AKSRT] Vue 挂载失败:', err)
console.error('[Jio] Vue 挂载失败:', err)
showError(getCleanContainer(), err)
}
})
})
})
}).catch((err) => {
console.error('[AKSRT] Router 初始化失败:', err)
console.error('[Jio] Router 初始化失败:', err)
})
+22 -22
View File
@@ -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>
+15 -15
View File
@@ -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;" />
+42 -42
View File
@@ -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>
+27 -27
View File
@@ -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>
+13 -13
View File
@@ -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;
}
+5 -5
View File
@@ -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;
+18 -18
View File
@@ -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;
}
+12 -12
View File
@@ -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;
}
+12 -12
View File
@@ -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>
+5 -5
View File
@@ -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>
+3 -3
View File
@@ -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>
+4 -4
View File
@@ -12,7 +12,7 @@ function resolveComponent(page) {
// Log missing component for debugging — avoids silent fallback to DeferredPage
if (page.component && page.component !== 'DeferredPage') {
console.warn(
`[AKSRT Route] Component "${page.component}" not found in componentLoaders for route "${page.route}". Falling back to DeferredPage.`
`[Jio Route] Component "${page.component}" not found in componentLoaders for route "${page.route}". Falling back to DeferredPage.`
)
}
@@ -77,9 +77,9 @@ function createSectionRedirectRoutes() {
* (封禁/举报 as a sidebar entry lives in constants/sections/users.js → /users/ban.)
*/
const NATIVE_OPS_REDIRECTS = [
{ path: '/users/messages', title: '消息中心', nativeAdminPath: 'users.php?page=aksrt_messages' },
{ path: '/users/report', title: '禁封/举报', nativeAdminPath: 'users.php?page=aksrt_user_ban' },
{ path: '/users/tickets', title: '工单管理', nativeAdminPath: 'users.php?page=aksrt_tickets' },
{ path: '/users/messages', title: '消息中心', nativeAdminPath: 'users.php?page=jio_messages' },
{ path: '/users/report', title: '禁封/举报', nativeAdminPath: 'users.php?page=jio_user_ban' },
{ path: '/users/tickets', title: '工单管理', nativeAdminPath: 'users.php?page=jio_tickets' },
]
const routes = [
+1 -1
View File
@@ -2,7 +2,7 @@
* Schema Registry — central index for all admin section schemas.
*
* Each section's schema defines the form fields, groups, API endpoints,
* and default values for a settings page. The AksFormRenderer component
* and default values for a settings page. The JioFormRenderer component
* consumes these schemas to render settings pages automatically.
*
* Schema shape per section:
@@ -1,5 +1,5 @@
const themeRoot = typeof window !== 'undefined' && window.aksrtAdminData?.themeUri
? String(window.aksrtAdminData.themeUri).replace(/\/$/, '')
const themeRoot = typeof window !== 'undefined' && window.jioAdminData?.themeUri
? String(window.jioAdminData.themeUri).replace(/\/$/, '')
: ''
const defaultThumbnail = themeRoot ? `${themeRoot}/assets/img/thumbnail.svg` : ''
@@ -37,7 +37,7 @@ export const i18nSchema = {
],
dependsOn: { key: 'i18n_enabled', value: true },
},
{ key: 'i18n_auto_detect', label: '自动检测浏览器语言', type: 'switch', default: true, dependsOn: { key: 'i18n_enabled', value: true }, help: '基于浏览器 Accept-Language 自动切换(AKSRT 方案,区别于 legacy IP 定位方案)' },
{ key: 'i18n_auto_detect', label: '自动检测浏览器语言', type: 'switch', default: true, dependsOn: { key: 'i18n_enabled', value: true }, help: '基于浏览器 Accept-Language 自动切换(Jio 方案,区别于 legacy IP 定位方案)' },
],
},
{
@@ -20,7 +20,7 @@ export const searchSchema = {
search_custom_key: ['title', 'content', 'excerpt', 'category', 'post_tag'],
search_facets: {},
search_ms_s: false,
search_ms_opt: { api_url: 'http://127.0.0.1:7700', api_key: '', index_prefix: 'aksrt', synonyms: [{ key: 'wordpress', val: 'wp,wordp,wordpre' }] },
search_ms_opt: { api_url: 'http://127.0.0.1:7700', api_key: '', index_prefix: 'jio', synonyms: [{ key: 'wordpress', val: 'wp,wordp,wordpre' }] },
},
groups: [
{
@@ -98,10 +98,10 @@ export const searchSchema = {
icon: 'fa fas fa-bolt',
fields: [
{ key: 'search_ms_s', label: '启用 Meilisearch', type: 'switch', default: false },
{ key: 'search_ms_opt', label: 'Meilisearch 参数', type: 'fieldset', sanitizeType: 'array', dependsOn: { key: 'search_ms_s', value: true }, default: { api_url: 'http://127.0.0.1:7700', api_key: '', index_prefix: 'aksrt', synonyms: [{ key: 'wordpress', val: 'wp,wordp,wordpre' }] }, fields: [
{ key: 'search_ms_opt', label: 'Meilisearch 参数', type: 'fieldset', sanitizeType: 'array', dependsOn: { key: 'search_ms_s', value: true }, default: { api_url: 'http://127.0.0.1:7700', api_key: '', index_prefix: 'jio', synonyms: [{ key: 'wordpress', val: 'wp,wordp,wordpre' }] }, fields: [
{ key: 'api_url', label: 'API 地址', type: 'input', default: 'http://127.0.0.1:7700' },
{ key: 'api_key', label: 'API 密钥', type: 'input', default: '' },
{ key: 'index_prefix', label: '索引前缀', type: 'input', default: 'aksrt' },
{ key: 'index_prefix', label: '索引前缀', type: 'input', default: 'jio' },
{ key: 'synonyms', label: '同义词', type: 'repeater', default: [{ key: 'wordpress', val: 'wp,wordp,wordpre' }], addText: '添加同义词', fields: [
{ key: 'key', label: '关键词', type: 'input', default: '' },
{ key: 'val', label: '同义词', type: 'textarea', default: '' },
@@ -1,5 +1,5 @@
const themeRoot = typeof window !== 'undefined' && window.aksrtAdminData?.themeUri
? String(window.aksrtAdminData.themeUri).replace(/\/$/, '')
const themeRoot = typeof window !== 'undefined' && window.jioAdminData?.themeUri
? String(window.jioAdminData.themeUri).replace(/\/$/, '')
: ''
const shareOptions = [
@@ -93,7 +93,7 @@ export const gatewaySchema = {
label: '',
type: 'content',
ui_only: true,
content: '<ul><li>以下收款接口,主题仅提供API接入服务,收款平台的可靠性请自行斟酌!</li><li>涉及到资金及信息安全,有相关执照的商家推荐使用官方接口</li><li>微信 / 支付宝接口可在「官方」与「易支付」之间选择;PayPal 与 Stripe 独立开关</li><li>异步回调由各网关验签,无需额外口令;回调地址固定为 /wp-json/aksrt/v1/payment/{gateway}/{notify|return}</li></ul>',
content: '<ul><li>以下收款接口,主题仅提供API接入服务,收款平台的可靠性请自行斟酌!</li><li>涉及到资金及信息安全,有相关执照的商家推荐使用官方接口</li><li>微信 / 支付宝接口可在「官方」与「易支付」之间选择;PayPal 与 Stripe 独立开关</li><li>异步回调由各网关验签,无需额外口令;回调地址固定为 /wp-json/jio/v1/payment/{gateway}/{notify|return}</li></ul>',
},
],
},
@@ -159,7 +159,7 @@ export const gatewaySchema = {
],
},
{ key: 'pay_sdk_custom_title_s', label: '自定义收款标题', type: 'switch', default: false, help: '默认为付款类型加网站名,如需自定义请开启' },
{ key: 'pay_sdk_custom_title', label: '自定义收款标题', type: 'input', default: '', dependsOn: { key: 'pay_sdk_custom_title_s', value: true }, help: '可使用变量:订单类型 %order_type%,例如:%order_type%-AKSRT;注意控制总长度,太长会导致部分接口报错' },
{ key: 'pay_sdk_custom_title', label: '自定义收款标题', type: 'input', default: '', dependsOn: { key: 'pay_sdk_custom_title_s', value: true }, help: '可使用变量:订单类型 %order_type%,例如:%order_type%-Jio;注意控制总长度,太长会导致部分接口报错' },
],
},
{
@@ -208,7 +208,7 @@ export const gatewaySchema = {
label: '',
type: 'content',
ui_only: true,
content: '<ul><li>支付宝公钥为必填项目(公钥错误可以成功付款,但会回调失败)</li><li>回调地址固定为 /wp-json/aksrt/v1/payment/alipay/{notify|return}</li><li>电脑端按「电脑端收款」选择站内二维码或跳转;手机端开启 H5 时跳转,否则显示二维码</li></ul>',
content: '<ul><li>支付宝公钥为必填项目(公钥错误可以成功付款,但会回调失败)</li><li>回调地址固定为 /wp-json/jio/v1/payment/alipay/{notify|return}</li><li>电脑端按「电脑端收款」选择站内二维码或跳转;手机端开启 H5 时跳转,否则显示二维码</li></ul>',
},
{ key: 'alipay_appid', label: '当面付:APPID', type: 'input', default: '' },
{ key: 'alipay_privatekey', label: '当面付:应用私钥', type: 'textarea', sanitize_type: 'code', default: '', rows: 4, secret: true },
@@ -243,7 +243,7 @@ export const gatewaySchema = {
label: '',
type: 'content',
ui_only: true,
content: '<ul><li>微信企业支付:官方接口,商家可申请,有年费,申请较为复杂</li><li>回调地址固定为 /wp-json/aksrt/v1/payment/wechatpay/{notify|return},请配置 Native 支付回调链接</li><li>电脑端显示站内二维码;手机端按下方开关选择 H5 跳转或微信内 JSAPI,未开启时同样显示二维码</li></ul>',
content: '<ul><li>微信企业支付:官方接口,商家可申请,有年费,申请较为复杂</li><li>回调地址固定为 /wp-json/jio/v1/payment/wechatpay/{notify|return},请配置 Native 支付回调链接</li><li>电脑端显示站内二维码;手机端按下方开关选择 H5 跳转或微信内 JSAPI,未开启时同样显示二维码</li></ul>',
},
{ key: 'wechat_merchantid', label: '商户号 PartnerID', type: 'input', default: '' },
{ key: 'wechat_appid', label: '授权绑定的AppID', type: 'input', default: '' },
@@ -1,6 +1,6 @@
/**
* 知识付费 — 1:1 复刻参考主题对应页面(免登陆购买 / 模块位置 / 优惠码 /
* 客户服务 / 付费下载 / 商品预置参数),并保留 AKSRT 订单展示与状态文案。
* 客户服务 / 付费下载 / 商品预置参数),并保留 Jio 订单展示与状态文案。
*/
export const knowledgeSchema = {
key: 'payment.knowledge',
@@ -34,7 +34,7 @@ const vipUnitOptions = [
{ label: '月', value: 'month' },
];
// 会员商品/续费商品:标题行显示价格与时长摘要(行默认收起由 AksField 统一处理)。
// 会员商品/续费商品:标题行显示价格与时长摘要(行默认收起由 JioField 统一处理)。
const vipProductGroupOptions = {
listPreview: { prefix: '价格:', titleKey: 'price', descKey: 'time', descUnitKey: 'unit' },
};
@@ -5,7 +5,7 @@
/**
* User type options shared by the upload limit repeaters.
* Mirrors AKSRT\Attachment\UploadLimits::user_type_options() (levels 2-10, VIP 1-2).
* Mirrors Jio\Attachment\UploadLimits::user_type_options() (levels 2-10, VIP 1-2).
*/
const uploadUserTypeOptions = [
{ label: '最小默认值(所有人)', value: 'default' },
@@ -33,7 +33,7 @@ export const commentSchema = {
type: 'content',
ui_only: true,
dependsOn: { key: 'close_comments', value: false },
content: '<p class="aksrt-hint"><i class="fa fas fa-fw fa-info-circle"></i> WordPress默认关闭评论翻页功能,如需启用请按此进行设置:<br/>1. 进入WP讨论设置,勾选 <code>分页显示评论</code><br/>2. 设置默认显示 <code>最前</code>一页<br/>3. 设置在每个页面顶部显示 <code>旧的</code>评论<br/>4. 根据需要设置每一页显示数量<br/>5. 根据需要设置评论嵌套(推荐开启并设置为3层)<br/>6. wp默认开启免登陆评论,如需关闭则勾选<code>需要登录后才能发表评论</code><br/><a href="options-discussion.php">【去设置】</a></p>',
content: '<p class="jio-hint"><i class="fa fas fa-fw fa-info-circle"></i> WordPress默认关闭评论翻页功能,如需启用请按此进行设置:<br/>1. 进入WP讨论设置,勾选 <code>分页显示评论</code><br/>2. 设置默认显示 <code>最前</code>一页<br/>3. 设置在每个页面顶部显示 <code>旧的</code>评论<br/>4. 根据需要设置每一页显示数量<br/>5. 根据需要设置评论嵌套(推荐开启并设置为3层)<br/>6. wp默认开启免登陆评论,如需关闭则勾选<code>需要登录后才能发表评论</code><br/><a href="options-discussion.php">【去设置】</a></p>',
},
{ key: 'close_comments', label: '关闭文章评论功能', type: 'switch', default: false, description: '部分网站无需交互,或需备案审核,可在此关闭所有文章的评论功能。同时每一篇文章可单独关闭评论功能' },
{
@@ -28,7 +28,7 @@ export const featureSchema = {
type: 'content',
ui_only: true,
dependsOn: { key: 'article_nav', value: true },
content: '<p class="aksrt-hint"><a href="https://www.zibll.com/1717.html" target="_blank">【查看官网教程】</a></p>',
content: '<p class="jio-hint"><a href="https://www.zibll.com/1717.html" target="_blank">【查看官网教程】</a></p>',
},
{ key: 'article_nav_mobile_nav_s', label: '在移动端弹出菜单内显示', type: 'switch', default: true, dependsOn: { key: 'article_nav', value: true }, description: '如需显示在侧边栏等其它位置,请使用小工具模块添加' },
{ key: 'imagelightbox', label: '图片灯箱', type: 'switch', default: true, description: '点击图片查看原图功能,共两种模式' },
@@ -38,7 +38,7 @@ export const featureSchema = {
type: 'content',
ui_only: true,
dependsOn: { key: 'imagelightbox', value: true },
content: '<p class="aksrt-hint"><a href="https://www.zibll.com/683.html" target="_blank">【查看官网教程】</a></p>',
content: '<p class="jio-hint"><a href="https://www.zibll.com/683.html" target="_blank">【查看官网教程】</a></p>',
},
{
key: 'imagelightbox_type',
@@ -18,7 +18,7 @@ export const filterSchema = {
key: 'filter_intro',
type: 'content',
ui_only: true,
content: '<p class="aksrt-hint"><b>文章高级筛选功能:</b>通过此功能可实现更加复杂、精细化的内容筛选<br/>添加筛选类型和内容值之后,编写文章时候,可以进行选择,且在前台也可以实现精准筛选<br/>例如影视网站:[类型]有[剧情/喜剧/悬疑/惊悚/犯罪],[地区]有[大陆/美国/日韩/港台/印度],[年份]有[2022/2021/2020/10年代/00年代]等<br/><span class="aksrt-warn">注意事项:添加类型key时候,只能使用英文加下划线,不能有空格,且尽量复杂一点(不能为tag,category等系统已存在的类型),避免与其他mate_key重复!类型名称不能为分类、标签等系统已存在的类型</span><br/><a href="https://www.zibll.com/15886.html" target="_blank">查看官网教程</a></p>',
content: '<p class="jio-hint"><b>文章高级筛选功能:</b>通过此功能可实现更加复杂、精细化的内容筛选<br/>添加筛选类型和内容值之后,编写文章时候,可以进行选择,且在前台也可以实现精准筛选<br/>例如影视网站:[类型]有[剧情/喜剧/悬疑/惊悚/犯罪],[地区]有[大陆/美国/日韩/港台/印度],[年份]有[2022/2021/2020/10年代/00年代]等<br/><span class="jio-warn">注意事项:添加类型key时候,只能使用英文加下划线,不能有空格,且尽量复杂一点(不能为tag,category等系统已存在的类型),避免与其他mate_key重复!类型名称不能为分类、标签等系统已存在的类型</span><br/><a href="https://www.zibll.com/15886.html" target="_blank">查看官网教程</a></p>',
},
{
key: 'custom_filter_show',
@@ -146,7 +146,7 @@ export const pageSchema = {
key: 'yiyan_intro',
type: 'content',
ui_only: true,
content: '<p class="aksrt-hint"><b>精彩一言功能:</b>随机显示中英文文案,可插入文章页或添加“一言”小工具。默认句库位于 <code>themes/aksrt/yiyan/qv-yiyan.txt</code>。您也可以将自定义句库保存为 <code>wp-content/yiyan.txt</code>,更新主题时即可保留自定义内容。</p>',
content: '<p class="jio-hint"><b>精彩一言功能:</b>随机显示中英文文案,可插入文章页或添加“一言”小工具。默认句库位于 <code>themes/jio/yiyan/qv-yiyan.txt</code>。您也可以将自定义句库保存为 <code>wp-content/yiyan.txt</code>,更新主题时即可保留自定义内容。</p>',
},
{ key: 'yiyan_single_content_header', label: '文章内容头部显示一言', type: 'switch', default: false },
{ key: 'yiyan_single_content_footer', label: '文章内容尾部显示一言', type: 'switch', default: false },
@@ -30,7 +30,7 @@ export const submitSchema = {
label: '',
type: 'content',
ui_only: true,
content: '<p class="aksrt-hint">此功能启用后,可以在<a href="admin.php?page=aksrt-settings#/permissions/capabilities">权限管理</a>中设置用户的发布、审核权限 <a href="admin.php?page=aksrt-settings#/permissions/capabilities">【去设置】</a></p>',
content: '<p class="jio-hint">此功能启用后,可以在<a href="admin.php?page=jio-settings#/permissions/capabilities">权限管理</a>中设置用户的发布、审核权限 <a href="admin.php?page=jio-settings#/permissions/capabilities">【去设置】</a></p>',
},
{ key: 'post_article_btn_txte', label: '按钮文字', type: 'input', default: '发布文章', dependsOn: { key: 'post_article_s', value: true }, description: '投稿按钮的显示的文字,推荐4个字更加协调' },
{ key: 'post_article_cat', label: '投稿允许选择的分类', type: 'taxonomy_select', taxonomy: 'category', multiple: true, default: [], placeholder: '输入关键词以搜索分类', dependsOn: { key: 'post_article_s', value: true }, description: '投稿允许选择的分类,为空则允许选择全部分类,所选分类下如果有子分类则会自动显示,如果选择了上级分类,则不要再选该分类下的子分类。注意:请确保所选分类包含子分类总数不要超过50个,否则可能会引起页面崩溃' },
@@ -40,7 +40,7 @@ export const submitSchema = {
label: '',
type: 'content',
ui_only: true,
content: '<p class="aksrt-hint">此功能启用后,请先在<a href="admin.php?page=aksrt-settings#/post-list/filter">文章列表/高级筛选</a>中添加高级筛选明细 <a href="admin.php?page=aksrt-settings#/post-list/filter">【去设置】</a></p>',
content: '<p class="jio-hint">此功能启用后,请先在<a href="admin.php?page=jio-settings#/post-list/filter">文章列表/高级筛选</a>中添加高级筛选明细 <a href="admin.php?page=jio-settings#/post-list/filter">【去设置】</a></p>',
},
{ key: 'post_article_tag', label: '允许插入标签', type: 'switch', default: true, dependsOn: { key: 'post_article_s', value: true }, description: '前台投稿时候允许设置文章标签' },
{ key: 'post_article_user', label: '免登陆投稿发布用户', type: 'user_select', default: 1, dependsOn: { key: 'post_article_s', value: true }, description: '当选择投稿权限为无需登录就能投稿时,投稿文章的用户' },
@@ -1,6 +1,6 @@
/** legacy 9.0 list-thumbnail settings. */
const themeRoot = typeof window !== 'undefined' && window.aksrtAdminData?.themeUri
? String(window.aksrtAdminData.themeUri).replace(/\/$/, '')
const themeRoot = typeof window !== 'undefined' && window.jioAdminData?.themeUri
? String(window.jioAdminData.themeUri).replace(/\/$/, '')
: ''
const spareThumbnailDefault = [{ img: `${themeRoot}/assets/img/thumbnail.svg` }]
@@ -11,7 +11,7 @@ export const importExportSchema = {
icon: 'fa fas fa-share',
fields: [
{ key: 'export_settings', label: '导出主题设置', type: 'button', help: '导出当前所有主题配置为 JSON 文件' },
{ key: 'export_options', label: '导出 WordPress 选项', type: 'button', help: '导出 aksrt_settings 等选项' },
{ key: 'export_options', label: '导出 WordPress 选项', type: 'button', help: '导出 jio_settings 等选项' },
],
},
{
@@ -74,7 +74,7 @@ export const authSchema = {
{ key: 'sign_modal_auto_waiting_time', label: '等待时间(秒)', type: 'number', default: 5, min: 1, max: 100, dependsOn: { key: 'sign_modal_auto_s', value: true } },
{ key: 'sign_modal_auto_expires', label: '自动弹窗周期(小时)', type: 'number', default: 1, min: 0, max: 2000, dependsOn: { key: 'sign_modal_auto_s', value: true } },
{ key: 'replace_wp_login', label: '代替 WP 自带登录页面', type: 'switch', default: true },
{ key: 'admin_sign_key', label: '应急登录 Key', type: 'input', default: '', dependsOn: { key: 'replace_wp_login', value: true }, help: '通过 /wp-login.php?aksrt_bypass=<key> 使用 WP 登录页' },
{ key: 'admin_sign_key', label: '应急登录 Key', type: 'input', default: '', dependsOn: { key: 'replace_wp_login', value: true }, help: '通过 /wp-login.php?jio_bypass=<key> 使用 WP 登录页' },
],
},
{
@@ -19,7 +19,7 @@ export const MEDAL_GET_TYPES = [
// Resolve medal SVG asset path from theme assets when running in admin context.
const MEDAL_BASE = (() => {
const root = window.aksrtAdminData?.themeUri || ''
const root = window.jioAdminData?.themeUri || ''
return root ? String(root).replace(/\/$/, '') + '/assets/img/medal' : '/assets/img/medal'
})()
@@ -82,7 +82,7 @@ export const creditsSchema = {
title: '积分抵扣(预留)',
icon: 'fa fas fa-percent',
fields: [
{ key: 'points_deduction_s', label: '启用积分抵扣', type: 'switch', default: false, help: '对齐 legacy:运行时暂未启用(aksrtpay_is_allow_points_deduction 恒为 false)。字段保留供后续接收银台现金单抵扣。' },
{ key: 'points_deduction_s', label: '启用积分抵扣', type: 'switch', default: false, help: '对齐 legacy:运行时暂未启用(jiopay_is_allow_points_deduction 恒为 false)。字段保留供后续接收银台现金单抵扣。' },
{ key: 'points_deduction_rate', label: '积分换算比例', type: 'number', default: 100, min: 1, max: 10000, dependsOn: { key: 'points_deduction_s', value: true }, help: 'legacy 语义:points_deduction_rate = 多少积分抵 1 元(示例 30 表示 30 积分=1 元)。当前未参与下单计算。' },
{ key: 'points_deduction_max', label: '最大抵扣比例(%)', type: 'number', default: 50, min: 1, max: 100, dependsOn: { key: 'points_deduction_s', value: true }, help: '预留:最多可抵订单金额的百分比。当前未参与下单计算。' },
],
@@ -1,5 +1,5 @@
const themeRoot = typeof window !== 'undefined' && window.aksrtAdminData?.themeUri
? String(window.aksrtAdminData.themeUri).replace(/\/$/, '')
const themeRoot = typeof window !== 'undefined' && window.jioAdminData?.themeUri
? String(window.jioAdminData.themeUri).replace(/\/$/, '')
: ''
export const featuresSchema = {
+141 -141
View File
@@ -1,33 +1,33 @@
#aksrt-admin-app,
#aksrt-admin-app * {
#jio-admin-app,
#jio-admin-app * {
box-sizing: border-box;
}
#aksrt-admin-app {
--aksrt-color-primary: #18A058;
--aksrt-color-primary-hover: #36AD6A;
--aksrt-color-primary-pressed: #0C7A43;
--aksrt-color-primary-soft: #EAF7EF;
--aksrt-color-canvas: #F5F7F6;
--aksrt-color-surface: #FFFFFF;
--aksrt-color-text: #1F2923;
--aksrt-color-text-secondary: #465149;
--aksrt-color-muted: #6F7A72;
--aksrt-color-border: #E2E8E3;
--aksrt-color-border-strong: #CCD7CE;
--aksrt-shadow-card: 0 1px 2px rgba(31, 41, 35, .04);
--aksrt-shadow-floating: 0 12px 32px rgba(31, 41, 35, .12);
#jio-admin-app {
--jio-color-primary: #18A058;
--jio-color-primary-hover: #36AD6A;
--jio-color-primary-pressed: #0C7A43;
--jio-color-primary-soft: #EAF7EF;
--jio-color-canvas: #F5F7F6;
--jio-color-surface: #FFFFFF;
--jio-color-text: #1F2923;
--jio-color-text-secondary: #465149;
--jio-color-muted: #6F7A72;
--jio-color-border: #E2E8E3;
--jio-color-border-strong: #CCD7CE;
--jio-shadow-card: 0 1px 2px rgba(31, 41, 35, .04);
--jio-shadow-floating: 0 12px 32px rgba(31, 41, 35, .12);
min-height: 100%;
color: var(--aksrt-color-text);
background: var(--aksrt-color-canvas);
color: var(--jio-color-text);
background: var(--jio-color-canvas);
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Microsoft YaHei", sans-serif;
font-size: 14px;
line-height: 1.6;
}
/* ==================== FA5 Icon in NaiveUI Menu ==================== */
#aksrt-admin-app .n-menu .n-menu-item-content i[class*="fa-"],
#aksrt-admin-app .n-menu-item-content i[class*="fa-"] {
#jio-admin-app .n-menu .n-menu-item-content i[class*="fa-"],
#jio-admin-app .n-menu-item-content i[class*="fa-"] {
font-size: 18px;
width: 18px;
text-align: center;
@@ -39,243 +39,243 @@
transition: opacity 0.15s;
}
#aksrt-admin-app .n-menu-item-content--selected i[class*="fa-"],
#aksrt-admin-app .n-menu-item-content:hover i[class*="fa-"] {
#jio-admin-app .n-menu-item-content--selected i[class*="fa-"],
#jio-admin-app .n-menu-item-content:hover i[class*="fa-"] {
opacity: 1;
}
#aksrt-admin-app .n-layout,
#aksrt-admin-app .n-layout-sider {
#jio-admin-app .n-layout,
#jio-admin-app .n-layout-sider {
min-height: 100vh;
}
#aksrt-admin-app .aksrt-admin-layout {
#jio-admin-app .jio-admin-layout {
min-height: 100vh;
background: var(--aksrt-color-canvas);
background: var(--jio-color-canvas);
}
#aksrt-admin-app .aksrt-admin-sider {
background: var(--aksrt-color-surface);
border-right: 1px solid var(--aksrt-color-border);
#jio-admin-app .jio-admin-sider {
background: var(--jio-color-surface);
border-right: 1px solid var(--jio-color-border);
}
#aksrt-admin-app .aksrt-admin-sider .n-layout-toggle-button {
border: 1px solid var(--aksrt-color-border);
background: var(--aksrt-color-surface);
color: var(--aksrt-color-muted);
box-shadow: var(--aksrt-shadow-card);
#jio-admin-app .jio-admin-sider .n-layout-toggle-button {
border: 1px solid var(--jio-color-border);
background: var(--jio-color-surface);
color: var(--jio-color-muted);
box-shadow: var(--jio-shadow-card);
}
#aksrt-admin-app .aksrt-admin-sider .n-layout-toggle-button:hover {
border-color: var(--aksrt-color-primary);
color: var(--aksrt-color-primary);
#jio-admin-app .jio-admin-sider .n-layout-toggle-button:hover {
border-color: var(--jio-color-primary);
color: var(--jio-color-primary);
}
#aksrt-admin-app .aksrt-admin-menu {
#jio-admin-app .jio-admin-menu {
padding: 10px 8px 18px;
}
#aksrt-admin-app .aksrt-admin-menu .n-menu-item-content {
#jio-admin-app .jio-admin-menu .n-menu-item-content {
position: relative;
border-radius: 8px;
transition: color .16s ease, background-color .16s ease;
}
#aksrt-admin-app .aksrt-admin-menu .n-menu-item-content--selected::after {
#jio-admin-app .jio-admin-menu .n-menu-item-content--selected::after {
position: absolute;
top: 9px;
bottom: 9px;
left: 0;
width: 3px;
border-radius: 0 3px 3px 0;
background: var(--aksrt-color-primary);
background: var(--jio-color-primary);
content: '';
}
#aksrt-admin-app .aksrt-admin-menu .n-submenu-children {
#jio-admin-app .jio-admin-menu .n-submenu-children {
margin: 2px 0 6px;
}
#aksrt-admin-app .aksrt-admin-menu .n-menu-item-content-header {
#jio-admin-app .jio-admin-menu .n-menu-item-content-header {
font-weight: 500;
}
#aksrt-admin-app .aksrt-menu-item--secondary .n-menu-item-content-header {
color: var(--aksrt-color-muted);
#jio-admin-app .jio-menu-item--secondary .n-menu-item-content-header {
color: var(--jio-color-muted);
font-size: 12px;
}
#aksrt-admin-app .aksrt-admin-content {
background: var(--aksrt-color-canvas);
#jio-admin-app .jio-admin-content {
background: var(--jio-color-canvas);
}
#aksrt-admin-app .aksrt-schema-page,
#aksrt-admin-app .aksrt-page-container,
#aksrt-admin-app .content-page {
#jio-admin-app .jio-schema-page,
#jio-admin-app .jio-page-container,
#jio-admin-app .content-page {
width: 100%;
max-width: 1180px;
margin: 0 auto;
}
#aksrt-admin-app .aksrt-form-renderer__save-bar {
#jio-admin-app .jio-form-renderer__save-bar {
right: 28px;
left: auto;
width: min(1180px, calc(100vw - 448px));
border: 1px solid var(--aksrt-color-border);
border: 1px solid var(--jio-color-border);
border-bottom: 0;
border-radius: 12px 12px 0 0;
background: rgba(255, 255, 255, .96);
box-shadow: var(--aksrt-shadow-floating);
box-shadow: var(--jio-shadow-floating);
backdrop-filter: blur(12px);
}
#aksrt-admin-app .aksrt-form-renderer__save-bar__inner {
#jio-admin-app .jio-form-renderer__save-bar__inner {
max-width: 1180px;
}
#aksrt-admin-app .aksrt-form-renderer__save-bar .n-button--primary-type {
#jio-admin-app .jio-form-renderer__save-bar .n-button--primary-type {
box-shadow: 0 4px 12px rgba(24, 160, 88, .18);
}
#aksrt-admin-app :where(a, button, input, textarea, select, [tabindex]):focus-visible {
outline: 2px solid var(--aksrt-color-primary);
#jio-admin-app :where(a, button, input, textarea, select, [tabindex]):focus-visible {
outline: 2px solid var(--jio-color-primary);
outline-offset: 2px;
}
#aksrt-admin-app .aksrt-page-title {
#jio-admin-app .jio-page-title {
margin: 0 0 12px;
color: var(--aksrt-color-text);
color: var(--jio-color-text);
font-size: 22px;
font-weight: 700;
letter-spacing: -0.02em;
}
#aksrt-admin-app .aksrt-page-desc {
#jio-admin-app .jio-page-desc {
margin: 0 0 24px;
color: var(--aksrt-color-muted);
color: var(--jio-color-muted);
font-size: 13px;
line-height: 1.7;
}
#aksrt-admin-app .aksrt-section-card {
#jio-admin-app .jio-section-card {
margin-bottom: 18px;
border-radius: 12px !important;
border: 1px solid var(--aksrt-color-border) !important;
background: var(--aksrt-color-surface);
box-shadow: var(--aksrt-shadow-card);
border: 1px solid var(--jio-color-border) !important;
background: var(--jio-color-surface);
box-shadow: var(--jio-shadow-card);
}
#aksrt-admin-app .aksrt-section-card .n-card__content {
#jio-admin-app .jio-section-card .n-card__content {
padding: 18px 20px 20px !important;
}
#aksrt-admin-app .aksrt-section-card .n-card-header {
#jio-admin-app .jio-section-card .n-card-header {
padding: 18px 20px 0 !important;
}
#aksrt-admin-app .aksrt-section-header {
#jio-admin-app .jio-section-header {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 14px;
}
#aksrt-admin-app .aksrt-section-header h3 {
#jio-admin-app .jio-section-header h3 {
margin: 0;
color: var(--aksrt-color-text);
color: var(--jio-color-text);
font-size: 15px;
font-weight: 600;
}
#aksrt-admin-app .section-icon,
#aksrt-admin-app .header-icon {
#jio-admin-app .section-icon,
#jio-admin-app .header-icon {
font-size: 17px;
opacity: 0.8;
display: inline-flex;
align-items: center;
}
#aksrt-admin-app .section-desc,
#aksrt-admin-app .aksrt-hint-text {
color: var(--aksrt-color-muted);
#jio-admin-app .section-desc,
#jio-admin-app .jio-hint-text {
color: var(--jio-color-muted);
font-size: 12px;
line-height: 1.6;
}
#aksrt-admin-app .section-desc {
#jio-admin-app .section-desc {
margin: 0 0 14px;
}
#aksrt-admin-app .aksrt-form .n-form-item {
#jio-admin-app .jio-form .n-form-item {
margin-bottom: 18px;
}
#aksrt-admin-app .aksrt-form .n-form-item:last-child {
#jio-admin-app .jio-form .n-form-item:last-child {
margin-bottom: 0;
}
#aksrt-admin-app .aksrt-form .n-form-item-label {
color: var(--aksrt-color-text-secondary) !important;
#jio-admin-app .jio-form .n-form-item-label {
color: var(--jio-color-text-secondary) !important;
font-size: 13px;
font-weight: 500;
}
#aksrt-admin-app .aksrt-form .n-input,
#aksrt-admin-app .aksrt-form .n-select .n-base-selection,
#aksrt-admin-app .aksrt-form .n-input-number {
#jio-admin-app .jio-form .n-input,
#jio-admin-app .jio-form .n-select .n-base-selection,
#jio-admin-app .jio-form .n-input-number {
min-height: 36px;
--n-height: 36px !important;
}
#aksrt-admin-app .aksrt-form .n-input--textarea textarea {
#jio-admin-app .jio-form .n-input--textarea textarea {
min-height: 84px;
}
#aksrt-admin-app .aksrt-form .n-switch {
#jio-admin-app .jio-form .n-switch {
--n-rail-height: 26px !important;
--n-rail-width: 48px !important;
}
#aksrt-admin-app .aksrt-form-actions {
#jio-admin-app .jio-form-actions {
display: flex;
justify-content: flex-end;
align-items: center;
gap: 12px;
padding: 24px 0 8px;
margin-top: 28px;
border-top: 1px solid var(--aksrt-color-border);
border-top: 1px solid var(--jio-color-border);
}
#aksrt-admin-app .aksrt-form-actions .n-button {
#jio-admin-app .jio-form-actions .n-button {
min-width: 120px;
height: 40px;
font-weight: 500;
}
#aksrt-admin-app .aksrt-tabs .n-tabs-nav {
#jio-admin-app .jio-tabs .n-tabs-nav {
margin-bottom: 20px !important;
}
#aksrt-admin-app .aksrt-tabs .n-tabs-tab {
#jio-admin-app .jio-tabs .n-tabs-tab {
padding: 10px 20px !important;
font-size: 14px !important;
font-weight: 500;
}
#aksrt-admin-app .n-data-table {
#jio-admin-app .n-data-table {
border-radius: 10px;
overflow: hidden;
}
#aksrt-admin-app .n-data-table .n-data-table-th {
#jio-admin-app .n-data-table .n-data-table-th {
background: #f7f9f7;
}
#aksrt-admin-app .n-empty {
#jio-admin-app .n-empty {
padding: 24px 0;
}
#aksrt-admin-app .aksrt-card-header-row {
#jio-admin-app .jio-card-header-row {
display: flex;
align-items: center;
justify-content: space-between;
@@ -284,19 +284,19 @@
flex-wrap: wrap;
}
#aksrt-admin-app .aksrt-card-header-row__left {
#jio-admin-app .jio-card-header-row__left {
display: inline-flex;
align-items: center;
gap: 8px;
min-width: 0;
}
#aksrt-admin-app .aksrt-card-header-row__title {
#jio-admin-app .jio-card-header-row__title {
font-weight: 600;
}
/* ==================== 卡片 header 行(标题 + 按钮) ==================== */
#aksrt-admin-app .aksrt-card-header-row {
#jio-admin-app .jio-card-header-row {
display: flex;
align-items: center;
justify-content: space-between;
@@ -305,18 +305,18 @@
flex-wrap: wrap;
}
#aksrt-admin-app .aksrt-card-header-row__left {
#jio-admin-app .jio-card-header-row__left {
display: flex;
align-items: center;
gap: 8px;
min-width: 0;
}
#aksrt-admin-app .aksrt-card-header-row__title {
#jio-admin-app .jio-card-header-row__title {
margin: 0;
font-size: 15px;
font-weight: 600;
color: var(--aksrt-color-text);
color: var(--jio-color-text);
}
/* ==================== 过渡 ==================== */
@@ -336,23 +336,23 @@
}
/* ==================== Modal 样式(弹层) ==================== */
.aksrt-modal-card {
.jio-modal-card {
width: 100%;
max-width: 520px;
}
/* 弹层底部操作栏;弹层 teleport 到 #aksrt-admin-app 之外,token 带回退值。 */
.aksrt-modal-footer {
/* 弹层底部操作栏;弹层 teleport 到 #jio-admin-app 之外,token 带回退值。 */
.jio-modal-footer {
display: flex;
justify-content: flex-end;
gap: 8px;
margin-top: 16px;
padding-top: 12px;
border-top: 1px solid var(--aksrt-color-border, #E2E8E3);
border-top: 1px solid var(--jio-color-border, #E2E8E3);
}
@media (max-width: 960px) {
#aksrt-admin-app .aksrt-form-renderer__save-bar {
#jio-admin-app .jio-form-renderer__save-bar {
right: 0;
left: 0;
width: auto;
@@ -361,11 +361,11 @@
border-radius: 0;
}
#aksrt-admin-app .aksrt-page-wrapper {
#jio-admin-app .jio-page-wrapper {
width: 100%;
}
#aksrt-admin-app .aksrt-admin-menu {
#jio-admin-app .jio-admin-menu {
padding-top: 8px;
}
}
@@ -373,50 +373,50 @@
/* ==================== 移动端适配 ==================== */
@media (max-width: 768px) {
/* 容器 */
#aksrt-admin-app .aksrt-page-container,
#aksrt-admin-app .content-page {
#jio-admin-app .jio-page-container,
#jio-admin-app .content-page {
max-width: 100%;
padding: 0;
}
#aksrt-admin-app .aksrt-field__desc {
#jio-admin-app .jio-field__desc {
margin: 2px 0 8px;
}
#aksrt-admin-app .aksrt-page-title {
#jio-admin-app .jio-page-title {
font-size: 18px;
margin-bottom: 8px;
}
#aksrt-admin-app .aksrt-page-desc {
#jio-admin-app .jio-page-desc {
font-size: 12px;
margin-bottom: 14px;
}
/* 卡片紧凑 */
#aksrt-admin-app .aksrt-section-card {
#jio-admin-app .jio-section-card {
margin-bottom: 12px;
border-radius: 10px !important;
}
#aksrt-admin-app .aksrt-section-card .n-card__content {
#jio-admin-app .jio-section-card .n-card__content {
padding: 14px !important;
}
#aksrt-admin-app .aksrt-section-card .n-card-header {
#jio-admin-app .jio-section-card .n-card-header {
padding: 14px 14px 0 !important;
}
#aksrt-admin-app .aksrt-section-header {
#jio-admin-app .jio-section-header {
margin-bottom: 10px;
}
/* 表单:label 改为顶部排列(覆盖 left 模式) */
#aksrt-admin-app .aksrt-form .n-form-item {
#jio-admin-app .jio-form .n-form-item {
margin-bottom: 14px;
}
#aksrt-admin-app .aksrt-form .n-form-item .n-form-item-label {
#jio-admin-app .jio-form .n-form-item .n-form-item-label {
text-align: left !important;
padding: 0 0 6px !important;
width: auto !important;
@@ -425,44 +425,44 @@
justify-content: flex-start !important;
}
#aksrt-admin-app .aksrt-form .n-form-item-blank {
#jio-admin-app .jio-form .n-form-item-blank {
width: 100%;
}
/* 强制行内表单单列 */
#aksrt-admin-app .aksrt-form .n-form-item .n-form-item-label,
#aksrt-admin-app .aksrt-form .n-form-item-row {
#jio-admin-app .jio-form .n-form-item .n-form-item-label,
#jio-admin-app .jio-form .n-form-item-row {
display: block !important;
}
/* radio button 自动换行 */
#aksrt-admin-app .aksrt-form .n-radio-group {
#jio-admin-app .jio-form .n-radio-group {
width: 100%;
}
#aksrt-admin-app .aksrt-form .n-radio-group .n-space {
#jio-admin-app .jio-form .n-radio-group .n-space {
flex-wrap: wrap !important;
gap: 6px 8px !important;
}
#aksrt-admin-app .aksrt-form .n-radio-button {
#jio-admin-app .jio-form .n-radio-button {
flex: 1 1 auto;
min-width: 0;
}
/* 输入组在窄屏堆叠 */
#aksrt-admin-app .aksrt-form .n-input-group {
#jio-admin-app .jio-form .n-input-group {
flex-wrap: wrap;
gap: 6px;
}
#aksrt-admin-app .aksrt-form .n-input-group > .n-input,
#aksrt-admin-app .aksrt-form .n-input-group > .n-button {
#jio-admin-app .jio-form .n-input-group > .n-input,
#jio-admin-app .jio-form .n-input-group > .n-button {
border-radius: 6px !important;
}
/* 表单底部按钮区 */
#aksrt-admin-app .aksrt-form-actions {
#jio-admin-app .jio-form-actions {
flex-direction: column-reverse;
align-items: stretch;
padding: 16px 0 8px;
@@ -470,14 +470,14 @@
gap: 8px;
}
#aksrt-admin-app .aksrt-form-actions .n-button {
#jio-admin-app .jio-form-actions .n-button {
width: 100%;
min-width: 0;
height: 42px;
}
/* 卡片 header 行:换行排列 */
#aksrt-admin-app .aksrt-card-header-row {
#jio-admin-app .jio-card-header-row {
gap: 8px;
}
@@ -491,7 +491,7 @@
min-height: 100vh;
}
.aksrt-modal-card {
.jio-modal-card {
max-width: 100vw !important;
width: 100vw !important;
min-height: 100vh;
@@ -499,19 +499,19 @@
}
/* 数据表格隐藏次要列 */
.aksrt-table-mobile-hide,
#aksrt-admin-app .n-data-table .aksrt-table-mobile-hide {
.jio-table-mobile-hide,
#jio-admin-app .n-data-table .jio-table-mobile-hide {
display: none !important;
}
/* 表格内边距收紧 */
#aksrt-admin-app .n-data-table .n-data-table-td,
#aksrt-admin-app .n-data-table .n-data-table-th {
#jio-admin-app .n-data-table .n-data-table-td,
#jio-admin-app .n-data-table .n-data-table-th {
padding: 8px 10px !important;
}
/* tabs */
#aksrt-admin-app .aksrt-tabs .n-tabs-tab {
#jio-admin-app .jio-tabs .n-tabs-tab {
padding: 8px 12px !important;
font-size: 13px !important;
}
@@ -524,19 +524,19 @@
/* ==================== 超窄设备(<= 480px)追加 ==================== */
@media (max-width: 480px) {
#aksrt-admin-app .aksrt-section-card .n-card__content {
#jio-admin-app .jio-section-card .n-card__content {
padding: 12px !important;
}
#aksrt-admin-app .aksrt-section-card .n-card-header {
#jio-admin-app .jio-section-card .n-card-header {
padding: 12px 12px 0 !important;
}
}
@media (prefers-reduced-motion: reduce) {
#aksrt-admin-app *,
#aksrt-admin-app *::before,
#aksrt-admin-app *::after {
#jio-admin-app *,
#jio-admin-app *::before,
#jio-admin-app *::after {
scroll-behavior: auto !important;
animation-duration: .01ms !important;
animation-iteration-count: 1 !important;
+65 -65
View File
@@ -4,36 +4,36 @@
* 后台所有可排序列表(schema 排序字段 / 重复器 / 启用-停用排序器 / 悬浮按钮 /
* 底部 Tab / 工单预设回复)统一使用这套类名,并配合 SORTABLE_LIST_ATTRS:
*
* .aksrt-sortable 列表容器(draggable 根节点)
* .aksrt-sortable__item 卡片行
* .aksrt-sortable__head 行头:handle / index / icon / main / actions
* .aksrt-sortable__body 可选:展开后的字段区
* .jio-sortable 列表容器(draggable 根节点)
* .jio-sortable__item 卡片行
* .jio-sortable__head 行头:handle / index / icon / main / actions
* .jio-sortable__body 可选:展开后的字段区
*
* 弹窗内容会被 teleport 到 #aksrt-admin-app 之外,因此 token 都带回退值。
* 弹窗内容会被 teleport 到 #jio-admin-app 之外,因此 token 都带回退值。
*/
.aksrt-sortable {
.jio-sortable {
display: flex;
flex-direction: column;
gap: 8px;
}
.aksrt-sortable--compact {
.jio-sortable--compact {
gap: 6px;
}
.aksrt-sortable__item {
border: 1px solid var(--aksrt-color-border, #E2E8E3);
.jio-sortable__item {
border: 1px solid var(--jio-color-border, #E2E8E3);
border-radius: 8px;
background: var(--aksrt-color-surface, #FFFFFF);
box-shadow: var(--aksrt-shadow-card, 0 1px 2px rgba(31, 41, 35, .04));
background: var(--jio-color-surface, #FFFFFF);
box-shadow: var(--jio-shadow-card, 0 1px 2px rgba(31, 41, 35, .04));
transition: border-color .15s ease, box-shadow .15s ease;
}
.aksrt-sortable__item:hover {
border-color: var(--aksrt-color-border-strong, #CCD7CE);
.jio-sortable__item:hover {
border-color: var(--jio-color-border-strong, #CCD7CE);
}
.aksrt-sortable__head {
.jio-sortable__head {
display: flex;
align-items: center;
gap: 10px;
@@ -41,29 +41,29 @@
padding: 8px 12px 8px 8px;
}
.aksrt-sortable--compact .aksrt-sortable__head {
.jio-sortable--compact .jio-sortable__head {
gap: 8px;
min-height: 38px;
padding: 4px 10px 4px 4px;
}
.aksrt-sortable__head.is-clickable {
.jio-sortable__head.is-clickable {
cursor: pointer;
user-select: none;
}
.aksrt-sortable__head.is-clickable:focus-visible {
outline: 2px solid var(--aksrt-color-primary, #18A058);
.jio-sortable__head.is-clickable:focus-visible {
outline: 2px solid var(--jio-color-primary, #18A058);
outline-offset: -2px;
border-radius: 8px;
}
.aksrt-sortable__head.is-clickable:hover .aksrt-sortable__title,
.aksrt-sortable__head.is-clickable:hover .aksrt-sortable__toggle {
color: var(--aksrt-color-primary, #18A058);
.jio-sortable__head.is-clickable:hover .jio-sortable__title,
.jio-sortable__head.is-clickable:hover .jio-sortable__toggle {
color: var(--jio-color-primary, #18A058);
}
.aksrt-sortable__handle {
.jio-sortable__handle {
display: inline-flex;
flex: 0 0 auto;
align-items: center;
@@ -74,25 +74,25 @@
border: 0;
border-radius: 6px;
background: transparent;
color: var(--aksrt-color-muted, #6F7A72);
color: var(--jio-color-muted, #6F7A72);
font-size: 13px;
cursor: grab;
touch-action: none;
transition: color .15s ease, background-color .15s ease;
}
.aksrt-sortable__handle:hover,
.aksrt-sortable__handle:focus-visible {
.jio-sortable__handle:hover,
.jio-sortable__handle:focus-visible {
outline: none;
background: var(--aksrt-color-primary-soft, #EAF7EF);
color: var(--aksrt-color-primary, #18A058);
background: var(--jio-color-primary-soft, #EAF7EF);
color: var(--jio-color-primary, #18A058);
}
.aksrt-sortable__handle:active {
.jio-sortable__handle:active {
cursor: grabbing;
}
.aksrt-sortable__index {
.jio-sortable__index {
display: inline-flex;
flex: 0 0 auto;
align-items: center;
@@ -101,14 +101,14 @@
height: 22px;
padding: 0 6px;
border-radius: 11px;
background: var(--aksrt-color-canvas, #F5F7F6);
color: var(--aksrt-color-muted, #6F7A72);
background: var(--jio-color-canvas, #F5F7F6);
color: var(--jio-color-muted, #6F7A72);
font-size: 12px;
font-weight: 600;
font-variant-numeric: tabular-nums;
}
.aksrt-sortable__icon {
.jio-sortable__icon {
display: inline-flex;
flex: 0 0 auto;
align-items: center;
@@ -117,19 +117,19 @@
height: 36px;
overflow: hidden;
border-radius: 8px;
background: var(--aksrt-color-primary-soft, #EAF7EF);
color: var(--aksrt-color-primary, #18A058);
background: var(--jio-color-primary-soft, #EAF7EF);
color: var(--jio-color-primary, #18A058);
font-size: 16px;
}
.aksrt-sortable__icon svg,
.aksrt-sortable__icon img {
.jio-sortable__icon svg,
.jio-sortable__icon img {
width: 20px;
height: 20px;
object-fit: contain;
}
.aksrt-sortable__main {
.jio-sortable__main {
display: flex;
flex: 1 1 auto;
flex-direction: column;
@@ -138,7 +138,7 @@
min-width: 0;
}
.aksrt-sortable__title-row {
.jio-sortable__title-row {
display: flex;
flex-wrap: wrap;
align-items: center;
@@ -146,10 +146,10 @@
min-width: 0;
}
.aksrt-sortable__title {
.jio-sortable__title {
min-width: 0;
overflow: hidden;
color: var(--aksrt-color-text, #1F2923);
color: var(--jio-color-text, #1F2923);
font-size: 13px;
font-weight: 600;
line-height: 1.4;
@@ -158,17 +158,17 @@
transition: color .15s ease;
}
.aksrt-sortable__desc {
.jio-sortable__desc {
min-width: 0;
overflow: hidden;
color: var(--aksrt-color-muted, #6F7A72);
color: var(--jio-color-muted, #6F7A72);
font-size: 12px;
line-height: 1.4;
text-overflow: ellipsis;
white-space: nowrap;
}
.aksrt-sortable__actions {
.jio-sortable__actions {
display: flex;
flex: 0 0 auto;
align-items: center;
@@ -176,67 +176,67 @@
margin-left: auto;
}
.aksrt-sortable__toggle {
.jio-sortable__toggle {
flex: 0 0 auto;
color: var(--aksrt-color-muted, #6F7A72);
color: var(--jio-color-muted, #6F7A72);
font-size: 12px;
transition: color .15s ease;
}
.aksrt-sortable__body {
.jio-sortable__body {
padding: 14px 16px 16px;
border-top: 1px solid var(--aksrt-color-border, #E2E8E3);
border-top: 1px solid var(--jio-color-border, #E2E8E3);
}
/* 拖拽中:原位置留下虚线占位,被拖动的卡片浮起。 */
.aksrt-sortable__chosen {
border-color: var(--aksrt-color-primary, #18A058);
.jio-sortable__chosen {
border-color: var(--jio-color-primary, #18A058);
}
.aksrt-sortable__drag {
box-shadow: var(--aksrt-shadow-floating, 0 12px 32px rgba(31, 41, 35, .12));
.jio-sortable__drag {
box-shadow: var(--jio-shadow-floating, 0 12px 32px rgba(31, 41, 35, .12));
}
.aksrt-sortable__ghost {
.jio-sortable__ghost {
border-style: dashed;
border-color: var(--aksrt-color-primary, #18A058);
background: var(--aksrt-color-primary-soft, #EAF7EF);
border-color: var(--jio-color-primary, #18A058);
background: var(--jio-color-primary-soft, #EAF7EF);
box-shadow: none;
}
.aksrt-sortable__ghost > * {
.jio-sortable__ghost > * {
visibility: hidden;
}
.aksrt-sortable__empty {
.jio-sortable__empty {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 6px;
padding: 20px 12px;
border: 1px dashed var(--aksrt-color-border-strong, #CCD7CE);
border: 1px dashed var(--jio-color-border-strong, #CCD7CE);
border-radius: 8px;
background: var(--aksrt-color-canvas, #F5F7F6);
color: var(--aksrt-color-muted, #6F7A72);
background: var(--jio-color-canvas, #F5F7F6);
color: var(--jio-color-muted, #6F7A72);
font-size: 13px;
}
@media (max-width: 640px) {
.aksrt-sortable__head {
.jio-sortable__head {
flex-wrap: wrap;
}
.aksrt-sortable__main {
.jio-sortable__main {
flex-basis: 160px;
}
}
@media (prefers-reduced-motion: reduce) {
.aksrt-sortable__item,
.aksrt-sortable__handle,
.aksrt-sortable__title,
.aksrt-sortable__toggle {
.jio-sortable__item,
.jio-sortable__handle,
.jio-sortable__title,
.jio-sortable__toggle {
transition: none;
}
}
+1 -1
View File
@@ -1,5 +1,5 @@
/**
* 颜色值归一化:与 PHP `AKSRT\Core\Color::sanitize()` 规则一致。
* 颜色值归一化:与 PHP `Jio\Core\Color::sanitize()` 规则一致。
*
* - 不带 alpha:仅 #rgb / #rrggbb;
* - 带 alpha:另允许 #rgba / #rrggbbaa 与 rgb()/rgba();
+1 -1
View File
@@ -3,7 +3,7 @@
*
* Supported stored formats:
* "fa fas fa-star" — FA5 class string
* "zibsvg-hot" — theme built-in SVG sprite key (window.aksrt_svgs)
* "zibsvg-hot" — theme built-in SVG sprite key (window.jio_svgs)
* "customsvg-<svg>" — inline user SVG markup
*/
+29 -29
View File
@@ -1,10 +1,10 @@
/* AKSRT universal icon picker (admin) */
/* Jio universal icon picker (admin) */
#aksrt-modal-icon.aksrt-icon-modal {
#jio-modal-icon.jio-icon-modal {
display: none;
}
#aksrt-modal-icon.aksrt-icon-modal:not(.hidden) {
#jio-modal-icon.jio-icon-modal:not(.hidden) {
display: flex;
position: fixed;
inset: 0;
@@ -15,17 +15,17 @@
/* Tab/search switching toggles the [hidden] attribute, but the explicit
display rules below would beat the UA's [hidden] rule — re-assert it. */
#aksrt-modal-icon [hidden] {
#jio-modal-icon [hidden] {
display: none !important;
}
#aksrt-modal-icon .aksrt-icon-modal__overlay {
#jio-modal-icon .jio-icon-modal__overlay {
position: absolute;
inset: 0;
background: rgba(0, 0, 0, 0.55);
}
#aksrt-modal-icon .aksrt-icon-modal__inner {
#jio-modal-icon .jio-icon-modal__inner {
position: relative;
z-index: 1;
display: flex;
@@ -38,7 +38,7 @@
overflow: hidden;
}
#aksrt-modal-icon .aksrt-icon-modal__header {
#jio-modal-icon .jio-icon-modal__header {
display: flex;
align-items: center;
justify-content: space-between;
@@ -47,14 +47,14 @@
font-size: 14px;
}
#aksrt-modal-icon .aksrt-icon-modal__close {
#jio-modal-icon .jio-icon-modal__close {
font-size: 20px;
line-height: 1;
text-decoration: none;
cursor: pointer;
}
#aksrt-modal-icon .aksrt-icon-modal__toolbar {
#jio-modal-icon .jio-icon-modal__toolbar {
display: flex;
flex-wrap: wrap;
gap: 8px;
@@ -63,40 +63,40 @@
border-bottom: 1px solid #e2e4e7;
}
#aksrt-modal-icon .aksrt-icon-modal__tabs {
#jio-modal-icon .jio-icon-modal__tabs {
display: flex;
flex-wrap: wrap;
gap: 6px;
}
#aksrt-modal-icon .aksrt-icon-modal__tab.is-active {
#jio-modal-icon .jio-icon-modal__tab.is-active {
border-color: #2271b1;
color: #2271b1;
}
#aksrt-modal-icon .aksrt-icon-modal__body {
#jio-modal-icon .jio-icon-modal__body {
position: relative;
overflow-y: auto;
padding: 12px 16px 16px;
}
#aksrt-modal-icon .aksrt-icon-modal__loading {
#jio-modal-icon .jio-icon-modal__loading {
padding: 24px 0;
text-align: center;
}
#aksrt-modal-icon .aksrt-icon-modal__error {
#jio-modal-icon .jio-icon-modal__error {
color: #b32d2e;
}
#aksrt-modal-icon .aksrt-icon-modal__grid {
#jio-modal-icon .jio-icon-modal__grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(42px, 1fr));
gap: 4px;
margin-top: 8px;
}
#aksrt-modal-icon .aksrt-icon-picker__item {
#jio-modal-icon .jio-icon-picker__item {
display: flex;
align-items: center;
justify-content: center;
@@ -111,18 +111,18 @@
cursor: pointer;
}
#aksrt-modal-icon .aksrt-icon-picker__item:hover {
#jio-modal-icon .jio-icon-picker__item:hover {
border-color: #2271b1;
color: #2271b1;
}
#aksrt-modal-icon .aksrt-icon-picker__item .icon {
#jio-modal-icon .jio-icon-picker__item .icon {
width: 20px;
height: 20px;
fill: currentColor;
}
#aksrt-modal-icon .aksrt-icon-picker__empty {
#jio-modal-icon .jio-icon-picker__empty {
grid-column: 1 / -1;
padding: 20px 0;
color: #787c82;
@@ -131,22 +131,22 @@
/* Custom SVG tab */
#aksrt-modal-icon .aksrt-icon-modal__custom {
#jio-modal-icon .jio-icon-modal__custom {
margin-top: 4px;
}
#aksrt-modal-icon .aksrt-icon-modal__custom textarea {
#jio-modal-icon .jio-icon-modal__custom textarea {
margin-top: 4px;
}
#aksrt-modal-icon .aksrt-icon-modal__custom-actions {
#jio-modal-icon .jio-icon-modal__custom-actions {
display: flex;
align-items: center;
gap: 10px;
margin-top: 8px;
}
#aksrt-modal-icon .aksrt-icon-modal__custom-preview {
#jio-modal-icon .jio-icon-modal__custom-preview {
display: inline-flex;
align-items: center;
justify-content: center;
@@ -157,12 +157,12 @@
font-size: 18px;
}
#aksrt-modal-icon .aksrt-icon-modal__custom-preview svg {
#jio-modal-icon .jio-icon-modal__custom-preview svg {
width: 20px;
height: 20px;
}
#aksrt-modal-icon .aksrt-icon-modal__grid--session {
#jio-modal-icon .jio-icon-modal__grid--session {
margin-top: 12px;
padding-top: 8px;
border-top: 1px solid #e2e4e7;
@@ -170,14 +170,14 @@
/* Field markup (widgets, nav menus, meta boxes) */
.aksrt-icon-picker {
.jio-icon-picker {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 8px;
}
.aksrt-icon-picker .aksrt-icon-picker__preview {
.jio-icon-picker .jio-icon-picker__preview {
display: inline-flex;
align-items: center;
justify-content: center;
@@ -189,13 +189,13 @@
font-size: 16px;
}
.aksrt-icon-picker .aksrt-icon-picker__preview svg {
.jio-icon-picker .jio-icon-picker__preview svg {
width: 18px;
height: 18px;
fill: currentColor;
}
.aksrt-icon-picker .aksrt-icon-picker__value {
.jio-icon-picker .jio-icon-picker__value {
flex: 1 1 160px;
min-width: 0;
}
+7 -7
View File
@@ -669,7 +669,7 @@ code {
/**---------------------通知结束-------------**/
/**---------批量编辑------------**/
.aksrt-bulk-edit-box {
.jio-bulk-edit-box {
margin: -1px;
background: #f8fcff;
border: 1px solid #d2d2d2;
@@ -677,25 +677,25 @@ code {
flex: auto;
}
.aksrt-bulk-edit-box label {
.jio-bulk-edit-box label {
line-height: 1.2;
}
.aksrt-bulk-edit-box > * + * {
.jio-bulk-edit-box > * + * {
margin-top: 6px;
}
.aksrt-bulk-edit-box select,
.aksrt-bulk-edit-box input[type="text"] {
.jio-bulk-edit-box select,
.jio-bulk-edit-box input[type="text"] {
max-width: 100%;
margin-right: 4px;
}
.inline-edit-row fieldset .aksrt-bulk-edit-box {
.inline-edit-row fieldset .jio-bulk-edit-box {
min-width: 168px;
}
.aksrt-bulk-edit-desc {
.jio-bulk-edit-desc {
color: #787c82;
}
+1 -1
View File
@@ -1 +1 @@
a:focus{box-shadow:none;outline:0}.px12{font-size:12px}.em12{font-size:1.2em}.em14{font-size:1.4em}.em16{font-size:1.6em}.em2x{font-size:2em}.em3x{font-size:3em}.em4x{font-size:4em}.em09{font-size:.9em}.dashicons{width:1em;height:1em}.text-center{text-align:center}.font-bold{font-weight:700}.opacity3{opacity:.3}.pointer{cursor:pointer}.relative{position:relative}.but[disabled],.but[disabled]:hover,.opacity5{opacity:.5}.opacity8{opacity:.8}badge{font-size:.8em;line-height:1.2;padding:.1em .4em;min-width:.8em;min-height:.8em;display:inline-block;vertical-align:.1em;border-radius:50px;background:var(--this-bg);color:var(--this-color);top:5px;--this-color:#fff;text-align:center;--this-bg:#fe3459}code{border-radius:4px}.badg,.but{border-radius:4px;display:inline-block;border-radius:4px;transition:.15s!important;vertical-align:middle;font-size:14px;padding:5px 20px;text-align:center;box-shadow:var(--this-shadow);background:var(--this-bg);color:var(--this-color);border:1px solid var(--this-border);--main-color:var(--this-color);--this-bg:rgba(136, 136, 136, 0.1);--this-border:transparent;--this-shadow:none;--this-color:#888;line-height:1.44;margin:2px;min-height:unset;text-decoration:none}.badg{font-size:.9em;padding:.05em .25em}.but a{color:inherit}.but svg.icon,.but>.fa{margin-right:.25em}.but.radius,.radius>.but{border-radius:50px;padding:.3em .8em}.badg.hollow,.but.hollow{background:0 0;--this-border:var(--this-color)}.but:focus,.but:hover{opacity:.8;background:var(--this-bg);color:var(--this-color);--this-shadow:0;box-shadow:none}.but:active{--this-shadow:inset 0 2px 6px rgba(0, 0, 0, 0.2);background:var(--this-bg);color:var(--this-color)}.but.hollow:hover{background:var(--this-color);color:#fff}[disabled]{opacity:.6!important;-webkit-filter:grayscale(20%);filter:grayscale(20%);cursor:no-drop!important}.but.padding-lg,.padding-lg{padding:.5em 2em}.b-black,.b-blue,.b-cyan,.b-green,.b-purple,.b-red,.b-theme,.b-yellow,.jb-blue,.jb-green,.jb-pink,.jb-purple,.jb-red,.jb-vip1,.jb-vip2,.jb-yellow{color:#fff;background:var(--this-bg);--this-color:#fff}.jb-blue,.jb-cyan,.jb-green,.jb-pink,.jb-purple,.jb-red,.jb-vip1,.jb-vip2,.jb-yellow{border:none}.b-cyan{--this-bg:#08c4c1}.b-theme{--this-bg:var(--focus-color)}.b-red{--this-bg:#ff5473}.b-yellow{--this-bg:#ff6f06}.b-blue{--this-bg:#2997f7}.b-green{--this-bg:#12b928}.b-purple{--this-bg:#d448f5}.b-black{--this-bg:#121517}.c-blue,.c-blue-2,.c-green,.c-purple,.c-red,.c-yellow{color:var(--this-color)}.c-red{--this-color:#ff5473;--this-bg:rgba(255, 84, 115, 0.1)}.c-yellow{--this-color:#ff6f06;--this-bg:rgba(255, 111, 6, 0.1)}.c-blue{--this-color:#2997f7;--this-bg:rgba(41, 151, 247, 0.1)}.c-blue-2{--this-color:#5c7cff;--this-bg:rgba(77, 130, 249, 0.1)}.c-green{--this-color:#12b928;--this-bg:rgba(18, 185, 40, 0.1)}.c-purple{--this-color:#d448f5;--this-bg:rgba(213, 72, 245, 0.1)}.jb-red{--this-bg:linear-gradient(135deg, #fd7a64 10%, #fb2d2d 100%)}.jb-yellow{--this-bg:linear-gradient(135deg, #f99d4d 10%, #f7631d 100%)}.jb-blue{--this-bg:linear-gradient(135deg, #59c3fb 10%, #268df7 100%)}.jb-green{--this-bg:linear-gradient(135deg, #60e464 10%, #5cb85b 100%)}.jb-purple{--this-bg:linear-gradient(135deg, #f98dfb 10%, #ea00f9 100%)}.jb-pink{--this-bg:linear-gradient(135deg, #ff5e7f 30%, #ff967e 100%)}.jb-vip1{--this-bg:linear-gradient(25deg, #eabe7b 10%, #f5e3c7 70%, #edc788 100%);--this-color:#866127}.jb-vip2{--this-bg:linear-gradient(317deg, #4d4c4c 30%, #7b7b7b 70%, #5f5c5c 100%);--this-color:#ddd}.c-cyan{--this-color:#09a4a1;--this-bg:rgba(8, 196, 193, 0.1)}.hide{display:none!important}.absolute{position:absolute;left:0;top:0;right:0;bottom:0;width:100%;height:100%}.flex{display:flex}.inflex{display:inline-flex}.flex.xx,.inflex.xx{flex-direction:column}.flex.hh{flex-wrap:wrap}.flex.ac,.inflex.ac{align-items:center}.flex.abl,.inflex.abl{align-items:baseline}.flex.ab,.inflex.ab{align-items:end}.flex.jc,.inflex.jc{align-items:center;justify-content:center}.flex.je{justify-content:flex-end}.flex.jsb,.inflex.jsb{justify-content:space-between}.flex .grow1{flex-grow:1}.flex .shrink0{flex-shrink:0}.flex .flex0{flex:none}.flex .flex1{flex:1}.overflow-hidden{overflow:hidden}.mm3{margin:3px}.mr3{margin-right:3px}.mr6{margin-right:6px}.mr10{margin-right:10px}.mr20{margin-right:20px}.ml3{margin-left:3px}.mln3{margin-left:-3px}.ml6{margin-left:6px}.ml10{margin-left:10px}.ml20{margin-left:20px}.mt3{margin-top:3px}.mt6{margin-top:6px}.mt10{margin-top:10px}.mt15{margin-top:15px}.mt20{margin-top:20px}.mb6{margin-bottom:6px}.mb10{margin-bottom:10px}.mb20{margin-bottom:20px}.padding-10{padding:10px}.padding-15{padding:15px}.padding-h6{padding-top:6px;padding-bottom:6px}.padding-h10{padding-top:10px;padding-bottom:10px}.border-bottom{border-bottom:1px solid #e8e8e8}.border-bottom:last-of-type{border:none}.max-vh5,.max-vh7{max-height:70vh;-ms-overflow-style:none;overflow:-moz-scrollbars-none;overflow-x:hidden;overflow-y:auto}.max-vh5{max-height:50vh}.muted-2-color{opacity:.6}.text-ellipsis{overflow:hLine truncated
a:focus{box-shadow:none;outline:0}.px12{font-size:12px}.em12{font-size:1.2em}.em14{font-size:1.4em}.em16{font-size:1.6em}.em2x{font-size:2em}.em3x{font-size:3em}.em4x{font-size:4em}.em09{font-size:.9em}.dashicons{width:1em;height:1em}.text-center{text-align:center}.font-bold{font-weight:700}.opacity3{opacity:.3}.pointer{cursor:pointer}.relative{position:relative}.but[disabled],.but[disabled]:hover,.opacity5{opacity:.5}.opacity8{opacity:.8}badge{font-size:.8em;line-height:1.2;padding:.1em .4em;min-width:.8em;min-height:.8em;display:inline-block;vertical-align:.1em;border-radius:50px;background:var(--this-bg);color:var(--this-color);top:5px;--this-color:#fff;text-align:center;--this-bg:#fe3459}code{border-radius:4px}.badg,.but{border-radius:4px;display:inline-block;border-radius:4px;transition:.15s!important;vertical-align:middle;font-size:14px;padding:5px 20px;text-align:center;box-shadow:var(--this-shadow);background:var(--this-bg);color:var(--this-color);border:1px solid var(--this-border);--main-color:var(--this-color);--this-bg:rgba(136, 136, 136, 0.1);--this-border:transparent;--this-shadow:none;--this-color:#888;line-height:1.44;margin:2px;min-height:unset;text-decoration:none}.badg{font-size:.9em;padding:.05em .25em}.but a{color:inherit}.but svg.icon,.but>.fa{margin-right:.25em}.but.radius,.radius>.but{border-radius:50px;padding:.3em .8em}.badg.hollow,.but.hollow{background:0 0;--this-border:var(--this-color)}.but:focus,.but:hover{opacity:.8;background:var(--this-bg);color:var(--this-color);--this-shadow:0;box-shadow:none}.but:active{--this-shadow:inset 0 2px 6px rgba(0, 0, 0, 0.2);background:var(--this-bg);color:var(--this-color)}.but.hollow:hover{background:var(--this-color);color:#fff}[disabled]{opacity:.6!important;-webkit-filter:grayscale(20%);filter:grayscale(20%);cursor:no-drop!important}.but.padding-lg,.padding-lg{padding:.5em 2em}.b-black,.b-blue,.b-cyan,.b-green,.b-purple,.b-red,.b-theme,.b-yellow,.jb-blue,.jb-green,.jb-pink,.jb-purple,.jb-red,.jb-vip1,.jb-vip2,.jb-yellow{color:#fff;background:var(--this-bg);--this-color:#fff}.jb-blue,.jb-cyan,.jb-green,.jb-pink,.jb-purple,.jb-red,.jb-vip1,.jb-vip2,.jb-yellow{border:none}.b-cyan{--this-bg:#08c4c1}.b-theme{--this-bg:var(--focus-color)}.b-red{--this-bg:#ff5473}.b-yellow{--this-bg:#ff6f06}.b-blue{--this-bg:#2997f7}.b-green{--this-bg:#12b928}.b-purple{--this-bg:#d448f5}.b-black{--this-bg:#121517}.c-blue,.c-blue-2,.c-green,.c-purple,.c-red,.c-yellow{color:var(--this-color)}.c-red{--this-color:#ff5473;--this-bg:rgba(255, 84, 115, 0.1)}.c-yellow{--this-color:#ff6f06;--this-bg:rgba(255, 111, 6, 0.1)}.c-blue{--this-color:#2997f7;--this-bg:rgba(41, 151, 247, 0.1)}.c-blue-2{--this-color:#5c7cff;--this-bg:rgba(77, 130, 249, 0.1)}.c-green{--this-color:#12b928;--this-bg:rgba(18, 185, 40, 0.1)}.c-purple{--this-color:#d448f5;--this-bg:rgba(213, 72, 245, 0.1)}.jb-red{--this-bg:linear-gradient(135deg, #fd7a64 10%, #fb2d2d 100%)}.jb-yellow{--this-bg:linear-gradient(135deg, #f99d4d 10%, #f7631d 100%)}.jb-blue{--this-bg:linear-gradient(135deg, #59c3fb 10%, #268df7 100%)}.jb-green{--this-bg:linear-gradient(135deg, #60e464 10%, #5cb85b 100%)}.jb-purple{--this-bg:linear-gradient(135deg, #f98dfb 10%, #ea00f9 100%)}.jb-pink{--this-bg:linear-gradient(135deg, #ff5e7f 30%, #ff967e 100%)}.jb-vip1{--this-bg:linear-gradient(25deg, #eabe7b 10%, #f5e3c7 70%, #edc788 100%);--this-color:#866127}.jb-vip2{--this-bg:linear-gradient(317deg, #4d4c4c 30%, #7b7b7b 70%, #5f5c5c 100%);--this-color:#ddd}.c-cyan{--this-color:#09a4a1;--this-bg:rgba(8, 196, 193, 0.1)}.hide{display:none!important}.absolute{position:absolute;left:0;top:0;right:0;bottom:0;width:100%;height:100%}.flex{display:flex}.inflex{display:inline-flex}.flex.xx,.inflex.xx{flex-direction:column}.flex.hh{flex-wrap:wrap}.flex.ac,.inflex.ac{align-items:center}.flex.abl,.inflex.abl{align-items:baseline}.flex.ab,.inflex.ab{align-items:end}.flex.jc,.inflex.jc{align-items:center;justify-content:center}.flex.je{justify-content:flex-end}.flex.jsb,.inflex.jsb{justify-content:space-between}.flex .grow1{flex-grow:1}.flex .shrink0{flex-shrink:0}.flex .flex0{flex:none}.flex .flex1{flex:1}.overflow-hidden{overflow:hidden}.mm3{margin:3px}.mr3{margin-right:3px}.mr6{margin-right:6px}.mr10{margin-right:10px}.mr20{margin-right:20px}.ml3{margin-left:3px}.mln3{margin-left:-3px}.ml6{margin-left:6px}.ml10{margin-left:10px}.ml20{margin-left:20px}.mt3{margin-top:3px}.mt6{margin-top:6px}.mt10{margin-top:10px}.mt15{margin-top:15px}.mt20{margin-top:20px}.mb6{margin-bottom:6px}.mb10{margin-bottom:10px}.mb20{margin-bottom:20px}.padding-10{padding:10px}.padding-15{padding:15px}.padding-h6{padding-top:6px;padding-bottom:6px}.padding-h10{padding-top:10px;padding-bottom:10px}.border-bottom{border-bottom:1px solid #e8e8e8}.border-bottom:last-of-type{border:none}.max-vh5,.max-vh7{max-height:70vh;-ms-overflow-style:none;overflow:-moz-scrollbars-none;overflow-x:hidden;overflow-y:auto}.max-vh5{max-height:50vh}.muted-2-color{opacity:.6}.text-ellipsis{overflow:hLine truncated
+17 -17
View File
@@ -1,45 +1,45 @@
body.toplevel_page_aksrt-settings {
body.toplevel_page_jio-settings {
background: #f5f7fb;
}
body.toplevel_page_aksrt-settings #wpcontent {
body.toplevel_page_jio-settings #wpcontent {
padding-left: 0;
}
body.toplevel_page_aksrt-settings #wpbody-content {
body.toplevel_page_jio-settings #wpbody-content {
padding-bottom: 0;
}
body.toplevel_page_aksrt-settings #wpbody-content .wrap {
body.toplevel_page_jio-settings #wpbody-content .wrap {
margin: 0;
padding: 0;
}
body.toplevel_page_aksrt-settings #wpbody-content .wrap > h1:first-child {
body.toplevel_page_jio-settings #wpbody-content .wrap > h1:first-child {
display: none !important;
}
body.toplevel_page_aksrt-settings #wpbody-content .notice,
body.toplevel_page_aksrt-settings #wpbody-content .updated,
body.toplevel_page_aksrt-settings #wpbody-content .error {
body.toplevel_page_jio-settings #wpbody-content .notice,
body.toplevel_page_jio-settings #wpbody-content .updated,
body.toplevel_page_jio-settings #wpbody-content .error {
position: relative;
z-index: 3;
margin: 18px 20px 0 0;
}
body.toplevel_page_aksrt-settings #collapse-menu {
body.toplevel_page_jio-settings #collapse-menu {
display: none !important;
}
#aksrt-admin-app {
#jio-admin-app {
position: relative;
min-height: calc(100vh - 32px);
isolation: isolate;
background: transparent;
}
#aksrt-admin-app:empty::before {
content: "AKSRT 管理台加载中...";
#jio-admin-app:empty::before {
content: "Jio 管理台加载中...";
display: flex;
align-items: center;
justify-content: center;
@@ -63,21 +63,21 @@ body.toplevel_page_aksrt-settings #collapse-menu {
@media screen and (max-width: 782px) {
/* 隐藏 WP 后台默认顶栏的多余间距 */
body.toplevel_page_aksrt-settings #wpbody {
body.toplevel_page_jio-settings #wpbody {
padding-top: 0;
}
body.toplevel_page_aksrt-settings #wpcontent {
body.toplevel_page_jio-settings #wpcontent {
margin-left: 0 !important;
}
#aksrt-admin-app,
#aksrt-admin-app:empty::before {
#jio-admin-app,
#jio-admin-app:empty::before {
min-height: calc(100vh - 46px);
}
/* 移动端把 WP 折叠菜单按钮藏掉,避免与自定义菜单按钮重叠 */
body.toplevel_page_aksrt-settings #wp-admin-bar-menu-toggle {
body.toplevel_page_jio-settings #wp-admin-bar-menu-toggle {
display: none;
}
}
+44 -44
View File
@@ -1,54 +1,54 @@
/* 优惠码(aksrt_coupons):页头按钮 + 新建/批量生成弹窗。复用 native-ui.css 的 --an-* 令牌,规则限定在本页类名下。 */
.aksrt-coupons-page [hidden],
.aksrt-coupon-dialog [hidden] { display: none !important; }
.aksrt-coupons-page .aksrt-native-header__actions .button,
.aksrt-coupon-generated .aksrt-native-card__actions .button { display: inline-flex; align-items: center; gap: 5px; }
.aksrt-coupons-page .aksrt-native-header__actions .dashicons { margin: 0; font-size: 17px; line-height: 20px; }
.aksrt-coupon-generated .aksrt-native-card__actions .dashicons { margin: 0; font-size: 14px; width: 14px; height: 14px; }
/* 优惠码(jio_coupons):页头按钮 + 新建/批量生成弹窗。复用 native-ui.css 的 --an-* 令牌,规则限定在本页类名下。 */
.jio-coupons-page [hidden],
.jio-coupon-dialog [hidden] { display: none !important; }
.jio-coupons-page .jio-native-header__actions .button,
.jio-coupon-generated .jio-native-card__actions .button { display: inline-flex; align-items: center; gap: 5px; }
.jio-coupons-page .jio-native-header__actions .dashicons { margin: 0; font-size: 17px; line-height: 20px; }
.jio-coupon-generated .jio-native-card__actions .dashicons { margin: 0; font-size: 14px; width: 14px; height: 14px; }
/* ---------- 列表 ---------- */
.aksrt-coupons-page .wp-list-table { min-width: 1000px; }
.aksrt-coupons-page .wp-list-table td { vertical-align: middle; overflow-wrap: anywhere; }
.aksrt-coupon-code { display: inline-flex; align-items: center; gap: 5px; max-width: 100%; padding: 4px 7px; color: var(--an-text); background: var(--an-bg-soft); border: 1px solid transparent; border-radius: 5px; text-align: left; font-size: 13px; overflow-wrap: anywhere; cursor: pointer; }
.aksrt-coupon-code .dashicons { flex: none; width: 14px; height: 14px; color: var(--an-muted); font-size: 14px; }
.aksrt-coupon-code:hover { color: var(--an-primary); background: var(--an-primary-soft); border-color: var(--an-primary); }
.aksrt-coupon-code:focus-visible { outline: 2px solid var(--an-primary); outline-offset: 2px; }
.aksrt-coupon-generated textarea { margin-top: 8px; resize: vertical; }
.jio-coupons-page .wp-list-table { min-width: 1000px; }
.jio-coupons-page .wp-list-table td { vertical-align: middle; overflow-wrap: anywhere; }
.jio-coupon-code { display: inline-flex; align-items: center; gap: 5px; max-width: 100%; padding: 4px 7px; color: var(--an-text); background: var(--an-bg-soft); border: 1px solid transparent; border-radius: 5px; text-align: left; font-size: 13px; overflow-wrap: anywhere; cursor: pointer; }
.jio-coupon-code .dashicons { flex: none; width: 14px; height: 14px; color: var(--an-muted); font-size: 14px; }
.jio-coupon-code:hover { color: var(--an-primary); background: var(--an-primary-soft); border-color: var(--an-primary); }
.jio-coupon-code:focus-visible { outline: 2px solid var(--an-primary); outline-offset: 2px; }
.jio-coupon-generated textarea { margin-top: 8px; resize: vertical; }
/* ---------- 弹窗 ---------- */
html.aksrt-coupons-modal-open { overflow: hidden; }
.aksrt-coupon-dialog { width: min(720px, calc(100vw - 32px)); max-width: none; max-height: calc(100vh - 48px); max-height: calc(100dvh - 48px); margin: auto; padding: 0; overflow: hidden; color: var(--an-text-2); background: var(--an-card); border: 0; border-radius: var(--an-radius); box-shadow: 0 16px 64px rgba(15, 23, 42, .2); }
.aksrt-coupon-dialog::backdrop { background: rgba(15, 23, 42, .45); }
.aksrt-coupon-dialog__frame { display: flex; flex-direction: column; max-height: inherit; margin: 0; }
.aksrt-coupon-dialog__head { display: flex; flex: none; align-items: flex-start; justify-content: space-between; gap: 16px; padding: 20px 24px 18px; border-bottom: 1px solid var(--an-border-soft); }
.aksrt-coupon-dialog .aksrt-coupon-dialog__head h2 { margin: 0; padding: 0; color: var(--an-text); font-size: 18px; font-weight: 600; line-height: 1.5; }
.aksrt-coupon-dialog__head p { margin: 5px 0 0; font-size: 13px; line-height: 1.6; }
.aksrt-coupon-dialog__close { display: inline-flex; flex: none; align-items: center; justify-content: center; width: 32px; height: 32px; padding: 0; color: var(--an-text-2); background: transparent; border: 0; border-radius: var(--an-radius-sm); cursor: pointer; }
.aksrt-coupon-dialog__close:hover { color: var(--an-text); background: var(--an-bg-soft); }
.aksrt-coupon-dialog__body { min-height: 0; padding: 20px 24px 24px; overflow-y: auto; overscroll-behavior: contain; }
.aksrt-coupon-dialog__foot { display: flex; flex: none; justify-content: flex-end; gap: 8px; padding: 14px 24px; background: var(--an-card); border-top: 1px solid var(--an-border-soft); }
.aksrt-coupon-dialog__foot .button { min-width: 110px; }
.aksrt-coupon-dialog .button:disabled { opacity: .65; cursor: not-allowed; }
.aksrt-coupon-dialog :is(a, button, input, select, textarea):focus-visible { outline: 2px solid var(--an-primary); outline-offset: 2px; }
.aksrt-coupon-dialog .aksrt-native-form-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.aksrt-coupon-dialog .aksrt-coupon-batch-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.aksrt-coupon-dialog .aksrt-coupon-section { margin: 0 0 12px; color: var(--an-text); font-size: 14px; font-weight: 600; line-height: 1.5; }
.aksrt-coupon-dialog .aksrt-coupon-section ~ .aksrt-coupon-section { margin-top: 22px; padding-top: 18px; border-top: 1px solid var(--an-border-soft); }
html.jio-coupons-modal-open { overflow: hidden; }
.jio-coupon-dialog { width: min(720px, calc(100vw - 32px)); max-width: none; max-height: calc(100vh - 48px); max-height: calc(100dvh - 48px); margin: auto; padding: 0; overflow: hidden; color: var(--an-text-2); background: var(--an-card); border: 0; border-radius: var(--an-radius); box-shadow: 0 16px 64px rgba(15, 23, 42, .2); }
.jio-coupon-dialog::backdrop { background: rgba(15, 23, 42, .45); }
.jio-coupon-dialog__frame { display: flex; flex-direction: column; max-height: inherit; margin: 0; }
.jio-coupon-dialog__head { display: flex; flex: none; align-items: flex-start; justify-content: space-between; gap: 16px; padding: 20px 24px 18px; border-bottom: 1px solid var(--an-border-soft); }
.jio-coupon-dialog .jio-coupon-dialog__head h2 { margin: 0; padding: 0; color: var(--an-text); font-size: 18px; font-weight: 600; line-height: 1.5; }
.jio-coupon-dialog__head p { margin: 5px 0 0; font-size: 13px; line-height: 1.6; }
.jio-coupon-dialog__close { display: inline-flex; flex: none; align-items: center; justify-content: center; width: 32px; height: 32px; padding: 0; color: var(--an-text-2); background: transparent; border: 0; border-radius: var(--an-radius-sm); cursor: pointer; }
.jio-coupon-dialog__close:hover { color: var(--an-text); background: var(--an-bg-soft); }
.jio-coupon-dialog__body { min-height: 0; padding: 20px 24px 24px; overflow-y: auto; overscroll-behavior: contain; }
.jio-coupon-dialog__foot { display: flex; flex: none; justify-content: flex-end; gap: 8px; padding: 14px 24px; background: var(--an-card); border-top: 1px solid var(--an-border-soft); }
.jio-coupon-dialog__foot .button { min-width: 110px; }
.jio-coupon-dialog .button:disabled { opacity: .65; cursor: not-allowed; }
.jio-coupon-dialog :is(a, button, input, select, textarea):focus-visible { outline: 2px solid var(--an-primary); outline-offset: 2px; }
.jio-coupon-dialog .jio-native-form-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.jio-coupon-dialog .jio-coupon-batch-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.jio-coupon-dialog .jio-coupon-section { margin: 0 0 12px; color: var(--an-text); font-size: 14px; font-weight: 600; line-height: 1.5; }
.jio-coupon-dialog .jio-coupon-section ~ .jio-coupon-section { margin-top: 22px; padding-top: 18px; border-top: 1px solid var(--an-border-soft); }
.aksrt-coupon-inline { display: flex; align-items: center; gap: 6px; }
.aksrt-coupon-inline input { flex: 1 1 auto; min-width: 0; }
.aksrt-coupon-unit { flex: none; min-width: 1.2em; color: var(--an-muted); }
.jio-coupon-inline { display: flex; align-items: center; gap: 6px; }
.jio-coupon-inline input { flex: 1 1 auto; min-width: 0; }
.jio-coupon-unit { flex: none; min-width: 1.2em; color: var(--an-muted); }
/* ---------- 复制提示 ---------- */
.aksrt-coupon-toast { position: fixed; right: 24px; bottom: 24px; z-index: 100000; max-width: min(360px, calc(100vw - 48px)); padding: 10px 14px; color: #fff; background: rgba(15, 23, 42, .9); border-radius: var(--an-radius-sm); font-size: 13px; opacity: 0; transform: translateY(8px); transition: opacity .2s, transform .2s; pointer-events: none; }
.aksrt-coupon-toast.is-visible { opacity: 1; transform: none; }
.jio-coupon-toast { position: fixed; right: 24px; bottom: 24px; z-index: 100000; max-width: min(360px, calc(100vw - 48px)); padding: 10px 14px; color: #fff; background: rgba(15, 23, 42, .9); border-radius: var(--an-radius-sm); font-size: 13px; opacity: 0; transform: translateY(8px); transition: opacity .2s, transform .2s; pointer-events: none; }
.jio-coupon-toast.is-visible { opacity: 1; transform: none; }
@media (max-width: 600px) {
.aksrt-coupon-dialog { width: calc(100vw - 24px); max-height: calc(100dvh - 24px); }
.aksrt-coupon-dialog__head,
.aksrt-coupon-dialog__body,
.aksrt-coupon-dialog__foot { padding-left: 16px; padding-right: 16px; }
.aksrt-coupon-dialog .aksrt-native-form-grid,
.aksrt-coupon-dialog .aksrt-coupon-batch-grid { grid-template-columns: 1fr; }
.aksrt-coupon-dialog__foot .button { flex: 1; min-width: 0; }
.jio-coupon-dialog { width: calc(100vw - 24px); max-height: calc(100dvh - 24px); }
.jio-coupon-dialog__head,
.jio-coupon-dialog__body,
.jio-coupon-dialog__foot { padding-left: 16px; padding-right: 16px; }
.jio-coupon-dialog .jio-native-form-grid,
.jio-coupon-dialog .jio-coupon-batch-grid { grid-template-columns: 1fr; }
.jio-coupon-dialog__foot .button { flex: 1; min-width: 0; }
}
+39 -39
View File
@@ -1,52 +1,52 @@
/* 创作分成(aksrt_income):统计 + 状态视图 + 筛选 + 分成表。复用 native-ui.css 的 --an-* 令牌,规则限定在 .aksrt-income-page 下。 */
/* 创作分成(jio_income):统计 + 状态视图 + 筛选 + 分成表。复用 native-ui.css 的 --an-* 令牌,规则限定在 .jio-income-page 下。 */
/* ---------- 状态视图 ---------- */
.aksrt-income-page .aksrt-income-views { display: flex; width: fit-content; max-width: 100%; }
.jio-income-page .jio-income-views { display: flex; width: fit-content; max-width: 100%; }
/* ---------- 筛选栏 ---------- */
.aksrt-income-filters { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 0; }
.aksrt-income-filters label { display: inline-flex; margin: 0; }
.aksrt-income-filters__search { flex: 1 1 220px; }
.aksrt-income-filters__search input { width: 100%; }
.aksrt-income-filters__range { display: inline-flex; align-items: center; gap: 6px; color: var(--an-muted); }
.aksrt-income-page .aksrt-income-filters__id { width: 96px; }
.aksrt-income-filters__submit { display: inline-flex; gap: 8px; }
.jio-income-filters { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 0; }
.jio-income-filters label { display: inline-flex; margin: 0; }
.jio-income-filters__search { flex: 1 1 220px; }
.jio-income-filters__search input { width: 100%; }
.jio-income-filters__range { display: inline-flex; align-items: center; gap: 6px; color: var(--an-muted); }
.jio-income-page .jio-income-filters__id { width: 96px; }
.jio-income-filters__submit { display: inline-flex; gap: 8px; }
/* ---------- 批量操作 ---------- */
.aksrt-income-bulk { margin: 0; }
.aksrt-income-bulk__count { color: var(--an-muted); font-size: 12px; font-variant-numeric: tabular-nums; }
.aksrt-income-bulk__count.is-active { color: var(--an-text); font-weight: 500; }
.aksrt-income-page .aksrt-income-bulk .button:disabled { opacity: .6; cursor: not-allowed; }
.aksrt-income-table .check-column input:disabled { cursor: not-allowed; opacity: .45; }
.jio-income-bulk { margin: 0; }
.jio-income-bulk__count { color: var(--an-muted); font-size: 12px; font-variant-numeric: tabular-nums; }
.jio-income-bulk__count.is-active { color: var(--an-text); font-weight: 500; }
.jio-income-page .jio-income-bulk .button:disabled { opacity: .6; cursor: not-allowed; }
.jio-income-table .check-column input:disabled { cursor: not-allowed; opacity: .45; }
/* ---------- 分成表 ---------- */
.aksrt-income-table { min-width: 1040px; table-layout: fixed; }
.aksrt-income-table .column-record { width: 13%; }
.aksrt-income-table .column-author { width: 15%; }
.aksrt-income-table .column-source { width: 24%; }
.aksrt-income-table .column-base { width: 14%; }
.aksrt-income-table .column-amount { width: 12%; }
.aksrt-income-table .column-status { width: 12%; }
.aksrt-income-table .column-actions { width: 13%; }
.aksrt-income-table td,
.aksrt-income-table tbody th { vertical-align: top; }
.aksrt-income-id { color: var(--an-text); font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 12px; font-weight: 600; }
.aksrt-income-post { display: block; color: var(--an-text); font-weight: 500; text-decoration: none; overflow-wrap: anywhere; }
a.aksrt-income-post:hover,
a.aksrt-income-post:focus { color: var(--an-primary); }
.aksrt-income-order { color: inherit; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; text-decoration: none; }
.aksrt-income-order:hover,
.aksrt-income-order:focus { color: var(--an-primary); }
.aksrt-income-sub { margin-top: 4px; color: var(--an-muted); font-size: 12px; line-height: 1.5; overflow-wrap: anywhere; }
.aksrt-income-table .column-base,
.aksrt-income-table .column-amount { font-variant-numeric: tabular-nums; }
.jio-income-table { min-width: 1040px; table-layout: fixed; }
.jio-income-table .column-record { width: 13%; }
.jio-income-table .column-author { width: 15%; }
.jio-income-table .column-source { width: 24%; }
.jio-income-table .column-base { width: 14%; }
.jio-income-table .column-amount { width: 12%; }
.jio-income-table .column-status { width: 12%; }
.jio-income-table .column-actions { width: 13%; }
.jio-income-table td,
.jio-income-table tbody th { vertical-align: top; }
.jio-income-id { color: var(--an-text); font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 12px; font-weight: 600; }
.jio-income-post { display: block; color: var(--an-text); font-weight: 500; text-decoration: none; overflow-wrap: anywhere; }
a.jio-income-post:hover,
a.jio-income-post:focus { color: var(--an-primary); }
.jio-income-order { color: inherit; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; text-decoration: none; }
.jio-income-order:hover,
.jio-income-order:focus { color: var(--an-primary); }
.jio-income-sub { margin-top: 4px; color: var(--an-muted); font-size: 12px; line-height: 1.5; overflow-wrap: anywhere; }
.jio-income-table .column-base,
.jio-income-table .column-amount { font-variant-numeric: tabular-nums; }
/* 行内操作:每个按钮是一个独立 POST 表单 */
.aksrt-income-actions { display: flex; flex-wrap: wrap; gap: 6px; }
.aksrt-income-action { display: inline-flex; margin: 0; }
.aksrt-income-action .button[disabled] { opacity: .6; cursor: progress; }
.jio-income-actions { display: flex; flex-wrap: wrap; gap: 6px; }
.jio-income-action { display: inline-flex; margin: 0; }
.jio-income-action .button[disabled] { opacity: .6; cursor: progress; }
@media (max-width: 782px) {
.aksrt-income-filters__search { flex-basis: 100%; }
.aksrt-income-filters__range { flex-wrap: wrap; }
.jio-income-filters__search { flex-basis: 100%; }
.jio-income-filters__range { flex-wrap: wrap; }
}
+103 -103
View File
@@ -1,109 +1,109 @@
/* 邀请码原生运营页;外壳、表格与表单令牌沿用 native-ui.css。 */
.aksrt-inv-page [hidden] { display: none !important; }
.aksrt-inv-page .aksrt-native-header__actions .button { display: inline-flex; align-items: center; gap: 5px; }
.aksrt-inv-page .aksrt-native-header__actions .dashicons { margin: 0; font-size: 17px; line-height: 20px; }
.aksrt-inv-toolbar { padding: 14px 20px; border-bottom: 1px solid var(--an-border-soft); }
.aksrt-inv-toolbar__views { display: flex; flex-wrap: wrap; align-items: center; gap: 12px 20px; }
.aksrt-inv-toolbar .subsubsub { margin: 0; padding: 0; box-shadow: none; }
.aksrt-inv-toolbar .aksrt-native-filters { margin: 0; }
.aksrt-inv-filter-remark { max-width: 240px; color: var(--an-text-2); font-size: 12px; overflow-wrap: anywhere; }
.aksrt-inv-bulk { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; padding: 12px 20px; border-bottom: 1px solid var(--an-border-soft); }
.aksrt-inv-selection { margin-right: auto; color: var(--an-text-2); font-size: 12px; font-variant-numeric: tabular-nums; }
.jio-inv-page [hidden] { display: none !important; }
.jio-inv-page .jio-native-header__actions .button { display: inline-flex; align-items: center; gap: 5px; }
.jio-inv-page .jio-native-header__actions .dashicons { margin: 0; font-size: 17px; line-height: 20px; }
.jio-inv-toolbar { padding: 14px 20px; border-bottom: 1px solid var(--an-border-soft); }
.jio-inv-toolbar__views { display: flex; flex-wrap: wrap; align-items: center; gap: 12px 20px; }
.jio-inv-toolbar .subsubsub { margin: 0; padding: 0; box-shadow: none; }
.jio-inv-toolbar .jio-native-filters { margin: 0; }
.jio-inv-filter-remark { max-width: 240px; color: var(--an-text-2); font-size: 12px; overflow-wrap: anywhere; }
.jio-inv-bulk { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; padding: 12px 20px; border-bottom: 1px solid var(--an-border-soft); }
.jio-inv-selection { margin-right: auto; color: var(--an-text-2); font-size: 12px; font-variant-numeric: tabular-nums; }
.aksrt-inv-page .aksrt-inv-table { min-width: 1000px; table-layout: fixed; }
.aksrt-inv-table .column-code { width: 21%; }
.aksrt-inv-table .column-rewards { width: 14%; }
.aksrt-inv-table .column-created_at,
.aksrt-inv-table .column-updated_at { width: 16%; }
.aksrt-inv-table .column-used_count { width: 13%; }
.aksrt-inv-table .column-remark { width: 20%; }
.aksrt-inv-page .aksrt-inv-table td { vertical-align: middle; overflow-wrap: anywhere; }
.aksrt-inv-table .orderby-but { display: inline-flex; align-items: center; gap: 3px; color: var(--an-text-2); text-decoration: none; }
.aksrt-inv-table .orderby-but .dashicons { width: 14px; height: 14px; font-size: 14px; opacity: .35; }
.aksrt-inv-table .orderby-but:hover,
.aksrt-inv-table .orderby-but.is-active { color: var(--an-primary); }
.aksrt-inv-table .orderby-but.is-active .dashicons { opacity: 1; }
.aksrt-inv-code { display: inline-flex; align-items: center; gap: 5px; max-width: 100%; padding: 5px 7px; color: var(--an-text); background: var(--an-bg-soft); border: 1px solid transparent; border-radius: 5px; text-align: left; font-size: 13px; overflow-wrap: anywhere; cursor: pointer; }
.aksrt-inv-code .dashicons { flex: none; width: 14px; height: 14px; color: var(--an-muted); font-size: 14px; }
.aksrt-inv-code:hover { color: var(--an-primary); background: var(--an-primary-soft); border-color: var(--an-primary); }
.aksrt-inv-date { font-variant-numeric: tabular-nums; font-size: 12px; }
.aksrt-inv-user { margin-top: 4px; font-size: 12px; }
.aksrt-inv-table tr.is-selected > td,
.aksrt-inv-table tr.is-selected > th { background: var(--an-primary-soft); }
.aksrt-inv-page .aksrt-inv-code:focus-visible,
.aksrt-inv-page .aksrt-inv-dialog__close:focus-visible { outline: 2px solid var(--an-primary); outline-offset: 2px; }
.jio-inv-page .jio-inv-table { min-width: 1000px; table-layout: fixed; }
.jio-inv-table .column-code { width: 21%; }
.jio-inv-table .column-rewards { width: 14%; }
.jio-inv-table .column-created_at,
.jio-inv-table .column-updated_at { width: 16%; }
.jio-inv-table .column-used_count { width: 13%; }
.jio-inv-table .column-remark { width: 20%; }
.jio-inv-page .jio-inv-table td { vertical-align: middle; overflow-wrap: anywhere; }
.jio-inv-table .orderby-but { display: inline-flex; align-items: center; gap: 3px; color: var(--an-text-2); text-decoration: none; }
.jio-inv-table .orderby-but .dashicons { width: 14px; height: 14px; font-size: 14px; opacity: .35; }
.jio-inv-table .orderby-but:hover,
.jio-inv-table .orderby-but.is-active { color: var(--an-primary); }
.jio-inv-table .orderby-but.is-active .dashicons { opacity: 1; }
.jio-inv-code { display: inline-flex; align-items: center; gap: 5px; max-width: 100%; padding: 5px 7px; color: var(--an-text); background: var(--an-bg-soft); border: 1px solid transparent; border-radius: 5px; text-align: left; font-size: 13px; overflow-wrap: anywhere; cursor: pointer; }
.jio-inv-code .dashicons { flex: none; width: 14px; height: 14px; color: var(--an-muted); font-size: 14px; }
.jio-inv-code:hover { color: var(--an-primary); background: var(--an-primary-soft); border-color: var(--an-primary); }
.jio-inv-date { font-variant-numeric: tabular-nums; font-size: 12px; }
.jio-inv-user { margin-top: 4px; font-size: 12px; }
.jio-inv-table tr.is-selected > td,
.jio-inv-table tr.is-selected > th { background: var(--an-primary-soft); }
.jio-inv-page .jio-inv-code:focus-visible,
.jio-inv-page .jio-inv-dialog__close:focus-visible { outline: 2px solid var(--an-primary); outline-offset: 2px; }
html.aksrt-inv-modal-open { overflow: hidden; }
.aksrt-inv-dialog { width: min(680px, calc(100vw - 32px)); max-width: none; max-height: calc(100vh - 64px); max-height: calc(100dvh - 64px); margin: auto; padding: 0; overflow: hidden; color: var(--an-text-2); background: var(--an-card); border: 0; border-radius: var(--an-radius); box-shadow: 0 16px 64px rgba(15, 23, 42, .2); }
.aksrt-inv-dialog::backdrop { background: rgba(15, 23, 42, .45); }
#aksrt-inv-export { width: min(560px, calc(100vw - 32px)); }
.aksrt-inv-dialog__frame { display: flex; flex-direction: column; max-height: inherit; margin: 0; }
.aksrt-inv-dialog__head { display: flex; flex: none; align-items: flex-start; justify-content: space-between; gap: 16px; padding: 20px 24px 18px; border-bottom: 1px solid var(--an-border-soft); }
.aksrt-inv-dialog .aksrt-inv-dialog__head h2 { margin: 0; padding: 0; color: var(--an-text); font-size: 18px; font-weight: 600; line-height: 1.5; }
.aksrt-inv-dialog__head p { margin: 5px 0 0; font-size: 12px; line-height: 1.7; }
.aksrt-inv-dialog__close { display: inline-flex; flex: none; align-items: center; justify-content: center; width: 30px; height: 30px; padding: 0; color: var(--an-text-2); background: transparent; border: 0; border-radius: 6px; cursor: pointer; }
.aksrt-inv-dialog__close:hover { color: var(--an-text); background: var(--an-bg-soft); }
.aksrt-inv-dialog__body { min-height: 0; padding: 20px 24px 24px; overflow-y: auto; overscroll-behavior: contain; }
.aksrt-inv-dialog__foot { display: flex; flex: none; justify-content: flex-end; gap: 8px; padding: 16px 24px; border-top: 1px solid var(--an-border-soft); background: var(--an-card); }
.aksrt-inv-dialog .aksrt-native-form-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.aksrt-inv-dialog .aksrt-native-field { min-width: 0; }
.aksrt-inv-dialog .aksrt-native-field > input,
.aksrt-inv-dialog .aksrt-native-field > textarea { width: 100%; max-width: 100%; }
.aksrt-inv-dialog textarea { resize: vertical; }
.aksrt-inv-pane { min-width: 0; margin: 0; padding: 0; border: 0; }
.aksrt-inv-modes { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 6px; margin: 0 0 22px; padding: 4px; background: var(--an-bg-soft); border: 0; border-radius: var(--an-radius-sm); }
.aksrt-inv-modes label { position: relative; cursor: pointer; }
.aksrt-inv-modes input { position: absolute; width: 1px; height: 1px; margin: -1px; opacity: 0; clip-path: inset(50%); }
.aksrt-inv-modes span { display: block; padding: 9px 12px; border: 1px solid transparent; border-radius: 6px; text-align: center; }
.aksrt-inv-modes input:checked + span { color: var(--an-primary); background: var(--an-card); border-color: var(--an-primary); font-weight: 600; }
.aksrt-inv-modes input:focus-visible + span { outline: 2px solid var(--an-primary); outline-offset: 2px; }
.aksrt-inv-rewards { min-width: 0; margin: 22px 0; padding: 18px; border: 1px solid var(--an-border); border-radius: var(--an-radius-sm); }
.aksrt-inv-rewards > legend,
.aksrt-inv-options > legend { padding: 0 5px; color: var(--an-text); font-weight: 600; }
.aksrt-inv-hint { margin: -2px 0 14px; font-size: 12px; line-height: 1.7; }
.aksrt-inv-dialog .aksrt-inv-reward-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.aksrt-inv-vip { margin: 16px 0 0; padding: 0; border: 0; }
.aksrt-inv-vip legend { margin-bottom: 8px; padding: 0; font-weight: 600; }
.aksrt-inv-radios { display: flex; flex-wrap: wrap; gap: 12px 18px; }
.aksrt-inv-radios label { display: inline-flex; align-items: center; gap: 6px; cursor: pointer; }
.aksrt-inv-radios input { margin: 0; }
.aksrt-inv-vip-time { max-width: 200px; margin-top: 14px; }
.aksrt-inv-advanced { display: inline-flex; align-items: center; gap: 6px; cursor: pointer; }
.aksrt-inv-advanced input { margin: 0; }
.aksrt-inv-length { margin-top: 12px; }
.aksrt-inv-dialog .aksrt-inv-length input { max-width: 160px; }
.aksrt-inv-separator { margin-top: 16px; }
.aksrt-inv-dialog .aksrt-inv-separator input { max-width: 100px; }
.aksrt-inv-help { margin-top: 20px; padding-top: 14px; border-top: 1px solid var(--an-border-soft); line-height: 1.8; }
.aksrt-inv-help summary { color: var(--an-primary); cursor: pointer; }
.aksrt-inv-help p { font-size: 12px; }
.aksrt-inv-help pre { padding: 12px; overflow: auto; font-size: 12px; background: var(--an-bg-soft); border-radius: 6px; }
.aksrt-inv-options { min-width: 0; margin: 0 0 22px; padding: 0; border: 0; }
.aksrt-inv-options > legend { margin-bottom: 12px; padding: 0; }
.aksrt-inv-formats { display: grid; gap: 10px; }
.aksrt-inv-formats label { display: flex; align-items: flex-start; gap: 10px; padding: 13px 14px; border: 1px solid var(--an-border); border-radius: var(--an-radius-sm); cursor: pointer; }
.aksrt-inv-formats label:has(input:checked) { background: var(--an-primary-soft); border-color: var(--an-primary); }
.aksrt-inv-formats input { flex: none; margin: 3px 0 0; }
.aksrt-inv-formats strong { display: block; color: var(--an-text); font-weight: 600; }
.aksrt-inv-formats small { display: block; margin-top: 5px; font-size: 12px; line-height: 1.7; }
.aksrt-inv-page .aksrt-inv-export-note { margin: 20px 0 0; padding: 12px 14px; font-size: 12px; line-height: 1.8; }
.aksrt-inv-toast { position: fixed; z-index: 100100; top: 48px; left: 50%; max-width: calc(100vw - 48px); padding: 10px 18px; transform: translateX(-50%); color: #fff; background: #1f2329; border-radius: var(--an-radius-sm); box-shadow: var(--an-shadow); opacity: 0; pointer-events: none; }
.aksrt-inv-toast.is-visible { opacity: 1; }
html.jio-inv-modal-open { overflow: hidden; }
.jio-inv-dialog { width: min(680px, calc(100vw - 32px)); max-width: none; max-height: calc(100vh - 64px); max-height: calc(100dvh - 64px); margin: auto; padding: 0; overflow: hidden; color: var(--an-text-2); background: var(--an-card); border: 0; border-radius: var(--an-radius); box-shadow: 0 16px 64px rgba(15, 23, 42, .2); }
.jio-inv-dialog::backdrop { background: rgba(15, 23, 42, .45); }
#jio-inv-export { width: min(560px, calc(100vw - 32px)); }
.jio-inv-dialog__frame { display: flex; flex-direction: column; max-height: inherit; margin: 0; }
.jio-inv-dialog__head { display: flex; flex: none; align-items: flex-start; justify-content: space-between; gap: 16px; padding: 20px 24px 18px; border-bottom: 1px solid var(--an-border-soft); }
.jio-inv-dialog .jio-inv-dialog__head h2 { margin: 0; padding: 0; color: var(--an-text); font-size: 18px; font-weight: 600; line-height: 1.5; }
.jio-inv-dialog__head p { margin: 5px 0 0; font-size: 12px; line-height: 1.7; }
.jio-inv-dialog__close { display: inline-flex; flex: none; align-items: center; justify-content: center; width: 30px; height: 30px; padding: 0; color: var(--an-text-2); background: transparent; border: 0; border-radius: 6px; cursor: pointer; }
.jio-inv-dialog__close:hover { color: var(--an-text); background: var(--an-bg-soft); }
.jio-inv-dialog__body { min-height: 0; padding: 20px 24px 24px; overflow-y: auto; overscroll-behavior: contain; }
.jio-inv-dialog__foot { display: flex; flex: none; justify-content: flex-end; gap: 8px; padding: 16px 24px; border-top: 1px solid var(--an-border-soft); background: var(--an-card); }
.jio-inv-dialog .jio-native-form-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.jio-inv-dialog .jio-native-field { min-width: 0; }
.jio-inv-dialog .jio-native-field > input,
.jio-inv-dialog .jio-native-field > textarea { width: 100%; max-width: 100%; }
.jio-inv-dialog textarea { resize: vertical; }
.jio-inv-pane { min-width: 0; margin: 0; padding: 0; border: 0; }
.jio-inv-modes { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 6px; margin: 0 0 22px; padding: 4px; background: var(--an-bg-soft); border: 0; border-radius: var(--an-radius-sm); }
.jio-inv-modes label { position: relative; cursor: pointer; }
.jio-inv-modes input { position: absolute; width: 1px; height: 1px; margin: -1px; opacity: 0; clip-path: inset(50%); }
.jio-inv-modes span { display: block; padding: 9px 12px; border: 1px solid transparent; border-radius: 6px; text-align: center; }
.jio-inv-modes input:checked + span { color: var(--an-primary); background: var(--an-card); border-color: var(--an-primary); font-weight: 600; }
.jio-inv-modes input:focus-visible + span { outline: 2px solid var(--an-primary); outline-offset: 2px; }
.jio-inv-rewards { min-width: 0; margin: 22px 0; padding: 18px; border: 1px solid var(--an-border); border-radius: var(--an-radius-sm); }
.jio-inv-rewards > legend,
.jio-inv-options > legend { padding: 0 5px; color: var(--an-text); font-weight: 600; }
.jio-inv-hint { margin: -2px 0 14px; font-size: 12px; line-height: 1.7; }
.jio-inv-dialog .jio-inv-reward-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.jio-inv-vip { margin: 16px 0 0; padding: 0; border: 0; }
.jio-inv-vip legend { margin-bottom: 8px; padding: 0; font-weight: 600; }
.jio-inv-radios { display: flex; flex-wrap: wrap; gap: 12px 18px; }
.jio-inv-radios label { display: inline-flex; align-items: center; gap: 6px; cursor: pointer; }
.jio-inv-radios input { margin: 0; }
.jio-inv-vip-time { max-width: 200px; margin-top: 14px; }
.jio-inv-advanced { display: inline-flex; align-items: center; gap: 6px; cursor: pointer; }
.jio-inv-advanced input { margin: 0; }
.jio-inv-length { margin-top: 12px; }
.jio-inv-dialog .jio-inv-length input { max-width: 160px; }
.jio-inv-separator { margin-top: 16px; }
.jio-inv-dialog .jio-inv-separator input { max-width: 100px; }
.jio-inv-help { margin-top: 20px; padding-top: 14px; border-top: 1px solid var(--an-border-soft); line-height: 1.8; }
.jio-inv-help summary { color: var(--an-primary); cursor: pointer; }
.jio-inv-help p { font-size: 12px; }
.jio-inv-help pre { padding: 12px; overflow: auto; font-size: 12px; background: var(--an-bg-soft); border-radius: 6px; }
.jio-inv-options { min-width: 0; margin: 0 0 22px; padding: 0; border: 0; }
.jio-inv-options > legend { margin-bottom: 12px; padding: 0; }
.jio-inv-formats { display: grid; gap: 10px; }
.jio-inv-formats label { display: flex; align-items: flex-start; gap: 10px; padding: 13px 14px; border: 1px solid var(--an-border); border-radius: var(--an-radius-sm); cursor: pointer; }
.jio-inv-formats label:has(input:checked) { background: var(--an-primary-soft); border-color: var(--an-primary); }
.jio-inv-formats input { flex: none; margin: 3px 0 0; }
.jio-inv-formats strong { display: block; color: var(--an-text); font-weight: 600; }
.jio-inv-formats small { display: block; margin-top: 5px; font-size: 12px; line-height: 1.7; }
.jio-inv-page .jio-inv-export-note { margin: 20px 0 0; padding: 12px 14px; font-size: 12px; line-height: 1.8; }
.jio-inv-toast { position: fixed; z-index: 100100; top: 48px; left: 50%; max-width: calc(100vw - 48px); padding: 10px 18px; transform: translateX(-50%); color: #fff; background: #1f2329; border-radius: var(--an-radius-sm); box-shadow: var(--an-shadow); opacity: 0; pointer-events: none; }
.jio-inv-toast.is-visible { opacity: 1; }
@media (max-width: 600px) {
.aksrt-inv-page .aksrt-native-header__actions { width: 100%; }
.aksrt-inv-page .aksrt-native-header__actions .button { flex: 1; justify-content: center; }
.aksrt-inv-toolbar,
.aksrt-inv-bulk { padding-left: 14px; padding-right: 14px; }
.aksrt-inv-toolbar .aksrt-native-filters { width: 100%; }
.aksrt-inv-toolbar input[type="search"] { flex: 1 1 calc(100% - 76px); width: 0; min-width: 0; }
.aksrt-inv-dialog { max-height: calc(100dvh - 24px); }
.aksrt-inv-dialog__head,
.aksrt-inv-dialog__body,
.aksrt-inv-dialog__foot { padding-left: 16px; padding-right: 16px; }
.aksrt-inv-dialog .aksrt-native-form-grid { grid-template-columns: 1fr; }
.aksrt-inv-rewards { padding: 12px; }
.aksrt-inv-dialog .aksrt-inv-reward-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
.aksrt-inv-radios { gap: 12px; }
.aksrt-inv-dialog__foot .button { flex: 1; }
.jio-inv-page .jio-native-header__actions { width: 100%; }
.jio-inv-page .jio-native-header__actions .button { flex: 1; justify-content: center; }
.jio-inv-toolbar,
.jio-inv-bulk { padding-left: 14px; padding-right: 14px; }
.jio-inv-toolbar .jio-native-filters { width: 100%; }
.jio-inv-toolbar input[type="search"] { flex: 1 1 calc(100% - 76px); width: 0; min-width: 0; }
.jio-inv-dialog { max-height: calc(100dvh - 24px); }
.jio-inv-dialog__head,
.jio-inv-dialog__body,
.jio-inv-dialog__foot { padding-left: 16px; padding-right: 16px; }
.jio-inv-dialog .jio-native-form-grid { grid-template-columns: 1fr; }
.jio-inv-rewards { padding: 12px; }
.jio-inv-dialog .jio-inv-reward-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
.jio-inv-radios { gap: 12px; }
.jio-inv-dialog__foot .button { flex: 1; }
}
+90 -90
View File
@@ -1,42 +1,42 @@
/* 消息管理原生页。共享卡片 / 表单 / 筛选沿用 native-ui.css 的 --an-* 令牌。 */
.aksrt-messages-admin [hidden] { display: none; }
.aksrt-messages-admin__muted { color: var(--an-muted); }
.aksrt-messages-admin__sub { margin-top: 3px; color: var(--an-muted); font-size: 12px; }
.aksrt-messages-admin__sub code { padding: 0 4px; font-size: 12px; background: var(--an-bg-soft); }
.aksrt-messages-admin .aksrt-native-header__actions .button { display: inline-flex; align-items: center; gap: 4px; }
.aksrt-messages-admin .aksrt-native-header__actions .button .dashicons { margin: 0; line-height: 1; vertical-align: middle; }
.aksrt-messages-admin .aksrt-native-stat:focus-visible { outline: 2px solid var(--an-primary); outline-offset: 2px; }
.jio-messages-admin [hidden] { display: none; }
.jio-messages-admin__muted { color: var(--an-muted); }
.jio-messages-admin__sub { margin-top: 3px; color: var(--an-muted); font-size: 12px; }
.jio-messages-admin__sub code { padding: 0 4px; font-size: 12px; background: var(--an-bg-soft); }
.jio-messages-admin .jio-native-header__actions .button { display: inline-flex; align-items: center; gap: 4px; }
.jio-messages-admin .jio-native-header__actions .button .dashicons { margin: 0; line-height: 1; vertical-align: middle; }
.jio-messages-admin .jio-native-stat:focus-visible { outline: 2px solid var(--an-primary); outline-offset: 2px; }
/* ---- 列表内的筛选与批量工具栏 ---- */
.aksrt-messages-admin__toolbar { padding: 14px 20px; border-bottom: 1px solid var(--an-border-soft); }
.aksrt-messages-admin__toolbar .subsubsub { margin: 0 0 12px; }
.aksrt-messages-admin__toolbar .aksrt-native-filters { margin: 0; }
.aksrt-messages-admin__bulk { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; padding: 12px 20px; }
.aksrt-messages-admin__selection { margin-right: auto; color: var(--an-muted); font-size: 12px; font-variant-numeric: tabular-nums; }
.aksrt-messages-admin .button:disabled,
.aksrt-messages-admin .button:disabled:hover { color: var(--an-muted) !important; background: var(--an-bg-soft) !important; border-color: var(--an-border-soft) !important; cursor: not-allowed; }
.aksrt-messages-admin__danger.button { color: var(--an-danger); border-color: var(--an-danger); }
.aksrt-messages-admin__danger.button:hover,
.aksrt-messages-admin__danger.button:focus { color: #fff; background: var(--an-danger); border-color: var(--an-danger); }
.jio-messages-admin__toolbar { padding: 14px 20px; border-bottom: 1px solid var(--an-border-soft); }
.jio-messages-admin__toolbar .subsubsub { margin: 0 0 12px; }
.jio-messages-admin__toolbar .jio-native-filters { margin: 0; }
.jio-messages-admin__bulk { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; padding: 12px 20px; }
.jio-messages-admin__selection { margin-right: auto; color: var(--an-muted); font-size: 12px; font-variant-numeric: tabular-nums; }
.jio-messages-admin .button:disabled,
.jio-messages-admin .button:disabled:hover { color: var(--an-muted) !important; background: var(--an-bg-soft) !important; border-color: var(--an-border-soft) !important; cursor: not-allowed; }
.jio-messages-admin__danger.button { color: var(--an-danger); border-color: var(--an-danger); }
.jio-messages-admin__danger.button:hover,
.jio-messages-admin__danger.button:focus { color: #fff; background: var(--an-danger); border-color: var(--an-danger); }
.aksrt-messages-admin__table .column-title { width: 32%; }
.aksrt-messages-admin__table .column-type { width: 10%; }
.aksrt-messages-admin__table .column-user { width: 16%; }
.aksrt-messages-admin__table .column-read { width: 8%; }
.aksrt-messages-admin__table .column-time { width: 16%; }
.aksrt-messages-admin .aksrt-messages-admin__table .column-actions { width: 18%; padding-left: 20px; padding-right: 20px; text-align: center; }
.aksrt-messages-admin__table td { vertical-align: middle; }
.aksrt-messages-admin__table .row-title { font-weight: 600; word-break: break-word; line-height: 1.5; }
.aksrt-messages-admin__table tr.is-unread .row-title { font-weight: 700; }
.aksrt-messages-admin__table tr.is-unread > th:first-child { box-shadow: inset 3px 0 0 var(--an-primary); }
.aksrt-messages-admin__table tr.is-selected > td,
.aksrt-messages-admin__table tr.is-selected > th { background: var(--an-primary-soft); }
.aksrt-messages-admin__desc { margin-top: 3px; color: var(--an-text-2); word-break: break-word; }
.aksrt-msg-row-actions { display: flex; flex-wrap: wrap; justify-content: center; gap: 6px 12px; }
.aksrt-msg-row-actions button { padding: 0; font-size: 12px; text-decoration: none; white-space: nowrap; }
.jio-messages-admin__table .column-title { width: 32%; }
.jio-messages-admin__table .column-type { width: 10%; }
.jio-messages-admin__table .column-user { width: 16%; }
.jio-messages-admin__table .column-read { width: 8%; }
.jio-messages-admin__table .column-time { width: 16%; }
.jio-messages-admin .jio-messages-admin__table .column-actions { width: 18%; padding-left: 20px; padding-right: 20px; text-align: center; }
.jio-messages-admin__table td { vertical-align: middle; }
.jio-messages-admin__table .row-title { font-weight: 600; word-break: break-word; line-height: 1.5; }
.jio-messages-admin__table tr.is-unread .row-title { font-weight: 700; }
.jio-messages-admin__table tr.is-unread > th:first-child { box-shadow: inset 3px 0 0 var(--an-primary); }
.jio-messages-admin__table tr.is-selected > td,
.jio-messages-admin__table tr.is-selected > th { background: var(--an-primary-soft); }
.jio-messages-admin__desc { margin-top: 3px; color: var(--an-text-2); word-break: break-word; }
.jio-msg-row-actions { display: flex; flex-wrap: wrap; justify-content: center; gap: 6px 12px; }
.jio-msg-row-actions button { padding: 0; font-size: 12px; text-decoration: none; white-space: nowrap; }
/* 类型徽章(可点击筛选) */
.aksrt-msg-badge {
.jio-msg-badge {
display: inline-flex;
align-items: center;
padding: 2px 8px;
@@ -45,27 +45,27 @@
line-height: 18px;
white-space: nowrap;
text-decoration: none;
color: var(--aksrt-msg-tone, var(--an-muted));
background: color-mix(in srgb, var(--aksrt-msg-tone, var(--an-muted)) 12%, #fff);
border: 1px solid color-mix(in srgb, var(--aksrt-msg-tone, var(--an-muted)) 30%, #fff);
color: var(--jio-msg-tone, var(--an-muted));
background: color-mix(in srgb, var(--jio-msg-tone, var(--an-muted)) 12%, #fff);
border: 1px solid color-mix(in srgb, var(--jio-msg-tone, var(--an-muted)) 30%, #fff);
}
.aksrt-msg-badge:hover,
.aksrt-msg-badge:focus { color: var(--aksrt-msg-tone, var(--an-muted)); border-color: var(--aksrt-msg-tone, var(--an-muted)); }
.aksrt-msg-badge.is-info { --aksrt-msg-tone: var(--an-info); }
.aksrt-msg-badge.is-success { --aksrt-msg-tone: #00a32a; }
.aksrt-msg-badge.is-danger { --aksrt-msg-tone: var(--an-danger); }
.aksrt-msg-badge.is-social { --aksrt-msg-tone: #8c5bd0; }
.aksrt-msg-state { display: inline-flex; align-items: center; gap: 5px; font-size: 12px; white-space: nowrap; }
.aksrt-msg-state::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: currentColor; }
.aksrt-msg-state.is-unread { color: var(--an-primary); font-weight: 600; }
.aksrt-msg-state.is-read { color: var(--an-muted); }
.aksrt-msg-user { display: inline-flex; align-items: center; gap: 6px; max-width: 100%; min-width: 0; text-decoration: none; }
.aksrt-msg-user img { flex: none; border-radius: 50%; }
.aksrt-msg-user span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.jio-msg-badge:hover,
.jio-msg-badge:focus { color: var(--jio-msg-tone, var(--an-muted)); border-color: var(--jio-msg-tone, var(--an-muted)); }
.jio-msg-badge.is-info { --jio-msg-tone: var(--an-info); }
.jio-msg-badge.is-success { --jio-msg-tone: #00a32a; }
.jio-msg-badge.is-danger { --jio-msg-tone: var(--an-danger); }
.jio-msg-badge.is-social { --jio-msg-tone: #8c5bd0; }
.jio-msg-state { display: inline-flex; align-items: center; gap: 5px; font-size: 12px; white-space: nowrap; }
.jio-msg-state::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: currentColor; }
.jio-msg-state.is-unread { color: var(--an-primary); font-weight: 600; }
.jio-msg-state.is-read { color: var(--an-muted); }
.jio-msg-user { display: inline-flex; align-items: center; gap: 6px; max-width: 100%; min-width: 0; text-decoration: none; }
.jio-msg-user img { flex: none; border-radius: 50%; }
.jio-msg-user span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* ---- 发送 / 详情 / 二次确认共用弹窗 ---- */
html.aksrt-msg-modal-open { overflow: hidden; }
.aksrt-msg-dialog {
html.jio-msg-modal-open { overflow: hidden; }
.jio-msg-dialog {
width: min(640px, calc(100vw - 32px));
max-height: calc(100vh - 64px);
padding: 0;
@@ -76,10 +76,10 @@ html.aksrt-msg-modal-open { overflow: hidden; }
border-radius: var(--an-radius);
box-shadow: 0 12px 48px rgba(15, 23, 42, .18);
}
.aksrt-msg-dialog::backdrop { background: rgba(15, 23, 42, .45); }
.aksrt-msg-dialog--confirm { width: min(440px, calc(100vw - 32px)); }
.aksrt-msg-dialog__frame { display: flex; flex-direction: column; max-height: inherit; margin: 0; }
.aksrt-msg-dialog__head {
.jio-msg-dialog::backdrop { background: rgba(15, 23, 42, .45); }
.jio-msg-dialog--confirm { width: min(440px, calc(100vw - 32px)); }
.jio-msg-dialog__frame { display: flex; flex-direction: column; max-height: inherit; margin: 0; }
.jio-msg-dialog__head {
display: flex;
flex-shrink: 0;
align-items: center;
@@ -88,47 +88,47 @@ html.aksrt-msg-modal-open { overflow: hidden; }
padding: 16px 20px;
border-bottom: 1px solid var(--an-border-soft);
}
.aksrt-msg-dialog .aksrt-msg-dialog__title { display: flex; align-items: center; gap: 8px; margin: 0; color: var(--an-text); font-size: 16px; font-weight: 600; line-height: 1.4; }
.aksrt-msg-dialog__title .dashicons { flex-shrink: 0; color: var(--an-primary); }
.aksrt-msg-dialog__close { display: inline-flex; flex-shrink: 0; align-items: center; justify-content: center; width: 32px; height: 32px; padding: 0; color: var(--an-muted); background: transparent; border: 0; border-radius: var(--an-radius-sm); cursor: pointer; }
.aksrt-msg-dialog__close:hover,
.aksrt-msg-dialog__close:focus-visible { color: var(--an-text); background: var(--an-bg-soft); }
.aksrt-msg-dialog__body { min-height: 0; padding: 18px 20px; overflow-y: auto; overscroll-behavior: contain; }
.aksrt-msg-dialog__note { margin: 14px 0 0; font-size: 12px; }
.aksrt-msg-dialog__foot { display: flex; flex-shrink: 0; justify-content: flex-end; gap: 8px; padding: 14px 20px; border-top: 1px solid var(--an-border-soft); }
.aksrt-msg-dialog .aksrt-native-form-grid { grid-template-columns: repeat(auto-fit, minmax(min(100%, 240px), 1fr)); }
.aksrt-msg-dialog--confirm .aksrt-msg-dialog__body p { margin: 0; line-height: 1.8; }
.jio-msg-dialog .jio-msg-dialog__title { display: flex; align-items: center; gap: 8px; margin: 0; color: var(--an-text); font-size: 16px; font-weight: 600; line-height: 1.4; }
.jio-msg-dialog__title .dashicons { flex-shrink: 0; color: var(--an-primary); }
.jio-msg-dialog__close { display: inline-flex; flex-shrink: 0; align-items: center; justify-content: center; width: 32px; height: 32px; padding: 0; color: var(--an-muted); background: transparent; border: 0; border-radius: var(--an-radius-sm); cursor: pointer; }
.jio-msg-dialog__close:hover,
.jio-msg-dialog__close:focus-visible { color: var(--an-text); background: var(--an-bg-soft); }
.jio-msg-dialog__body { min-height: 0; padding: 18px 20px; overflow-y: auto; overscroll-behavior: contain; }
.jio-msg-dialog__note { margin: 14px 0 0; font-size: 12px; }
.jio-msg-dialog__foot { display: flex; flex-shrink: 0; justify-content: flex-end; gap: 8px; padding: 14px 20px; border-top: 1px solid var(--an-border-soft); }
.jio-msg-dialog .jio-native-form-grid { grid-template-columns: repeat(auto-fit, minmax(min(100%, 240px), 1fr)); }
.jio-msg-dialog--confirm .jio-msg-dialog__body p { margin: 0; line-height: 1.8; }
/* 分段单选:保留键盘语义,隐藏 WP 默认勾选标记。 */
.aksrt-msg-modes { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; margin: 0 0 16px; padding: 0; border: 0; }
.aksrt-msg-modes legend { margin-bottom: 8px; padding: 0; }
.aksrt-msg-mode { position: relative; cursor: pointer; }
.aksrt-msg-mode input[type="radio"] { position: absolute; width: 1px; height: 1px; min-width: 0; margin: -1px; padding: 0; overflow: hidden; clip-path: inset(50%); border: 0; opacity: 0; appearance: none; }
.aksrt-msg-mode > span { display: flex; align-items: center; justify-content: center; gap: 6px; padding: 10px; color: var(--an-text-2); border: 1px solid var(--an-border); border-radius: var(--an-radius-sm); }
.aksrt-msg-mode input:checked + span { color: var(--an-primary); background: var(--an-primary-soft); border-color: var(--an-primary); font-weight: 600; }
.aksrt-msg-mode:hover > span { border-color: var(--an-primary); }
.aksrt-msg-mode input:focus-visible + span { outline: 2px solid var(--an-primary); outline-offset: 2px; }
.aksrt-msg-counter { align-self: flex-end; color: var(--an-muted); font-size: 12px; font-variant-numeric: tabular-nums; }
.aksrt-msg-counter.is-over { color: var(--an-danger); font-weight: 600; }
.jio-msg-modes { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; margin: 0 0 16px; padding: 0; border: 0; }
.jio-msg-modes legend { margin-bottom: 8px; padding: 0; }
.jio-msg-mode { position: relative; cursor: pointer; }
.jio-msg-mode input[type="radio"] { position: absolute; width: 1px; height: 1px; min-width: 0; margin: -1px; padding: 0; overflow: hidden; clip-path: inset(50%); border: 0; opacity: 0; appearance: none; }
.jio-msg-mode > span { display: flex; align-items: center; justify-content: center; gap: 6px; padding: 10px; color: var(--an-text-2); border: 1px solid var(--an-border); border-radius: var(--an-radius-sm); }
.jio-msg-mode input:checked + span { color: var(--an-primary); background: var(--an-primary-soft); border-color: var(--an-primary); font-weight: 600; }
.jio-msg-mode:hover > span { border-color: var(--an-primary); }
.jio-msg-mode input:focus-visible + span { outline: 2px solid var(--an-primary); outline-offset: 2px; }
.jio-msg-counter { align-self: flex-end; color: var(--an-muted); font-size: 12px; font-variant-numeric: tabular-nums; }
.jio-msg-counter.is-over { color: var(--an-danger); font-weight: 600; }
/* 详情原样展示纯文本,保留换行,不插入消息中的 HTML。 */
.aksrt-msg-detail__title { margin: 0 0 16px; color: var(--an-text); font-size: 17px; line-height: 1.5; overflow-wrap: anywhere; }
.aksrt-msg-detail__meta { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; margin: 0; padding: 14px; background: var(--an-bg-soft); border-radius: var(--an-radius-sm); }
.aksrt-msg-detail__meta dt { color: var(--an-muted); font-size: 12px; }
.aksrt-msg-detail__meta dd { margin: 4px 0 0; overflow-wrap: anywhere; }
.aksrt-msg-detail__content { line-height: 1.8; white-space: pre-wrap; overflow-wrap: anywhere; }
.aksrt-msg-detail__link { display: block; margin-top: 16px; overflow-wrap: anywhere; }
.jio-msg-detail__title { margin: 0 0 16px; color: var(--an-text); font-size: 17px; line-height: 1.5; overflow-wrap: anywhere; }
.jio-msg-detail__meta { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; margin: 0; padding: 14px; background: var(--an-bg-soft); border-radius: var(--an-radius-sm); }
.jio-msg-detail__meta dt { color: var(--an-muted); font-size: 12px; }
.jio-msg-detail__meta dd { margin: 4px 0 0; overflow-wrap: anywhere; }
.jio-msg-detail__content { line-height: 1.8; white-space: pre-wrap; overflow-wrap: anywhere; }
.jio-msg-detail__link { display: block; margin-top: 16px; overflow-wrap: anywhere; }
@media (max-width: 782px) {
.aksrt-messages-admin__toolbar,
.aksrt-messages-admin__bulk { padding: 12px 14px; }
.aksrt-messages-admin__table .column-type,
.aksrt-messages-admin__table .column-read { display: none; }
.jio-messages-admin__toolbar,
.jio-messages-admin__bulk { padding: 12px 14px; }
.jio-messages-admin__table .column-type,
.jio-messages-admin__table .column-read { display: none; }
}
@media (max-width: 480px) {
.aksrt-msg-dialog { max-height: calc(100dvh - 32px); }
.aksrt-msg-dialog__head,
.aksrt-msg-dialog__body,
.aksrt-msg-dialog__foot { padding-left: 14px; padding-right: 14px; }
.aksrt-msg-detail__meta { grid-template-columns: 1fr; }
.jio-msg-dialog { max-height: calc(100dvh - 32px); }
.jio-msg-dialog__head,
.jio-msg-dialog__body,
.jio-msg-dialog__foot { padding-left: 14px; padding-right: 14px; }
.jio-msg-detail__meta { grid-template-columns: 1fr; }
}
+205 -205
View File
@@ -1,12 +1,12 @@
/*
* AKSRT 原生后台运营页共享 UI(支付中心 / 用户子菜单)。
* Jio 原生后台运营页共享 UI(支付中心 / 用户子菜单)。
*
* 只在 NativeUi::SLUGS 列出的页面入队,全部规则限定在 .aksrt-native 下,
* 只在 NativeUi::SLUGS 列出的页面入队,全部规则限定在 .jio-native 下,
* 不影响 WP 其它后台页。色板与圆角对齐 SPA 的 Naive UI 主题(App.vue)。
* 标记由 src/Admin/Native/NativeUi.php 输出。
*/
.aksrt-native {
.jio-native {
--an-primary: #18a058;
--an-primary-hover: #36ad6a;
--an-primary-soft: #e8f6ee;
@@ -31,7 +31,7 @@
}
/* ---------- 页头 ---------- */
.aksrt-native-header {
.jio-native-header {
display: flex;
flex-wrap: wrap;
align-items: center;
@@ -39,8 +39,8 @@
gap: 12px 16px;
margin: 18px 0 16px;
}
.aksrt-native-header__main { min-width: 0; }
.aksrt-native .aksrt-native-header__title {
.jio-native-header__main { min-width: 0; }
.jio-native .jio-native-header__title {
display: flex;
align-items: center;
gap: 10px;
@@ -51,7 +51,7 @@
font-weight: 600;
line-height: 1.3;
}
.aksrt-native-header__icon {
.jio-native-header__icon {
display: inline-flex;
align-items: center;
justify-content: center;
@@ -61,17 +61,17 @@
background: var(--an-primary-soft);
border-radius: 10px;
}
.aksrt-native-header__icon.dashicons:before { font-size: 20px; line-height: 36px; }
.aksrt-native-header__icon.dashicons { width: 36px; height: 36px; }
.aksrt-native-header__desc { margin: 6px 0 0; color: var(--an-muted); }
.aksrt-native-header__actions { display: flex; flex-wrap: wrap; gap: 8px; }
.jio-native-header__icon.dashicons:before { font-size: 20px; line-height: 36px; }
.jio-native-header__icon.dashicons { width: 36px; height: 36px; }
.jio-native-header__desc { margin: 6px 0 0; color: var(--an-muted); }
.jio-native-header__actions { display: flex; flex-wrap: wrap; gap: 8px; }
/* WP 把 .notice 挪到首个 h1/h2 后;保持与卡片同宽同圆角。 */
.aksrt-native .notice { margin: 0 0 16px; border-radius: var(--an-radius-sm); box-shadow: var(--an-shadow); }
.jio-native .notice { margin: 0 0 16px; border-radius: var(--an-radius-sm); box-shadow: var(--an-shadow); }
/* ---------- 标签导航(.subsubsub / .nav-tab-wrapper / .aksrt-native-tabs) ---------- */
.aksrt-native .subsubsub,
.aksrt-native-tabs {
/* ---------- 标签导航(.subsubsub / .nav-tab-wrapper / .jio-native-tabs) ---------- */
.jio-native .subsubsub,
.jio-native-tabs {
display: inline-flex;
flex-wrap: wrap;
float: none;
@@ -84,10 +84,10 @@
box-shadow: var(--an-shadow);
font-size: 13px;
}
.aksrt-native .subsubsub li { margin: 0; font-size: 0; }
.aksrt-native .subsubsub li > * { font-size: 13px; }
.aksrt-native .subsubsub a,
.aksrt-native-tabs a {
.jio-native .subsubsub li { margin: 0; font-size: 0; }
.jio-native .subsubsub li > * { font-size: 13px; }
.jio-native .subsubsub a,
.jio-native-tabs a {
display: inline-flex;
align-items: center;
gap: 6px;
@@ -98,17 +98,17 @@
line-height: 1.4;
transition: background .15s, color .15s;
}
.aksrt-native .subsubsub a:hover,
.aksrt-native-tabs a:hover { color: var(--an-primary); background: var(--an-bg-soft); }
.aksrt-native .subsubsub a.current,
.aksrt-native-tabs a.is-active,
.aksrt-native-tabs a[aria-current="page"] {
.jio-native .subsubsub a:hover,
.jio-native-tabs a:hover { color: var(--an-primary); background: var(--an-bg-soft); }
.jio-native .subsubsub a.current,
.jio-native-tabs a.is-active,
.jio-native-tabs a[aria-current="page"] {
color: var(--an-primary);
background: var(--an-primary-soft);
font-weight: 600;
}
.aksrt-native .subsubsub a .count,
.aksrt-native-tabs .count {
.jio-native .subsubsub a .count,
.jio-native-tabs .count {
padding: 0 6px;
color: inherit;
font-size: 12px;
@@ -116,14 +116,14 @@
background: rgba(0, 0, 0, .05);
border-radius: 999px;
}
.aksrt-native .nav-tab-wrapper {
.jio-native .nav-tab-wrapper {
display: flex;
gap: 4px;
margin: 0 0 16px;
padding: 0;
border-bottom: 1px solid var(--an-border);
}
.aksrt-native .nav-tab {
.jio-native .nav-tab {
margin: 0 0 -1px;
padding: 8px 14px;
color: var(--an-text-2);
@@ -132,21 +132,21 @@
border-bottom: 2px solid transparent;
font-weight: 500;
}
.aksrt-native .nav-tab:hover { color: var(--an-primary); background: transparent; }
.aksrt-native .nav-tab-active,
.aksrt-native .nav-tab-active:hover { color: var(--an-primary); border-bottom-color: var(--an-primary); background: transparent; }
.aksrt-native-toolbar { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px 12px; }
.aksrt-native-toolbar > .subsubsub,
.aksrt-native-toolbar > .aksrt-native-tabs { margin-bottom: 0; }
.jio-native .nav-tab:hover { color: var(--an-primary); background: transparent; }
.jio-native .nav-tab-active,
.jio-native .nav-tab-active:hover { color: var(--an-primary); border-bottom-color: var(--an-primary); background: transparent; }
.jio-native-toolbar { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px 12px; }
.jio-native-toolbar > .subsubsub,
.jio-native-toolbar > .jio-native-tabs { margin-bottom: 0; }
/* ---------- 统计卡 ---------- */
.aksrt-native-stats {
.jio-native-stats {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
gap: 12px;
margin: 0 0 16px;
}
.aksrt-native-stat {
.jio-native-stat {
--an-tone: var(--an-primary);
position: relative;
display: flex;
@@ -162,7 +162,7 @@
overflow: hidden;
transition: box-shadow .2s, transform .2s;
}
.aksrt-native-stat::after {
.jio-native-stat::after {
content: "";
position: absolute;
top: 0;
@@ -172,12 +172,12 @@
background: radial-gradient(circle at top right, color-mix(in srgb, var(--an-tone) 16%, transparent), transparent 70%);
pointer-events: none;
}
a.aksrt-native-stat:hover,
a.aksrt-native-stat:focus { color: var(--an-text-2); box-shadow: var(--an-shadow-hover); transform: translateY(-1px); }
a.aksrt-native-stat:focus { outline: 2px solid color-mix(in srgb, var(--an-tone) 40%, transparent); outline-offset: 1px; }
.aksrt-native-stat__label { display: flex; align-items: center; gap: 6px; color: var(--an-muted); font-size: 13px; }
.aksrt-native-stat__label .dashicons { width: 16px; height: 16px; color: var(--an-tone); font-size: 16px; }
.aksrt-native-stat__value {
a.jio-native-stat:hover,
a.jio-native-stat:focus { color: var(--an-text-2); box-shadow: var(--an-shadow-hover); transform: translateY(-1px); }
a.jio-native-stat:focus { outline: 2px solid color-mix(in srgb, var(--an-tone) 40%, transparent); outline-offset: 1px; }
.jio-native-stat__label { display: flex; align-items: center; gap: 6px; color: var(--an-muted); font-size: 13px; }
.jio-native-stat__label .dashicons { width: 16px; height: 16px; color: var(--an-tone); font-size: 16px; }
.jio-native-stat__value {
color: var(--an-text);
font-size: 26px;
font-weight: 600;
@@ -185,24 +185,24 @@ a.aksrt-native-stat:focus { outline: 2px solid color-mix(in srgb, var(--an-tone)
font-variant-numeric: tabular-nums;
word-break: break-all;
}
.aksrt-native-stat__unit { margin-right: 2px; color: var(--an-muted); font-size: 14px; font-weight: 400; }
.aksrt-native-stat__hint { color: var(--an-muted); font-size: 12px; }
.aksrt-native-stat--success { --an-tone: var(--an-primary); }
.aksrt-native-stat--info { --an-tone: var(--an-info); }
.aksrt-native-stat--warning { --an-tone: var(--an-warning); }
.aksrt-native-stat--danger { --an-tone: var(--an-danger); }
.aksrt-native-stat--neutral { --an-tone: var(--an-muted); }
.aksrt-native-stat--warning .aksrt-native-stat__value { color: #c27c0e; }
.aksrt-native-stat--danger .aksrt-native-stat__value { color: var(--an-danger); }
.jio-native-stat__unit { margin-right: 2px; color: var(--an-muted); font-size: 14px; font-weight: 400; }
.jio-native-stat__hint { color: var(--an-muted); font-size: 12px; }
.jio-native-stat--success { --an-tone: var(--an-primary); }
.jio-native-stat--info { --an-tone: var(--an-info); }
.jio-native-stat--warning { --an-tone: var(--an-warning); }
.jio-native-stat--danger { --an-tone: var(--an-danger); }
.jio-native-stat--neutral { --an-tone: var(--an-muted); }
.jio-native-stat--warning .jio-native-stat__value { color: #c27c0e; }
.jio-native-stat--danger .jio-native-stat__value { color: var(--an-danger); }
/* ---------- 卡片 ---------- */
.aksrt-native-card {
.jio-native-card {
margin: 0 0 16px;
background: var(--an-card);
border-radius: var(--an-radius);
box-shadow: var(--an-shadow);
}
.aksrt-native-card__head {
.jio-native-card__head {
display: flex;
flex-wrap: wrap;
align-items: center;
@@ -211,7 +211,7 @@ a.aksrt-native-stat:focus { outline: 2px solid color-mix(in srgb, var(--an-tone)
padding: 14px 20px;
border-bottom: 1px solid var(--an-border-soft);
}
.aksrt-native .aksrt-native-card__title {
.jio-native .jio-native-card__title {
position: relative;
margin: 0;
padding: 0 0 0 12px;
@@ -220,7 +220,7 @@ a.aksrt-native-stat:focus { outline: 2px solid color-mix(in srgb, var(--an-tone)
font-weight: 600;
line-height: 1.4;
}
.aksrt-native-card__title::before {
.jio-native-card__title::before {
content: "";
position: absolute;
top: 3px;
@@ -230,12 +230,12 @@ a.aksrt-native-stat:focus { outline: 2px solid color-mix(in srgb, var(--an-tone)
background: var(--an-primary);
border-radius: 4px;
}
.aksrt-native-card__actions { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.aksrt-native-card__body { padding: 16px 20px; }
.aksrt-native-card__body > :first-child { margin-top: 0; }
.aksrt-native-card__body > :last-child { margin-bottom: 0; }
.aksrt-native-card--flush > .aksrt-native-card__body { padding: 0; }
.aksrt-native-card__foot {
.jio-native-card__actions { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.jio-native-card__body { padding: 16px 20px; }
.jio-native-card__body > :first-child { margin-top: 0; }
.jio-native-card__body > :last-child { margin-bottom: 0; }
.jio-native-card--flush > .jio-native-card__body { padding: 0; }
.jio-native-card__foot {
display: flex;
flex-wrap: wrap;
align-items: center;
@@ -245,8 +245,8 @@ a.aksrt-native-stat:focus { outline: 2px solid color-mix(in srgb, var(--an-tone)
border-top: 1px solid var(--an-border-soft);
}
/* 折叠卡片:<details class="aksrt-native-card aksrt-native-collapse"><summary>… */
.aksrt-native-collapse > summary {
/* 折叠卡片:<details class="jio-native-card jio-native-collapse"><summary>… */
.jio-native-collapse > summary {
display: flex;
align-items: center;
gap: 8px;
@@ -257,75 +257,75 @@ a.aksrt-native-stat:focus { outline: 2px solid color-mix(in srgb, var(--an-tone)
cursor: pointer;
list-style: none;
}
.aksrt-native-collapse > summary::-webkit-details-marker { display: none; }
.aksrt-native-collapse > summary::after {
.jio-native-collapse > summary::-webkit-details-marker { display: none; }
.jio-native-collapse > summary::after {
content: "\f347";
margin-left: auto;
color: var(--an-muted);
font: normal 16px/1 dashicons;
transition: transform .2s;
}
.aksrt-native-collapse[open] > summary { border-bottom: 1px solid var(--an-border-soft); }
.aksrt-native-collapse[open] > summary::after { transform: rotate(180deg); }
.aksrt-native-collapse > summary .dashicons { color: var(--an-primary); }
.jio-native-collapse[open] > summary { border-bottom: 1px solid var(--an-border-soft); }
.jio-native-collapse[open] > summary::after { transform: rotate(180deg); }
.jio-native-collapse > summary .dashicons { color: var(--an-primary); }
/* ---------- 筛选栏 ---------- */
.aksrt-native-filters {
.jio-native-filters {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 8px;
margin: 0;
}
.aksrt-native-filters label { display: inline-flex; align-items: center; gap: 6px; color: var(--an-muted); }
.aksrt-native-filters input[type="search"] { min-width: 220px; }
.aksrt-native-filters__spacer { flex: 1 1 auto; }
.aksrt-native-card__body > .aksrt-native-filters + .aksrt-native-filters { margin-top: 10px; }
.jio-native-filters label { display: inline-flex; align-items: center; gap: 6px; color: var(--an-muted); }
.jio-native-filters input[type="search"] { min-width: 220px; }
.jio-native-filters__spacer { flex: 1 1 auto; }
.jio-native-card__body > .jio-native-filters + .jio-native-filters { margin-top: 10px; }
/* ---------- 表单 ---------- */
.aksrt-native input[type="text"],
.aksrt-native input[type="search"],
.aksrt-native input[type="number"],
.aksrt-native input[type="date"],
.aksrt-native input[type="datetime-local"],
.aksrt-native input[type="email"],
.aksrt-native input[type="url"],
.aksrt-native input[type="password"],
.aksrt-native select,
.aksrt-native textarea {
.jio-native input[type="text"],
.jio-native input[type="search"],
.jio-native input[type="number"],
.jio-native input[type="date"],
.jio-native input[type="datetime-local"],
.jio-native input[type="email"],
.jio-native input[type="url"],
.jio-native input[type="password"],
.jio-native select,
.jio-native textarea {
min-height: 32px;
border-color: var(--an-border);
border-radius: var(--an-radius-sm);
box-shadow: none;
}
.aksrt-native select { padding-right: 28px; }
.aksrt-native input:focus,
.aksrt-native select:focus,
.aksrt-native textarea:focus {
.jio-native select { padding-right: 28px; }
.jio-native input:focus,
.jio-native select:focus,
.jio-native textarea:focus {
border-color: var(--an-primary);
box-shadow: 0 0 0 2px color-mix(in srgb, var(--an-primary) 20%, transparent);
outline: 0;
}
.aksrt-native-form-grid {
.jio-native-form-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
gap: 14px 16px;
}
.aksrt-native-form-grid .is-wide { grid-column: 1 / -1; }
.aksrt-native-field { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.aksrt-native-field__label { color: var(--an-text); font-weight: 500; }
.aksrt-native-field__hint { color: var(--an-muted); font-size: 12px; }
.aksrt-native-field input,
.aksrt-native-field select,
.aksrt-native-field textarea { width: 100%; max-width: none; }
.aksrt-native-form-foot { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-top: 16px; }
.aksrt-native .form-table th { color: var(--an-text); font-weight: 500; }
.aksrt-native .form-table td,
.aksrt-native .form-table th { padding-top: 12px; padding-bottom: 12px; }
.jio-native-form-grid .is-wide { grid-column: 1 / -1; }
.jio-native-field { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.jio-native-field__label { color: var(--an-text); font-weight: 500; }
.jio-native-field__hint { color: var(--an-muted); font-size: 12px; }
.jio-native-field input,
.jio-native-field select,
.jio-native-field textarea { width: 100%; max-width: none; }
.jio-native-form-foot { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-top: 16px; }
.jio-native .form-table th { color: var(--an-text); font-weight: 500; }
.jio-native .form-table td,
.jio-native .form-table th { padding-top: 12px; padding-bottom: 12px; }
/* ---------- 按钮 ---------- */
.aksrt-native .button,
.aksrt-native .page-title-action {
.jio-native .button,
.jio-native .page-title-action {
min-height: 32px;
padding: 0 14px;
color: var(--an-text-2);
@@ -335,42 +335,42 @@ a.aksrt-native-stat:focus { outline: 2px solid color-mix(in srgb, var(--an-tone)
border-radius: var(--an-radius-sm);
transition: border-color .15s, color .15s, background .15s;
}
.aksrt-native .page-title-action { top: 0; display: inline-flex; align-items: center; }
.aksrt-native .button:hover,
.aksrt-native .button:focus,
.aksrt-native .page-title-action:hover {
.jio-native .page-title-action { top: 0; display: inline-flex; align-items: center; }
.jio-native .button:hover,
.jio-native .button:focus,
.jio-native .page-title-action:hover {
color: var(--an-primary);
background: #fff;
border-color: var(--an-primary);
box-shadow: none;
}
.aksrt-native .button-primary,
.aksrt-native .button.button-primary {
.jio-native .button-primary,
.jio-native .button.button-primary {
color: #fff;
background: var(--an-primary);
border-color: var(--an-primary);
}
.aksrt-native .button-primary:hover,
.aksrt-native .button-primary:focus,
.aksrt-native .button.button-primary:hover {
.jio-native .button-primary:hover,
.jio-native .button-primary:focus,
.jio-native .button.button-primary:hover {
color: #fff;
background: var(--an-primary-hover);
border-color: var(--an-primary-hover);
}
.aksrt-native .button-small,
.aksrt-native .button.button-small { min-height: 26px; padding: 0 10px; font-size: 12px; line-height: 24px; }
.aksrt-native .button-link-delete,
.aksrt-native .button.is-danger { color: var(--an-danger); }
.aksrt-native .button.is-danger:hover { color: #fff; background: var(--an-danger); border-color: var(--an-danger); }
.aksrt-native .button .dashicons { width: 16px; height: 16px; margin: 0 4px 0 -2px; font-size: 16px; line-height: inherit; vertical-align: -1px; }
.aksrt-native .submit { margin: 0; padding: 0; }
.jio-native .button-small,
.jio-native .button.button-small { min-height: 26px; padding: 0 10px; font-size: 12px; line-height: 24px; }
.jio-native .button-link-delete,
.jio-native .button.is-danger { color: var(--an-danger); }
.jio-native .button.is-danger:hover { color: #fff; background: var(--an-danger); border-color: var(--an-danger); }
.jio-native .button .dashicons { width: 16px; height: 16px; margin: 0 4px 0 -2px; font-size: 16px; line-height: inherit; vertical-align: -1px; }
.jio-native .submit { margin: 0; padding: 0; }
/* 批量操作行:下拉与「应用」按钮锁定同一高度与字号。
WP 核心给 select 14px/line-height:2、给 .button 13px,且 782px 以下再把两者各自放大,
只设 min-height 时两者会因字号、行高和基线对齐不同而错位,这里显式给定。 */
.aksrt-native-bulk { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.aksrt-native-bulk select,
.aksrt-native-bulk .button {
.jio-native-bulk { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.jio-native-bulk select,
.jio-native-bulk .button {
box-sizing: border-box;
height: 32px;
min-height: 32px;
@@ -379,21 +379,21 @@ a.aksrt-native-stat:focus { outline: 2px solid color-mix(in srgb, var(--an-tone)
line-height: 30px;
vertical-align: middle;
}
.aksrt-native-bulk select { width: auto; max-width: 12.5rem; }
.jio-native-bulk select { width: auto; max-width: 12.5rem; }
/* ---------- 表格 ---------- */
.aksrt-native-table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.aksrt-native .widefat,
.aksrt-native .wp-list-table {
.jio-native-table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.jio-native .widefat,
.jio-native .wp-list-table {
border: 0;
border-radius: 0;
box-shadow: none;
}
.aksrt-native .aksrt-native-card .widefat { background: transparent; }
.aksrt-native .widefat thead th,
.aksrt-native .widefat thead td,
.aksrt-native .widefat tfoot th,
.aksrt-native .widefat tfoot td {
.jio-native .jio-native-card .widefat { background: transparent; }
.jio-native .widefat thead th,
.jio-native .widefat thead td,
.jio-native .widefat tfoot th,
.jio-native .widefat tfoot td {
padding: 10px 12px;
color: var(--an-muted);
font-size: 12px;
@@ -401,24 +401,24 @@ a.aksrt-native-stat:focus { outline: 2px solid color-mix(in srgb, var(--an-tone)
background: var(--an-bg-soft);
border-bottom: 1px solid var(--an-border-soft);
}
.aksrt-native .widefat thead th a { color: var(--an-muted); }
.aksrt-native .widefat td,
.aksrt-native .widefat tbody th {
.jio-native .widefat thead th a { color: var(--an-muted); }
.jio-native .widefat td,
.jio-native .widefat tbody th {
padding: 12px;
color: var(--an-text-2);
vertical-align: middle;
border-bottom: 1px solid var(--an-border-soft);
}
.aksrt-native .widefat tbody tr:last-child > td,
.aksrt-native .widefat tbody tr:last-child > th { border-bottom: 0; }
.aksrt-native .striped > tbody > :nth-child(odd) { background: transparent; }
.aksrt-native .widefat tbody tr { transition: background .15s; }
.aksrt-native .widefat tbody tr:hover { background: #fafbfc; }
.aksrt-native .widefat .check-column { width: 2.4em; padding: 12px 0 12px 12px; vertical-align: middle; }
.aksrt-native .widefat thead .check-column { padding-top: 10px; padding-bottom: 10px; }
.aksrt-native .widefat .check-column input { margin: 0; }
.aksrt-native .widefat code,
.aksrt-native-mono {
.jio-native .widefat tbody tr:last-child > td,
.jio-native .widefat tbody tr:last-child > th { border-bottom: 0; }
.jio-native .striped > tbody > :nth-child(odd) { background: transparent; }
.jio-native .widefat tbody tr { transition: background .15s; }
.jio-native .widefat tbody tr:hover { background: #fafbfc; }
.jio-native .widefat .check-column { width: 2.4em; padding: 12px 0 12px 12px; vertical-align: middle; }
.jio-native .widefat thead .check-column { padding-top: 10px; padding-bottom: 10px; }
.jio-native .widefat .check-column input { margin: 0; }
.jio-native .widefat code,
.jio-native-mono {
padding: 1px 6px;
color: var(--an-text);
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
@@ -426,36 +426,36 @@ a.aksrt-native-stat:focus { outline: 2px solid color-mix(in srgb, var(--an-tone)
background: var(--an-bg-soft);
border-radius: 4px;
}
.aksrt-native .row-actions { color: var(--an-muted); }
.aksrt-native .row-title,
.aksrt-native .widefat strong { color: var(--an-text); }
.aksrt-native-card > .aksrt-native-card__body > .widefat:first-child thead th:first-child,
.aksrt-native-card--flush .widefat thead > tr > :first-child { padding-left: 20px; }
.aksrt-native-card--flush .widefat tbody > tr > :first-child { padding-left: 20px; }
.aksrt-native-card--flush .widefat thead > tr > :last-child,
.aksrt-native-card--flush .widefat tbody > tr > :last-child { padding-right: 20px; }
.aksrt-native-card--flush .widefat thead th:first-child,
.aksrt-native-card--flush .widefat thead td:first-child { border-top-left-radius: 0; }
.jio-native .row-actions { color: var(--an-muted); }
.jio-native .row-title,
.jio-native .widefat strong { color: var(--an-text); }
.jio-native-card > .jio-native-card__body > .widefat:first-child thead th:first-child,
.jio-native-card--flush .widefat thead > tr > :first-child { padding-left: 20px; }
.jio-native-card--flush .widefat tbody > tr > :first-child { padding-left: 20px; }
.jio-native-card--flush .widefat thead > tr > :last-child,
.jio-native-card--flush .widefat tbody > tr > :last-child { padding-right: 20px; }
.jio-native-card--flush .widefat thead th:first-child,
.jio-native-card--flush .widefat thead td:first-child { border-top-left-radius: 0; }
/* 行内操作表单:单元格里的一组小控件 */
.aksrt-native-inline {
.jio-native-inline {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 6px;
margin: 0;
}
.aksrt-native-inline + .aksrt-native-inline { margin-top: 6px; }
.aksrt-native-inline input[type="text"] { min-width: 0; width: 140px; }
.jio-native-inline + .jio-native-inline { margin-top: 6px; }
.jio-native-inline input[type="text"] { min-width: 0; width: 140px; }
/* 用户单元格:头像 + 名称 + 次要信息 */
.aksrt-native-user { display: inline-flex; align-items: center; gap: 8px; min-width: 0; color: var(--an-text); text-decoration: none; }
.aksrt-native-user img { flex: none; border-radius: 50%; }
.aksrt-native-user__name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.aksrt-native-user__meta { display: block; color: var(--an-muted); font-size: 12px; }
.jio-native-user { display: inline-flex; align-items: center; gap: 8px; min-width: 0; color: var(--an-text); text-decoration: none; }
.jio-native-user img { flex: none; border-radius: 50%; }
.jio-native-user__name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.jio-native-user__meta { display: block; color: var(--an-muted); font-size: 12px; }
/* ---------- 徽标 ---------- */
.aksrt-native-badge {
.jio-native-badge {
--an-tone: var(--an-muted);
display: inline-flex;
align-items: center;
@@ -469,22 +469,22 @@ a.aksrt-native-stat:focus { outline: 2px solid color-mix(in srgb, var(--an-tone)
background: color-mix(in srgb, var(--an-tone) 10%, #fff);
border-radius: 999px;
}
.aksrt-native-badge.has-dot::before {
.jio-native-badge.has-dot::before {
content: "";
width: 6px;
height: 6px;
background: currentColor;
border-radius: 50%;
}
.aksrt-native-badge--success { --an-tone: var(--an-primary); }
.aksrt-native-badge--info { --an-tone: var(--an-info); }
.aksrt-native-badge--warning { --an-tone: #c27c0e; }
.aksrt-native-badge--danger { --an-tone: var(--an-danger); }
.aksrt-native-badge--neutral { --an-tone: #6b7785; }
.aksrt-native-badge--primary { --an-tone: #7c4dff; }
.jio-native-badge--success { --an-tone: var(--an-primary); }
.jio-native-badge--info { --an-tone: var(--an-info); }
.jio-native-badge--warning { --an-tone: #c27c0e; }
.jio-native-badge--danger { --an-tone: var(--an-danger); }
.jio-native-badge--neutral { --an-tone: #6b7785; }
.jio-native-badge--primary { --an-tone: #7c4dff; }
/* ---------- 空状态 / 提示 ---------- */
.aksrt-native-empty {
.jio-native-empty {
display: flex;
flex-direction: column;
align-items: center;
@@ -493,19 +493,19 @@ a.aksrt-native-stat:focus { outline: 2px solid color-mix(in srgb, var(--an-tone)
color: var(--an-muted);
text-align: center;
}
.aksrt-native-empty .dashicons { width: 40px; height: 40px; color: #c9cdd4; font-size: 40px; }
.aksrt-native-empty__title { color: var(--an-text-2); font-size: 14px; font-weight: 500; }
.aksrt-native .widefat td.aksrt-native-empty-cell { padding: 0; }
.aksrt-native-muted,
.aksrt-native .description { color: var(--an-muted); }
.aksrt-native-text--success { color: var(--an-primary); }
.aksrt-native-text--info { color: var(--an-info); }
.aksrt-native-text--warning { color: #c27c0e; }
.aksrt-native-text--danger { color: var(--an-danger); }
.aksrt-native-amount { color: var(--an-text); font-weight: 600; font-variant-numeric: tabular-nums; }
.aksrt-native-amount.is-positive { color: var(--an-primary); }
.aksrt-native-amount.is-negative { color: var(--an-danger); }
.aksrt-native-callout {
.jio-native-empty .dashicons { width: 40px; height: 40px; color: #c9cdd4; font-size: 40px; }
.jio-native-empty__title { color: var(--an-text-2); font-size: 14px; font-weight: 500; }
.jio-native .widefat td.jio-native-empty-cell { padding: 0; }
.jio-native-muted,
.jio-native .description { color: var(--an-muted); }
.jio-native-text--success { color: var(--an-primary); }
.jio-native-text--info { color: var(--an-info); }
.jio-native-text--warning { color: #c27c0e; }
.jio-native-text--danger { color: var(--an-danger); }
.jio-native-amount { color: var(--an-text); font-weight: 600; font-variant-numeric: tabular-nums; }
.jio-native-amount.is-positive { color: var(--an-primary); }
.jio-native-amount.is-negative { color: var(--an-danger); }
.jio-native-callout {
margin: 0 0 16px;
padding: 12px 16px;
color: var(--an-text-2);
@@ -513,43 +513,43 @@ a.aksrt-native-stat:focus { outline: 2px solid color-mix(in srgb, var(--an-tone)
border-left: 3px solid var(--an-info);
border-radius: var(--an-radius-sm);
}
.aksrt-native-callout.is-warning { background: #fff8eb; border-left-color: var(--an-warning); }
.aksrt-native-callout.is-danger { background: #fdf0f2; border-left-color: var(--an-danger); }
.jio-native-callout.is-warning { background: #fff8eb; border-left-color: var(--an-warning); }
.jio-native-callout.is-danger { background: #fdf0f2; border-left-color: var(--an-danger); }
/* ---------- 分页条(AdminListPagination / paginate_links) ---------- */
.aksrt-native .tablenav { height: auto; margin: 0; padding: 12px 20px; }
.aksrt-native .aksrt-native-card .tablenav.bottom { border-top: 1px solid var(--an-border-soft); }
.aksrt-native .tablenav-pages { float: right; margin: 0; color: var(--an-muted); }
.aksrt-native .tablenav-pages .button,
.aksrt-native .tablenav-pages .page-numbers {
.jio-native .tablenav { height: auto; margin: 0; padding: 12px 20px; }
.jio-native .jio-native-card .tablenav.bottom { border-top: 1px solid var(--an-border-soft); }
.jio-native .tablenav-pages { float: right; margin: 0; color: var(--an-muted); }
.jio-native .tablenav-pages .button,
.jio-native .tablenav-pages .page-numbers {
min-width: 30px;
min-height: 30px;
padding: 0 8px;
line-height: 28px;
text-align: center;
}
.aksrt-native .tablenav-pages .page-numbers {
.jio-native .tablenav-pages .page-numbers {
display: inline-block;
color: var(--an-text-2);
border: 1px solid var(--an-border);
border-radius: var(--an-radius-sm);
text-decoration: none;
}
.aksrt-native .tablenav-pages .page-numbers.current { color: #fff; background: var(--an-primary); border-color: var(--an-primary); }
.aksrt-native .tablenav-pages .page-numbers.dots { border-color: transparent; }
.aksrt-native .tablenav-pages .button.disabled { color: #c9cdd4 !important; background: var(--an-bg-soft) !important; border-color: var(--an-border-soft) !important; }
.aksrt-native .tablenav .actions { padding: 0; }
.aksrt-native .tablenav::after { content: ""; display: table; clear: both; }
.jio-native .tablenav-pages .page-numbers.current { color: #fff; background: var(--an-primary); border-color: var(--an-primary); }
.jio-native .tablenav-pages .page-numbers.dots { border-color: transparent; }
.jio-native .tablenav-pages .button.disabled { color: #c9cdd4 !important; background: var(--an-bg-soft) !important; border-color: var(--an-border-soft) !important; }
.jio-native .tablenav .actions { padding: 0; }
.jio-native .tablenav::after { content: ""; display: table; clear: both; }
@media (max-width: 782px) {
.aksrt-native { margin-right: 10px; }
.aksrt-native-stats { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
.aksrt-native-stat { padding: 12px 14px; }
.aksrt-native-stat__value { font-size: 20px; }
.aksrt-native-card__head,
.aksrt-native-card__body,
.aksrt-native-collapse > summary { padding-left: 14px; padding-right: 14px; }
.aksrt-native .tablenav { padding: 10px 14px; }
.aksrt-native .tablenav-pages { float: none; }
.aksrt-native-filters input[type="search"] { min-width: 0; flex: 1 1 100%; }
.jio-native { margin-right: 10px; }
.jio-native-stats { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
.jio-native-stat { padding: 12px 14px; }
.jio-native-stat__value { font-size: 20px; }
.jio-native-card__head,
.jio-native-card__body,
.jio-native-collapse > summary { padding-left: 14px; padding-right: 14px; }
.jio-native .tablenav { padding: 10px 14px; }
.jio-native .tablenav-pages { float: none; }
.jio-native-filters input[type="search"] { min-width: 0; flex: 1 1 100%; }
}
Loaded 100 of 997 files, more files were not shown because too many files have changed in this diff. Show more