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>
186 lines
6.0 KiB
Vue
186 lines
6.0 KiB
Vue
<template>
|
||
<div class="jio-page-container content-page">
|
||
<PageHeader title="右侧悬浮按钮" desc="显示在页面右侧的悬浮按钮,支持排序及添加自定义按钮。" />
|
||
|
||
<n-spin :show="loading" style="width: 100%; min-height: 200px;">
|
||
<n-alert type="warning" :bordered="false" class="float-settings__notice">
|
||
<b>全局悬浮按钮:</b>显示在页面右侧的悬浮按钮,支持排序及添加自定义按钮
|
||
</n-alert>
|
||
|
||
<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>
|
||
<n-radio value="round">圆角按钮</n-radio>
|
||
<n-radio value="square">方形按钮</n-radio>
|
||
</n-space>
|
||
</n-radio-group>
|
||
</n-form-item>
|
||
<n-form-item label="显示位置">
|
||
<n-radio-group v-model:value="form.position">
|
||
<n-space>
|
||
<n-radio value="center">右侧居中</n-radio>
|
||
<n-radio value="bottom">右侧底部</n-radio>
|
||
</n-space>
|
||
</n-radio-group>
|
||
</n-form-item>
|
||
<n-form-item label="背景高斯模糊">
|
||
<div class="float-settings__block">
|
||
<n-checkbox-group v-model:value="form.filter_blur">
|
||
<n-space>
|
||
<n-checkbox value="pc_s">PC端开启</n-checkbox>
|
||
<n-checkbox value="m_s">移动端开启</n-checkbox>
|
||
</n-space>
|
||
</n-checkbox-group>
|
||
<div class="float-settings__desc">开启后如果按钮过多会影响浏览器性能,部分性能较低的设备会不流畅</div>
|
||
</div>
|
||
</n-form-item>
|
||
<n-form-item label="页面滚动时隐藏">
|
||
<n-switch v-model:value="form.scroll_hide" />
|
||
<span class="float-settings__label">滚动过程中隐藏</span>
|
||
</n-form-item>
|
||
<n-form-item label="页面向下滚动时隐藏">
|
||
<n-switch v-model:value="form.scroll_down_hide" />
|
||
<span class="float-settings__label">下滚动隐藏,上滚动显示</span>
|
||
</n-form-item>
|
||
</n-form>
|
||
|
||
<div class="float-settings__section">
|
||
<div class="float-settings__section-title">悬浮按钮</div>
|
||
<div class="float-settings__desc">设置并排序需要显示的按钮</div>
|
||
<draggable
|
||
v-model="form.items"
|
||
v-bind="SORTABLE_LIST_ATTRS"
|
||
item-key="type"
|
||
class="jio-sortable"
|
||
>
|
||
<template #item="{ element, index }">
|
||
<FloatBtnItemPanel :model-value="element" @update:model-value="updateItem(index, $event)" />
|
||
</template>
|
||
</draggable>
|
||
</div>
|
||
</n-card>
|
||
</n-spin>
|
||
|
||
<JioSaveBar :dirty="dirty" :saving="saving" @save="handleSave" @reload="loadSettings" />
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { computed, onMounted, reactive, ref } from 'vue'
|
||
import { useMessage } from 'naive-ui'
|
||
import draggable from 'vuedraggable'
|
||
import api from '@/api'
|
||
import PageHeader from '@/components/PageHeader.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'
|
||
|
||
const message = useMessage()
|
||
const loading = ref(true)
|
||
const saving = ref(false)
|
||
const form = reactive(defaultSettings())
|
||
|
||
// 与全局保存栏一致:仅在有未保存更改时显示。以最近一次加载/保存的快照为基准。
|
||
const snapshot = ref('')
|
||
const serialize = () => JSON.stringify(form)
|
||
const dirty = computed(() => !loading.value && snapshot.value !== '' && serialize() !== snapshot.value)
|
||
function markClean() {
|
||
snapshot.value = serialize()
|
||
}
|
||
|
||
function updateItem(index, value) {
|
||
form.items.splice(index, 1, value)
|
||
}
|
||
|
||
function applySettings(data) {
|
||
const defaults = defaultSettings()
|
||
form.style = data?.style || defaults.style
|
||
form.position = data?.position || defaults.position
|
||
form.filter_blur = Array.isArray(data?.filter_blur) ? data.filter_blur : defaults.filter_blur
|
||
form.scroll_hide = !!data?.scroll_hide
|
||
form.scroll_down_hide = data ? !!data.scroll_down_hide : defaults.scroll_down_hide
|
||
form.items = normalizeItems(data?.items)
|
||
}
|
||
|
||
async function loadSettings() {
|
||
loading.value = true
|
||
try {
|
||
const res = await api.getFloatingButtons()
|
||
if (res.code === 'success') applySettings(res.data)
|
||
markClean()
|
||
} catch (error) {
|
||
console.error('[FloatingButtons] load failed:', error)
|
||
message.error('加载配置失败')
|
||
} finally {
|
||
loading.value = false
|
||
}
|
||
}
|
||
|
||
async function handleSave() {
|
||
saving.value = true
|
||
try {
|
||
const res = await api.saveFloatingButtons({
|
||
style: form.style,
|
||
position: form.position,
|
||
filter_blur: form.filter_blur,
|
||
scroll_hide: form.scroll_hide,
|
||
scroll_down_hide: form.scroll_down_hide,
|
||
items: form.items,
|
||
})
|
||
if (res.code === 'success') {
|
||
if (res.data) applySettings(res.data)
|
||
markClean()
|
||
message.success(res.message || '保存成功')
|
||
} else {
|
||
message.error(res.message || '保存失败')
|
||
}
|
||
} catch (error) {
|
||
console.error('[FloatingButtons] save failed:', error)
|
||
message.error('保存失败')
|
||
} finally {
|
||
saving.value = false
|
||
}
|
||
}
|
||
|
||
onMounted(loadSettings)
|
||
</script>
|
||
|
||
<style scoped>
|
||
.float-settings__notice {
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
.float-settings__block {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 8px;
|
||
width: 100%;
|
||
}
|
||
|
||
.float-settings__desc {
|
||
font-size: 12px;
|
||
color: var(--jio-color-muted, #6F7A72);
|
||
}
|
||
|
||
.float-settings__label {
|
||
margin-left: 12px;
|
||
font-size: 13px;
|
||
color: var(--jio-color-muted, #6F7A72);
|
||
}
|
||
|
||
.float-settings__section {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 8px;
|
||
margin-top: 8px;
|
||
}
|
||
|
||
.float-settings__section-title {
|
||
font-weight: 600;
|
||
font-size: 14px;
|
||
}
|
||
</style>
|