去掉多语言
This commit is contained in:
parent
0788ddfb8a
commit
02cbe30117
@ -23,14 +23,14 @@ async function initSetupVbenForm() {
|
||||
},
|
||||
},
|
||||
defineRules: {
|
||||
// 输入项目必填国际化适配
|
||||
// 输入项目必填提示
|
||||
required: (value, _params, ctx) => {
|
||||
if (value === undefined || value === null || value.length === 0) {
|
||||
return $t('ui.formRules.required', [ctx.label]);
|
||||
}
|
||||
return true;
|
||||
},
|
||||
// 选择项目必填国际化适配
|
||||
// 选择项目必填提示
|
||||
selectRequired: (value, _params, ctx) => {
|
||||
if (value === undefined || value === null) {
|
||||
return $t('ui.formRules.selectRequired', [ctx.label]);
|
||||
|
||||
@ -145,12 +145,6 @@ export async function approveReportedNotPass(data: Record<string, any>[]) {
|
||||
return requestClient.post('/approval/reported/not/pass', data);
|
||||
}
|
||||
|
||||
export async function getDynamicReportPage(params: Record<string, any>) {
|
||||
return requestClient.get<LegacyPageResult>('/dynamic/report/page', {
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
export async function pageUserIntegralOriginStream(
|
||||
params: Record<string, any>,
|
||||
) {
|
||||
@ -162,26 +156,6 @@ export async function pageUserIntegralOriginStream(
|
||||
);
|
||||
}
|
||||
|
||||
export async function processDynamicReport(data: Record<string, any>) {
|
||||
return requestClient.post('/dynamic/report', data);
|
||||
}
|
||||
|
||||
export async function getDynamicContentPage(params: Record<string, any>) {
|
||||
return requestClient.get<LegacyPageResult>('/approval/dynamic/content/page', {
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
export async function approveDynamicContentPass(data: Array<number | string>) {
|
||||
return requestClient.post('/approval/dynamic/content/pass', data);
|
||||
}
|
||||
|
||||
export async function approveDynamicContentNotPass(
|
||||
data: Array<number | string>,
|
||||
) {
|
||||
return requestClient.post('/approval/dynamic/content/not/pass', data);
|
||||
}
|
||||
|
||||
export async function getViolationHistoryPage(params: Record<string, any>) {
|
||||
return requestClient.get<LegacyPageResult>('/approval/history/page', {
|
||||
params,
|
||||
|
||||
@ -1,65 +0,0 @@
|
||||
import { requestClient } from '#/api/request';
|
||||
|
||||
export interface LegacyPageResult<T = Record<string, any>> {
|
||||
records: T[];
|
||||
total: number;
|
||||
}
|
||||
|
||||
export async function dynamicBlacklistPage(params: Record<string, any>) {
|
||||
return requestClient.get<LegacyPageResult<Record<string, any>>>(
|
||||
'/dynamic/blacklist/page',
|
||||
{
|
||||
params,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
export async function addDynamicBlacklist(data: Record<string, any>) {
|
||||
return requestClient.post('/dynamic/blacklist/add', data);
|
||||
}
|
||||
|
||||
export async function deleteDynamicBlacklist(userId: number | string) {
|
||||
return requestClient.get(`/dynamic/blacklist/delete/${userId}`);
|
||||
}
|
||||
|
||||
export async function dynamicTagTable(params: Record<string, any>) {
|
||||
return requestClient.get<LegacyPageResult<Record<string, any>>>(
|
||||
'/dynamic/tag/page',
|
||||
{
|
||||
params,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
export async function saveDynamicTag(data: Record<string, any>) {
|
||||
return requestClient.post('/dynamic/tag/add-or-update', data);
|
||||
}
|
||||
|
||||
export async function getDynamicPopularConfig() {
|
||||
return requestClient.get<Record<string, any>>('/dynamic/popular/config');
|
||||
}
|
||||
|
||||
export async function saveDynamicPopularConfig(data: Record<string, any>) {
|
||||
return requestClient.post('/dynamic/popular/config', data);
|
||||
}
|
||||
|
||||
export async function userDynamicTable(params: Record<string, any>) {
|
||||
return requestClient.get<LegacyPageResult<Record<string, any>>>(
|
||||
'/user/dynamic/page',
|
||||
{
|
||||
params,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
export async function deleteUserDynamic(data: Array<number | string>) {
|
||||
return requestClient.post('/user/dynamic/delete', data);
|
||||
}
|
||||
|
||||
export async function setUserDynamicTop(data: Record<string, any>) {
|
||||
return requestClient.post('/user/dynamic/setUpTop', data);
|
||||
}
|
||||
|
||||
export async function closeUserDynamicTop(dynamicId: number | string) {
|
||||
return requestClient.get(`/user/dynamic/closeTop/${dynamicId}`);
|
||||
}
|
||||
@ -60,7 +60,7 @@ function createRequestClient(baseURL: string, options?: RequestClientOptions) {
|
||||
} else {
|
||||
delete config.headers.Authorization;
|
||||
}
|
||||
config.headers['Accept-Language'] = preferences.app.locale;
|
||||
config.headers['Accept-Language'] = 'zh-CN';
|
||||
config.headers['Req-Client'] = 'Ops';
|
||||
config.headers['Req-Version'] = 'v2';
|
||||
return config;
|
||||
|
||||
@ -9,14 +9,14 @@ import '@vben/styles/antdv-next';
|
||||
|
||||
import { useTitle } from '@vueuse/core';
|
||||
|
||||
import { $t, setupI18n } from '#/locales';
|
||||
import SysOriginSelect from '#/components/sys-origin-select.vue';
|
||||
import { $t, setupLocale } from '#/locales';
|
||||
|
||||
import { initComponentAdapter } from './adapter/component';
|
||||
import { initSetupVbenForm } from './adapter/form';
|
||||
import App from './app.vue';
|
||||
import { setupRuntimeLocaleSync } from './locales/runtime';
|
||||
import { router } from './router';
|
||||
|
||||
import './styles/table-filters.css';
|
||||
|
||||
async function bootstrap(namespace: string) {
|
||||
@ -44,8 +44,8 @@ async function bootstrap(namespace: string) {
|
||||
spinning: 'spinning',
|
||||
});
|
||||
|
||||
// 国际化 i18n 配置
|
||||
await setupI18n(app);
|
||||
// 固定中文基础文案
|
||||
await setupLocale(app);
|
||||
|
||||
// 配置 pinia-tore
|
||||
await initStores(app, { namespace });
|
||||
@ -75,7 +75,6 @@ async function bootstrap(namespace: string) {
|
||||
});
|
||||
|
||||
app.mount('#app');
|
||||
setupRuntimeLocaleSync();
|
||||
}
|
||||
|
||||
export { bootstrap };
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
# locale
|
||||
|
||||
每个app使用的国际化可能不同,这里用于扩展国际化的功能,例如扩展 dayjs、antd组件库的多语言切换,以及app本身的国际化文件。
|
||||
后台固定使用中文,这里只保留 dayjs、antd 组件库和应用基础文案的中文配置。
|
||||
|
||||
@ -2,117 +2,71 @@ import type { Locale } from 'antdv-next/dist/locale/index';
|
||||
|
||||
import type { App } from 'vue';
|
||||
|
||||
import type { LocaleSetupOptions, SupportedLanguagesType } from '@vben/locales';
|
||||
|
||||
import { ref } from 'vue';
|
||||
|
||||
import {
|
||||
$t,
|
||||
setupI18n as coreSetup,
|
||||
loadLocalesMapFromDir,
|
||||
setupLocale as coreSetup,
|
||||
mergeLocaleMessages,
|
||||
} from '@vben/locales';
|
||||
import { preferences } from '@vben/preferences';
|
||||
|
||||
import antdEnLocale from 'antdv-next/dist/locale/en_US';
|
||||
import antdDefaultLocale from 'antdv-next/dist/locale/zh_CN';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
const antdLocale = ref<Locale>(antdDefaultLocale);
|
||||
|
||||
const modules = import.meta.glob('./langs/**/*.json');
|
||||
const runtimeModules = import.meta.glob('./langs/*/runtime.json');
|
||||
const modules = import.meta.glob('./langs/zh-CN/*.json', { eager: true });
|
||||
|
||||
const localesMap = loadLocalesMapFromDir(
|
||||
/\.\/langs\/([^/]+)\/(.*)\.json$/,
|
||||
modules,
|
||||
);
|
||||
/**
|
||||
* 加载应用特有的语言包
|
||||
* 这里也可以改造为从服务端获取翻译数据
|
||||
* @param lang
|
||||
*/
|
||||
async function loadMessages(lang: SupportedLanguagesType) {
|
||||
const [appLocaleMessages, runtimeMessages] = await Promise.all([
|
||||
localesMap[lang]?.(),
|
||||
loadRuntimeMessages(lang),
|
||||
loadThirdPartyMessage(lang),
|
||||
]);
|
||||
const appMessages = appLocaleMessages?.default ?? {};
|
||||
const { runtime: _runtime, ...rest } = appMessages;
|
||||
|
||||
return {
|
||||
...(runtimeMessages ?? {}),
|
||||
...rest,
|
||||
};
|
||||
function normalizeModule(module: unknown) {
|
||||
return module && typeof module === 'object' && 'default' in module
|
||||
? (module as { default: Record<string, any> }).default
|
||||
: module;
|
||||
}
|
||||
|
||||
async function loadRuntimeMessages(lang: SupportedLanguagesType) {
|
||||
const runtimeLoader = runtimeModules[`./langs/${lang}/runtime.json`];
|
||||
const runtimeMessages = runtimeLoader
|
||||
? ((await runtimeLoader()) as { default?: Record<string, string> })
|
||||
: undefined;
|
||||
return runtimeMessages?.default;
|
||||
function loadAppMessages() {
|
||||
const messages: Record<string, any> = {};
|
||||
for (const [path, module] of Object.entries(modules)) {
|
||||
const fileName = path.match(/\.\/langs\/zh-CN\/(.*)\.json$/)?.[1];
|
||||
if (!fileName) {
|
||||
continue;
|
||||
}
|
||||
const value = normalizeModule(module);
|
||||
if (fileName === 'runtime') {
|
||||
Object.assign(messages, value);
|
||||
} else {
|
||||
messages[fileName] = value;
|
||||
}
|
||||
}
|
||||
return messages;
|
||||
}
|
||||
|
||||
mergeLocaleMessages(loadAppMessages());
|
||||
|
||||
/**
|
||||
* 加载第三方组件库的语言包
|
||||
* @param lang
|
||||
*/
|
||||
async function loadThirdPartyMessage(lang: SupportedLanguagesType) {
|
||||
await Promise.all([loadAntdLocale(lang), loadDayjsLocale(lang)]);
|
||||
async function loadThirdPartyMessage() {
|
||||
await Promise.all([loadAntdLocale(), loadDayjsLocale()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载dayjs的语言包
|
||||
* @param lang
|
||||
*/
|
||||
async function loadDayjsLocale(lang: SupportedLanguagesType) {
|
||||
let locale;
|
||||
switch (lang) {
|
||||
case 'en-US': {
|
||||
locale = await import('dayjs/locale/en');
|
||||
break;
|
||||
}
|
||||
case 'zh-CN': {
|
||||
locale = await import('dayjs/locale/zh-cn');
|
||||
break;
|
||||
}
|
||||
// 默认使用英语
|
||||
default: {
|
||||
locale = await import('dayjs/locale/en');
|
||||
}
|
||||
}
|
||||
if (locale) {
|
||||
dayjs.locale(locale);
|
||||
} else {
|
||||
console.error(`Failed to load dayjs locale for ${lang}`);
|
||||
}
|
||||
async function loadDayjsLocale() {
|
||||
await import('dayjs/locale/zh-cn');
|
||||
dayjs.locale('zh-cn');
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载antd的语言包
|
||||
* @param lang
|
||||
*/
|
||||
async function loadAntdLocale(lang: SupportedLanguagesType) {
|
||||
switch (lang) {
|
||||
case 'en-US': {
|
||||
antdLocale.value = antdEnLocale;
|
||||
break;
|
||||
}
|
||||
case 'zh-CN': {
|
||||
antdLocale.value = antdDefaultLocale;
|
||||
break;
|
||||
}
|
||||
}
|
||||
async function loadAntdLocale() {
|
||||
antdLocale.value = antdDefaultLocale;
|
||||
}
|
||||
|
||||
async function setupI18n(app: App, options: LocaleSetupOptions = {}) {
|
||||
await coreSetup(app, {
|
||||
defaultLocale: preferences.app.locale,
|
||||
loadMessages,
|
||||
missingWarn: !import.meta.env.PROD,
|
||||
...options,
|
||||
});
|
||||
async function setupLocale(app: App) {
|
||||
await coreSetup(app);
|
||||
await loadThirdPartyMessage();
|
||||
}
|
||||
|
||||
export { $t, antdLocale, setupI18n };
|
||||
export { $t, antdLocale, setupLocale };
|
||||
|
||||
@ -1,14 +0,0 @@
|
||||
{
|
||||
"auth": {
|
||||
"login": "Login",
|
||||
"register": "Register",
|
||||
"codeLogin": "Code Login",
|
||||
"qrcodeLogin": "Qr Code Login",
|
||||
"forgetPassword": "Forget Password",
|
||||
"profile": "Profile"
|
||||
},
|
||||
"dashboard": {
|
||||
"title": "Data Platform",
|
||||
"workspace": "Data Platform"
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -107,7 +107,6 @@
|
||||
"编辑应用": "编辑应用",
|
||||
"编辑用户": "编辑用户",
|
||||
"编辑游戏": "编辑游戏",
|
||||
"编辑置顶动态": "编辑置顶动态",
|
||||
"编辑资料": "编辑资料",
|
||||
"编辑资源": "编辑资源",
|
||||
"编码": "编码",
|
||||
@ -161,7 +160,6 @@
|
||||
"不允许跨年查询": "不允许跨年查询",
|
||||
"不在预计状态内": "不在预计状态内",
|
||||
"财富": "财富",
|
||||
"财富、魅力等级多少级才能发布动态": "财富、魅力等级多少级才能发布动态",
|
||||
"财富等级": "财富等级",
|
||||
"菜单": "菜单",
|
||||
"菜单编辑": "菜单编辑",
|
||||
@ -223,7 +221,6 @@
|
||||
"超级货运": "超级货运",
|
||||
"超级经销商": "超级经销商",
|
||||
"超商条码": "超商条码",
|
||||
"超限制发动态支付金币": "超限制发动态支付金币",
|
||||
"朝拜": "朝拜",
|
||||
"朝拜描述": "朝拜描述",
|
||||
"车辆": "车辆",
|
||||
@ -443,13 +440,6 @@
|
||||
"动画": "动画",
|
||||
"动画资源": "动画资源",
|
||||
"动画资源图": "动画资源图",
|
||||
"动态-禁止用户发动态": "动态-禁止用户发动态",
|
||||
"动态管理": "动态管理",
|
||||
"动态举报审批": "动态举报审批",
|
||||
"动态内容": "动态内容",
|
||||
"动态内容审批": "动态内容审批",
|
||||
"动态数量": "动态数量",
|
||||
"动态图片": "动态图片",
|
||||
"动效": "动效",
|
||||
"冻结": "冻结",
|
||||
"豆子": "豆子",
|
||||
@ -856,7 +846,6 @@
|
||||
"几时": "几时",
|
||||
"记录数": "记录数",
|
||||
"记录ID": "记录ID",
|
||||
"继续发送每条动态支付多少金币": "继续发送每条动态支付多少金币",
|
||||
"加入": "加入",
|
||||
"加入成员金币": "加入成员金币",
|
||||
"加入房间": "加入房间",
|
||||
@ -1198,7 +1187,6 @@
|
||||
"美元": "美元",
|
||||
"美元汇率": "美元汇率",
|
||||
"魅力等级": "魅力等级",
|
||||
"魅力等级多少级才能发布动态": "魅力等级多少级才能发布动态",
|
||||
"门票": "门票",
|
||||
"密码": "密码",
|
||||
"密码不能少于4位": "密码不能少于4位",
|
||||
@ -1700,7 +1688,6 @@
|
||||
"确认审核选中记录吗": "确认审核选中记录吗",
|
||||
"确认选择": "确认选择",
|
||||
"热门": "热门",
|
||||
"热门动态权重计分设置": "热门动态权重计分设置",
|
||||
"热门房间": "热门房间",
|
||||
"人": "人",
|
||||
"人身攻击": "人身攻击",
|
||||
@ -2347,10 +2334,7 @@
|
||||
"用户:数据分配图": "用户:数据分配图",
|
||||
"用户1V1": "用户1V1",
|
||||
"用户充值抽奖活动奖励": "用户充值抽奖活动奖励",
|
||||
"用户当天发送动态数量达到限制后": "用户当天发送动态数量达到限制后",
|
||||
"用户当天发送动态数量达到限制后,继续发送每条动态支付多少金币": "用户当天发送动态数量达到限制后,继续发送每条动态支付多少金币",
|
||||
"用户道具流水": "用户道具流水",
|
||||
"用户动态": "用户动态",
|
||||
"用户房间区域变动": "用户房间区域变动",
|
||||
"用户个性签名审批": "用户个性签名审批",
|
||||
"用户观看广告配置": "用户观看广告配置",
|
||||
@ -2486,7 +2470,6 @@
|
||||
"暂无备注": "暂无备注",
|
||||
"暂无查看权限": "暂无查看权限",
|
||||
"暂无道具配置": "暂无道具配置",
|
||||
"暂无动态": "暂无动态",
|
||||
"暂无购买记录": "暂无购买记录",
|
||||
"暂无可复制内容": "暂无可复制内容",
|
||||
"暂无可选资源": "暂无可选资源",
|
||||
|
||||
@ -1,267 +0,0 @@
|
||||
import { nextTick, watch } from 'vue';
|
||||
|
||||
import { i18n } from '@vben/locales';
|
||||
|
||||
const CHINESE_RE = /[\u3400-\u9fff]/;
|
||||
const SKIP_ATTRIBUTE_SELECTOR =
|
||||
'[data-no-runtime-locale], .ace_editor, .monaco-editor, noscript, script, style';
|
||||
const SKIP_TEXT_SELECTOR = `${SKIP_ATTRIBUTE_SELECTOR}, [contenteditable="true"], code, pre`;
|
||||
const TRANSLATABLE_ATTRIBUTES = [
|
||||
'alt',
|
||||
'aria-label',
|
||||
'placeholder',
|
||||
'title',
|
||||
] as const;
|
||||
|
||||
const elementOriginals = new WeakMap<Element, Map<string, string>>();
|
||||
const textOriginals = new WeakMap<Text, string>();
|
||||
|
||||
let initialized = false;
|
||||
let observer: MutationObserver | undefined;
|
||||
let runtimeMatcherCache:
|
||||
| {
|
||||
dict: Record<string, string>;
|
||||
locale: string;
|
||||
pattern?: RegExp;
|
||||
}
|
||||
| undefined;
|
||||
|
||||
function escapeRegExp(text: string) {
|
||||
return text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||||
}
|
||||
|
||||
function getRuntimeDictionary(locale: string) {
|
||||
const messages = i18n.global.getLocaleMessage(locale) as Record<string, unknown>;
|
||||
const dictionary: Record<string, string> = {};
|
||||
|
||||
for (const [key, value] of Object.entries(messages)) {
|
||||
if (typeof value === 'string' && CHINESE_RE.test(key)) {
|
||||
dictionary[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
return dictionary;
|
||||
}
|
||||
|
||||
function getRuntimeMatcher(locale: string) {
|
||||
if (runtimeMatcherCache?.locale === locale) {
|
||||
return runtimeMatcherCache;
|
||||
}
|
||||
|
||||
const dict = locale === 'en-US' ? getRuntimeDictionary(locale) : {};
|
||||
const keys = Object.keys(dict).sort((left, right) => right.length - left.length);
|
||||
|
||||
runtimeMatcherCache = {
|
||||
dict,
|
||||
locale,
|
||||
pattern:
|
||||
keys.length > 0
|
||||
? new RegExp(keys.map((key) => escapeRegExp(key)).join('|'), 'g')
|
||||
: undefined,
|
||||
};
|
||||
|
||||
return runtimeMatcherCache;
|
||||
}
|
||||
|
||||
function getElementOriginalMap(element: Element) {
|
||||
let originalMap = elementOriginals.get(element);
|
||||
|
||||
if (!originalMap) {
|
||||
originalMap = new Map<string, string>();
|
||||
elementOriginals.set(element, originalMap);
|
||||
}
|
||||
|
||||
return originalMap;
|
||||
}
|
||||
|
||||
function shouldSkipElement(element: Element) {
|
||||
return element.matches(SKIP_ATTRIBUTE_SELECTOR) || !!element.closest(SKIP_ATTRIBUTE_SELECTOR);
|
||||
}
|
||||
|
||||
function shouldSkipTextNode(node: Text) {
|
||||
return !!node.parentElement?.closest(SKIP_TEXT_SELECTOR);
|
||||
}
|
||||
|
||||
function getCurrentLocale() {
|
||||
return String(i18n.global.locale.value);
|
||||
}
|
||||
|
||||
function translateText(text: string) {
|
||||
if (!text || !CHINESE_RE.test(text)) {
|
||||
return text;
|
||||
}
|
||||
|
||||
const locale = getCurrentLocale();
|
||||
if (locale !== 'en-US') {
|
||||
return text;
|
||||
}
|
||||
|
||||
const { dict, pattern } = getRuntimeMatcher(locale);
|
||||
if (!pattern) {
|
||||
return text;
|
||||
}
|
||||
|
||||
return text.replace(pattern, (matched) => dict[matched] ?? matched);
|
||||
}
|
||||
|
||||
function translateElementAttributes(element: Element) {
|
||||
if (shouldSkipElement(element)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const locale = getCurrentLocale();
|
||||
const originals = getElementOriginalMap(element);
|
||||
|
||||
for (const attribute of TRANSLATABLE_ATTRIBUTES) {
|
||||
const rawValue = element.getAttribute(attribute);
|
||||
if (rawValue == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (locale === 'en-US') {
|
||||
const originalValue = CHINESE_RE.test(rawValue)
|
||||
? rawValue
|
||||
: (originals.get(attribute) ?? rawValue);
|
||||
if (!CHINESE_RE.test(originalValue)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const translatedValue = translateText(originalValue);
|
||||
if (translatedValue !== originalValue) {
|
||||
originals.set(attribute, originalValue);
|
||||
if (rawValue !== translatedValue) {
|
||||
element.setAttribute(attribute, translatedValue);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
const originalValue = originals.get(attribute);
|
||||
if (originalValue !== undefined && rawValue !== originalValue) {
|
||||
element.setAttribute(attribute, originalValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function translateTextNode(node: Text) {
|
||||
if (shouldSkipTextNode(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const rawValue = node.nodeValue ?? '';
|
||||
const locale = getCurrentLocale();
|
||||
|
||||
if (locale === 'en-US') {
|
||||
const originalValue = CHINESE_RE.test(rawValue)
|
||||
? rawValue
|
||||
: (textOriginals.get(node) ?? rawValue);
|
||||
if (!CHINESE_RE.test(originalValue)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const translatedValue = translateText(originalValue);
|
||||
if (translatedValue !== originalValue) {
|
||||
textOriginals.set(node, originalValue);
|
||||
if (rawValue !== translatedValue) {
|
||||
node.nodeValue = translatedValue;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const originalValue = textOriginals.get(node);
|
||||
if (originalValue !== undefined && rawValue !== originalValue) {
|
||||
node.nodeValue = originalValue;
|
||||
}
|
||||
}
|
||||
|
||||
function processNode(root: Node) {
|
||||
const stack: Node[] = [root];
|
||||
|
||||
while (stack.length > 0) {
|
||||
const node = stack.pop();
|
||||
if (!node) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (node.nodeType === Node.TEXT_NODE) {
|
||||
translateTextNode(node as Text);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (node.nodeType !== Node.ELEMENT_NODE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const element = node as Element;
|
||||
translateElementAttributes(element);
|
||||
|
||||
for (let index = element.childNodes.length - 1; index >= 0; index -= 1) {
|
||||
const childNode = element.childNodes[index];
|
||||
if (childNode) {
|
||||
stack.push(childNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function refreshRuntimeLocale() {
|
||||
if (typeof document === 'undefined' || !document.body) {
|
||||
return;
|
||||
}
|
||||
|
||||
processNode(document.body);
|
||||
}
|
||||
|
||||
function startObserver() {
|
||||
if (
|
||||
observer ||
|
||||
typeof document === 'undefined' ||
|
||||
typeof MutationObserver === 'undefined' ||
|
||||
!document.body
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
observer = new MutationObserver((mutations) => {
|
||||
for (const mutation of mutations) {
|
||||
if (mutation.type === 'attributes' || mutation.type === 'characterData') {
|
||||
processNode(mutation.target);
|
||||
continue;
|
||||
}
|
||||
|
||||
mutation.addedNodes.forEach((node) => processNode(node));
|
||||
}
|
||||
});
|
||||
|
||||
observer.observe(document.body, {
|
||||
attributeFilter: [...TRANSLATABLE_ATTRIBUTES],
|
||||
attributes: true,
|
||||
characterData: true,
|
||||
childList: true,
|
||||
subtree: true,
|
||||
});
|
||||
}
|
||||
|
||||
function setupRuntimeLocaleSync() {
|
||||
if (initialized) {
|
||||
return;
|
||||
}
|
||||
initialized = true;
|
||||
|
||||
watch(
|
||||
() => getCurrentLocale(),
|
||||
async () => {
|
||||
runtimeMatcherCache = undefined;
|
||||
await nextTick();
|
||||
refreshRuntimeLocale();
|
||||
startObserver();
|
||||
},
|
||||
{
|
||||
flush: 'post',
|
||||
immediate: true,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
export { setupRuntimeLocaleSync, translateText as translateLocaleText };
|
||||
@ -1,8 +1,9 @@
|
||||
import type { RouteRecordRaw } from 'vue-router';
|
||||
|
||||
import type {
|
||||
ComponentRecordType,
|
||||
GenerateMenuAndRoutesOptions,
|
||||
} from '@vben/types';
|
||||
import type { RouteRecordRaw } from 'vue-router';
|
||||
|
||||
import { generateAccessible } from '@vben/access';
|
||||
import { preferences } from '@vben/preferences';
|
||||
@ -24,8 +25,6 @@ const ROUTE_MENU_OVERRIDES: Record<
|
||||
}
|
||||
> = {
|
||||
BdLead: { aliases: ['BdLead'], routers: ['team/bd-lead'] },
|
||||
DynamicTagList: { aliases: ['DynamicTag'], routers: ['dynamic/tag'] },
|
||||
DynamicUserList: { aliases: ['UserDynamicList'], routers: ['user/dynamic/list'] },
|
||||
OperateBusinessDevelopment: {
|
||||
aliases: ['BusinessDevelopment'],
|
||||
routers: ['room/business-development'],
|
||||
@ -63,16 +62,16 @@ const ROUTE_MENU_OVERRIDES: Record<
|
||||
};
|
||||
|
||||
const LOCAL_RESIDENT_ACTIVITY_FALLBACK_ROUTES = new Set([
|
||||
'ResidentWheelConfig',
|
||||
'ResidentSmashGoldenEggConfig',
|
||||
'ResidentVoiceRoomRocket',
|
||||
'ResidentWheelConfig',
|
||||
]);
|
||||
|
||||
const LOCAL_APP_SYSTEM_FALLBACK_ROUTES = new Set([
|
||||
'AppSystemAgoraErrorLog',
|
||||
]);
|
||||
|
||||
function normalizeRoutePath(path?: string | null) {
|
||||
function normalizeRoutePath(path?: null | string) {
|
||||
return String(path || '')
|
||||
.trim()
|
||||
.replace(/^\/+/, '')
|
||||
@ -95,9 +94,9 @@ function collectRoutePaths(route: RouteRecordRaw) {
|
||||
const values = [normalizeRoutePath(route.path)];
|
||||
const aliases = Array.isArray(route.alias)
|
||||
? route.alias
|
||||
: route.alias
|
||||
: (route.alias
|
||||
? [route.alias]
|
||||
: [];
|
||||
: []);
|
||||
values.push(...aliases.map((item) => normalizeRoutePath(String(item))));
|
||||
const override = ROUTE_MENU_OVERRIDES[String(route.name || '')];
|
||||
if (override?.routers) {
|
||||
|
||||
@ -82,18 +82,6 @@ const routes: RouteRecordRaw[] = [
|
||||
component: () => import('#/views/approval/index.vue'),
|
||||
meta: { title: '家族头像审批' },
|
||||
},
|
||||
{
|
||||
name: 'ApprovalDynamicContent',
|
||||
path: 'dynamic/content/approval',
|
||||
component: () => import('#/views/approval/index.vue'),
|
||||
meta: { title: '动态内容审批' },
|
||||
},
|
||||
{
|
||||
name: 'ApprovalDynamicReport',
|
||||
path: 'dynamic/report',
|
||||
component: () => import('#/views/approval/index.vue'),
|
||||
meta: { title: '动态举报审批' },
|
||||
},
|
||||
{
|
||||
name: 'ApprovalUserBankCard',
|
||||
path: 'user/bank-card/approval',
|
||||
|
||||
@ -1,41 +0,0 @@
|
||||
import type { RouteRecordRaw } from 'vue-router';
|
||||
|
||||
const routes: RouteRecordRaw[] = [
|
||||
{
|
||||
meta: {
|
||||
icon: 'lucide:messages-square',
|
||||
order: 14,
|
||||
title: '动态管理',
|
||||
},
|
||||
name: 'DynamicManager',
|
||||
path: '/dynamic/manager',
|
||||
children: [
|
||||
{
|
||||
name: 'DynamicTagList',
|
||||
path: 'dynamic/tag',
|
||||
component: () => import('#/views/dynamic/tag-list.vue'),
|
||||
meta: { title: '标签列表' },
|
||||
},
|
||||
{
|
||||
name: 'DynamicPopularConfig',
|
||||
path: 'dynamic/popular/config',
|
||||
component: () => import('#/views/dynamic/popular-config.vue'),
|
||||
meta: { title: '权重配置' },
|
||||
},
|
||||
{
|
||||
name: 'DynamicUserList',
|
||||
path: 'user/dynamic/list',
|
||||
component: () => import('#/views/dynamic/user-dynamic-list.vue'),
|
||||
meta: { title: '用户动态' },
|
||||
},
|
||||
{
|
||||
name: 'DynamicBlacklist',
|
||||
path: 'dynamic/blacklist',
|
||||
component: () => import('#/views/dynamic/dynamic-blacklist.vue'),
|
||||
meta: { title: '黑名单' },
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export default routes;
|
||||
@ -1,7 +1,5 @@
|
||||
import {
|
||||
approveData,
|
||||
approveDynamicContentNotPass,
|
||||
approveDynamicContentPass,
|
||||
approvePhotoWallNotPass,
|
||||
approvePhotoWallPass,
|
||||
approveReportedNotPass,
|
||||
@ -10,8 +8,6 @@ import {
|
||||
approveUserBankCardNotPass,
|
||||
approveUserBankCardPass,
|
||||
batchProcessFeedback,
|
||||
getDynamicContentPage,
|
||||
getDynamicReportPage,
|
||||
getFamilyApprovalPage,
|
||||
getFeedbackPage,
|
||||
getPhotoWallApprovalPage,
|
||||
@ -23,7 +19,6 @@ import {
|
||||
getUserProfileDescApprovalPage,
|
||||
getViolationHistoryPage,
|
||||
markFamilyNotPass,
|
||||
processDynamicReport,
|
||||
} from '#/api/legacy/approval';
|
||||
|
||||
type ApprovalActionType = 'danger' | 'primary';
|
||||
@ -181,12 +176,6 @@ const REPORT_STATUS_OPTIONS: ApprovalFilterOption[] = [
|
||||
{ label: '无效', value: 2 },
|
||||
];
|
||||
|
||||
const DYNAMIC_REPORT_STATUS_OPTIONS: ApprovalFilterOption[] = [
|
||||
{ label: '待审核', value: 0 },
|
||||
{ label: '违规', value: 1 },
|
||||
{ label: '正常', value: 2 },
|
||||
];
|
||||
|
||||
const REPORT_TYPE_OPTIONS: ApprovalFilterOption[] = [
|
||||
{ label: '非法信息', value: 0 },
|
||||
{ label: '人身攻击', value: 1 },
|
||||
@ -230,7 +219,7 @@ function splitCsv(value: any) {
|
||||
return [];
|
||||
}
|
||||
if (Array.isArray(value)) {
|
||||
return value.filter(Boolean).map((item) => String(item));
|
||||
return value.filter(Boolean).map(String);
|
||||
}
|
||||
return String(value)
|
||||
.split(',')
|
||||
@ -248,7 +237,7 @@ function buildApprovalDataAction(
|
||||
await approveData({
|
||||
approvalStatus,
|
||||
approvalType,
|
||||
waitApprovalUser: records.map(mapRecord),
|
||||
waitApprovalUser: records.map((record) => mapRecord(record)),
|
||||
});
|
||||
},
|
||||
label: approvalStatus === 'PASS' ? '鉴定通过' : '鉴定违规',
|
||||
@ -262,7 +251,7 @@ function familyNotPassAction(
|
||||
): ApprovalBulkAction {
|
||||
return {
|
||||
execute: async (records) => {
|
||||
const approvalRecords = records.map(mapRecord);
|
||||
const approvalRecords = records.map((record) => mapRecord(record));
|
||||
await approveData({
|
||||
approvalStatus: 'NOT_PASS',
|
||||
approvalType,
|
||||
@ -867,9 +856,9 @@ const approvalPages: Record<string, ApprovalPage> = {
|
||||
`年龄:${record.userProfile?.age || '-'}`,
|
||||
`创建时间:${record.createTime || '-'}`,
|
||||
`修改时间:${record.updateTime || '-'}`,
|
||||
...(query.themeStatus !== 'PENDING'
|
||||
? [`审核人:${record.optUserNickname || '-'}`]
|
||||
: []),
|
||||
...(query.themeStatus === 'PENDING'
|
||||
? []
|
||||
: [`审核人:${record.optUserNickname || '-'}`]),
|
||||
],
|
||||
title: record.userProfile?.userNickname || '-',
|
||||
titleUserId: record.userProfile?.id,
|
||||
@ -1183,10 +1172,10 @@ const approvalPages: Record<string, ApprovalPage> = {
|
||||
record.violationType === 'PHOTO_WALL' ||
|
||||
record.violationType === 'ROOM_AVATAR'
|
||||
? 'images'
|
||||
: record.violationType === 'LIVE' ||
|
||||
: (record.violationType === 'LIVE' ||
|
||||
record.violationType === 'SHORT_VIDEO'
|
||||
? 'videos'
|
||||
: 'text';
|
||||
: 'text');
|
||||
return {
|
||||
content:
|
||||
contentType === 'text' ? record.content || '-' : splitCsv(record.content),
|
||||
@ -1471,238 +1460,6 @@ const approvalPages: Record<string, ApprovalPage> = {
|
||||
},
|
||||
title: '家族审批',
|
||||
},
|
||||
'/approval/manager/dynamic/content/approval': {
|
||||
actions: [
|
||||
{
|
||||
execute: async (records) => {
|
||||
await approveDynamicContentPass(records.map((record) => record.dynamicId));
|
||||
},
|
||||
label: '鉴定通过',
|
||||
show: (query) => query.approveStatus === 'PENDING',
|
||||
type: 'primary',
|
||||
},
|
||||
{
|
||||
execute: async (records) => {
|
||||
await approveDynamicContentNotPass(
|
||||
records.map((record) => record.dynamicId),
|
||||
);
|
||||
},
|
||||
label: '鉴定违规',
|
||||
show: (query) =>
|
||||
query.approveStatus === 'PENDING' || query.approveStatus === 'PASS',
|
||||
type: 'danger',
|
||||
},
|
||||
],
|
||||
buildCard: (record, query) => ({
|
||||
actions: [{ label: '账号处理', type: 'account', value: record.userId }],
|
||||
galleryImages: (record.pictures || [])
|
||||
.map((item: any) => item.resourceUrl)
|
||||
.filter(Boolean),
|
||||
leadText: record.dynamicContent || '',
|
||||
lines: [
|
||||
`性别:${record.userSexName || record.userBaseInfo?.userSexName || '-'}`,
|
||||
`年龄:${record.userBaseInfo?.age || '-'}`,
|
||||
`创建时间:${record.createTime || '-'}`,
|
||||
...(query.approveStatus !== 'PENDING'
|
||||
? [`审批时间:${record.updateTime || '-'}`]
|
||||
: []),
|
||||
],
|
||||
overlay:
|
||||
(record.pictures || [])
|
||||
.map((item: any) => item.labelNames)
|
||||
.filter(Boolean)
|
||||
.join(' / ') || '',
|
||||
title: record.userBaseInfo?.userNickname || '-',
|
||||
titleUserId: record.userId,
|
||||
}),
|
||||
defaultQuery: {
|
||||
approveStatus: 'PENDING',
|
||||
cursor: 1,
|
||||
endDateTime: '',
|
||||
limit: 20,
|
||||
startDateTime: '',
|
||||
sysOrigin: DEFAULT_SYS_ORIGIN,
|
||||
userId: '',
|
||||
},
|
||||
fetch: getDynamicContentPage,
|
||||
filters: [
|
||||
{ field: 'sysOrigin', label: '系统', placeholder: '系统', type: 'sysOrigin' },
|
||||
{
|
||||
field: 'approveStatus',
|
||||
label: '审核',
|
||||
options: COMMON_APPROVAL_ALL_OPTIONS,
|
||||
placeholder: '审核',
|
||||
type: 'select',
|
||||
},
|
||||
{
|
||||
endField: 'endDateTime',
|
||||
label: '时间范围',
|
||||
placeholder: '时间范围',
|
||||
startField: 'startDateTime',
|
||||
type: 'dateRange',
|
||||
},
|
||||
{ field: 'userId', label: '用户ID', placeholder: '用户ID', type: 'input' },
|
||||
],
|
||||
kind: 'gallery',
|
||||
selectable: (query) =>
|
||||
query.approveStatus === 'PENDING' || query.approveStatus === 'PASS',
|
||||
title: '动态内容审批',
|
||||
},
|
||||
'/approval/manager/dynamic/report': {
|
||||
actions: [
|
||||
{
|
||||
execute: async (records) => {
|
||||
await processDynamicReport({
|
||||
approvalStatus: 2,
|
||||
contentIds: records.map((record) => record.dynamicContentId),
|
||||
});
|
||||
},
|
||||
label: '正常',
|
||||
show: (query) => query.approvalStatus === 0,
|
||||
type: 'primary',
|
||||
},
|
||||
{
|
||||
execute: async (records) => {
|
||||
await processDynamicReport({
|
||||
approvalStatus: 1,
|
||||
contentIds: records.map((record) => record.dynamicContentId),
|
||||
});
|
||||
},
|
||||
label: '违规',
|
||||
show: (query) => query.approvalStatus === 0,
|
||||
type: 'danger',
|
||||
},
|
||||
],
|
||||
columns: [
|
||||
{
|
||||
key: 'sysOrigin',
|
||||
render: (record) => ({
|
||||
text: record.sysOrigin || '-',
|
||||
type: 'origin',
|
||||
}),
|
||||
title: '系统',
|
||||
width: 90,
|
||||
},
|
||||
{
|
||||
key: 'reportUser',
|
||||
render: (record) => ({
|
||||
text: record.reportUser?.userNickname || '-',
|
||||
type: 'link',
|
||||
userId: record.reportUser?.id,
|
||||
}),
|
||||
title: '举报人',
|
||||
},
|
||||
{
|
||||
key: 'reportedUser',
|
||||
render: (record) => ({
|
||||
text: record.reportedUser?.userNickname || '-',
|
||||
type: 'link',
|
||||
userId: record.reportedUser?.id,
|
||||
}),
|
||||
title: '被举报人',
|
||||
},
|
||||
{
|
||||
key: 'reportType',
|
||||
render: (record) => ({
|
||||
text:
|
||||
REPORT_TYPE_OPTIONS.find((item) => item.value === record.reportType)
|
||||
?.label || '-',
|
||||
type: 'text',
|
||||
}),
|
||||
title: '举报类型',
|
||||
},
|
||||
{
|
||||
key: 'dynamicContent',
|
||||
render: (record) => ({
|
||||
text: record.dynamicContent || '-',
|
||||
type: 'text',
|
||||
}),
|
||||
title: '动态内容',
|
||||
},
|
||||
{
|
||||
key: 'time',
|
||||
render: (record) => ({
|
||||
text:
|
||||
record.createTime && record.updateTime
|
||||
? `${record.createTime} / ${record.updateTime}`
|
||||
: record.createTime || '-',
|
||||
type: 'text',
|
||||
}),
|
||||
title: '时间',
|
||||
width: 240,
|
||||
},
|
||||
],
|
||||
defaultQuery: {
|
||||
approvalStatus: 0,
|
||||
cursor: 1,
|
||||
endTime: '',
|
||||
limit: 20,
|
||||
reportType: '',
|
||||
reportUserId: '',
|
||||
reportedUserId: '',
|
||||
startTime: '',
|
||||
sysOrigin: DEFAULT_SYS_ORIGIN,
|
||||
},
|
||||
expandable: (record) => [
|
||||
{ label: '举报图片', type: 'images', value: splitCsv(record.reportedUrls) },
|
||||
{
|
||||
label: '动态图片',
|
||||
type: 'images',
|
||||
value: (record.dynamicPictures || [])
|
||||
.map((item: any) => item.resourceUrl)
|
||||
.filter(Boolean),
|
||||
},
|
||||
{ label: '举报内容', value: record.reportedContent || '-' },
|
||||
],
|
||||
fetch: getDynamicReportPage,
|
||||
filters: [
|
||||
{ field: 'sysOrigin', label: '系统', placeholder: '系统', type: 'sysOrigin' },
|
||||
{
|
||||
field: 'approvalStatus',
|
||||
label: '状态',
|
||||
options: DYNAMIC_REPORT_STATUS_OPTIONS,
|
||||
placeholder: '状态',
|
||||
type: 'select',
|
||||
},
|
||||
{
|
||||
clearable: true,
|
||||
field: 'reportType',
|
||||
label: '举报类型',
|
||||
options: REPORT_TYPE_OPTIONS,
|
||||
placeholder: '举报类型',
|
||||
type: 'select',
|
||||
},
|
||||
{
|
||||
field: 'reportUserId',
|
||||
label: '举报人ID',
|
||||
placeholder: '举报人ID',
|
||||
type: 'input',
|
||||
},
|
||||
{
|
||||
field: 'reportedUserId',
|
||||
label: '被举报人ID',
|
||||
placeholder: '被举报人ID',
|
||||
type: 'input',
|
||||
},
|
||||
{
|
||||
endField: 'endTime',
|
||||
label: '时间范围',
|
||||
placeholder: '时间范围',
|
||||
startField: 'startTime',
|
||||
type: 'dateRange',
|
||||
},
|
||||
],
|
||||
kind: 'table',
|
||||
rowActions: (record) => [
|
||||
{
|
||||
label: '被举报账号处理',
|
||||
type: 'account',
|
||||
value: record.reportedUser?.id,
|
||||
},
|
||||
],
|
||||
selectable: (query) => query.approvalStatus === 0,
|
||||
title: '动态举报审批',
|
||||
},
|
||||
'/approval/manager/user/bank-card/approval': {
|
||||
actions: [
|
||||
{
|
||||
@ -1760,15 +1517,15 @@ const approvalPages: Record<string, ApprovalPage> = {
|
||||
color:
|
||||
record.status === 'PENDING'
|
||||
? 'default'
|
||||
: record.status === 'PASS'
|
||||
: (record.status === 'PASS'
|
||||
? 'success'
|
||||
: 'error',
|
||||
: 'error'),
|
||||
text:
|
||||
record.status === 'PENDING'
|
||||
? '待审核'
|
||||
: record.status === 'PASS'
|
||||
: (record.status === 'PASS'
|
||||
? '通过'
|
||||
: '驳回',
|
||||
: '驳回'),
|
||||
type: 'tag',
|
||||
}),
|
||||
title: '状态',
|
||||
@ -1821,12 +1578,11 @@ const approvalPages: Record<string, ApprovalPage> = {
|
||||
|
||||
export {
|
||||
APPROVAL_TYPE_OPTIONS,
|
||||
approvalPages,
|
||||
BANK_CARD_OPTIONS,
|
||||
DYNAMIC_REPORT_STATUS_OPTIONS,
|
||||
FEEDBACK_STATUS_OPTIONS,
|
||||
PHOTO_WALL_STATUS_OPTIONS,
|
||||
REPORT_STATUS_OPTIONS,
|
||||
REPORT_TYPE_OPTIONS,
|
||||
SYS_ORIGIN_OPTIONS,
|
||||
approvalPages,
|
||||
};
|
||||
|
||||
@ -1,256 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref, watch } from 'vue';
|
||||
|
||||
import {
|
||||
OSS_FILE_BUCKETS,
|
||||
getAccessImgUrl,
|
||||
simpleUploadFile,
|
||||
} from '#/api/legacy/oss';
|
||||
import { saveDynamicTag } from '#/api/legacy/dynamic';
|
||||
import { LANGUAGE_OPTIONS } from '#/views/system/shared';
|
||||
|
||||
import {
|
||||
Button,
|
||||
Form,
|
||||
FormItem,
|
||||
Image,
|
||||
Input,
|
||||
InputNumber,
|
||||
Modal,
|
||||
Select,
|
||||
Space,
|
||||
message,
|
||||
} from 'antdv-next';
|
||||
|
||||
const props = defineProps<{
|
||||
open: boolean;
|
||||
record: null | Record<string, any>;
|
||||
sysOriginOptions: Array<{ label: string; value: string }>;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
close: [];
|
||||
success: [];
|
||||
}>();
|
||||
|
||||
const fileInputRef = ref<HTMLInputElement | null>(null);
|
||||
const saving = ref(false);
|
||||
const uploadLoading = ref(false);
|
||||
|
||||
const form = reactive({
|
||||
del: false as boolean,
|
||||
description: '',
|
||||
id: '',
|
||||
imageUrl: '',
|
||||
languageType: '',
|
||||
sort: undefined as number | string | undefined,
|
||||
sysOrigin: '',
|
||||
tag: '',
|
||||
});
|
||||
|
||||
watch(
|
||||
() => props.open,
|
||||
(open) => {
|
||||
if (!open) {
|
||||
return;
|
||||
}
|
||||
const record = props.record;
|
||||
form.id = String(record?.id || '');
|
||||
form.imageUrl = record?.imageUrl || '';
|
||||
form.sysOrigin =
|
||||
record?.sysOrigin || props.sysOriginOptions[0]?.value || 'LIKEI';
|
||||
form.tag = record?.tag || '';
|
||||
form.description = record?.description || '';
|
||||
form.del = Boolean(record?.del);
|
||||
form.sort = record?.sort ?? undefined;
|
||||
form.languageType = record?.languageType || '';
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
|
||||
const title = ref('新增标签');
|
||||
|
||||
watch(
|
||||
() => props.record,
|
||||
(value) => {
|
||||
title.value = value?.id ? '修改标签' : '新增标签';
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
|
||||
function openFileDialog() {
|
||||
fileInputRef.value?.click();
|
||||
}
|
||||
|
||||
async function handleFileChange(event: Event) {
|
||||
const target = event.target as HTMLInputElement;
|
||||
const file = target.files?.[0];
|
||||
target.value = '';
|
||||
if (!file) {
|
||||
return;
|
||||
}
|
||||
uploadLoading.value = true;
|
||||
try {
|
||||
const result = await simpleUploadFile(file, OSS_FILE_BUCKETS.other);
|
||||
form.imageUrl = getAccessImgUrl(result.name);
|
||||
message.success('上传成功');
|
||||
} finally {
|
||||
uploadLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function resetImage() {
|
||||
form.imageUrl = '';
|
||||
}
|
||||
|
||||
async function handleSubmit() {
|
||||
if (!form.imageUrl) {
|
||||
message.warning('请上传背景图');
|
||||
return;
|
||||
}
|
||||
if (!form.sysOrigin) {
|
||||
message.warning('请选择系统');
|
||||
return;
|
||||
}
|
||||
if (!form.tag.trim()) {
|
||||
message.warning('请输入标签');
|
||||
return;
|
||||
}
|
||||
if (!form.description.trim()) {
|
||||
message.warning('请输入描述');
|
||||
return;
|
||||
}
|
||||
if (!form.languageType) {
|
||||
message.warning('请选择语言');
|
||||
return;
|
||||
}
|
||||
if (form.sort === undefined || form.sort === null || form.sort === '') {
|
||||
message.warning('请输入排序');
|
||||
return;
|
||||
}
|
||||
|
||||
saving.value = true;
|
||||
try {
|
||||
await saveDynamicTag({
|
||||
del: form.del,
|
||||
description: form.description.trim(),
|
||||
id: form.id || undefined,
|
||||
imageUrl: form.imageUrl,
|
||||
languageType: form.languageType,
|
||||
sort: Number(form.sort),
|
||||
sysOrigin: form.sysOrigin,
|
||||
tag: form.tag.trim(),
|
||||
});
|
||||
message.success('保存成功');
|
||||
emit('success');
|
||||
emit('close');
|
||||
} finally {
|
||||
saving.value = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Modal
|
||||
:confirm-loading="saving"
|
||||
:open="open"
|
||||
destroy-on-close
|
||||
:title="title"
|
||||
width="680"
|
||||
@cancel="emit('close')"
|
||||
@ok="handleSubmit"
|
||||
>
|
||||
<Form layout="vertical">
|
||||
<FormItem label="背景">
|
||||
<input
|
||||
ref="fileInputRef"
|
||||
accept="image/*"
|
||||
class="hidden-input"
|
||||
type="file"
|
||||
@change="handleFileChange"
|
||||
/>
|
||||
<div class="cover-field">
|
||||
<div v-if="form.imageUrl" class="cover-preview">
|
||||
<Image :src="form.imageUrl" class="cover-image" />
|
||||
</div>
|
||||
<div v-else class="cover-empty">请选择背景图</div>
|
||||
<Space>
|
||||
<Button :loading="uploadLoading" @click="openFileDialog">
|
||||
{{ form.imageUrl ? '重新上传' : '上传图片' }}
|
||||
</Button>
|
||||
<Button v-if="form.imageUrl" danger @click="resetImage">移除</Button>
|
||||
</Space>
|
||||
</div>
|
||||
</FormItem>
|
||||
<FormItem label="系统">
|
||||
<SysOriginSelect v-model:value="form.sysOrigin"
|
||||
:options="sysOriginOptions"
|
||||
></SysOriginSelect>
|
||||
</FormItem>
|
||||
<FormItem label="标签">
|
||||
<Input v-model:value="form.tag" />
|
||||
</FormItem>
|
||||
<FormItem label="描述">
|
||||
<Input v-model:value="form.description" />
|
||||
</FormItem>
|
||||
<FormItem label="语言">
|
||||
<Select
|
||||
option-label-prop="label"
|
||||
v-model:value="form.languageType"
|
||||
:options="LANGUAGE_OPTIONS.map((item) => ({ label: item.name, value: item.value }))"
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem label="状态">
|
||||
<Select
|
||||
option-label-prop="label"
|
||||
v-model:value="form.del"
|
||||
:options="[
|
||||
{ label: '上架', value: false as any },
|
||||
{ label: '下架', value: true as any },
|
||||
]"
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem label="排序">
|
||||
<InputNumber
|
||||
v-model:value="form.sort"
|
||||
:min="0"
|
||||
placeholder="数字越大越靠前"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</Modal>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.hidden-input {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.cover-field {
|
||||
display: grid;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.cover-preview,
|
||||
.cover-empty {
|
||||
align-items: center;
|
||||
background: #f8fafc;
|
||||
border: 1px dashed rgb(148 163 184 / 35%);
|
||||
border-radius: 16px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
min-height: 180px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.cover-empty {
|
||||
color: #94a3b8;
|
||||
}
|
||||
|
||||
.cover-image {
|
||||
height: 180px;
|
||||
object-fit: cover;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
@ -1,267 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import {
|
||||
reactive,
|
||||
ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
|
||||
import { Page } from '@vben/common-ui';
|
||||
import { useAccessStore } from '@vben/stores';
|
||||
|
||||
import {
|
||||
addDynamicBlacklist,
|
||||
deleteDynamicBlacklist,
|
||||
dynamicBlacklistPage,
|
||||
} from '#/api/legacy/dynamic';
|
||||
import AccountInput from '#/components/account-input.vue';
|
||||
import SysOriginLabel from '#/components/sys-origin-label.vue';
|
||||
import { formatDate,
|
||||
getAllowedSysOrigins } from '#/views/system/shared';
|
||||
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
Form,
|
||||
FormItem,
|
||||
Input,
|
||||
Modal,
|
||||
Pagination,
|
||||
Table,
|
||||
Tag,
|
||||
message,
|
||||
} from 'antdv-next';
|
||||
|
||||
defineOptions({ name: 'DynamicBlacklist' });
|
||||
|
||||
const router = useRouter();
|
||||
const accessStore = useAccessStore();
|
||||
const sysOriginOptions = getAllowedSysOrigins(accessStore.accessCodes || []);
|
||||
|
||||
const loading = ref(false);
|
||||
const total = ref(0);
|
||||
const list = ref<Array<Record<string, any>>>([]);
|
||||
const modalOpen = ref(false);
|
||||
const saving = ref(false);
|
||||
|
||||
const query = reactive({
|
||||
cursor: 1,
|
||||
limit: 20,
|
||||
sysOrigin: sysOriginOptions[0]?.value ?? 'LIKEI',
|
||||
userId: '',
|
||||
});
|
||||
|
||||
const form = reactive({
|
||||
account: '',
|
||||
});
|
||||
|
||||
const columns = [
|
||||
{ dataIndex: 'originSys', key: 'originSys', title: '系统', width: 120 },
|
||||
{ dataIndex: 'user', key: 'user', title: '用户', width: 220 },
|
||||
{ dataIndex: 'nickname', key: 'nickname', title: '昵称', width: 180 },
|
||||
{ dataIndex: 'userSex', key: 'userSex', title: '性别', width: 100 },
|
||||
{ dataIndex: 'country', key: 'country', title: '国家/地区', width: 160 },
|
||||
{ dataIndex: 'createTime', key: 'createTime', title: '拉黑时间', width: 180 },
|
||||
{ dataIndex: 'actions', key: 'actions', title: '操作', width: 100 },
|
||||
];
|
||||
|
||||
async function loadData(reset = false) {
|
||||
if (reset) {
|
||||
query.cursor = 1;
|
||||
}
|
||||
loading.value = true;
|
||||
try {
|
||||
const result = await dynamicBlacklistPage({ ...query });
|
||||
list.value = result.records || [];
|
||||
total.value = result.total || 0;
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function handleSearch() {
|
||||
loadData(true);
|
||||
}
|
||||
|
||||
function handlePageChange(page: number, pageSize: number) {
|
||||
query.cursor = page;
|
||||
query.limit = pageSize;
|
||||
loadData();
|
||||
}
|
||||
|
||||
function openCreate() {
|
||||
form.account = '';
|
||||
modalOpen.value = true;
|
||||
}
|
||||
|
||||
function openUserDetails(record: Record<string, any>) {
|
||||
const userId = record.id || record.userId;
|
||||
if (!userId) {
|
||||
return;
|
||||
}
|
||||
router.push(`/common/user/deatils/${userId}`);
|
||||
}
|
||||
|
||||
async function handleDelete(record: Record<string, any>) {
|
||||
loading.value = true;
|
||||
try {
|
||||
await deleteDynamicBlacklist(record.id);
|
||||
message.success('删除成功');
|
||||
await loadData();
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function handleSubmit() {
|
||||
if (!form.account.trim()) {
|
||||
message.warning('请输入账号');
|
||||
return;
|
||||
}
|
||||
saving.value = true;
|
||||
try {
|
||||
await addDynamicBlacklist({
|
||||
account: form.account.trim(),
|
||||
sysOrigin: query.sysOrigin,
|
||||
});
|
||||
message.success('保存成功');
|
||||
modalOpen.value = false;
|
||||
await loadData(true);
|
||||
} finally {
|
||||
saving.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
loadData(true);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Page title="黑名单">
|
||||
<Card>
|
||||
<div class="toolbar">
|
||||
<SysOriginSelect
|
||||
v-model:value="query.sysOrigin"
|
||||
style="width: 140px"
|
||||
@change="handleSearch"
|
||||
|
||||
:options="sysOriginOptions"
|
||||
></SysOriginSelect>
|
||||
<AccountInput
|
||||
v-model:value="query.userId"
|
||||
:sys-origin="query.sysOrigin"
|
||||
placeholder="用户ID"
|
||||
style="width: 220px"
|
||||
/>
|
||||
<Button :loading="loading" type="primary" @click="handleSearch">
|
||||
搜索
|
||||
</Button>
|
||||
<Button @click="openCreate">加入黑名单</Button>
|
||||
</div>
|
||||
|
||||
<Table
|
||||
:columns="columns"
|
||||
:data-source="list"
|
||||
:loading="loading"
|
||||
:pagination="false"
|
||||
row-key="id"
|
||||
>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.key === 'originSys'">
|
||||
<SysOriginLabel :value="record.originSys || record.sysOrigin" />
|
||||
</template>
|
||||
<template v-else-if="column.key === 'user'">
|
||||
<div class="user-cell">
|
||||
<img
|
||||
:src="record.userAvatar || 'https://dummyimage.com/44x44/e2e8f0/64748b&text=U'"
|
||||
alt=""
|
||||
class="user-avatar"
|
||||
>
|
||||
<div class="user-info">
|
||||
<div>{{ record.actualAccount || '-' }}</div>
|
||||
<Tag v-if="record.countryCode">{{ record.countryCode }}</Tag>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="column.key === 'nickname'">
|
||||
<Button type="link" @click="openUserDetails(record)">
|
||||
{{ record.userNickname || '-' }}
|
||||
</Button>
|
||||
</template>
|
||||
<template v-else-if="column.key === 'userSex'">
|
||||
{{ Number(record.userSex) === 1 ? '男' : '女' }}
|
||||
</template>
|
||||
<template v-else-if="column.key === 'country'">
|
||||
{{ record.countryName || '-' }}
|
||||
</template>
|
||||
<template v-else-if="column.key === 'createTime'">
|
||||
{{ formatDate(record.createTime) }}
|
||||
</template>
|
||||
<template v-else-if="column.key === 'actions'">
|
||||
<Button danger size="small" type="link" @click="handleDelete(record)">
|
||||
删除
|
||||
</Button>
|
||||
</template>
|
||||
</template>
|
||||
</Table>
|
||||
|
||||
<div class="pagination">
|
||||
<Pagination
|
||||
:current="query.cursor"
|
||||
:page-size="query.limit"
|
||||
:total="total"
|
||||
show-size-changer
|
||||
@change="handlePageChange"
|
||||
@showSizeChange="handlePageChange"
|
||||
/>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
<Modal
|
||||
:confirm-loading="saving"
|
||||
:open="modalOpen"
|
||||
destroy-on-close
|
||||
title="动态-禁止用户发动态"
|
||||
@cancel="modalOpen = false"
|
||||
@ok="handleSubmit"
|
||||
>
|
||||
<Form layout="vertical">
|
||||
<FormItem label="平台">
|
||||
<Input :value="query.sysOrigin" disabled />
|
||||
</FormItem>
|
||||
<FormItem label="账号">
|
||||
<Input v-model:value="form.account" />
|
||||
</FormItem>
|
||||
</Form>
|
||||
</Modal>
|
||||
</Page>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.toolbar {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 12px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.user-cell {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.user-avatar {
|
||||
border-radius: 999px;
|
||||
height: 44px;
|
||||
object-fit: cover;
|
||||
width: 44px;
|
||||
}
|
||||
|
||||
.user-info {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.pagination {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin-top: 16px;
|
||||
}
|
||||
</style>
|
||||
@ -1,139 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, reactive, ref } from 'vue';
|
||||
|
||||
import { Page } from '@vben/common-ui';
|
||||
|
||||
import {
|
||||
getDynamicPopularConfig,
|
||||
saveDynamicPopularConfig,
|
||||
} from '#/api/legacy/dynamic';
|
||||
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
Form,
|
||||
FormItem,
|
||||
InputNumber,
|
||||
Modal,
|
||||
message,
|
||||
} from 'antdv-next';
|
||||
|
||||
defineOptions({ name: 'DynamicPopularConfig' });
|
||||
|
||||
const loading = ref(false);
|
||||
const saving = ref(false);
|
||||
|
||||
const form = reactive({
|
||||
commentScore: undefined as number | undefined,
|
||||
dynamicFees: undefined as number | undefined,
|
||||
levelLimit: undefined as number | undefined,
|
||||
likeScore: undefined as number | undefined,
|
||||
quantityLimit: undefined as number | undefined,
|
||||
});
|
||||
|
||||
async function loadData() {
|
||||
loading.value = true;
|
||||
try {
|
||||
const result = await getDynamicPopularConfig();
|
||||
form.likeScore = result?.likeScore;
|
||||
form.commentScore = result?.commentScore;
|
||||
form.levelLimit = result?.levelLimit;
|
||||
form.quantityLimit = result?.quantityLimit;
|
||||
form.dynamicFees = result?.dynamicFees;
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function handleSubmit() {
|
||||
Modal.confirm({
|
||||
title: '是否确定修改配置值?',
|
||||
async onOk() {
|
||||
saving.value = true;
|
||||
try {
|
||||
await saveDynamicPopularConfig({ ...form });
|
||||
message.success('保存成功');
|
||||
await loadData();
|
||||
} finally {
|
||||
saving.value = false;
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
onMounted(loadData);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Page title="权重配置">
|
||||
<Card :loading="loading">
|
||||
<Form layout="vertical">
|
||||
<div class="section">
|
||||
<div class="section-title">热门动态权重计分设置</div>
|
||||
<div class="grid">
|
||||
<FormItem label="点赞增加分数">
|
||||
<InputNumber v-model:value="form.likeScore" :min="0" style="width: 100%" />
|
||||
</FormItem>
|
||||
<FormItem label="评论增加分数">
|
||||
<InputNumber v-model:value="form.commentScore" :min="0" style="width: 100%" />
|
||||
</FormItem>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<div class="section-title">财富、魅力等级多少级才能发布动态</div>
|
||||
<FormItem label="等级限制">
|
||||
<InputNumber v-model:value="form.levelLimit" :min="0" style="width: 100%" />
|
||||
</FormItem>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<div class="section-title">每个用户当天允许发送多少条动态</div>
|
||||
<FormItem label="动态数量">
|
||||
<InputNumber v-model:value="form.quantityLimit" :min="0" style="width: 100%" />
|
||||
</FormItem>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<div class="section-title">
|
||||
用户当天发送动态数量达到限制后,继续发送每条动态支付多少金币
|
||||
</div>
|
||||
<FormItem label="金币数">
|
||||
<InputNumber v-model:value="form.dynamicFees" :min="0" style="width: 100%" />
|
||||
</FormItem>
|
||||
</div>
|
||||
|
||||
<Button :loading="saving" type="primary" @click="handleSubmit">
|
||||
修改
|
||||
</Button>
|
||||
</Form>
|
||||
</Card>
|
||||
</Page>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.section + .section {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
background: rgb(37 99 235 / 6%);
|
||||
border-left: 3px solid #2563eb;
|
||||
border-radius: 10px;
|
||||
color: #1e293b;
|
||||
margin-bottom: 16px;
|
||||
padding: 12px 14px;
|
||||
}
|
||||
|
||||
.grid {
|
||||
display: grid;
|
||||
gap: 16px;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
@media (width <= 768px) {
|
||||
.grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -1,216 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import {
|
||||
computed,
|
||||
reactive,
|
||||
ref } from 'vue';
|
||||
|
||||
import { Page } from '@vben/common-ui';
|
||||
import { useAccessStore } from '@vben/stores';
|
||||
|
||||
import { dynamicTagTable } from '#/api/legacy/dynamic';
|
||||
import SysOriginLabel from '#/components/sys-origin-label.vue';
|
||||
import {
|
||||
LANGUAGE_OPTIONS,
|
||||
formatDate,
|
||||
getAllowedSysOrigins,
|
||||
} from '#/views/system/shared';
|
||||
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
Image,
|
||||
Pagination,
|
||||
Select,
|
||||
Space,
|
||||
Table,
|
||||
Tag
|
||||
} from 'antdv-next';
|
||||
|
||||
import TagEditModal from './components/tag-edit-modal.vue';
|
||||
|
||||
defineOptions({ name: 'DynamicTagList' });
|
||||
|
||||
const accessStore = useAccessStore();
|
||||
const sysOriginOptions = getAllowedSysOrigins(accessStore.accessCodes || []);
|
||||
|
||||
const loading = ref(false);
|
||||
const total = ref(0);
|
||||
const list = ref<Array<Record<string, any>>>([]);
|
||||
const modalOpen = ref(false);
|
||||
const activeRecord = ref<null | Record<string, any>>(null);
|
||||
|
||||
const query = reactive({
|
||||
cursor: 1,
|
||||
del: false as boolean,
|
||||
languageType: '',
|
||||
limit: 20,
|
||||
sysOrigin: sysOriginOptions[0]?.value ?? 'LIKEI',
|
||||
});
|
||||
|
||||
const columns = [
|
||||
{ dataIndex: 'id', key: 'id', title: 'ID', width: 90 },
|
||||
{ dataIndex: 'sysOrigin', key: 'sysOrigin', title: '归属系统', width: 120 },
|
||||
{ dataIndex: 'imageUrl', key: 'imageUrl', title: '背景', width: 240 },
|
||||
{ dataIndex: 'tag', key: 'tag', title: '标签', width: 160 },
|
||||
{ dataIndex: 'description', key: 'description', title: '描述', width: 220 },
|
||||
{ dataIndex: 'sort', key: 'sort', title: '排序', width: 100 },
|
||||
{ dataIndex: 'languageType', key: 'languageType', title: '语言', width: 120 },
|
||||
{ dataIndex: 'del', key: 'del', title: '状态', width: 120 },
|
||||
{ dataIndex: 'updateTime', key: 'updateTime', title: '更新时间', width: 180 },
|
||||
{ dataIndex: 'actions', key: 'actions', title: '操作', width: 100 },
|
||||
];
|
||||
|
||||
const scroll = computed(() => ({ x: 1500 }));
|
||||
|
||||
function getLanguage(value?: string) {
|
||||
return LANGUAGE_OPTIONS.find((item) => item.value === value)?.name || '-';
|
||||
}
|
||||
|
||||
async function loadData(reset = false) {
|
||||
if (reset) {
|
||||
query.cursor = 1;
|
||||
}
|
||||
loading.value = true;
|
||||
try {
|
||||
const result = await dynamicTagTable({ ...query });
|
||||
list.value = result.records || [];
|
||||
total.value = result.total || 0;
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function handleSearch() {
|
||||
loadData(true);
|
||||
}
|
||||
|
||||
function handlePageChange(page: number, pageSize: number) {
|
||||
query.cursor = page;
|
||||
query.limit = pageSize;
|
||||
loadData();
|
||||
}
|
||||
|
||||
function openCreate() {
|
||||
activeRecord.value = null;
|
||||
modalOpen.value = true;
|
||||
}
|
||||
|
||||
function openEdit(record: Record<string, any>) {
|
||||
activeRecord.value = { ...record };
|
||||
modalOpen.value = true;
|
||||
}
|
||||
|
||||
loadData(true);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Page title="标签列表">
|
||||
<Card>
|
||||
<div class="toolbar">
|
||||
<Space wrap>
|
||||
<SysOriginSelect
|
||||
v-model:value="query.sysOrigin"
|
||||
style="width: 140px"
|
||||
@change="handleSearch"
|
||||
|
||||
:options="sysOriginOptions"
|
||||
></SysOriginSelect>
|
||||
<Select
|
||||
v-model:value="query.del"
|
||||
option-label-prop="label"
|
||||
style="width: 140px"
|
||||
@change="handleSearch"
|
||||
|
||||
:options="[{ label: '上架', value: false as any }, { label: '下架', value: true as any }]"
|
||||
/>
|
||||
<Select
|
||||
v-model:value="query.languageType"
|
||||
allow-clear
|
||||
option-label-prop="label"
|
||||
placeholder="语言"
|
||||
style="width: 160px"
|
||||
@change="handleSearch"
|
||||
|
||||
:options="LANGUAGE_OPTIONS.map((item) => ({ label: item.name, value: item.value as any }))"
|
||||
/>
|
||||
<Button :loading="loading" type="primary" @click="handleSearch">
|
||||
搜索
|
||||
</Button>
|
||||
<Button @click="openCreate">新增</Button>
|
||||
</Space>
|
||||
</div>
|
||||
|
||||
<Table
|
||||
:columns="columns"
|
||||
:data-source="list"
|
||||
:loading="loading"
|
||||
:pagination="false"
|
||||
:scroll="scroll"
|
||||
row-key="id"
|
||||
>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.key === 'sysOrigin'">
|
||||
<SysOriginLabel :value="record.sysOrigin" />
|
||||
</template>
|
||||
<template v-else-if="column.key === 'imageUrl'">
|
||||
<Image :src="record.imageUrl" class="cover-image" />
|
||||
</template>
|
||||
<template v-else-if="column.key === 'languageType'">
|
||||
{{ getLanguage(record.languageType) }}
|
||||
</template>
|
||||
<template v-else-if="column.key === 'del'">
|
||||
<Tag :color="record.del ? 'error' : 'success'">
|
||||
{{ record.del ? '已下架' : '已上架' }}
|
||||
</Tag>
|
||||
</template>
|
||||
<template v-else-if="column.key === 'updateTime'">
|
||||
{{ formatDate(record.updateTime || record.createTime) }}
|
||||
</template>
|
||||
<template v-else-if="column.key === 'actions'">
|
||||
<Button size="small" type="link" @click="openEdit(record)">
|
||||
修改
|
||||
</Button>
|
||||
</template>
|
||||
</template>
|
||||
</Table>
|
||||
|
||||
<div class="pagination">
|
||||
<Pagination
|
||||
:current="query.cursor"
|
||||
:page-size="query.limit"
|
||||
:total="total"
|
||||
show-size-changer
|
||||
@change="handlePageChange"
|
||||
@showSizeChange="handlePageChange"
|
||||
/>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
<TagEditModal
|
||||
:open="modalOpen"
|
||||
:record="activeRecord"
|
||||
:sys-origin-options="sysOriginOptions"
|
||||
@close="modalOpen = false"
|
||||
@success="loadData(true)"
|
||||
/>
|
||||
</Page>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.toolbar {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.cover-image {
|
||||
border-radius: 12px;
|
||||
height: 84px;
|
||||
object-fit: cover;
|
||||
width: 168px;
|
||||
}
|
||||
|
||||
.pagination {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin-top: 16px;
|
||||
}
|
||||
</style>
|
||||
@ -1,519 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import {
|
||||
computed,
|
||||
reactive,
|
||||
ref,
|
||||
watch } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
|
||||
import { Page } from '@vben/common-ui';
|
||||
import { useAccessStore } from '@vben/stores';
|
||||
|
||||
import {
|
||||
closeUserDynamicTop,
|
||||
deleteUserDynamic,
|
||||
setUserDynamicTop,
|
||||
userDynamicTable,
|
||||
} from '#/api/legacy/dynamic';
|
||||
import AccountInput from '#/components/account-input.vue';
|
||||
import SysOriginTag from '#/components/sys-origin-tag.vue';
|
||||
import { formatDate,
|
||||
getAllowedSysOrigins } from '#/views/system/shared';
|
||||
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
Checkbox,
|
||||
Col,
|
||||
DateRangePicker,
|
||||
Empty,
|
||||
Image,
|
||||
InputNumber,
|
||||
Modal,
|
||||
Pagination,
|
||||
Row,
|
||||
Select,
|
||||
Space,
|
||||
Spin,
|
||||
Tag,
|
||||
message
|
||||
} from 'antdv-next';
|
||||
|
||||
import AccountHandleModal from '#/views/approval/components/account-handle-modal.vue';
|
||||
|
||||
defineOptions({ name: 'DynamicUserDynamicList' });
|
||||
|
||||
const router = useRouter();
|
||||
const accessStore = useAccessStore();
|
||||
const sysOriginOptions = getAllowedSysOrigins(accessStore.accessCodes || []);
|
||||
|
||||
const loading = ref(false);
|
||||
const total = ref(0);
|
||||
const list = ref<Array<Record<string, any>>>([]);
|
||||
const rangeDate = ref<[string, string] | null>(null);
|
||||
const selectedKeys = ref<string[]>([]);
|
||||
const topModalOpen = ref(false);
|
||||
const topSaving = ref(false);
|
||||
const accountHandleOpen = ref(false);
|
||||
const activeUserId = ref('');
|
||||
const topForm = reactive({
|
||||
dynamicId: '',
|
||||
sysOrigin: '',
|
||||
weights: undefined as number | undefined,
|
||||
});
|
||||
|
||||
const query = reactive({
|
||||
cursor: 1,
|
||||
endTime: '',
|
||||
limit: 30,
|
||||
startTime: '',
|
||||
sysOrigin: sysOriginOptions[0]?.value ?? 'LIKEI',
|
||||
top: '',
|
||||
userId: '',
|
||||
});
|
||||
|
||||
watch(rangeDate, (value) => {
|
||||
query.startTime = value?.[0] || '';
|
||||
query.endTime = value?.[1] || '';
|
||||
});
|
||||
|
||||
const allChecked = computed(
|
||||
() => list.value.length > 0 && selectedKeys.value.length === list.value.length,
|
||||
);
|
||||
const indeterminate = computed(
|
||||
() =>
|
||||
selectedKeys.value.length > 0 &&
|
||||
selectedKeys.value.length < list.value.length,
|
||||
);
|
||||
|
||||
function getPictures(record: Record<string, any>) {
|
||||
return (Array.isArray(record.pictures) ? record.pictures : [])
|
||||
.map((item: any) => item?.resourceUrl || item?.url || '')
|
||||
.filter(Boolean);
|
||||
}
|
||||
|
||||
function getUserAvatar(record: Record<string, any>) {
|
||||
return record.userBaseInfo?.userAvatar || record.userAvatar || '';
|
||||
}
|
||||
|
||||
function getUserName(record: Record<string, any>) {
|
||||
return record.userBaseInfo?.userNickname || record.userNickname || '-';
|
||||
}
|
||||
|
||||
function getUserAccount(record: Record<string, any>) {
|
||||
return record.userBaseInfo?.actualAccount || record.actualAccount || '-';
|
||||
}
|
||||
|
||||
function getRowKey(record: Record<string, any>) {
|
||||
return String(record.id || '');
|
||||
}
|
||||
|
||||
async function loadData(reset = false) {
|
||||
if (reset) {
|
||||
query.cursor = 1;
|
||||
}
|
||||
loading.value = true;
|
||||
try {
|
||||
const result = await userDynamicTable({ ...query });
|
||||
list.value = result.records || [];
|
||||
total.value = result.total || 0;
|
||||
selectedKeys.value = [];
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function handleSearch() {
|
||||
loadData(true);
|
||||
}
|
||||
|
||||
function handlePageChange(page: number, pageSize: number) {
|
||||
query.cursor = page;
|
||||
query.limit = pageSize;
|
||||
loadData();
|
||||
}
|
||||
|
||||
function toggleAll(checked: boolean) {
|
||||
selectedKeys.value = checked ? list.value.map((item) => getRowKey(item)) : [];
|
||||
}
|
||||
|
||||
function toggleRecord(record: Record<string, any>) {
|
||||
const key = getRowKey(record);
|
||||
const index = selectedKeys.value.findIndex((item) => item === key);
|
||||
if (index >= 0) {
|
||||
selectedKeys.value.splice(index, 1);
|
||||
return;
|
||||
}
|
||||
selectedKeys.value.push(key);
|
||||
}
|
||||
|
||||
function openUserDetails(record: Record<string, any>) {
|
||||
const userId = record.userId || record.userBaseInfo?.id;
|
||||
if (!userId) {
|
||||
return;
|
||||
}
|
||||
router.push(`/common/user/deatils/${userId}`);
|
||||
}
|
||||
|
||||
function openAccountHandle(record: Record<string, any>) {
|
||||
activeUserId.value = String(record.userId || record.userBaseInfo?.id || '');
|
||||
accountHandleOpen.value = true;
|
||||
}
|
||||
|
||||
function openTopEdit(record: Record<string, any>) {
|
||||
topForm.dynamicId = String(record.id || '');
|
||||
topForm.sysOrigin = query.sysOrigin;
|
||||
topForm.weights = Number(record.weights || 0);
|
||||
topModalOpen.value = true;
|
||||
}
|
||||
|
||||
async function handleCloseTop(record: Record<string, any>) {
|
||||
await closeUserDynamicTop(record.id);
|
||||
message.success('操作成功');
|
||||
await loadData(true);
|
||||
}
|
||||
|
||||
async function handleSubmitTop() {
|
||||
if (!topForm.dynamicId) {
|
||||
return;
|
||||
}
|
||||
if (topForm.weights === undefined || topForm.weights === null) {
|
||||
message.warning('请输入权重');
|
||||
return;
|
||||
}
|
||||
topSaving.value = true;
|
||||
try {
|
||||
await setUserDynamicTop({
|
||||
dynamicId: topForm.dynamicId,
|
||||
sysOrigin: topForm.sysOrigin,
|
||||
weights: topForm.weights,
|
||||
});
|
||||
message.success('保存成功');
|
||||
topModalOpen.value = false;
|
||||
await loadData(true);
|
||||
} finally {
|
||||
topSaving.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
function handleDeleteSelected() {
|
||||
if (selectedKeys.value.length === 0) {
|
||||
message.warning('请勾选审批项');
|
||||
return;
|
||||
}
|
||||
Modal.confirm({
|
||||
title: '确认删除选中记录吗?',
|
||||
async onOk() {
|
||||
await deleteUserDynamic(selectedKeys.value);
|
||||
message.success('删除成功');
|
||||
await loadData();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
loadData(true);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Page title="用户动态">
|
||||
<div class="page-grid">
|
||||
<Card>
|
||||
<div class="toolbar">
|
||||
<Space wrap>
|
||||
<SysOriginSelect
|
||||
v-model:value="query.sysOrigin"
|
||||
style="width: 140px"
|
||||
@change="handleSearch"
|
||||
|
||||
:options="sysOriginOptions"
|
||||
></SysOriginSelect>
|
||||
<Select
|
||||
v-model:value="query.top"
|
||||
option-label-prop="label"
|
||||
style="width: 140px"
|
||||
@change="handleSearch"
|
||||
|
||||
:options="[{ label: '全部', value: '' as any }, { label: '已置顶', value: '1' as any }, { label: '未置顶', value: '0' as any }]"
|
||||
/>
|
||||
<DateRangePicker
|
||||
v-model:value="rangeDate"
|
||||
show-time
|
||||
style="width: 360px"
|
||||
value-format="x"
|
||||
/>
|
||||
<AccountInput
|
||||
v-model:value="query.userId"
|
||||
:sys-origin="query.sysOrigin"
|
||||
placeholder="用户ID"
|
||||
style="width: 220px"
|
||||
/>
|
||||
<Button :loading="loading" type="primary" @click="handleSearch">
|
||||
搜索
|
||||
</Button>
|
||||
</Space>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<div class="selection-bar">
|
||||
<Checkbox
|
||||
:checked="allChecked"
|
||||
:indeterminate="indeterminate"
|
||||
@change="(event) => toggleAll(!!event.target.checked)"
|
||||
>
|
||||
全选
|
||||
</Checkbox>
|
||||
<span class="selection-text">
|
||||
已勾选 <strong>{{ selectedKeys.length }}</strong>
|
||||
</span>
|
||||
<Button danger @click="handleDeleteSelected">删除</Button>
|
||||
</div>
|
||||
|
||||
<Spin :spinning="loading">
|
||||
<Empty v-if="list.length === 0" description="暂无动态" />
|
||||
<Row v-else :gutter="[16, 16]">
|
||||
<Col
|
||||
v-for="record in list"
|
||||
:key="getRowKey(record)"
|
||||
:lg="8"
|
||||
:md="12"
|
||||
:sm="24"
|
||||
:xs="24"
|
||||
>
|
||||
<Card class="dynamic-card">
|
||||
<div class="card-header">
|
||||
<Checkbox
|
||||
:checked="selectedKeys.includes(getRowKey(record))"
|
||||
@change="() => toggleRecord(record)"
|
||||
>
|
||||
选中
|
||||
</Checkbox>
|
||||
<Tag v-if="record.top === true" color="magenta">
|
||||
置顶权重:{{ record.weights || 0 }}
|
||||
</Tag>
|
||||
</div>
|
||||
|
||||
<div class="content-block">
|
||||
<div class="content-label">动态内容</div>
|
||||
<div class="content-text">{{ record.content || '-' }}</div>
|
||||
</div>
|
||||
|
||||
<div v-if="getPictures(record).length > 0" class="picture-row">
|
||||
<div
|
||||
v-for="item in getPictures(record)"
|
||||
:key="item"
|
||||
class="picture-item"
|
||||
>
|
||||
<Image :src="item" class="picture-image" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="user-row">
|
||||
<img
|
||||
:src="getUserAvatar(record) || 'https://dummyimage.com/48x48/e2e8f0/64748b&text=U'"
|
||||
alt=""
|
||||
class="user-avatar"
|
||||
>
|
||||
<div class="user-meta">
|
||||
<Button class="user-link" type="link" @click="openUserDetails(record)">
|
||||
{{ getUserName(record) }}
|
||||
</Button>
|
||||
<div class="meta-line">{{ getUserAccount(record) }}</div>
|
||||
<div class="meta-line">
|
||||
性别:{{ record.userSexName || '-' }} / 年龄:{{ record.userBaseInfo?.age || '-' }}
|
||||
</div>
|
||||
<div class="meta-line">创建时间:{{ formatDate(record.createTime) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-actions">
|
||||
<Button size="small" type="link" @click="openAccountHandle(record)">
|
||||
账号处理
|
||||
</Button>
|
||||
<Button size="small" type="link" @click="openTopEdit(record)">
|
||||
置顶
|
||||
</Button>
|
||||
<Button
|
||||
v-if="record.top === true"
|
||||
size="small"
|
||||
type="link"
|
||||
@click="handleCloseTop(record)"
|
||||
>
|
||||
取消置顶
|
||||
</Button>
|
||||
</div>
|
||||
</Card>
|
||||
</Col>
|
||||
</Row>
|
||||
</Spin>
|
||||
|
||||
<div class="pagination">
|
||||
<Pagination
|
||||
:current="query.cursor"
|
||||
:page-size="query.limit"
|
||||
:total="total"
|
||||
show-size-changer
|
||||
@change="handlePageChange"
|
||||
@showSizeChange="handlePageChange"
|
||||
/>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
<Modal
|
||||
:confirm-loading="topSaving"
|
||||
:open="topModalOpen"
|
||||
destroy-on-close
|
||||
title="编辑置顶动态"
|
||||
@cancel="topModalOpen = false"
|
||||
@ok="handleSubmitTop"
|
||||
>
|
||||
<div class="top-form">
|
||||
<div class="top-row">
|
||||
<span>平台</span>
|
||||
<SysOriginTag :value="query.sysOrigin" />
|
||||
</div>
|
||||
<div class="top-row top-input">
|
||||
<span>权重</span>
|
||||
<InputNumber
|
||||
v-model:value="topForm.weights"
|
||||
:min="0"
|
||||
placeholder="数字越大越排在前面"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
<AccountHandleModal
|
||||
:open="accountHandleOpen"
|
||||
:user-id="activeUserId"
|
||||
@close="accountHandleOpen = false"
|
||||
@success="loadData()"
|
||||
/>
|
||||
</Page>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.page-grid {
|
||||
display: grid;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.toolbar {
|
||||
min-height: 40px;
|
||||
}
|
||||
|
||||
.selection-bar {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.selection-text {
|
||||
color: #64748b;
|
||||
}
|
||||
|
||||
.dynamic-card {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.content-block {
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
|
||||
.content-label {
|
||||
color: #2563eb;
|
||||
font-weight: 600;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.content-text {
|
||||
color: #334155;
|
||||
line-height: 1.7;
|
||||
min-height: 48px;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.picture-row {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
margin-bottom: 14px;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.picture-item {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.picture-image {
|
||||
border-radius: 12px;
|
||||
height: 220px;
|
||||
object-fit: cover;
|
||||
width: 180px;
|
||||
}
|
||||
|
||||
.user-row {
|
||||
align-items: flex-start;
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.user-avatar {
|
||||
border-radius: 999px;
|
||||
height: 48px;
|
||||
object-fit: cover;
|
||||
width: 48px;
|
||||
}
|
||||
|
||||
.user-meta {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.user-link {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.meta-line {
|
||||
color: #64748b;
|
||||
line-height: 1.8;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.card-actions {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 4px;
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.pagination {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.top-form {
|
||||
display: grid;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.top-row {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.top-input {
|
||||
align-items: stretch;
|
||||
flex-direction: column;
|
||||
}
|
||||
</style>
|
||||
@ -232,7 +232,6 @@ export const CURRENCY_ORIGIN_OPTIONS = [
|
||||
{ value: 'USER_REFUND', name: '用户退款' },
|
||||
{ value: 'ACTIVITY_FRIENDSHIP_CARD_REWARDS', name: '每周特殊关系卡片奖励' },
|
||||
{ value: 'WEEKLY_GAME_TASKS', name: '每周游戏任务奖励' },
|
||||
{ value: 'SEND_DYNAMIC_PAY_GOLD', name: '超限制发动态支付金币' },
|
||||
{ value: 'BUY_EMOJI', name: '购买表情包' },
|
||||
{ value: 'BET_TEEN_PATTI', name: '炸金花' },
|
||||
{ value: 'TEEN_PATTI', name: '炸金花游戏 ' },
|
||||
|
||||
@ -82,7 +82,7 @@ const pageActionOpen = ref(false);
|
||||
const tableAreaRef = ref<HTMLDivElement | null>(null);
|
||||
const pagerRef = ref<HTMLDivElement | null>(null);
|
||||
const tableScrollY = ref(320);
|
||||
const amountFormatter = new Intl.NumberFormat('en-US', {
|
||||
const amountFormatter = new Intl.NumberFormat('zh-CN', {
|
||||
maximumFractionDigits: 2,
|
||||
});
|
||||
const tableScroll = computed(() => ({ x: 1000, y: tableScrollY.value }));
|
||||
@ -685,7 +685,7 @@ loadData(true);
|
||||
</template>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.key === 'cover'">
|
||||
<RewardIcon :item="record" :size="48" />
|
||||
<RewardIcon :item="record" :size="42" />
|
||||
</template>
|
||||
<template v-else-if="column.key === 'del'">
|
||||
<Switch
|
||||
@ -893,6 +893,7 @@ loadData(true);
|
||||
|
||||
:global(.table-action-menu__item) {
|
||||
color: rgb(71 84 103);
|
||||
height: var(--density-button-height) !important;
|
||||
justify-content: flex-start;
|
||||
padding-inline: 10px;
|
||||
text-align: left;
|
||||
@ -931,6 +932,7 @@ loadData(true);
|
||||
|
||||
.resource-table :deep(.ant-table) {
|
||||
color: rgb(52 64 84);
|
||||
font-size: var(--density-table-body-font-size);
|
||||
}
|
||||
|
||||
.resource-table {
|
||||
@ -962,10 +964,11 @@ loadData(true);
|
||||
background: #fafafa;
|
||||
border-bottom-color: rgb(237 240 244);
|
||||
color: rgb(71 84 103);
|
||||
font-size: var(--font-size-base);
|
||||
font-size: var(--density-table-header-font-size);
|
||||
font-weight: 500;
|
||||
line-height: 1.35;
|
||||
padding: 10px 16px;
|
||||
height: var(--density-table-header-height);
|
||||
padding: 8px var(--density-table-cell-padding-x);
|
||||
}
|
||||
|
||||
.resource-table :deep(.ant-table-thead > tr > th::before) {
|
||||
@ -974,9 +977,9 @@ loadData(true);
|
||||
|
||||
.resource-table :deep(.ant-table-tbody > tr > td) {
|
||||
border-bottom-color: rgb(237 240 244);
|
||||
height: 54px;
|
||||
height: var(--density-table-row-height);
|
||||
line-height: 1.35;
|
||||
padding: 3px 16px;
|
||||
padding: 3px var(--density-table-cell-padding-x);
|
||||
}
|
||||
|
||||
.resource-table :deep(.ant-table-body) {
|
||||
@ -984,13 +987,13 @@ loadData(true);
|
||||
}
|
||||
|
||||
.resource-table :deep(.switch-column) {
|
||||
padding-left: 5px !important;
|
||||
padding-right: 5px !important;
|
||||
padding-left: var(--density-table-fixed-cell-padding-x) !important;
|
||||
padding-right: var(--density-table-fixed-cell-padding-x) !important;
|
||||
}
|
||||
|
||||
.resource-table :deep(.action-column) {
|
||||
padding-left: 5px !important;
|
||||
padding-right: 5px !important;
|
||||
padding-left: var(--density-table-fixed-cell-padding-x) !important;
|
||||
padding-right: var(--density-table-fixed-cell-padding-x) !important;
|
||||
}
|
||||
|
||||
.resource-table :deep(.ant-table-tbody > tr:hover > td) {
|
||||
|
||||
@ -35,7 +35,7 @@ function formatPrice(value: any) {
|
||||
if (!Number.isFinite(amount)) {
|
||||
return String(value || '-');
|
||||
}
|
||||
return amount.toLocaleString('en-US', {
|
||||
return amount.toLocaleString('zh-CN', {
|
||||
maximumFractionDigits: 2,
|
||||
});
|
||||
}
|
||||
@ -123,7 +123,7 @@ onBeforeUnmount(() => {
|
||||
"
|
||||
alt=""
|
||||
class="latest-purchase__avatar"
|
||||
>
|
||||
/>
|
||||
<div class="latest-purchase__content">
|
||||
<div class="latest-purchase__header">
|
||||
<span
|
||||
|
||||
@ -26,7 +26,7 @@ function normalizeNumber(value: any) {
|
||||
}
|
||||
|
||||
function formatValue(value: number) {
|
||||
return value.toLocaleString('en-US', {
|
||||
return value.toLocaleString('zh-CN', {
|
||||
maximumFractionDigits: 2,
|
||||
});
|
||||
}
|
||||
|
||||
@ -768,13 +768,13 @@ function calcPercent(numerator?: null | number | string, denominator?: null | nu
|
||||
|
||||
function formatInteger(value?: null | number | string) {
|
||||
const number = Number(value || 0);
|
||||
return Number.isFinite(number) ? number.toLocaleString('en-US', { maximumFractionDigits: 0 }) : '0';
|
||||
return Number.isFinite(number) ? number.toLocaleString('zh-CN', { maximumFractionDigits: 0 }) : '0';
|
||||
}
|
||||
|
||||
function formatAmount(value?: null | number | string) {
|
||||
const number = Number(value || 0);
|
||||
return Number.isFinite(number)
|
||||
? number.toLocaleString('en-US', {
|
||||
? number.toLocaleString('zh-CN', {
|
||||
maximumFractionDigits: 2,
|
||||
minimumFractionDigits: 0,
|
||||
})
|
||||
@ -784,7 +784,7 @@ function formatAmount(value?: null | number | string) {
|
||||
function formatPercent(value?: null | number | string) {
|
||||
const number = Number(value || 0);
|
||||
return Number.isFinite(number)
|
||||
? `${number.toLocaleString('en-US', {
|
||||
? `${number.toLocaleString('zh-CN', {
|
||||
maximumFractionDigits: 2,
|
||||
minimumFractionDigits: 2,
|
||||
})}%`
|
||||
|
||||
@ -27,7 +27,6 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@intlify/unplugin-vue-i18n": "catalog:",
|
||||
"@jspm/generator": "catalog:",
|
||||
"@tailwindcss/vite": "catalog:",
|
||||
"@vben/node-utils": "workspace:*",
|
||||
|
||||
@ -33,7 +33,6 @@ function defineApplicationConfig(userConfigPromise?: DefineApplicationOptions) {
|
||||
env,
|
||||
extraAppConfig: true,
|
||||
html: true,
|
||||
i18n: true,
|
||||
importmapOptions: defaultImportmapOptions,
|
||||
injectAppLoading: true,
|
||||
injectMetadata: true,
|
||||
|
||||
@ -36,7 +36,6 @@ const defaultImportmapOptions: ImportmapPluginOptions = {
|
||||
{ name: 'vue' },
|
||||
{ name: 'pinia' },
|
||||
{ name: 'vue-router' },
|
||||
// { name: 'vue-i18n' },
|
||||
{ name: 'dayjs' },
|
||||
{ name: 'vue-demi' },
|
||||
],
|
||||
|
||||
@ -7,7 +7,6 @@ import type {
|
||||
LibraryPluginOptions,
|
||||
} from '../typing';
|
||||
|
||||
import viteVueI18nPlugin from '@intlify/unplugin-vue-i18n/vite';
|
||||
import tailwindcss from '@tailwindcss/vite';
|
||||
import viteVue from '@vitejs/plugin-vue';
|
||||
import viteVueJsx from '@vitejs/plugin-vue-jsx';
|
||||
@ -104,7 +103,6 @@ async function loadApplicationPlugins(
|
||||
compressTypes,
|
||||
extraAppConfig,
|
||||
html,
|
||||
i18n,
|
||||
importmap,
|
||||
importmapOptions,
|
||||
injectAppLoading,
|
||||
@ -121,18 +119,6 @@ async function loadApplicationPlugins(
|
||||
|
||||
return await loadConditionPlugins([
|
||||
...commonPlugins,
|
||||
{
|
||||
condition: i18n,
|
||||
plugins: async () => {
|
||||
return [
|
||||
viteVueI18nPlugin({
|
||||
compositionOnly: true,
|
||||
fullInstall: true,
|
||||
runtimeOnly: true,
|
||||
}),
|
||||
];
|
||||
},
|
||||
},
|
||||
{
|
||||
condition: print,
|
||||
plugins: async () => {
|
||||
|
||||
@ -194,11 +194,6 @@ interface ApplicationPluginOptions extends CommonPluginOptions {
|
||||
* @default true
|
||||
*/
|
||||
html?: boolean;
|
||||
/**
|
||||
* 是否开启国际化
|
||||
* @default false
|
||||
*/
|
||||
i18n?: boolean;
|
||||
/**
|
||||
* 是否开启 ImportMap CDN
|
||||
* @default false
|
||||
|
||||
@ -93,7 +93,24 @@
|
||||
|
||||
/* 基本文字大小 */
|
||||
--font-size-base: 14px;
|
||||
--menu-font-size: calc(var(--font-size-base) * 0.875);
|
||||
--menu-font-size: var(--font-size-base);
|
||||
|
||||
/* 后台紧凑密度 */
|
||||
--density-button-height: 30px;
|
||||
--density-button-sm-height: 24px;
|
||||
--density-menu-font-size: 14px;
|
||||
--density-menu-icon-size: 16px;
|
||||
--density-menu-indent: 12px;
|
||||
--density-menu-item-height: 40px;
|
||||
--density-sub-menu-item-height: 36px;
|
||||
--density-pagination-height: 28px;
|
||||
--density-resource-image-size: 42px;
|
||||
--density-table-body-font-size: 13px;
|
||||
--density-table-cell-padding-x: 12px;
|
||||
--density-table-fixed-cell-padding-x: 6px;
|
||||
--density-table-header-font-size: 13px;
|
||||
--density-table-header-height: 42px;
|
||||
--density-table-row-height: 54px;
|
||||
|
||||
/* =============component & UI============= */
|
||||
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
# Simple i18n
|
||||
# Simple Messages
|
||||
|
||||
Simple i18 implementation
|
||||
Static Chinese messages for shared UI defaults.
|
||||
|
||||
@ -1,27 +1,17 @@
|
||||
import type { Locale } from './messages';
|
||||
|
||||
import { computed, ref } from 'vue';
|
||||
import { computed } from 'vue';
|
||||
|
||||
import { createSharedComposable } from '@vueuse/core';
|
||||
|
||||
import { getMessages } from './messages';
|
||||
|
||||
export const useSimpleLocale = createSharedComposable(() => {
|
||||
const currentLocale = ref<Locale>('zh-CN');
|
||||
|
||||
const setSimpleLocale = (locale: Locale) => {
|
||||
currentLocale.value = locale;
|
||||
};
|
||||
|
||||
const $t = computed(() => {
|
||||
const localeMessages = getMessages(currentLocale.value);
|
||||
const localeMessages = getMessages();
|
||||
return (key: string) => {
|
||||
return localeMessages[key] || key;
|
||||
};
|
||||
});
|
||||
return {
|
||||
$t,
|
||||
currentLocale,
|
||||
setSimpleLocale,
|
||||
};
|
||||
});
|
||||
|
||||
@ -1,24 +1,11 @@
|
||||
export type Locale = 'en-US' | 'zh-CN';
|
||||
|
||||
export const messages: Record<Locale, Record<string, string>> = {
|
||||
'en-US': {
|
||||
cancel: 'Cancel',
|
||||
collapse: 'Collapse',
|
||||
confirm: 'Confirm',
|
||||
expand: 'Expand',
|
||||
prompt: 'Prompt',
|
||||
reset: 'Reset',
|
||||
submit: 'Submit',
|
||||
},
|
||||
'zh-CN': {
|
||||
cancel: '取消',
|
||||
collapse: '收起',
|
||||
confirm: '确认',
|
||||
expand: '展开',
|
||||
prompt: '提示',
|
||||
reset: '重置',
|
||||
submit: '提交',
|
||||
},
|
||||
export const messages: Record<string, string> = {
|
||||
cancel: '取消',
|
||||
collapse: '收起',
|
||||
confirm: '确认',
|
||||
expand: '展开',
|
||||
prompt: '提示',
|
||||
reset: '重置',
|
||||
submit: '提交',
|
||||
};
|
||||
|
||||
export const getMessages = (locale: Locale) => messages[locale];
|
||||
export const getMessages = () => messages;
|
||||
|
||||
@ -26,7 +26,6 @@ exports[`defaultPreferences immutability test > should not modify the config obj
|
||||
"enableStickyPreferencesNavigationBar": true,
|
||||
"isMobile": false,
|
||||
"layout": "sidebar-nav",
|
||||
"locale": "zh-CN",
|
||||
"loginExpiredMode": "page",
|
||||
"name": "Vben Admin",
|
||||
"preferencesButtonPosition": "auto",
|
||||
@ -117,7 +116,6 @@ exports[`defaultPreferences immutability test > should not modify the config obj
|
||||
"widget": {
|
||||
"fullscreen": true,
|
||||
"globalSearch": true,
|
||||
"languageToggle": true,
|
||||
"lockScreen": true,
|
||||
"refresh": true,
|
||||
"sidebarToggle": true,
|
||||
|
||||
@ -32,7 +32,7 @@ describe('preferences', () => {
|
||||
it('initializes preferences with overrides', async () => {
|
||||
const overrides: any = {
|
||||
app: {
|
||||
locale: 'en-US',
|
||||
name: '测试后台',
|
||||
},
|
||||
};
|
||||
await preferenceManager.initPreferences({
|
||||
@ -110,14 +110,6 @@ describe('preferences', () => {
|
||||
expect(preferenceManager.getPreferences().app.isMobile).toBe(true);
|
||||
});
|
||||
|
||||
it('updates the locale preference correctly', () => {
|
||||
preferenceManager.updatePreferences({
|
||||
app: { locale: 'en-US' },
|
||||
});
|
||||
|
||||
expect(preferenceManager.getPreferences().app.locale).toBe('en-US');
|
||||
});
|
||||
|
||||
it('updates the sidebar width correctly', () => {
|
||||
preferenceManager.updatePreferences({
|
||||
sidebar: { width: 200 },
|
||||
@ -145,7 +137,7 @@ describe('preferences', () => {
|
||||
it('resets preferences to default correctly', () => {
|
||||
// 先更新一些偏好设置
|
||||
preferenceManager.updatePreferences({
|
||||
app: { locale: 'en-US' },
|
||||
app: { name: '测试后台' },
|
||||
sidebar: { collapsed: true, width: 200 },
|
||||
theme: {
|
||||
radius: '0.75',
|
||||
@ -169,15 +161,13 @@ describe('preferences', () => {
|
||||
});
|
||||
|
||||
it('reverts to default when a preference field is deleted', () => {
|
||||
preferenceManager.updatePreferences({
|
||||
app: { locale: 'en-US' },
|
||||
});
|
||||
const originalName = preferenceManager.getPreferences().app.name;
|
||||
|
||||
preferenceManager.updatePreferences({
|
||||
app: { locale: undefined },
|
||||
app: { name: undefined },
|
||||
});
|
||||
|
||||
expect(preferenceManager.getPreferences().app.locale).toBe('en-US');
|
||||
expect(preferenceManager.getPreferences().app.name).toBe(originalName);
|
||||
});
|
||||
|
||||
it('ignores updates with invalid preference value types', () => {
|
||||
@ -209,7 +199,7 @@ describe('preferences', () => {
|
||||
it('applies updates immediately after initialization', async () => {
|
||||
const overrides: any = {
|
||||
app: {
|
||||
locale: 'en-US',
|
||||
name: '测试后台',
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@ -26,7 +26,6 @@ const defaultPreferences: Preferences = {
|
||||
enableStickyPreferencesNavigationBar: true,
|
||||
isMobile: false,
|
||||
layout: 'sidebar-nav',
|
||||
locale: 'zh-CN',
|
||||
loginExpiredMode: 'page',
|
||||
name: 'Vben Admin',
|
||||
preferencesButtonPosition: 'auto',
|
||||
@ -118,7 +117,6 @@ const defaultPreferences: Preferences = {
|
||||
widget: {
|
||||
fullscreen: true,
|
||||
globalSearch: true,
|
||||
languageToggle: true,
|
||||
lockScreen: true,
|
||||
refresh: true,
|
||||
sidebarToggle: true,
|
||||
|
||||
@ -18,7 +18,6 @@ import { updateCSSVariables } from './update-css-variables';
|
||||
|
||||
const STORAGE_KEYS = {
|
||||
MAIN: 'preferences',
|
||||
LOCALE: 'preferences-locale',
|
||||
} as const;
|
||||
|
||||
function pickKnownPreferences(preferences: DeepPartial<Preferences>) {
|
||||
@ -203,7 +202,6 @@ class PreferenceManager {
|
||||
*/
|
||||
private saveToCache(preference: Preferences) {
|
||||
this.cache.setItem(STORAGE_KEYS.MAIN, preference);
|
||||
this.cache.setItem(STORAGE_KEYS.LOCALE, preference.app.locale);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -13,8 +13,6 @@ import type {
|
||||
TabsStyleType,
|
||||
} from '@vben-core/typings';
|
||||
|
||||
type SupportedLanguagesType = 'en-US' | 'zh-CN';
|
||||
|
||||
interface AppPreferences {
|
||||
/** 权限模式 */
|
||||
accessMode: AccessModeType;
|
||||
@ -66,8 +64,6 @@ interface AppPreferences {
|
||||
isMobile: boolean;
|
||||
/** 布局方式 */
|
||||
layout: LayoutType;
|
||||
/** 支持的语言 */
|
||||
locale: SupportedLanguagesType;
|
||||
/** 登录过期模式 */
|
||||
loginExpiredMode: LoginExpiredModeType;
|
||||
/** 应用名 */
|
||||
@ -241,8 +237,6 @@ interface WidgetPreferences {
|
||||
fullscreen: boolean;
|
||||
/** 是否启用全局搜索部件 */
|
||||
globalSearch: boolean;
|
||||
/** 是否启用语言切换部件 */
|
||||
languageToggle: boolean;
|
||||
/** 是否开启锁屏功能 */
|
||||
lockScreen: boolean;
|
||||
/** 显示刷新按钮 */
|
||||
@ -297,7 +291,6 @@ export type {
|
||||
PreferencesKeys,
|
||||
ShortcutKeyPreferences,
|
||||
SidebarPreferences,
|
||||
SupportedLanguagesType,
|
||||
TabbarPreferences,
|
||||
ThemePreferences,
|
||||
TransitionPreferences,
|
||||
|
||||
@ -29,7 +29,7 @@ function updateCSSVariables(preferences: Preferences) {
|
||||
);
|
||||
document.documentElement.style.setProperty(
|
||||
'--menu-font-size',
|
||||
`calc(${fontSize}px * 0.875)`,
|
||||
`${fontSize}px`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -22,10 +22,6 @@ function usePreferences() {
|
||||
return false;
|
||||
});
|
||||
|
||||
const locale = computed(() => {
|
||||
return preferences.app.locale;
|
||||
});
|
||||
|
||||
const isMobile = computed(() => {
|
||||
return appPreferences.value.isMobile;
|
||||
});
|
||||
@ -238,7 +234,6 @@ function usePreferences() {
|
||||
isSideNav,
|
||||
keepAlive,
|
||||
layout,
|
||||
locale,
|
||||
preferencesButtonPosition,
|
||||
sidebarCollapsed,
|
||||
theme,
|
||||
|
||||
@ -433,7 +433,7 @@ $namespace: vben;
|
||||
max-width: var(--menu-title-width);
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
font-size: var(--menu-font-size) !important;
|
||||
font-size: var(--density-menu-font-size, var(--menu-font-size)) !important;
|
||||
white-space: nowrap;
|
||||
opacity: 1;
|
||||
}
|
||||
@ -445,20 +445,21 @@ $namespace: vben;
|
||||
.#{$namespace}-menu__popup-container,
|
||||
.#{$namespace}-menu {
|
||||
--menu-title-width: 140px;
|
||||
--menu-item-icon-size: var(--font-size-base, 16px);
|
||||
--menu-item-height: 38px;
|
||||
--menu-item-padding-y: 21px;
|
||||
--menu-item-padding-x: 12px;
|
||||
--menu-item-popup-padding-y: 20px;
|
||||
--menu-item-icon-size: var(--density-menu-icon-size, 16px);
|
||||
--menu-item-height: var(--density-menu-item-height, 40px);
|
||||
--menu-sub-item-height: var(--density-sub-menu-item-height, 36px);
|
||||
--menu-item-padding-y: 0px;
|
||||
--menu-item-padding-x: 10px;
|
||||
--menu-item-popup-padding-y: 12px;
|
||||
--menu-item-popup-padding-x: 12px;
|
||||
--menu-item-margin-y: 2px;
|
||||
--menu-item-margin-x: 0px;
|
||||
--menu-item-collapse-padding-y: 23.5px;
|
||||
--menu-item-collapse-padding-y: 18px;
|
||||
--menu-item-collapse-padding-x: 0px;
|
||||
--menu-item-collapse-margin-y: 4px;
|
||||
--menu-item-collapse-margin-y: 2px;
|
||||
--menu-item-collapse-margin-x: 0px;
|
||||
--menu-item-radius: 0px;
|
||||
--menu-item-indent: 16px;
|
||||
--menu-item-indent: var(--density-menu-indent, 12px);
|
||||
|
||||
&.is-light {
|
||||
--menu-background-color: hsl(var(--menu));
|
||||
@ -529,6 +530,10 @@ $namespace: vben;
|
||||
// 垂直菜单
|
||||
&.is-vertical {
|
||||
&:not(.#{$namespace}-menu.is-collapse) {
|
||||
& .#{$namespace}-sub-menu > .#{$namespace}-menu {
|
||||
--menu-item-height: var(--menu-sub-item-height);
|
||||
}
|
||||
|
||||
& .#{$namespace}-menu-item,
|
||||
& .#{$namespace}-sub-menu-content,
|
||||
& .#{$namespace}-menu-item-group__title {
|
||||
@ -680,7 +685,7 @@ $namespace: vben;
|
||||
}
|
||||
|
||||
&__popup {
|
||||
padding: 10px 0;
|
||||
padding: 6px 0;
|
||||
border-radius: var(--menu-item-radius);
|
||||
|
||||
.#{$namespace}-sub-menu-content,
|
||||
@ -762,7 +767,7 @@ $namespace: vben;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 0 var(--menu-item-padding-x);
|
||||
font-size: var(--menu-font-size) !important;
|
||||
font-size: var(--density-menu-font-size, var(--menu-font-size)) !important;
|
||||
line-height: var(--menu-item-height);
|
||||
}
|
||||
}
|
||||
@ -789,7 +794,7 @@ $namespace: vben;
|
||||
|
||||
.#{$namespace}-sub-menu-content {
|
||||
height: var(--menu-item-height);
|
||||
font-size: var(--menu-font-size) !important;
|
||||
font-size: var(--density-menu-font-size, var(--menu-font-size)) !important;
|
||||
|
||||
@include menu-item;
|
||||
|
||||
|
||||
@ -61,9 +61,9 @@ function menuIcon(menu: MenuRecordRaw) {
|
||||
@reference "@vben/tailwind-config/theme";
|
||||
|
||||
.vben-normal-menu {
|
||||
--menu-item-margin-y: 4px;
|
||||
--menu-item-margin-y: 2px;
|
||||
--menu-item-margin-x: 0px;
|
||||
--menu-item-padding-y: 9px;
|
||||
--menu-item-padding-y: 6px;
|
||||
--menu-item-padding-x: 0px;
|
||||
--menu-item-radius: 0px;
|
||||
|
||||
@ -84,7 +84,7 @@ function menuIcon(menu: MenuRecordRaw) {
|
||||
}
|
||||
|
||||
.vben-normal-menu.is-collapse .vben-normal-menu__icon {
|
||||
font-size: calc(var(--font-size-base, 16px) * 1.25);
|
||||
font-size: var(--density-menu-icon-size, 16px);
|
||||
}
|
||||
|
||||
.vben-normal-menu__item {
|
||||
@ -128,7 +128,7 @@ function menuIcon(menu: MenuRecordRaw) {
|
||||
.vben-normal-menu__icon {
|
||||
@apply max-h-5;
|
||||
|
||||
font-size: calc(var(--font-size-base, 16px) * 1.25);
|
||||
font-size: var(--density-menu-icon-size, 16px);
|
||||
transition: all 0.25s ease;
|
||||
}
|
||||
|
||||
@ -137,7 +137,7 @@ function menuIcon(menu: MenuRecordRaw) {
|
||||
|
||||
width: 100%;
|
||||
margin-bottom: 0;
|
||||
font-size: calc(var(--font-size-base, 16px) * 0.75);
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
text-align: center;
|
||||
transition: all 0.25s ease;
|
||||
|
||||
@ -2,22 +2,3 @@
|
||||
* @zh_CN 登录页面 url 地址
|
||||
*/
|
||||
export const LOGIN_PATH = '/auth/login';
|
||||
|
||||
export interface LanguageOption {
|
||||
label: string;
|
||||
value: 'en-US' | 'zh-CN';
|
||||
}
|
||||
|
||||
/**
|
||||
* Supported languages
|
||||
*/
|
||||
export const SUPPORT_LANGUAGES: LanguageOption[] = [
|
||||
{
|
||||
label: '简体中文',
|
||||
value: 'zh-CN',
|
||||
},
|
||||
{
|
||||
label: 'English',
|
||||
value: 'en-US',
|
||||
},
|
||||
];
|
||||
|
||||
@ -24,7 +24,11 @@ export function useAntdDesignTokens() {
|
||||
colorPrimary: '',
|
||||
colorSuccess: '',
|
||||
colorTextBase: '',
|
||||
controlHeight: 30,
|
||||
controlHeightLG: 34,
|
||||
controlHeightSM: 24,
|
||||
fontSize: 14,
|
||||
fontSizeSM: 13,
|
||||
colorWarning: '',
|
||||
zIndexPopupBase: 2000, // 调整基础弹层层级,避免下拉等组件被弹窗或者最大化状态下的表格遮挡
|
||||
});
|
||||
@ -51,6 +55,16 @@ export function useAntdDesignTokens() {
|
||||
tokens.fontSize = Number.parseFloat(
|
||||
getCssVariableValue('--font-size-base', false),
|
||||
);
|
||||
tokens.fontSizeSM = Number.parseFloat(
|
||||
getCssVariableValue('--density-table-body-font-size', false),
|
||||
);
|
||||
tokens.controlHeight = Number.parseFloat(
|
||||
getCssVariableValue('--density-button-height', false),
|
||||
);
|
||||
tokens.controlHeightSM = Number.parseFloat(
|
||||
getCssVariableValue('--density-button-sm-height', false),
|
||||
);
|
||||
tokens.controlHeightLG = Math.max(tokens.controlHeight + 4, 34);
|
||||
|
||||
getCssVariableValue('--primary-foreground');
|
||||
|
||||
|
||||
@ -58,7 +58,7 @@ export function useTabs() {
|
||||
* 设置当前标签页的标题
|
||||
*
|
||||
* @description 支持设置静态标题字符串或动态计算标题
|
||||
* @description 动态标题会在每次渲染时重新计算,适用于多语言或状态相关的标题
|
||||
* @description 动态标题会在每次渲染时重新计算,适用于状态相关的标题
|
||||
*
|
||||
* @param title - 标题内容
|
||||
* - 静态标题: 直接传入字符串
|
||||
@ -68,8 +68,8 @@ export function useTabs() {
|
||||
* // 静态标题
|
||||
* setTabTitle('标签页')
|
||||
*
|
||||
* // 动态标题(多语言)
|
||||
* setTabTitle(computed(() => t('page.title')))
|
||||
* // 动态标题
|
||||
* setTabTitle(computed(() => `标签页 ${count.value}`))
|
||||
*/
|
||||
async function setTabTitle(title: ComputedRef<string> | string) {
|
||||
tabbarStore.setUpdateTime();
|
||||
|
||||
@ -32,7 +32,7 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
pageTitle: '',
|
||||
sloganImage: '',
|
||||
toolbar: true,
|
||||
toolbarList: () => ['language', 'layout'],
|
||||
toolbarList: () => ['layout'],
|
||||
clickLogo: () => {},
|
||||
});
|
||||
|
||||
|
||||
@ -1,12 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import type { ToolbarType } from './types';
|
||||
|
||||
import { preferences } from '@vben/preferences';
|
||||
|
||||
import {
|
||||
AuthenticationLayoutToggle,
|
||||
LanguageToggle,
|
||||
} from '../widgets';
|
||||
import { AuthenticationLayoutToggle } from '../widgets';
|
||||
|
||||
interface Props {
|
||||
toolbarList?: ToolbarType[];
|
||||
@ -17,11 +12,10 @@ defineOptions({
|
||||
});
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
toolbarList: () => ['language', 'layout'],
|
||||
toolbarList: () => ['layout'],
|
||||
});
|
||||
|
||||
const showLayout = () => props.toolbarList.includes('layout');
|
||||
const showLanguage = () => props.toolbarList.includes('language');
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@ -35,6 +29,5 @@ const showLanguage = () => props.toolbarList.includes('language');
|
||||
<div class="hidden md:flex">
|
||||
<AuthenticationLayoutToggle v-if="showLayout()" />
|
||||
</div>
|
||||
<LanguageToggle v-if="showLanguage() && preferences.widget.languageToggle" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -1 +1 @@
|
||||
export type ToolbarType = 'language' | 'layout';
|
||||
export type ToolbarType = 'layout';
|
||||
|
||||
@ -10,7 +10,6 @@ import { VbenFullScreen, VbenIconButton } from '@vben-core/shadcn-ui';
|
||||
|
||||
import {
|
||||
GlobalSearch,
|
||||
LanguageToggle,
|
||||
PreferencesButton,
|
||||
TimezoneButton,
|
||||
} from '../../widgets';
|
||||
@ -54,12 +53,6 @@ const rightSlots = computed(() => {
|
||||
name: 'preferences',
|
||||
});
|
||||
}
|
||||
if (preferences.widget.languageToggle) {
|
||||
list.push({
|
||||
index: REFERENCE_VALUE + 30,
|
||||
name: 'language-toggle',
|
||||
});
|
||||
}
|
||||
if (preferences.widget.timezone) {
|
||||
list.push({
|
||||
index: REFERENCE_VALUE + 40,
|
||||
@ -148,9 +141,6 @@ function clearPreferencesAndLogout() {
|
||||
@clear-preferences-and-logout="clearPreferencesAndLogout"
|
||||
/>
|
||||
</template>
|
||||
<template v-else-if="slot.name === 'language-toggle'">
|
||||
<LanguageToggle class="mr-1" />
|
||||
</template>
|
||||
<template v-else-if="slot.name === 'fullscreen'">
|
||||
<VbenFullScreen class="mr-1" />
|
||||
</template>
|
||||
|
||||
@ -8,7 +8,7 @@ import { computed, onMounted, useSlots, watch } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
|
||||
import { useRefresh } from '@vben/hooks';
|
||||
import { $t, i18n } from '@vben/locales';
|
||||
import { $t } from '@vben/locales';
|
||||
import {
|
||||
preferences,
|
||||
updatePreferences,
|
||||
@ -200,10 +200,6 @@ function refreshAll() {
|
||||
refresh();
|
||||
}
|
||||
|
||||
// 语言更新后,刷新页面
|
||||
// i18n.global.locale会在preference.app.locale变更之后才会更新,因此watchpreference.app.locale是不合适的,刷新页面时可能语言配置尚未完全加载完成
|
||||
watch(i18n.global.locale, refreshAll, { flush: 'post' });
|
||||
|
||||
// 时区更新后,刷新页面
|
||||
watch(() => timezoneStore.timezone, refreshAll, { flush: 'post' });
|
||||
|
||||
|
||||
@ -21,7 +21,7 @@ import {
|
||||
RotateCw,
|
||||
X,
|
||||
} from '@vben/icons';
|
||||
import { $t, useI18n } from '@vben/locales';
|
||||
import { $t } from '@vben/locales';
|
||||
import { getTabKey, useAccessStore, useTabbarStore } from '@vben/stores';
|
||||
import { filterTree } from '@vben/utils';
|
||||
|
||||
@ -51,13 +51,11 @@ export function useTabbar() {
|
||||
return getTabKey(route);
|
||||
});
|
||||
|
||||
const { locale } = useI18n();
|
||||
const currentTabs = ref<RouteLocationNormalizedGeneric[]>();
|
||||
watch(
|
||||
[
|
||||
() => tabbarStore.getTabs,
|
||||
() => tabbarStore.updateTime,
|
||||
() => locale.value,
|
||||
],
|
||||
([tabs]) => {
|
||||
currentTabs.value = tabs.map((item) => wrapperTabLocale(item));
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
export * from './check-updates';
|
||||
export * from './global-search';
|
||||
export { default as LanguageToggle } from './language-toggle.vue';
|
||||
export { default as AuthenticationLayoutToggle } from './layout-toggle.vue';
|
||||
export * from './lock-screen';
|
||||
export * from './preferences';
|
||||
|
||||
@ -1,39 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
import type { SupportedLanguagesType } from '@vben/locales';
|
||||
|
||||
import { SUPPORT_LANGUAGES } from '@vben/constants';
|
||||
import { Languages } from '@vben/icons';
|
||||
import { loadLocaleMessages } from '@vben/locales';
|
||||
import { preferences, updatePreferences } from '@vben/preferences';
|
||||
|
||||
import { VbenDropdownRadioMenu, VbenIconButton } from '@vben-core/shadcn-ui';
|
||||
|
||||
defineOptions({
|
||||
name: 'LanguageToggle',
|
||||
});
|
||||
|
||||
async function handleUpdate(value: string | undefined) {
|
||||
if (!value) return;
|
||||
const locale = value as SupportedLanguagesType;
|
||||
updatePreferences({
|
||||
app: {
|
||||
locale,
|
||||
},
|
||||
});
|
||||
await loadLocaleMessages(locale);
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<VbenDropdownRadioMenu
|
||||
:menus="SUPPORT_LANGUAGES"
|
||||
:model-value="preferences.app.locale"
|
||||
@update:model-value="handleUpdate"
|
||||
>
|
||||
<VbenIconButton class="hover:animate-[shrink_0.3s_ease-in-out]">
|
||||
<Languages class="size-4 text-foreground" />
|
||||
</VbenIconButton>
|
||||
</VbenDropdownRadioMenu>
|
||||
</div>
|
||||
</template>
|
||||
@ -2,7 +2,7 @@
|
||||
import { computed, reactive, ref } from 'vue';
|
||||
|
||||
import { LockKeyhole } from '@vben/icons';
|
||||
import { $t, useI18n } from '@vben/locales';
|
||||
import { $t } from '@vben/locales';
|
||||
import { storeToRefs, useAccessStore } from '@vben/stores';
|
||||
|
||||
import { useScrollLock } from '@vben-core/composables';
|
||||
@ -25,14 +25,13 @@ withDefaults(defineProps<Props>(), {
|
||||
|
||||
defineEmits<{ toLogin: [] }>();
|
||||
|
||||
const { locale } = useI18n();
|
||||
const accessStore = useAccessStore();
|
||||
|
||||
const now = useNow();
|
||||
const meridiem = useDateFormat(now, 'A');
|
||||
const hour = useDateFormat(now, 'HH');
|
||||
const minute = useDateFormat(now, 'mm');
|
||||
const date = useDateFormat(now, 'YYYY-MM-DD dddd', { locales: locale.value });
|
||||
const date = useDateFormat(now, 'YYYY-MM-DD dddd', { locales: 'zh-CN' });
|
||||
|
||||
const showUnlockForm = ref(false);
|
||||
const { lockScreenPassword } = storeToRefs(accessStore);
|
||||
|
||||
@ -1,16 +1,13 @@
|
||||
<script setup lang="ts">
|
||||
import { SUPPORT_LANGUAGES } from '@vben/constants';
|
||||
import { $t } from '@vben/locales';
|
||||
|
||||
import InputItem from '../input-item.vue';
|
||||
import SelectItem from '../select-item.vue';
|
||||
import SwitchItem from '../switch-item.vue';
|
||||
|
||||
defineOptions({
|
||||
name: 'PreferenceGeneralConfig',
|
||||
});
|
||||
|
||||
const appLocale = defineModel<string>('appLocale');
|
||||
const appDynamicTitle = defineModel<boolean>('appDynamicTitle');
|
||||
const appWatermark = defineModel<boolean>('appWatermark');
|
||||
const appWatermarkContent = defineModel<string>('appWatermarkContent');
|
||||
@ -21,9 +18,6 @@ const appEnableCopyPreferences = defineModel<boolean>(
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<SelectItem v-model="appLocale" :items="SUPPORT_LANGUAGES">
|
||||
{{ $t('preferences.language') }}
|
||||
</SelectItem>
|
||||
<SwitchItem v-model="appDynamicTitle">
|
||||
{{ $t('preferences.dynamicTitle') }}
|
||||
</SwitchItem>
|
||||
|
||||
@ -14,7 +14,6 @@ defineOptions({
|
||||
|
||||
const widgetGlobalSearch = defineModel<boolean>('widgetGlobalSearch');
|
||||
const widgetFullscreen = defineModel<boolean>('widgetFullscreen');
|
||||
const widgetLanguageToggle = defineModel<boolean>('widgetLanguageToggle');
|
||||
const widgetSidebarToggle = defineModel<boolean>('widgetSidebarToggle');
|
||||
const widgetLockScreen = defineModel<boolean>('widgetLockScreen');
|
||||
const appPreferencesButtonPosition = defineModel<string>(
|
||||
@ -42,9 +41,6 @@ const positionItems = computed((): SelectOption[] => [
|
||||
<SwitchItem v-model="widgetGlobalSearch">
|
||||
{{ $t('preferences.widget.globalSearch') }}
|
||||
</SwitchItem>
|
||||
<SwitchItem v-model="widgetLanguageToggle">
|
||||
{{ $t('preferences.widget.languageToggle') }}
|
||||
</SwitchItem>
|
||||
<SwitchItem v-model="widgetFullscreen">
|
||||
{{ $t('preferences.widget.fullscreen') }}
|
||||
</SwitchItem>
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
<script setup lang="ts">
|
||||
import type { SupportedLanguagesType } from '@vben/locales';
|
||||
import type {
|
||||
ContentCompactType,
|
||||
LayoutHeaderMenuAlignType,
|
||||
@ -14,10 +13,9 @@ import type { SegmentedItem } from '@vben-core/shadcn-ui';
|
||||
import { computed, ref } from 'vue';
|
||||
|
||||
import { Copy, Pin, PinOff, RotateCw } from '@vben/icons';
|
||||
import { $t, loadLocaleMessages } from '@vben/locales';
|
||||
import { $t } from '@vben/locales';
|
||||
import {
|
||||
clearCache,
|
||||
preferences,
|
||||
resetPreferences,
|
||||
usePreferences,
|
||||
} from '@vben/preferences';
|
||||
@ -55,7 +53,6 @@ const emit = defineEmits<{ clearPreferencesAndLogout: [] }>();
|
||||
|
||||
const message = globalShareState.getMessage();
|
||||
|
||||
const appLocale = defineModel<SupportedLanguagesType>('appLocale');
|
||||
const appDynamicTitle = defineModel<boolean>('appDynamicTitle');
|
||||
const appLayout = defineModel<LayoutType>('appLayout');
|
||||
const appColorGrayMode = defineModel<boolean>('appColorGrayMode');
|
||||
@ -149,7 +146,6 @@ const shortcutKeysGlobalLockScreen = defineModel<boolean>(
|
||||
|
||||
const widgetGlobalSearch = defineModel<boolean>('widgetGlobalSearch');
|
||||
const widgetFullscreen = defineModel<boolean>('widgetFullscreen');
|
||||
const widgetLanguageToggle = defineModel<boolean>('widgetLanguageToggle');
|
||||
const widgetSidebarToggle = defineModel<boolean>('widgetSidebarToggle');
|
||||
const widgetLockScreen = defineModel<boolean>('widgetLockScreen');
|
||||
const widgetRefresh = defineModel<boolean>('widgetRefresh');
|
||||
@ -202,12 +198,11 @@ async function handleClearCache() {
|
||||
emit('clearPreferencesAndLogout');
|
||||
}
|
||||
|
||||
async function handleReset() {
|
||||
function handleReset() {
|
||||
if (!diffPreference.value) {
|
||||
return;
|
||||
}
|
||||
resetPreferences();
|
||||
await loadLocaleMessages(preferences.app.locale);
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -268,7 +263,6 @@ async function handleReset() {
|
||||
v-model:app-dynamic-title="appDynamicTitle"
|
||||
v-model:app-enable-check-updates="appEnableCheckUpdates"
|
||||
v-model:app-enable-copy-preferences="appEnableCopyPreferences"
|
||||
v-model:app-locale="appLocale"
|
||||
v-model:app-watermark="appWatermark"
|
||||
v-model:app-watermark-content="appWatermarkContent"
|
||||
/>
|
||||
@ -362,7 +356,6 @@ async function handleReset() {
|
||||
"
|
||||
v-model:widget-fullscreen="widgetFullscreen"
|
||||
v-model:widget-global-search="widgetGlobalSearch"
|
||||
v-model:widget-language-toggle="widgetLanguageToggle"
|
||||
v-model:widget-lock-screen="widgetLockScreen"
|
||||
v-model:widget-refresh="widgetRefresh"
|
||||
v-model:widget-sidebar-toggle="widgetSidebarToggle"
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
import { computed } from 'vue';
|
||||
|
||||
import { Settings } from '@vben/icons';
|
||||
import { $t, loadLocaleMessages } from '@vben/locales';
|
||||
import { $t } from '@vben/locales';
|
||||
import { preferences, updatePreferences } from '@vben/preferences';
|
||||
import { capitalizeFirstLetter } from '@vben/utils';
|
||||
|
||||
@ -42,9 +42,6 @@ const listen = computed(() => {
|
||||
val: any,
|
||||
) => {
|
||||
updatePreferences({ [key]: { [subKey]: val } });
|
||||
if (key === 'app' && subKey === 'locale') {
|
||||
loadLocaleMessages(val);
|
||||
}
|
||||
};
|
||||
}
|
||||
} else {
|
||||
|
||||
@ -19,7 +19,6 @@ import {
|
||||
VxeUI,
|
||||
VxeUpload,
|
||||
} from 'vxe-pc-ui';
|
||||
import enUS from 'vxe-pc-ui/lib/language/en-US'; // 导入默认的语言
|
||||
import zhCN from 'vxe-pc-ui/lib/language/zh-CN';
|
||||
import {
|
||||
VxeColgroup,
|
||||
@ -117,19 +116,15 @@ export function setupVbenVxeTable(setupOptions: SetupVxeTable) {
|
||||
if (useVbenFormFromParam) {
|
||||
tableFormFactory = useVbenFormFromParam;
|
||||
}
|
||||
const { isDark, locale } = usePreferences();
|
||||
|
||||
const localMap = {
|
||||
'zh-CN': normalizeVxeLocale(zhCN),
|
||||
'en-US': normalizeVxeLocale(enUS),
|
||||
};
|
||||
const { isDark } = usePreferences();
|
||||
const zhCNLocale = normalizeVxeLocale(zhCN);
|
||||
|
||||
watch(
|
||||
[() => isDark.value, () => locale.value],
|
||||
([isDarkValue, localeValue]) => {
|
||||
() => isDark.value,
|
||||
(isDarkValue) => {
|
||||
VxeUI.setTheme(isDarkValue ? 'dark' : 'light');
|
||||
VxeUI.setI18n(localeValue, localMap[localeValue]);
|
||||
VxeUI.setLanguage(localeValue);
|
||||
VxeUI.setI18n('zh-CN', zhCNLocale);
|
||||
VxeUI.setLanguage('zh-CN');
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
|
||||
@ -20,9 +20,7 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@intlify/core-base": "catalog:",
|
||||
"@vben-core/composables": "workspace:*",
|
||||
"vue": "catalog:",
|
||||
"vue-i18n": "catalog:"
|
||||
"vue": "catalog:"
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,147 +0,0 @@
|
||||
import type { App } from 'vue';
|
||||
import type { Locale } from 'vue-i18n';
|
||||
|
||||
import type {
|
||||
ImportLocaleFn,
|
||||
LoadMessageFn,
|
||||
LocaleSetupOptions,
|
||||
SupportedLanguagesType,
|
||||
} from './typing';
|
||||
|
||||
import { unref } from 'vue';
|
||||
import { createI18n } from 'vue-i18n';
|
||||
|
||||
import { useSimpleLocale } from '@vben-core/composables';
|
||||
|
||||
const i18n = createI18n({
|
||||
globalInjection: true,
|
||||
legacy: false,
|
||||
locale: '',
|
||||
messages: {},
|
||||
});
|
||||
|
||||
const modules = import.meta.glob('./langs/**/*.json');
|
||||
|
||||
const { setSimpleLocale } = useSimpleLocale();
|
||||
|
||||
const localesMap = loadLocalesMapFromDir(
|
||||
/\.\/langs\/([^/]+)\/(.*)\.json$/,
|
||||
modules,
|
||||
);
|
||||
let loadMessages: LoadMessageFn;
|
||||
|
||||
/**
|
||||
* Load locale modules
|
||||
* @param modules
|
||||
*/
|
||||
function loadLocalesMap(modules: Record<string, () => Promise<unknown>>) {
|
||||
const localesMap: Record<Locale, ImportLocaleFn> = {};
|
||||
|
||||
for (const [path, loadLocale] of Object.entries(modules)) {
|
||||
const key = path.match(/([\w-]*)\.(json)/)?.[1];
|
||||
if (key) {
|
||||
localesMap[key] = loadLocale as ImportLocaleFn;
|
||||
}
|
||||
}
|
||||
return localesMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load locale modules with directory structure
|
||||
* @param regexp - Regular expression to match language and file names
|
||||
* @param modules - The modules object containing paths and import functions
|
||||
* @returns A map of locales to their corresponding import functions
|
||||
*/
|
||||
function loadLocalesMapFromDir(
|
||||
regexp: RegExp,
|
||||
modules: Record<string, () => Promise<unknown>>,
|
||||
): Record<Locale, ImportLocaleFn> {
|
||||
const localesRaw: Record<Locale, Record<string, () => Promise<unknown>>> = {};
|
||||
const localesMap: Record<Locale, ImportLocaleFn> = {};
|
||||
|
||||
// Iterate over the modules to extract language and file names
|
||||
for (const path in modules) {
|
||||
const match = path.match(regexp);
|
||||
if (match) {
|
||||
const [_, locale, fileName] = match;
|
||||
if (locale && fileName) {
|
||||
if (!localesRaw[locale]) {
|
||||
localesRaw[locale] = {};
|
||||
}
|
||||
if (modules[path]) {
|
||||
localesRaw[locale][fileName] = modules[path];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Convert raw locale data into async import functions
|
||||
for (const [locale, files] of Object.entries(localesRaw)) {
|
||||
localesMap[locale] = async () => {
|
||||
const messages: Record<string, any> = {};
|
||||
for (const [fileName, importFn] of Object.entries(files)) {
|
||||
messages[fileName] = ((await importFn()) as any)?.default;
|
||||
}
|
||||
return { default: messages };
|
||||
};
|
||||
}
|
||||
|
||||
return localesMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set i18n language
|
||||
* @param locale
|
||||
*/
|
||||
function setI18nLanguage(locale: Locale) {
|
||||
i18n.global.locale.value = locale;
|
||||
|
||||
document?.querySelector('html')?.setAttribute('lang', locale);
|
||||
}
|
||||
|
||||
async function setupI18n(app: App, options: LocaleSetupOptions = {}) {
|
||||
const { defaultLocale = 'zh-CN' } = options;
|
||||
// app可以自行扩展一些第三方库和组件库的国际化
|
||||
loadMessages = options.loadMessages || (async () => ({}));
|
||||
app.use(i18n);
|
||||
await loadLocaleMessages(defaultLocale);
|
||||
|
||||
// 在控制台打印警告
|
||||
i18n.global.setMissingHandler((locale, key) => {
|
||||
if (options.missingWarn && key.includes('.')) {
|
||||
console.warn(
|
||||
`[intlify] Not found '${key}' key in '${locale}' locale messages.`,
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Load locale messages
|
||||
* @param lang
|
||||
*/
|
||||
async function loadLocaleMessages(lang: SupportedLanguagesType) {
|
||||
if (unref(i18n.global.locale) === lang) {
|
||||
return setI18nLanguage(lang);
|
||||
}
|
||||
setSimpleLocale(lang);
|
||||
|
||||
const message = await localesMap[lang]?.();
|
||||
|
||||
if (message?.default) {
|
||||
i18n.global.setLocaleMessage(lang, message.default);
|
||||
}
|
||||
|
||||
const mergeMessage = await loadMessages(lang);
|
||||
i18n.global.mergeLocaleMessage(lang, mergeMessage);
|
||||
|
||||
return setI18nLanguage(lang);
|
||||
}
|
||||
|
||||
export {
|
||||
i18n,
|
||||
loadLocaleMessages,
|
||||
loadLocalesMap,
|
||||
loadLocalesMapFromDir,
|
||||
setupI18n,
|
||||
};
|
||||
@ -1,30 +1,8 @@
|
||||
import {
|
||||
i18n,
|
||||
loadLocaleMessages,
|
||||
loadLocalesMap,
|
||||
loadLocalesMapFromDir,
|
||||
setupI18n,
|
||||
} from './i18n';
|
||||
|
||||
const $t = i18n.global.t;
|
||||
const $te = i18n.global.te;
|
||||
|
||||
export {
|
||||
$t,
|
||||
$te,
|
||||
i18n,
|
||||
loadLocaleMessages,
|
||||
loadLocalesMap,
|
||||
loadLocalesMapFromDir,
|
||||
setupI18n,
|
||||
};
|
||||
export {
|
||||
type ImportLocaleFn,
|
||||
type LocaleSetupOptions,
|
||||
type SupportedLanguagesType,
|
||||
} from './typing';
|
||||
export type { CompileError } from '@intlify/core-base';
|
||||
mergeLocaleMessages,
|
||||
setupLocale,
|
||||
} from './locale';
|
||||
|
||||
export { useI18n } from 'vue-i18n';
|
||||
|
||||
export type { Locale } from 'vue-i18n';
|
||||
export type { LocaleSetupOptions } from './typing';
|
||||
|
||||
@ -1,65 +0,0 @@
|
||||
{
|
||||
"welcomeBack": "Welcome Back",
|
||||
"pageTitle": "Plug-and-play Admin system",
|
||||
"pageDesc": "Efficient, versatile frontend template",
|
||||
"loginSuccess": "Login Successful",
|
||||
"loginSuccessDesc": "Welcome Back",
|
||||
"loginSubtitle": "Enter your account details to manage your projects",
|
||||
"selectAccount": "Quick Select Account",
|
||||
"username": "Username",
|
||||
"password": "Password",
|
||||
"usernameTip": "Please enter username",
|
||||
"passwordErrorTip": "Password is incorrect",
|
||||
"passwordTip": "Please enter password",
|
||||
"verifyRequiredTip": "Please complete the verification first",
|
||||
"rememberMe": "Remember Me",
|
||||
"createAnAccount": "Create an Account",
|
||||
"createAccount": "Create Account",
|
||||
"alreadyHaveAccount": "Already have an account?",
|
||||
"accountTip": "Don't have an account?",
|
||||
"signUp": "Sign Up",
|
||||
"signUpSubtitle": "Make managing your applications simple and fun",
|
||||
"confirmPassword": "Confirm Password",
|
||||
"confirmPasswordTip": "The passwords do not match",
|
||||
"agree": "I agree to",
|
||||
"privacyPolicy": "Privacy-policy",
|
||||
"terms": "Terms",
|
||||
"agreeTip": "Please agree to the Privacy Policy and Terms",
|
||||
"goToLogin": "Login instead",
|
||||
"passwordStrength": "Use 8 or more characters with a mix of letters, numbers & symbols",
|
||||
"forgetPassword": "Forget Password?",
|
||||
"forgetPasswordSubtitle": "Enter your email and we'll send you instructions to reset your password",
|
||||
"emailTip": "Please enter email",
|
||||
"emailValidErrorTip": "The email format you entered is incorrect",
|
||||
"sendResetLink": "Send Reset Link",
|
||||
"email": "Email",
|
||||
"qrcodeSubtitle": "Scan the QR code with your phone to login",
|
||||
"qrcodePrompt": "Click 'Confirm' after scanning to complete login",
|
||||
"qrcodeLogin": "QR Code Login",
|
||||
"wechatLogin": "Wechat Login",
|
||||
"qqLogin": "QQ Login",
|
||||
"githubLogin": "Github Login",
|
||||
"googleLogin": "Google Login",
|
||||
"dingdingLogin": "Dingding Login",
|
||||
"codeSubtitle": "Enter your phone number to start managing your project",
|
||||
"code": "Security code",
|
||||
"codeTip": "Security code required {0} characters",
|
||||
"mobile": "Mobile",
|
||||
"mobileLogin": "Mobile Login",
|
||||
"mobileTip": "Please enter mobile number",
|
||||
"mobileErrortip": "The phone number format is incorrect",
|
||||
"sendCode": "Get Security code",
|
||||
"sendText": "Resend in {0}s",
|
||||
"thirdPartyLogin": "Or continue with",
|
||||
"weChat": "WeChat",
|
||||
"qq": "QQ",
|
||||
"gitHub": "GitHub",
|
||||
"google": "Google",
|
||||
"loginAgainTitle": "Please Log In Again",
|
||||
"loginAgainSubTitle": "Your login session has expired. Please log in again to continue.",
|
||||
"layout": {
|
||||
"center": "Align Center",
|
||||
"alignLeft": "Align Left",
|
||||
"alignRight": "Align Right"
|
||||
}
|
||||
}
|
||||
@ -1,24 +0,0 @@
|
||||
{
|
||||
"back": "Back",
|
||||
"backToHome": "Back To Home",
|
||||
"login": "Login",
|
||||
"logout": "Logout",
|
||||
"prompt": "Prompt",
|
||||
"cancel": "Cancel",
|
||||
"confirm": "Confirm",
|
||||
"reset": "Reset",
|
||||
"noData": "No Data",
|
||||
"refresh": "Refresh",
|
||||
"loadingMenu": "Loading Menu",
|
||||
"query": "Search",
|
||||
"search": "Search",
|
||||
"enabled": "Enabled",
|
||||
"disabled": "Disabled",
|
||||
"edit": "Edit",
|
||||
"delete": "Delete",
|
||||
"create": "Create",
|
||||
"yes": "Yes",
|
||||
"no": "No",
|
||||
"showSearchPanel": "Show search panel",
|
||||
"hideSearchPanel": "Hide search panel"
|
||||
}
|
||||
@ -1,165 +0,0 @@
|
||||
{
|
||||
"title": "Preferences",
|
||||
"subtitle": "Customize Preferences & Preview in Real Time",
|
||||
"enableStickyPreferencesNavigationBar": "Enable sticky preferences navigation bar",
|
||||
"disableStickyPreferencesNavigationBar": "Disable sticky preferences navigation bar",
|
||||
"resetTip": "Data has changed, click to reset",
|
||||
"resetTitle": "Reset Preferences",
|
||||
"resetSuccess": "Preferences reset successfully",
|
||||
"appearance": "Appearance",
|
||||
"layout": "Layout",
|
||||
"content": "Content",
|
||||
"other": "Other",
|
||||
"wide": "Wide",
|
||||
"compact": "Fixed",
|
||||
"followSystem": "Follow System",
|
||||
"vertical": "Vertical",
|
||||
"verticalTip": "Side vertical menu mode",
|
||||
"horizontal": "Horizontal",
|
||||
"horizontalTip": "Horizontal menu mode, all menus displayed at the top",
|
||||
"twoColumn": "Two Column",
|
||||
"twoColumnTip": "Vertical Two Column Menu Mode",
|
||||
"headerSidebarNav": "Header Vertical",
|
||||
"headerSidebarNavTip": "Header Full Width, Sidebar Navigation Mode",
|
||||
"headerTwoColumn": "Header Two Column",
|
||||
"headerTwoColumnTip": "Header Navigation & Sidebar Two Column co-exists",
|
||||
"mixedMenu": "Mixed Menu",
|
||||
"mixedMenuTip": "Vertical & Horizontal Menu Co-exists",
|
||||
"fullContent": "Full Content",
|
||||
"fullContentTip": "Only display content body, hide all menus",
|
||||
"normal": "Normal",
|
||||
"plain": "Plain",
|
||||
"rounded": "Rounded",
|
||||
"copyPreferences": "Copy Preferences",
|
||||
"enableCopyPreferences": "Show copy preferences button",
|
||||
"copyPreferencesSuccessTitle": "Copy successful",
|
||||
"copyPreferencesSuccess": "Copy successful, please override in `src/preferences.ts` under app",
|
||||
"clearAndLogout": "Clear Cache & Logout",
|
||||
"mode": "Mode",
|
||||
"general": "General",
|
||||
"language": "Language",
|
||||
"dynamicTitle": "Dynamic Title",
|
||||
"watermark": "Watermark",
|
||||
"watermarkContent": "Please input Watermark content",
|
||||
"checkUpdates": "Periodic update check",
|
||||
"position": {
|
||||
"title": "Preferences Postion",
|
||||
"header": "Header",
|
||||
"auto": "Auto",
|
||||
"fixed": "Fixed"
|
||||
},
|
||||
"sidebar": {
|
||||
"buttons": "Show Buttons",
|
||||
"buttonFixed": "Fixed",
|
||||
"buttonCollapsed": "Collapsed",
|
||||
"title": "Sidebar",
|
||||
"width": "Width",
|
||||
"visible": "Show Sidebar",
|
||||
"draggable": "Drag Sidebar Menu",
|
||||
"collapsed": "Collpase Menu",
|
||||
"collapsedShowTitle": "Show Menu Title",
|
||||
"autoActivateChild": "Auto Activate SubMenu",
|
||||
"autoActivateChildTip": "`Enabled` to automatically activate the submenu while click menu.",
|
||||
"expandOnHover": "Expand On Hover",
|
||||
"expandOnHoverTip": "When the mouse hovers over menu, \n `Enabled` to expand children menus \n `Disabled` to expand whole sidebar."
|
||||
},
|
||||
"tabbar": {
|
||||
"title": "Tabbar",
|
||||
"enable": "Enable Tab Bar",
|
||||
"icon": "Show Tabbar Icon",
|
||||
"showMore": "Show More Button",
|
||||
"showMaximize": "Show Maximize Button",
|
||||
"persist": "Persist Tabs",
|
||||
"visitHistory": "Visit History",
|
||||
"visitHistoryTip": "When enabled, the tab bar records tab visit history. \nClosing the current tab will automatically select the last opened tab.",
|
||||
"maxCount": "Max Count of Tabs",
|
||||
"maxCountTip": "When the number of tabs exceeds the maximum,\nthe oldest tab will be closed.\n Set to 0 to disable count checking.",
|
||||
"draggable": "Enable Draggable Sort",
|
||||
"wheelable": "Support Mouse Wheel",
|
||||
"middleClickClose": "Close Tab when Mouse Middle Button Click",
|
||||
"wheelableTip": "When enabled, the Tabbar area responds to vertical scrolling events of the scroll wheel.",
|
||||
"styleType": {
|
||||
"title": "Tabs Style",
|
||||
"chrome": "Chrome",
|
||||
"card": "Card",
|
||||
"plain": "Plain",
|
||||
"brisk": "Brisk"
|
||||
},
|
||||
"contextMenu": {
|
||||
"reload": "Reload",
|
||||
"close": "Close",
|
||||
"pin": "Pin",
|
||||
"unpin": "Unpin",
|
||||
"closeLeft": "Close Left Tabs",
|
||||
"closeRight": "Close Right Tabs",
|
||||
"closeOther": "Close Other Tabs",
|
||||
"closeAll": "Close All Tabs",
|
||||
"openInNewWindow": "Open in New Window",
|
||||
"maximize": "Maximize",
|
||||
"restoreMaximize": "Restore"
|
||||
}
|
||||
},
|
||||
"navigationMenu": {
|
||||
"title": "Navigation Menu",
|
||||
"style": "Navigation Menu Style",
|
||||
"accordion": "Sidebar Accordion Menu",
|
||||
"split": "Navigation Menu Separation",
|
||||
"splitTip": "When enabled, the sidebar displays the top bar's submenu"
|
||||
},
|
||||
"animation": {
|
||||
"title": "Animation",
|
||||
"loading": "Page Loading",
|
||||
"transition": "Page Transition",
|
||||
"progress": "Page Progress"
|
||||
},
|
||||
"theme": {
|
||||
"title": "Theme",
|
||||
"radius": "Radius",
|
||||
"fontSize": "Font Size",
|
||||
"fontSizeTip": "Adjust global font size with real-time preview",
|
||||
"weakMode": "Weak Mode",
|
||||
"grayMode": "Gray Mode"
|
||||
},
|
||||
"header": {
|
||||
"title": "Header",
|
||||
"visible": "Show Header",
|
||||
"modeStatic": "Static",
|
||||
"modeFixed": "Fixed",
|
||||
"modeAuto": "Auto hide & Show",
|
||||
"modeAutoScroll": "Scroll to Hide & Show",
|
||||
"menuAlign": "Menu Align",
|
||||
"menuAlignStart": "Start",
|
||||
"menuAlignEnd": "End",
|
||||
"menuAlignCenter": "Center"
|
||||
},
|
||||
"footer": {
|
||||
"title": "Footer",
|
||||
"visible": "Show Footer",
|
||||
"fixed": "Fixed at Bottom"
|
||||
},
|
||||
"copyright": {
|
||||
"title": "Copyright",
|
||||
"enable": "Enable Copyright",
|
||||
"companyName": "Company Name",
|
||||
"companySiteLink": "Company Site Link",
|
||||
"date": "Date",
|
||||
"icp": "ICP License Number",
|
||||
"icpLink": "ICP Site Link"
|
||||
},
|
||||
"shortcutKeys": {
|
||||
"title": "Shortcut Keys",
|
||||
"global": "Global",
|
||||
"search": "Global Search",
|
||||
"logout": "Logout",
|
||||
"preferences": "Preferences"
|
||||
},
|
||||
"widget": {
|
||||
"title": "Widget",
|
||||
"globalSearch": "Enable Global Search",
|
||||
"fullscreen": "Enable Fullscreen",
|
||||
"languageToggle": "Enable Language Toggle",
|
||||
"sidebarToggle": "Enable Sidebar Toggle",
|
||||
"lockScreen": "Enable Lock Screen",
|
||||
"refresh": "Enable Refresh"
|
||||
}
|
||||
}
|
||||
@ -1,4 +0,0 @@
|
||||
{
|
||||
"updatePassword": "Update Password",
|
||||
"updateBasicProfile": "Update Basic Profile"
|
||||
}
|
||||
@ -1,117 +0,0 @@
|
||||
{
|
||||
"formRules": {
|
||||
"required": "Please enter {0}",
|
||||
"selectRequired": "Please select {0}",
|
||||
"minLength": "{0} must be at least {1} characters",
|
||||
"maxLength": "{0} can be at most {1} characters",
|
||||
"length": "{0} must be {1} characters long",
|
||||
"alreadyExists": "{0} `{1}` already exists",
|
||||
"startWith": "{0} must start with `{1}`",
|
||||
"invalidURL": "Please input a valid URL",
|
||||
"sizeLimit": "The file size cannot exceed {0}MB",
|
||||
"previewWarning": "Unable to open the file, there is no available URL or preview address"
|
||||
},
|
||||
"actionTitle": {
|
||||
"edit": "Modify {0}",
|
||||
"create": "Create {0}",
|
||||
"delete": "Delete {0}",
|
||||
"view": "View {0}"
|
||||
},
|
||||
"actionMessage": {
|
||||
"deleteConfirm": "Are you sure to delete {0}?",
|
||||
"deleting": "Deleting {0} ...",
|
||||
"deleteSuccess": "{0} deleted successfully",
|
||||
"operationSuccess": "Operation succeeded",
|
||||
"operationFailed": "Operation failed"
|
||||
},
|
||||
"placeholder": {
|
||||
"input": "Please enter",
|
||||
"select": "Please select",
|
||||
"upload": "Click to upload"
|
||||
},
|
||||
"captcha": {
|
||||
"title": "Please complete the security verification",
|
||||
"sliderSuccessText": "Passed",
|
||||
"sliderDefaultText": "Slider and drag",
|
||||
"alt": "Supports img tag src attribute value",
|
||||
"sliderRotateDefaultTip": "Click picture to refresh",
|
||||
"sliderTranslateDefaultTip": "Click picture to refresh",
|
||||
"sliderRotateFailTip": "Validation failed",
|
||||
"sliderRotateSuccessTip": "Validation successful, time {0} seconds",
|
||||
"sliderTranslateFailTip": "Validation failed",
|
||||
"sliderTranslateSuccessTip": "Validation successful, time {0} seconds",
|
||||
"refreshAriaLabel": "Refresh captcha",
|
||||
"confirmAriaLabel": "Confirm selection",
|
||||
"confirm": "Confirm",
|
||||
"pointAriaLabel": "Click point",
|
||||
"clickInOrder": "Please click in order"
|
||||
},
|
||||
"iconPicker": {
|
||||
"placeholder": "Select an icon",
|
||||
"search": "Search icon..."
|
||||
},
|
||||
"jsonViewer": {
|
||||
"copy": "Copy",
|
||||
"copied": "Copied"
|
||||
},
|
||||
"crop": {
|
||||
"title": "Image Cropping",
|
||||
"titleTip": "Cropping Ratio {0}",
|
||||
"confirm": "Crop",
|
||||
"cancel": "Cancel cropping",
|
||||
"errorTip": "Cropping error"
|
||||
},
|
||||
"fallback": {
|
||||
"pageNotFound": "Oops! Page Not Found",
|
||||
"pageNotFoundDesc": "Sorry, we couldn't find the page you were looking for.",
|
||||
"forbidden": "Oops! Access Denied",
|
||||
"forbiddenDesc": "Sorry, but you don't have permission to access this page.",
|
||||
"internalError": "Oops! Something Went Wrong",
|
||||
"internalErrorDesc": "Sorry, but the server encountered an error.",
|
||||
"offline": "Offline Page",
|
||||
"offlineError": "Oops! Network Error",
|
||||
"offlineErrorDesc": "Sorry, can't connect to the internet. Check your connection.",
|
||||
"comingSoon": "Coming Soon",
|
||||
"http": {
|
||||
"requestTimeout": "The request timed out. Please try again later.",
|
||||
"networkError": "A network error occurred. Please check your internet connection and try again.",
|
||||
"badRequest": "Bad Request. Please check your input and try again.",
|
||||
"unauthorized": "Unauthorized. Please log in to continue.",
|
||||
"forbidden": "Forbidden. You do not have permission to access this resource.",
|
||||
"notFound": "Not Found. The requested resource could not be found.",
|
||||
"internalServerError": "Internal Server Error. Something went wrong on our end. Please try again later."
|
||||
}
|
||||
},
|
||||
"widgets": {
|
||||
"document": "Document",
|
||||
"qa": "Q&A",
|
||||
"setting": "Settings",
|
||||
"logoutTip": "Do you want to logout?",
|
||||
"checkUpdatesTitle": "New Version Available",
|
||||
"checkUpdatesDescription": "Click to refresh and get the latest version",
|
||||
"search": {
|
||||
"title": "Search",
|
||||
"searchNavigate": "Search Navigation",
|
||||
"select": "Select",
|
||||
"navigate": "Navigate",
|
||||
"close": "Close",
|
||||
"noResults": "No Search Results Found",
|
||||
"noRecent": "No Search History",
|
||||
"recent": "Search History"
|
||||
},
|
||||
"lockScreen": {
|
||||
"title": "Lock Screen",
|
||||
"screenButton": "Locking",
|
||||
"password": "Password",
|
||||
"placeholder": "Please enter password",
|
||||
"unlock": "Click to unlock",
|
||||
"errorPasswordTip": "Password error, please re-enter",
|
||||
"backToLogin": "Back to login",
|
||||
"entry": "Enter the system"
|
||||
},
|
||||
"timezone": {
|
||||
"setTimezone": "Set Timezone",
|
||||
"setSuccess": "Timezone set successfully"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -157,7 +157,6 @@
|
||||
"title": "小部件",
|
||||
"globalSearch": "启用全局搜索",
|
||||
"fullscreen": "启用全屏",
|
||||
"languageToggle": "启用语言切换",
|
||||
"sidebarToggle": "启用侧边栏切换",
|
||||
"lockScreen": "启用锁屏",
|
||||
"refresh": "启用刷新"
|
||||
|
||||
106
packages/locales/src/locale.ts
Normal file
106
packages/locales/src/locale.ts
Normal file
@ -0,0 +1,106 @@
|
||||
import type { App } from 'vue';
|
||||
|
||||
import type { LocaleSetupOptions } from './typing';
|
||||
|
||||
const messages: Record<string, any> = {};
|
||||
const coreModules = import.meta.glob('./langs/zh-CN/*.json', { eager: true });
|
||||
|
||||
function isRecord(value: unknown): value is Record<string, any> {
|
||||
return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
|
||||
}
|
||||
|
||||
function normalizeModule(module: unknown) {
|
||||
return isRecord(module) && 'default' in module ? module.default : module;
|
||||
}
|
||||
|
||||
function mergeDeep(target: Record<string, any>, source?: Record<string, any>) {
|
||||
if (!source) {
|
||||
return target;
|
||||
}
|
||||
for (const [key, value] of Object.entries(source)) {
|
||||
if (isRecord(value) && isRecord(target[key])) {
|
||||
mergeDeep(target[key], value);
|
||||
} else {
|
||||
target[key] = value;
|
||||
}
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
function toLocaleMessages(
|
||||
modules: Record<string, unknown>,
|
||||
regexp = /\.\/langs\/zh-CN\/(.*)\.json$/,
|
||||
) {
|
||||
const result: Record<string, any> = {};
|
||||
for (const [path, module] of Object.entries(modules)) {
|
||||
const fileName = path.match(regexp)?.[1];
|
||||
if (!fileName) {
|
||||
continue;
|
||||
}
|
||||
result[fileName] = normalizeModule(module);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function mergeLocaleMessages(message: Record<string, any>) {
|
||||
mergeDeep(messages, message);
|
||||
}
|
||||
|
||||
mergeLocaleMessages(toLocaleMessages(coreModules));
|
||||
|
||||
function getValueByPath(path: string) {
|
||||
if (!path) {
|
||||
return path;
|
||||
}
|
||||
let current: unknown = messages;
|
||||
for (const key of path.split('.')) {
|
||||
current = isRecord(current) ? current[key] : undefined;
|
||||
}
|
||||
return current;
|
||||
}
|
||||
|
||||
function $te(key: string) {
|
||||
return getValueByPath(key) !== undefined;
|
||||
}
|
||||
|
||||
function formatMessage(
|
||||
message: string,
|
||||
params?: Array<unknown> | Record<string, unknown>,
|
||||
) {
|
||||
if (!params) {
|
||||
return message;
|
||||
}
|
||||
|
||||
return message.replaceAll(/\{(\w+)\}/g, (placeholder, key: string) => {
|
||||
const value = Array.isArray(params) ? params[Number(key)] : params[key];
|
||||
return value === undefined || value === null ? placeholder : String(value);
|
||||
});
|
||||
}
|
||||
|
||||
function $t(
|
||||
key?: null | string,
|
||||
params?: Array<unknown> | Record<string, unknown>,
|
||||
) {
|
||||
if (!key) {
|
||||
return '';
|
||||
}
|
||||
const value = getValueByPath(key);
|
||||
return typeof value === 'string' ? formatMessage(value, params) : key;
|
||||
}
|
||||
|
||||
function setLocale() {
|
||||
document?.querySelector('html')?.setAttribute('lang', 'zh-CN');
|
||||
}
|
||||
|
||||
async function setupLocale(app: App, options: LocaleSetupOptions = {}) {
|
||||
void app;
|
||||
void options;
|
||||
setLocale();
|
||||
}
|
||||
|
||||
export {
|
||||
$t,
|
||||
$te,
|
||||
mergeLocaleMessages,
|
||||
setupLocale,
|
||||
};
|
||||
@ -1,23 +1,4 @@
|
||||
export type SupportedLanguagesType = 'en-US' | 'zh-CN';
|
||||
|
||||
export type ImportLocaleFn = () => Promise<{ default: Record<string, string> }>;
|
||||
|
||||
export type LoadMessageFn = (
|
||||
lang: SupportedLanguagesType,
|
||||
) => Promise<Record<string, string> | undefined>;
|
||||
|
||||
export interface LocaleSetupOptions {
|
||||
/**
|
||||
* Default language
|
||||
* @default zh-CN
|
||||
*/
|
||||
defaultLocale?: SupportedLanguagesType;
|
||||
/**
|
||||
* Load message function
|
||||
* @param lang
|
||||
* @returns
|
||||
*/
|
||||
loadMessages?: LoadMessageFn;
|
||||
/**
|
||||
* Whether to warn when the key is not found
|
||||
*/
|
||||
|
||||
@ -468,7 +468,7 @@ export const useTabbarStore = defineStore('core-tabbar', {
|
||||
*
|
||||
* @zh_CN 支持设置静态标题字符串或计算属性作为动态标题
|
||||
* @zh_CN 当标题为计算属性时,标题会随计算属性值变化而自动更新
|
||||
* @zh_CN 适用于需要根据状态或多语言动态更新标题的场景
|
||||
* @zh_CN 适用于需要根据业务状态动态更新标题的场景
|
||||
*
|
||||
* @param {TabDefinition} tab - 标签页对象
|
||||
* @param {ComputedRef<string> | string} title - 标题内容,支持静态字符串或计算属性
|
||||
|
||||
@ -7,6 +7,12 @@
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.ant-app .ant-btn {
|
||||
height: var(--density-button-height) !important;
|
||||
padding-inline: 12px;
|
||||
font-size: var(--font-size-base);
|
||||
}
|
||||
|
||||
.ant-btn {
|
||||
.anticon {
|
||||
display: inline-flex;
|
||||
@ -24,6 +30,56 @@
|
||||
}
|
||||
}
|
||||
|
||||
.ant-app .ant-btn-sm {
|
||||
height: var(--density-button-sm-height) !important;
|
||||
padding-inline: 8px;
|
||||
}
|
||||
|
||||
.ant-app .ant-btn-icon-only {
|
||||
width: var(--density-button-height) !important;
|
||||
padding-inline: 0;
|
||||
}
|
||||
|
||||
.ant-app .ant-btn-sm.ant-btn-icon-only {
|
||||
width: var(--density-button-sm-height) !important;
|
||||
}
|
||||
|
||||
.ant-table-wrapper .ant-table {
|
||||
font-size: var(--density-table-body-font-size);
|
||||
}
|
||||
|
||||
.ant-table-wrapper .ant-table-thead > tr > th {
|
||||
height: var(--density-table-header-height);
|
||||
padding: 8px var(--density-table-cell-padding-x);
|
||||
font-size: var(--density-table-header-font-size);
|
||||
}
|
||||
|
||||
.ant-table-wrapper .ant-table-tbody > tr > td {
|
||||
height: var(--density-table-row-height);
|
||||
padding: 3px var(--density-table-cell-padding-x);
|
||||
}
|
||||
|
||||
.ant-pagination {
|
||||
font-size: var(--density-table-body-font-size);
|
||||
}
|
||||
|
||||
.ant-pagination .ant-pagination-item,
|
||||
.ant-pagination .ant-pagination-next,
|
||||
.ant-pagination .ant-pagination-prev {
|
||||
min-width: var(--density-pagination-height);
|
||||
height: var(--density-pagination-height);
|
||||
line-height: calc(var(--density-pagination-height) - 2px);
|
||||
}
|
||||
|
||||
.ant-pagination .ant-select-selector {
|
||||
min-height: var(--density-pagination-height) !important;
|
||||
}
|
||||
|
||||
.ant-pagination .ant-select-single,
|
||||
.ant-pagination .ant-select-single .ant-select-selector {
|
||||
height: var(--density-pagination-height) !important;
|
||||
}
|
||||
|
||||
.ant-tag {
|
||||
> svg {
|
||||
display: inline-block;
|
||||
|
||||
472
pnpm-lock.yaml
generated
472
pnpm-lock.yaml
generated
@ -30,12 +30,6 @@ catalogs:
|
||||
'@iconify/vue':
|
||||
specifier: ^5.0.0
|
||||
version: 5.0.0
|
||||
'@intlify/core-base':
|
||||
specifier: ^11.3.0
|
||||
version: 11.3.0
|
||||
'@intlify/unplugin-vue-i18n':
|
||||
specifier: ^11.0.7
|
||||
version: 11.0.7
|
||||
'@jspm/generator':
|
||||
specifier: ^2.12.0
|
||||
version: 2.12.0
|
||||
@ -360,9 +354,6 @@ catalogs:
|
||||
vue-eslint-parser:
|
||||
specifier: ^10.4.0
|
||||
version: 10.4.0
|
||||
vue-i18n:
|
||||
specifier: ^11.3.0
|
||||
version: 11.3.0
|
||||
vue-json-viewer:
|
||||
specifier: ^3.0.4
|
||||
version: 3.0.4
|
||||
@ -706,9 +697,6 @@ importers:
|
||||
|
||||
internal/vite-config:
|
||||
dependencies:
|
||||
'@intlify/unplugin-vue-i18n':
|
||||
specifier: 'catalog:'
|
||||
version: 11.0.7(@vue/compiler-dom@3.5.30)(eslint@10.1.0(jiti@2.6.1))(rollup@4.60.0)(typescript@5.9.3)(vue-i18n@11.3.0(vue@3.5.30(typescript@5.9.3)))(vue@3.5.30(typescript@5.9.3))
|
||||
'@jspm/generator':
|
||||
specifier: 'catalog:'
|
||||
version: 2.12.0
|
||||
@ -1339,18 +1327,12 @@ importers:
|
||||
|
||||
packages/locales:
|
||||
dependencies:
|
||||
'@intlify/core-base':
|
||||
specifier: 'catalog:'
|
||||
version: 11.3.0
|
||||
'@vben-core/composables':
|
||||
specifier: workspace:*
|
||||
version: link:../@core/composables
|
||||
vue:
|
||||
specifier: ^3.5.30
|
||||
version: 3.5.30(typescript@5.9.3)
|
||||
vue-i18n:
|
||||
specifier: 'catalog:'
|
||||
version: 11.3.0(vue@3.5.30(typescript@5.9.3))
|
||||
|
||||
packages/preferences:
|
||||
dependencies:
|
||||
@ -2481,312 +2463,156 @@ packages:
|
||||
'@epic-web/invariant@1.0.0':
|
||||
resolution: {integrity: sha512-lrTPqgvfFQtR/eY/qkIzp98OGdNJu0m5ji3q/nJI8v3SXkRKEnWiOxMmbvcSoAIzv/cGiuvRy57k4suKQSAdwA==}
|
||||
|
||||
'@esbuild/aix-ppc64@0.25.12':
|
||||
resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [ppc64]
|
||||
os: [aix]
|
||||
|
||||
'@esbuild/aix-ppc64@0.27.4':
|
||||
resolution: {integrity: sha512-cQPwL2mp2nSmHHJlCyoXgHGhbEPMrEEU5xhkcy3Hs/O7nGZqEpZ2sUtLaL9MORLtDfRvVl2/3PAuEkYZH0Ty8Q==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [ppc64]
|
||||
os: [aix]
|
||||
|
||||
'@esbuild/android-arm64@0.25.12':
|
||||
resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [android]
|
||||
|
||||
'@esbuild/android-arm64@0.27.4':
|
||||
resolution: {integrity: sha512-gdLscB7v75wRfu7QSm/zg6Rx29VLdy9eTr2t44sfTW7CxwAtQghZ4ZnqHk3/ogz7xao0QAgrkradbBzcqFPasw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [android]
|
||||
|
||||
'@esbuild/android-arm@0.25.12':
|
||||
resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm]
|
||||
os: [android]
|
||||
|
||||
'@esbuild/android-arm@0.27.4':
|
||||
resolution: {integrity: sha512-X9bUgvxiC8CHAGKYufLIHGXPJWnr0OCdR0anD2e21vdvgCI8lIfqFbnoeOz7lBjdrAGUhqLZLcQo6MLhTO2DKQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm]
|
||||
os: [android]
|
||||
|
||||
'@esbuild/android-x64@0.25.12':
|
||||
resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [android]
|
||||
|
||||
'@esbuild/android-x64@0.27.4':
|
||||
resolution: {integrity: sha512-PzPFnBNVF292sfpfhiyiXCGSn9HZg5BcAz+ivBuSsl6Rk4ga1oEXAamhOXRFyMcjwr2DVtm40G65N3GLeH1Lvw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [android]
|
||||
|
||||
'@esbuild/darwin-arm64@0.25.12':
|
||||
resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@esbuild/darwin-arm64@0.27.4':
|
||||
resolution: {integrity: sha512-b7xaGIwdJlht8ZFCvMkpDN6uiSmnxxK56N2GDTMYPr2/gzvfdQN8rTfBsvVKmIVY/X7EM+/hJKEIbbHs9oA4tQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@esbuild/darwin-x64@0.25.12':
|
||||
resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@esbuild/darwin-x64@0.27.4':
|
||||
resolution: {integrity: sha512-sR+OiKLwd15nmCdqpXMnuJ9W2kpy0KigzqScqHI3Hqwr7IXxBp3Yva+yJwoqh7rE8V77tdoheRYataNKL4QrPw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@esbuild/freebsd-arm64@0.25.12':
|
||||
resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [freebsd]
|
||||
|
||||
'@esbuild/freebsd-arm64@0.27.4':
|
||||
resolution: {integrity: sha512-jnfpKe+p79tCnm4GVav68A7tUFeKQwQyLgESwEAUzyxk/TJr4QdGog9sqWNcUbr/bZt/O/HXouspuQDd9JxFSw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [freebsd]
|
||||
|
||||
'@esbuild/freebsd-x64@0.25.12':
|
||||
resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
|
||||
'@esbuild/freebsd-x64@0.27.4':
|
||||
resolution: {integrity: sha512-2kb4ceA/CpfUrIcTUl1wrP/9ad9Atrp5J94Lq69w7UwOMolPIGrfLSvAKJp0RTvkPPyn6CIWrNy13kyLikZRZQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
|
||||
'@esbuild/linux-arm64@0.25.12':
|
||||
resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-arm64@0.27.4':
|
||||
resolution: {integrity: sha512-7nQOttdzVGth1iz57kxg9uCz57dxQLHWxopL6mYuYthohPKEK0vU0C3O21CcBK6KDlkYVcnDXY099HcCDXd9dA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-arm@0.25.12':
|
||||
resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-arm@0.27.4':
|
||||
resolution: {integrity: sha512-aBYgcIxX/wd5n2ys0yESGeYMGF+pv6g0DhZr3G1ZG4jMfruU9Tl1i2Z+Wnj9/KjGz1lTLCcorqE2viePZqj4Eg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-ia32@0.25.12':
|
||||
resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [ia32]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-ia32@0.27.4':
|
||||
resolution: {integrity: sha512-oPtixtAIzgvzYcKBQM/qZ3R+9TEUd1aNJQu0HhGyqtx6oS7qTpvjheIWBbes4+qu1bNlo2V4cbkISr8q6gRBFA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [ia32]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-loong64@0.25.12':
|
||||
resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [loong64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-loong64@0.27.4':
|
||||
resolution: {integrity: sha512-8mL/vh8qeCoRcFH2nM8wm5uJP+ZcVYGGayMavi8GmRJjuI3g1v6Z7Ni0JJKAJW+m0EtUuARb6Lmp4hMjzCBWzA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [loong64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-mips64el@0.25.12':
|
||||
resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [mips64el]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-mips64el@0.27.4':
|
||||
resolution: {integrity: sha512-1RdrWFFiiLIW7LQq9Q2NES+HiD4NyT8Itj9AUeCl0IVCA459WnPhREKgwrpaIfTOe+/2rdntisegiPWn/r/aAw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [mips64el]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-ppc64@0.25.12':
|
||||
resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-ppc64@0.27.4':
|
||||
resolution: {integrity: sha512-tLCwNG47l3sd9lpfyx9LAGEGItCUeRCWeAx6x2Jmbav65nAwoPXfewtAdtbtit/pJFLUWOhpv0FpS6GQAmPrHA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-riscv64@0.25.12':
|
||||
resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-riscv64@0.27.4':
|
||||
resolution: {integrity: sha512-BnASypppbUWyqjd1KIpU4AUBiIhVr6YlHx/cnPgqEkNoVOhHg+YiSVxM1RLfiy4t9cAulbRGTNCKOcqHrEQLIw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-s390x@0.25.12':
|
||||
resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-s390x@0.27.4':
|
||||
resolution: {integrity: sha512-+eUqgb/Z7vxVLezG8bVB9SfBie89gMueS+I0xYh2tJdw3vqA/0ImZJ2ROeWwVJN59ihBeZ7Tu92dF/5dy5FttA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-x64@0.25.12':
|
||||
resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-x64@0.27.4':
|
||||
resolution: {integrity: sha512-S5qOXrKV8BQEzJPVxAwnryi2+Iq5pB40gTEIT69BQONqR7JH1EPIcQ/Uiv9mCnn05jff9umq/5nqzxlqTOg9NA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/netbsd-arm64@0.25.12':
|
||||
resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [netbsd]
|
||||
|
||||
'@esbuild/netbsd-arm64@0.27.4':
|
||||
resolution: {integrity: sha512-xHT8X4sb0GS8qTqiwzHqpY00C95DPAq7nAwX35Ie/s+LO9830hrMd3oX0ZMKLvy7vsonee73x0lmcdOVXFzd6Q==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [netbsd]
|
||||
|
||||
'@esbuild/netbsd-x64@0.25.12':
|
||||
resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [netbsd]
|
||||
|
||||
'@esbuild/netbsd-x64@0.27.4':
|
||||
resolution: {integrity: sha512-RugOvOdXfdyi5Tyv40kgQnI0byv66BFgAqjdgtAKqHoZTbTF2QqfQrFwa7cHEORJf6X2ht+l9ABLMP0dnKYsgg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [netbsd]
|
||||
|
||||
'@esbuild/openbsd-arm64@0.25.12':
|
||||
resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [openbsd]
|
||||
|
||||
'@esbuild/openbsd-arm64@0.27.4':
|
||||
resolution: {integrity: sha512-2MyL3IAaTX+1/qP0O1SwskwcwCoOI4kV2IBX1xYnDDqthmq5ArrW94qSIKCAuRraMgPOmG0RDTA74mzYNQA9ow==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [openbsd]
|
||||
|
||||
'@esbuild/openbsd-x64@0.25.12':
|
||||
resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [openbsd]
|
||||
|
||||
'@esbuild/openbsd-x64@0.27.4':
|
||||
resolution: {integrity: sha512-u8fg/jQ5aQDfsnIV6+KwLOf1CmJnfu1ShpwqdwC0uA7ZPwFws55Ngc12vBdeUdnuWoQYx/SOQLGDcdlfXhYmXQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [openbsd]
|
||||
|
||||
'@esbuild/openharmony-arm64@0.25.12':
|
||||
resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [openharmony]
|
||||
|
||||
'@esbuild/openharmony-arm64@0.27.4':
|
||||
resolution: {integrity: sha512-JkTZrl6VbyO8lDQO3yv26nNr2RM2yZzNrNHEsj9bm6dOwwu9OYN28CjzZkH57bh4w0I2F7IodpQvUAEd1mbWXg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [openharmony]
|
||||
|
||||
'@esbuild/sunos-x64@0.25.12':
|
||||
resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [sunos]
|
||||
|
||||
'@esbuild/sunos-x64@0.27.4':
|
||||
resolution: {integrity: sha512-/gOzgaewZJfeJTlsWhvUEmUG4tWEY2Spp5M20INYRg2ZKl9QPO3QEEgPeRtLjEWSW8FilRNacPOg8R1uaYkA6g==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [sunos]
|
||||
|
||||
'@esbuild/win32-arm64@0.25.12':
|
||||
resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@esbuild/win32-arm64@0.27.4':
|
||||
resolution: {integrity: sha512-Z9SExBg2y32smoDQdf1HRwHRt6vAHLXcxD2uGgO/v2jK7Y718Ix4ndsbNMU/+1Qiem9OiOdaqitioZwxivhXYg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@esbuild/win32-ia32@0.25.12':
|
||||
resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
|
||||
'@esbuild/win32-ia32@0.27.4':
|
||||
resolution: {integrity: sha512-DAyGLS0Jz5G5iixEbMHi5KdiApqHBWMGzTtMiJ72ZOLhbu/bzxgAe8Ue8CTS3n3HbIUHQz/L51yMdGMeoxXNJw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
|
||||
'@esbuild/win32-x64@0.25.12':
|
||||
resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@esbuild/win32-x64@0.27.4':
|
||||
resolution: {integrity: sha512-+knoa0BDoeXgkNvvV1vvbZX4+hizelrkwmGJBdT17t8FNPwG2lKemmuMZlmaNQ3ws3DKKCxpb4zRZEIp3UxFCg==}
|
||||
engines: {node: '>=18'}
|
||||
@ -2897,65 +2723,6 @@ packages:
|
||||
'@internationalized/number@3.6.5':
|
||||
resolution: {integrity: sha512-6hY4Kl4HPBvtfS62asS/R22JzNNy8vi/Ssev7x6EobfCp+9QIB2hKvI2EtbdJ0VSQacxVNtqhE/NmF/NZ0gm6g==}
|
||||
|
||||
'@intlify/bundle-utils@11.0.7':
|
||||
resolution: {integrity: sha512-fEO3CJGPymxieGh8BHox7d6stgajDQae7wgpH6YYw7WX+cdW6jTTXyljZqz7OV3JcwlS9M9UHSoO+YwiO56IhA==}
|
||||
engines: {node: '>= 20'}
|
||||
peerDependencies:
|
||||
petite-vue-i18n: '*'
|
||||
vue-i18n: '*'
|
||||
peerDependenciesMeta:
|
||||
petite-vue-i18n:
|
||||
optional: true
|
||||
vue-i18n:
|
||||
optional: true
|
||||
|
||||
'@intlify/core-base@11.3.0':
|
||||
resolution: {integrity: sha512-NNX5jIwF4TJBe7RtSKDMOA6JD9mp2mRcBHAwt2X+Q8PvnZub0yj5YYXlFu2AcESdgQpEv/5Yx2uOCV/yh7YkZg==}
|
||||
engines: {node: '>= 16'}
|
||||
|
||||
'@intlify/devtools-types@11.3.0':
|
||||
resolution: {integrity: sha512-G9CNL4WpANWVdUjubOIIS7/D2j/0j+1KJmhBJxHilWNKr9mmt3IjFV3Hq4JoBP23uOoC5ynxz/FHZ42M+YxfGw==}
|
||||
engines: {node: '>= 16'}
|
||||
|
||||
'@intlify/message-compiler@11.3.0':
|
||||
resolution: {integrity: sha512-RAJp3TMsqohg/Wa7bVF3cChRhecSYBLrTCQSj7j0UtWVFLP+6iEJoE2zb7GU5fp+fmG5kCbUdzhmlAUCWXiUJw==}
|
||||
engines: {node: '>= 16'}
|
||||
|
||||
'@intlify/shared@11.3.0':
|
||||
resolution: {integrity: sha512-LC6P/uay7rXL5zZ5+5iRJfLs/iUN8apu9tm8YqQVmW3Uq3X4A0dOFUIDuAmB7gAC29wTHOS3EiN/IosNSz0eNQ==}
|
||||
engines: {node: '>= 16'}
|
||||
|
||||
'@intlify/unplugin-vue-i18n@11.0.7':
|
||||
resolution: {integrity: sha512-wswKprS1D8VfnxxVhKxug5wa3MbDSOcCoXOBjnzhMK+6NfP6h6UI8pFqSBIvcW8nPDuzweTc0Sk3PeBCcubfoQ==}
|
||||
engines: {node: '>= 20'}
|
||||
peerDependencies:
|
||||
petite-vue-i18n: '*'
|
||||
vue: ^3.5.30
|
||||
vue-i18n: '*'
|
||||
peerDependenciesMeta:
|
||||
petite-vue-i18n:
|
||||
optional: true
|
||||
vue-i18n:
|
||||
optional: true
|
||||
|
||||
'@intlify/vue-i18n-extensions@8.0.0':
|
||||
resolution: {integrity: sha512-w0+70CvTmuqbskWfzeYhn0IXxllr6mU+IeM2MU0M+j9OW64jkrvqY+pYFWrUnIIC9bEdij3NICruicwd5EgUuQ==}
|
||||
engines: {node: '>= 18'}
|
||||
peerDependencies:
|
||||
'@intlify/shared': ^9.0.0 || ^10.0.0 || ^11.0.0
|
||||
'@vue/compiler-dom': ^3.0.0
|
||||
vue: ^3.5.30
|
||||
vue-i18n: ^9.0.0 || ^10.0.0 || ^11.0.0
|
||||
peerDependenciesMeta:
|
||||
'@intlify/shared':
|
||||
optional: true
|
||||
'@vue/compiler-dom':
|
||||
optional: true
|
||||
vue:
|
||||
optional: true
|
||||
vue-i18n:
|
||||
optional: true
|
||||
|
||||
'@isaacs/cliui@8.0.2':
|
||||
resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
|
||||
engines: {node: '>=12'}
|
||||
@ -4240,9 +4007,6 @@ packages:
|
||||
'@vue/compiler-ssr@3.5.30':
|
||||
resolution: {integrity: sha512-NsYK6OMTnx109PSL2IAyf62JP6EUdk4Dmj6AkWcJGBvN0dQoMYtVekAmdqgTtWQgEJo+Okstbf/1p7qZr5H+bA==}
|
||||
|
||||
'@vue/devtools-api@6.6.4':
|
||||
resolution: {integrity: sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==}
|
||||
|
||||
'@vue/devtools-api@7.7.9':
|
||||
resolution: {integrity: sha512-kIE8wvwlcZ6TJTbNeU2HQNtaxLx3a84aotTITUuL/4bzfPxzajGBOoqjMhwZJ8L9qFYDU/lAYMEEm11dnZOD6g==}
|
||||
|
||||
@ -5403,11 +5167,6 @@ packages:
|
||||
resolution: {integrity: sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==}
|
||||
engines: {node: '>=0.12'}
|
||||
|
||||
esbuild@0.25.12:
|
||||
resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==}
|
||||
engines: {node: '>=18'}
|
||||
hasBin: true
|
||||
|
||||
esbuild@0.27.4:
|
||||
resolution: {integrity: sha512-Rq4vbHnYkK5fws5NF7MYTU68FPRE1ajX7heQ/8QXXWqNgqqJ/GkmmyxIzUnf2Sr/bakf8l54716CcMGHYhMrrQ==}
|
||||
engines: {node: '>=18'}
|
||||
@ -5436,11 +5195,6 @@ packages:
|
||||
resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
escodegen@2.1.0:
|
||||
resolution: {integrity: sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==}
|
||||
engines: {node: '>=6.0'}
|
||||
hasBin: true
|
||||
|
||||
eslint-compat-utils@0.5.1:
|
||||
resolution: {integrity: sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q==}
|
||||
engines: {node: '>=12'}
|
||||
@ -5552,10 +5306,6 @@ packages:
|
||||
resolution: {integrity: sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==}
|
||||
engines: {node: ^20.19.0 || ^22.13.0 || >=24}
|
||||
|
||||
espree@9.6.1:
|
||||
resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==}
|
||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||
|
||||
esprima@4.0.1:
|
||||
resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==}
|
||||
engines: {node: '>=4'}
|
||||
@ -6413,10 +6163,6 @@ packages:
|
||||
engines: {node: '>=6'}
|
||||
hasBin: true
|
||||
|
||||
jsonc-eslint-parser@2.4.2:
|
||||
resolution: {integrity: sha512-1e4qoRgnn448pRuMvKGsFFymUCquZV0mpGgOyIKNgD3JVDTsVJyRBGH/Fm0tBb8WsWGgmB1mDe6/yJMQM37DUA==}
|
||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||
|
||||
jsonc-eslint-parser@3.1.0:
|
||||
resolution: {integrity: sha512-75EA7EWZExL/j+MDKQrRbdzcRI2HOkRlmUw8fZJc1ioqFEOvBsq7Rt+A6yCxOt9w/TYNpkt52gC6nm/g5tFIng==}
|
||||
engines: {node: ^20.19.0 || ^22.13.0 || >=24}
|
||||
@ -8567,12 +8313,6 @@ packages:
|
||||
peerDependencies:
|
||||
eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
|
||||
|
||||
vue-i18n@11.3.0:
|
||||
resolution: {integrity: sha512-1J+xDfDJTLhDxElkd3+XUhT7FYSZd2b8pa7IRKGxhWH/8yt6PTvi3xmWhGwhYT5EaXdatui11pF2R6tL73/zPA==}
|
||||
engines: {node: '>= 16'}
|
||||
peerDependencies:
|
||||
vue: ^3.5.30
|
||||
|
||||
vue-json-viewer@3.0.4:
|
||||
resolution: {integrity: sha512-pnC080rTub6YjccthVSNQod2z9Sl5IUUq46srXtn6rxwhW8QM4rlYn+CTSLFKXWfw+N3xv77Cioxw7B4XUKIbQ==}
|
||||
peerDependencies:
|
||||
@ -8848,10 +8588,6 @@ packages:
|
||||
yallist@4.0.0:
|
||||
resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
|
||||
|
||||
yaml-eslint-parser@1.3.2:
|
||||
resolution: {integrity: sha512-odxVsHAkZYYglR30aPYRY4nUGJnoJ2y1ww2HDvZALo0BDETv9kWbi16J52eHs+PWRNmF4ub6nZqfVOeesOvntg==}
|
||||
engines: {node: ^14.17.0 || >=16.0.0}
|
||||
|
||||
yaml-eslint-parser@2.0.0:
|
||||
resolution: {integrity: sha512-h0uDm97wvT2bokfwwTmY6kJ1hp6YDFL0nRHwNKz8s/VD1FH/vvZjAKoMUE+un0eaYBSG7/c6h+lJTP+31tjgTw==}
|
||||
engines: {node: ^20.19.0 || ^22.13.0 || >=24}
|
||||
@ -10188,159 +9924,81 @@ snapshots:
|
||||
|
||||
'@epic-web/invariant@1.0.0': {}
|
||||
|
||||
'@esbuild/aix-ppc64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/aix-ppc64@0.27.4':
|
||||
optional: true
|
||||
|
||||
'@esbuild/android-arm64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/android-arm64@0.27.4':
|
||||
optional: true
|
||||
|
||||
'@esbuild/android-arm@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/android-arm@0.27.4':
|
||||
optional: true
|
||||
|
||||
'@esbuild/android-x64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/android-x64@0.27.4':
|
||||
optional: true
|
||||
|
||||
'@esbuild/darwin-arm64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/darwin-arm64@0.27.4':
|
||||
optional: true
|
||||
|
||||
'@esbuild/darwin-x64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/darwin-x64@0.27.4':
|
||||
optional: true
|
||||
|
||||
'@esbuild/freebsd-arm64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/freebsd-arm64@0.27.4':
|
||||
optional: true
|
||||
|
||||
'@esbuild/freebsd-x64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/freebsd-x64@0.27.4':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-arm64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-arm64@0.27.4':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-arm@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-arm@0.27.4':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-ia32@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-ia32@0.27.4':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-loong64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-loong64@0.27.4':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-mips64el@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-mips64el@0.27.4':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-ppc64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-ppc64@0.27.4':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-riscv64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-riscv64@0.27.4':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-s390x@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-s390x@0.27.4':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-x64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-x64@0.27.4':
|
||||
optional: true
|
||||
|
||||
'@esbuild/netbsd-arm64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/netbsd-arm64@0.27.4':
|
||||
optional: true
|
||||
|
||||
'@esbuild/netbsd-x64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/netbsd-x64@0.27.4':
|
||||
optional: true
|
||||
|
||||
'@esbuild/openbsd-arm64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/openbsd-arm64@0.27.4':
|
||||
optional: true
|
||||
|
||||
'@esbuild/openbsd-x64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/openbsd-x64@0.27.4':
|
||||
optional: true
|
||||
|
||||
'@esbuild/openharmony-arm64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/openharmony-arm64@0.27.4':
|
||||
optional: true
|
||||
|
||||
'@esbuild/sunos-x64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/sunos-x64@0.27.4':
|
||||
optional: true
|
||||
|
||||
'@esbuild/win32-arm64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/win32-arm64@0.27.4':
|
||||
optional: true
|
||||
|
||||
'@esbuild/win32-ia32@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/win32-ia32@0.27.4':
|
||||
optional: true
|
||||
|
||||
'@esbuild/win32-x64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/win32-x64@0.27.4':
|
||||
optional: true
|
||||
|
||||
@ -10459,71 +10117,6 @@ snapshots:
|
||||
dependencies:
|
||||
'@swc/helpers': 0.5.19
|
||||
|
||||
'@intlify/bundle-utils@11.0.7(vue-i18n@11.3.0(vue@3.5.30(typescript@5.9.3)))':
|
||||
dependencies:
|
||||
'@intlify/message-compiler': 11.3.0
|
||||
'@intlify/shared': 11.3.0
|
||||
acorn: 8.16.0
|
||||
esbuild: 0.25.12
|
||||
escodegen: 2.1.0
|
||||
estree-walker: 2.0.2
|
||||
jsonc-eslint-parser: 2.4.2
|
||||
source-map-js: 1.2.1
|
||||
yaml-eslint-parser: 1.3.2
|
||||
optionalDependencies:
|
||||
vue-i18n: 11.3.0(vue@3.5.30(typescript@5.9.3))
|
||||
|
||||
'@intlify/core-base@11.3.0':
|
||||
dependencies:
|
||||
'@intlify/devtools-types': 11.3.0
|
||||
'@intlify/message-compiler': 11.3.0
|
||||
'@intlify/shared': 11.3.0
|
||||
|
||||
'@intlify/devtools-types@11.3.0':
|
||||
dependencies:
|
||||
'@intlify/core-base': 11.3.0
|
||||
'@intlify/shared': 11.3.0
|
||||
|
||||
'@intlify/message-compiler@11.3.0':
|
||||
dependencies:
|
||||
'@intlify/shared': 11.3.0
|
||||
source-map-js: 1.2.1
|
||||
|
||||
'@intlify/shared@11.3.0': {}
|
||||
|
||||
'@intlify/unplugin-vue-i18n@11.0.7(@vue/compiler-dom@3.5.30)(eslint@10.1.0(jiti@2.6.1))(rollup@4.60.0)(typescript@5.9.3)(vue-i18n@11.3.0(vue@3.5.30(typescript@5.9.3)))(vue@3.5.30(typescript@5.9.3))':
|
||||
dependencies:
|
||||
'@eslint-community/eslint-utils': 4.9.1(eslint@10.1.0(jiti@2.6.1))
|
||||
'@intlify/bundle-utils': 11.0.7(vue-i18n@11.3.0(vue@3.5.30(typescript@5.9.3)))
|
||||
'@intlify/shared': 11.3.0
|
||||
'@intlify/vue-i18n-extensions': 8.0.0(@intlify/shared@11.3.0)(@vue/compiler-dom@3.5.30)(vue-i18n@11.3.0(vue@3.5.30(typescript@5.9.3)))(vue@3.5.30(typescript@5.9.3))
|
||||
'@rollup/pluginutils': 5.3.0(rollup@4.60.0)
|
||||
'@typescript-eslint/scope-manager': 8.57.1
|
||||
'@typescript-eslint/typescript-estree': 8.57.1(typescript@5.9.3)
|
||||
debug: 4.4.3
|
||||
fast-glob: 3.3.3
|
||||
pathe: 2.0.3
|
||||
picocolors: 1.1.1
|
||||
unplugin: 2.3.11
|
||||
vue: 3.5.30(typescript@5.9.3)
|
||||
optionalDependencies:
|
||||
vue-i18n: 11.3.0(vue@3.5.30(typescript@5.9.3))
|
||||
transitivePeerDependencies:
|
||||
- '@vue/compiler-dom'
|
||||
- eslint
|
||||
- rollup
|
||||
- supports-color
|
||||
- typescript
|
||||
|
||||
'@intlify/vue-i18n-extensions@8.0.0(@intlify/shared@11.3.0)(@vue/compiler-dom@3.5.30)(vue-i18n@11.3.0(vue@3.5.30(typescript@5.9.3)))(vue@3.5.30(typescript@5.9.3))':
|
||||
dependencies:
|
||||
'@babel/parser': 7.29.2
|
||||
optionalDependencies:
|
||||
'@intlify/shared': 11.3.0
|
||||
'@vue/compiler-dom': 3.5.30
|
||||
vue: 3.5.30(typescript@5.9.3)
|
||||
vue-i18n: 11.3.0(vue@3.5.30(typescript@5.9.3))
|
||||
|
||||
'@isaacs/cliui@8.0.2':
|
||||
dependencies:
|
||||
string-width: 5.1.2
|
||||
@ -11773,8 +11366,6 @@ snapshots:
|
||||
'@vue/compiler-dom': 3.5.30
|
||||
'@vue/shared': 3.5.30
|
||||
|
||||
'@vue/devtools-api@6.6.4': {}
|
||||
|
||||
'@vue/devtools-api@7.7.9':
|
||||
dependencies:
|
||||
'@vue/devtools-kit': 7.7.9
|
||||
@ -13150,35 +12741,6 @@ snapshots:
|
||||
ext: 1.7.0
|
||||
optional: true
|
||||
|
||||
esbuild@0.25.12:
|
||||
optionalDependencies:
|
||||
'@esbuild/aix-ppc64': 0.25.12
|
||||
'@esbuild/android-arm': 0.25.12
|
||||
'@esbuild/android-arm64': 0.25.12
|
||||
'@esbuild/android-x64': 0.25.12
|
||||
'@esbuild/darwin-arm64': 0.25.12
|
||||
'@esbuild/darwin-x64': 0.25.12
|
||||
'@esbuild/freebsd-arm64': 0.25.12
|
||||
'@esbuild/freebsd-x64': 0.25.12
|
||||
'@esbuild/linux-arm': 0.25.12
|
||||
'@esbuild/linux-arm64': 0.25.12
|
||||
'@esbuild/linux-ia32': 0.25.12
|
||||
'@esbuild/linux-loong64': 0.25.12
|
||||
'@esbuild/linux-mips64el': 0.25.12
|
||||
'@esbuild/linux-ppc64': 0.25.12
|
||||
'@esbuild/linux-riscv64': 0.25.12
|
||||
'@esbuild/linux-s390x': 0.25.12
|
||||
'@esbuild/linux-x64': 0.25.12
|
||||
'@esbuild/netbsd-arm64': 0.25.12
|
||||
'@esbuild/netbsd-x64': 0.25.12
|
||||
'@esbuild/openbsd-arm64': 0.25.12
|
||||
'@esbuild/openbsd-x64': 0.25.12
|
||||
'@esbuild/openharmony-arm64': 0.25.12
|
||||
'@esbuild/sunos-x64': 0.25.12
|
||||
'@esbuild/win32-arm64': 0.25.12
|
||||
'@esbuild/win32-ia32': 0.25.12
|
||||
'@esbuild/win32-x64': 0.25.12
|
||||
|
||||
esbuild@0.27.4:
|
||||
optionalDependencies:
|
||||
'@esbuild/aix-ppc64': 0.27.4
|
||||
@ -13221,14 +12783,6 @@ snapshots:
|
||||
|
||||
escape-string-regexp@5.0.0: {}
|
||||
|
||||
escodegen@2.1.0:
|
||||
dependencies:
|
||||
esprima: 4.0.1
|
||||
estraverse: 5.3.0
|
||||
esutils: 2.0.3
|
||||
optionalDependencies:
|
||||
source-map: 0.6.1
|
||||
|
||||
eslint-compat-utils@0.5.1(eslint@10.1.0(jiti@2.6.1)):
|
||||
dependencies:
|
||||
eslint: 10.1.0(jiti@2.6.1)
|
||||
@ -13412,12 +12966,6 @@ snapshots:
|
||||
acorn-jsx: 5.3.2(acorn@8.16.0)
|
||||
eslint-visitor-keys: 5.0.1
|
||||
|
||||
espree@9.6.1:
|
||||
dependencies:
|
||||
acorn: 8.16.0
|
||||
acorn-jsx: 5.3.2(acorn@8.16.0)
|
||||
eslint-visitor-keys: 3.4.3
|
||||
|
||||
esprima@4.0.1: {}
|
||||
|
||||
esquery@1.7.0:
|
||||
@ -14254,13 +13802,6 @@ snapshots:
|
||||
|
||||
json5@2.2.3: {}
|
||||
|
||||
jsonc-eslint-parser@2.4.2:
|
||||
dependencies:
|
||||
acorn: 8.16.0
|
||||
eslint-visitor-keys: 3.4.3
|
||||
espree: 9.6.1
|
||||
semver: 7.7.4
|
||||
|
||||
jsonc-eslint-parser@3.1.0:
|
||||
dependencies:
|
||||
acorn: 8.16.0
|
||||
@ -16511,14 +16052,6 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
vue-i18n@11.3.0(vue@3.5.30(typescript@5.9.3)):
|
||||
dependencies:
|
||||
'@intlify/core-base': 11.3.0
|
||||
'@intlify/devtools-types': 11.3.0
|
||||
'@intlify/shared': 11.3.0
|
||||
'@vue/devtools-api': 6.6.4
|
||||
vue: 3.5.30(typescript@5.9.3)
|
||||
|
||||
vue-json-viewer@3.0.4(vue@3.5.30(typescript@5.9.3)):
|
||||
dependencies:
|
||||
clipboard: 2.0.11
|
||||
@ -16883,11 +16416,6 @@ snapshots:
|
||||
|
||||
yallist@4.0.0: {}
|
||||
|
||||
yaml-eslint-parser@1.3.2:
|
||||
dependencies:
|
||||
eslint-visitor-keys: 3.4.3
|
||||
yaml: 2.8.3
|
||||
|
||||
yaml-eslint-parser@2.0.0:
|
||||
dependencies:
|
||||
eslint-visitor-keys: 5.0.1
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user