diff --git a/.env.development b/.env.development index 03e2369..ee70122 100644 --- a/.env.development +++ b/.env.development @@ -1,6 +1,5 @@ # 开发环境配置 # 基础API地址 VITE_API_BASE_URL=http://cpms.op.nps.yunvip123.cn/cpms - # 是否开启本地调试 LOCAL_DEBUG=true diff --git a/package.json b/package.json index 710375f..3f0af62 100644 --- a/package.json +++ b/package.json @@ -7,8 +7,8 @@ "scripts": { "serve": "vite", "serve:prod": "vite --mode production", - "build:dev": "vue-tsc --noEmit && vite build --mode development", - "build:test": "vue-tsc --noEmit && vite build --mode test", + "build:dev": "node --max-old-space-size=4096 ./node_modules/vite/bin/vite.js build --mode development", + "build:test": "node --max-old-space-size=4096 ./node_modules/vite/bin/vite.js build --mode test", "build:prod": "node --max-old-space-size=4096 ./node_modules/vite/bin/vite.js build --mode production", "test": "vitest", "test:run": "vitest run", @@ -23,16 +23,11 @@ }, "dependencies": { "@ant-design/icons-vue": "^7.0.1", - "@types/big.js": "^7.0.0", "@yp-component/root": "^0.0.48", "ant-design-vue": "^4.0.0", - "big.js": "^7.0.1", "china-area-data": "^5.0.1", "dayjs": "^1.11.21", "echarts": "^5.6.0", - "express": "^5.2.1", - "html2canvas": "^1.4.1", - "qs": "^6.15.0", "vue": "^3.3.0", "vue-icons-plus": "^0.1.8", "vue-router": "^4.2.0" @@ -42,7 +37,6 @@ "@commitlint/config-conventional": "^20.4.3", "@rollup/plugin-strip": "^3.0.4", "@types/node": "^20.10.0", - "@types/qs": "^6.15.0", "@typescript-eslint/eslint-plugin": "^6.0.0", "@typescript-eslint/parser": "^6.0.0", "@vitejs/plugin-vue": "^4.5.0", diff --git a/src/assets/styles/pageLayout.module.less b/src/assets/styles/pageLayout.module.less index b5ba3fb..16637dc 100644 --- a/src/assets/styles/pageLayout.module.less +++ b/src/assets/styles/pageLayout.module.less @@ -4,6 +4,32 @@ flex-direction: column; height: 100%; + // Tabs 容器:撑满高度 + .tabs { + flex: 1; + min-height: 0; + display: flex; + flex-direction: column; + + :global { + .ant-tabs-content-holder { + flex: 1; + min-height: 0; + overflow: hidden; + } + + .ant-tabs-content { + height: 100%; + } + + .ant-tabs-tabpane { + height: 100%; + display: flex; + flex-direction: column; + } + } + } + // 页面筛选区域:横向 flex,可换行 .filter { display: flex; diff --git a/src/config/fallbackRoutes.ts b/src/config/fallbackRoutes.ts index c74f954..af5d3a6 100644 --- a/src/config/fallbackRoutes.ts +++ b/src/config/fallbackRoutes.ts @@ -184,6 +184,15 @@ export const FALLBACK_MENU_NODES: MenuNode[] = [ icon: 'AiOutlineSetting', permission: 'system.params.view', }, + { + id: 'system_ai_agent', + name: 'AI 场景配置', + path: 'system/ai-agent', + component: 'system/ai-agent', + componentName: 'SystemAiAgent', + icon: 'AiOutlineRobot', + permission: 'system.ai.view', + }, { id: 'system_logs', name: '操作日志', diff --git a/src/main.ts b/src/main.ts index 2c16dae..c2a3140 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,7 +1,7 @@ import { createApp } from 'vue'; import Antd from 'ant-design-vue'; import 'ant-design-vue/dist/reset.css'; - +import './styles.less'; import App from './App'; import router from './router'; import './router/guard'; // 路由守卫:登录鉴权 + 动态菜单加载 diff --git a/src/pages/login/index.tsx b/src/pages/login/index.tsx index cb7f965..96fd597 100644 --- a/src/pages/login/index.tsx +++ b/src/pages/login/index.tsx @@ -57,8 +57,8 @@ export default defineComponent({
-
6
- 羽友赛事 +
六
+ 羽赛事

六个羽友赛事运营平台

diff --git a/src/pages/system/ai-agent/components/AiAgentEditModal.module.less b/src/pages/system/ai-agent/components/AiAgentEditModal.module.less new file mode 100644 index 0000000..42082e6 --- /dev/null +++ b/src/pages/system/ai-agent/components/AiAgentEditModal.module.less @@ -0,0 +1,21 @@ +.form { + padding-top: 8px; + + :global(.ant-form-item) { + margin-bottom: 16px; + } +} + +.tip { + margin-top: 4px; + font-size: 12px; + color: rgba(0, 0, 0, 0.45); + line-height: 1.5; +} + +.footer { + display: flex; + justify-content: flex-end; + gap: 8px; + margin-bottom: 0; +} diff --git a/src/pages/system/ai-agent/components/AiAgentEditModal.tsx b/src/pages/system/ai-agent/components/AiAgentEditModal.tsx new file mode 100644 index 0000000..25f9429 --- /dev/null +++ b/src/pages/system/ai-agent/components/AiAgentEditModal.tsx @@ -0,0 +1,187 @@ +import { defineComponent, reactive } from 'vue'; +import { Modal, Form, Input, InputNumber, Switch, Button, message } from 'ant-design-vue'; +import { useEffect } from '@/hooks/useEffect'; +import type { AiAgentConfigVO, AiAgentUpdateParams } from '../model/services'; +import { MIN_MULTIPLIER, MAX_FREE_POINTS } from '../model/config'; +import styles from './AiAgentEditModal.module.less'; + +const { TextArea } = Input; + +interface AiAgentEditModalProps { + visible: boolean; + record: AiAgentConfigVO | null; + submitting: boolean; + onClose: () => void; + onSubmit: (params: AiAgentUpdateParams) => void; +} + +const DEFAULT_FORM = { + enabled: false, + billingEnabled: false, + billingMultiplier: 1, + dailyFreePoints: 0, + descr: '', +}; + +/** + * AI 场景配置编辑弹窗 + * + * 字段:业务开关 / 计费开关 / 计费倍率 / 每日免费额度 / 备注 + * 注意:场景名称和业务类型不可编辑(由代码注册) + */ +export default defineComponent({ + name: 'AiAgentEditModal', + props: { + visible: { type: Boolean, default: false }, + record: { type: Object, default: null }, + submitting: { type: Boolean, default: false }, + onClose: { type: Function, default: null }, + onSubmit: { type: Function, default: null }, + }, + setup(props: AiAgentEditModalProps) { + const formState = reactive({ ...DEFAULT_FORM }); + + /** 根据 record 初始化表单(与项目其他弹窗保持一致的写法) */ + const initFormFromRecord = (record: AiAgentConfigVO | null) => { + if (record) { + Object.assign(formState, { + enabled: String(record.enabled) === '1', + billingEnabled: String(record.billingEnabled) === '1', + billingMultiplier: Number(record.billingMultiplier) || 1, + dailyFreePoints: Number(record.dailyFreePoints) || 0, + descr: record.descr || '', + }); + } else { + Object.assign(formState, DEFAULT_FORM); + } + }; + + // 弹窗打开时回填表单(useEffect 内置 immediate,首次挂载也会执行) + useEffect(() => { + if (props.visible) { + initFormFromRecord(props.record); + } + }, [() => props.visible]); + + const handleSubmit = () => { + // 校验 + if (formState.billingMultiplier < MIN_MULTIPLIER) { + message.warning(`计费倍率必须大于 ${MIN_MULTIPLIER}`); + return; + } + if (formState.dailyFreePoints < 0 || formState.dailyFreePoints > MAX_FREE_POINTS) { + message.warning(`每日免费额度范围为 0 ~ ${MAX_FREE_POINTS}`); + return; + } + + // 构造提交参数(对齐文档 POST /admin/manager/ai/agent/update Body 格式) + const params: AiAgentUpdateParams = { + id: props.record!.id, + enabled: formState.enabled ? 1 : 0, + billingEnabled: formState.billingEnabled ? 1 : 0, + billingMultiplier: formState.billingMultiplier, + dailyFreePoints: formState.dailyFreePoints, + descr: formState.descr.trim(), + }; + + props.onSubmit?.(params); + }; + + return () => ( + +

+ {/* 场景信息(只读) */} + + + + + + + + {/* 业务开关 */} + + (formState.enabled = !!checked)} + checkedChildren="开启" + unCheckedChildren="关闭" + /> + + + {/* 计费开关 */} + + + (formState.billingEnabled = !!checked) + } + checkedChildren="计费" + unCheckedChildren="免费" + /> + + + {/* 计费倍率 */} + + + (formState.billingMultiplier = typeof value === 'number' ? value : 1) + } + min={MIN_MULTIPLIER} + step={0.1} + precision={2} + style={{ width: '100%' }} + /> +
倍率必须大于 0,如 1.0 = 原价,1.5 = 1.5 倍计费
+
+ + {/* 每日免费额度 */} + + + (formState.dailyFreePoints = typeof value === 'number' ? value : 0) + } + min={0} + max={MAX_FREE_POINTS} + step={1} + precision={0} + style={{ width: '100%' }} + /> +
每日免费结算条数,0 = 无免费额度
+
+ + {/* 备注 */} + +