From f0819281872dbfc27bb180b9d82db946c0190abc Mon Sep 17 00:00:00 2001 From: GiveMePast <1248298477@qq.com> Date: Wed, 5 Aug 2026 11:14:17 +0800 Subject: [PATCH] =?UTF-8?q?AI=E5=88=9D=E6=AD=A5=E4=BF=AE=E6=94=B9=E6=95=B4?= =?UTF-8?q?=E4=BD=93=E5=B8=83=E5=B1=80=E9=A3=8E=E6=A0=BC=E4=BB=A5=E5=8F=8A?= =?UTF-8?q?=E6=A0=B7=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/agents/vue-expert.agent.md | 30 ++ src/assets/main.css | 294 ++++++++++++++++---- src/components/ticket/TicketList.vue | 172 +++++++----- src/layouts/MainLayout.vue | 159 ++++++++--- src/main.js | 2 + src/views/AccountRegistrationView.vue | 16 +- src/views/CompanyAndOperatorsManagement.vue | 27 +- src/views/LoginView.vue | 89 ++++-- src/views/StatsView.vue | 52 ++-- src/views/TicketManagement.vue | 163 +++++++---- 10 files changed, 726 insertions(+), 278 deletions(-) create mode 100644 .github/agents/vue-expert.agent.md diff --git a/.github/agents/vue-expert.agent.md b/.github/agents/vue-expert.agent.md new file mode 100644 index 0000000..59fbc54 --- /dev/null +++ b/.github/agents/vue-expert.agent.md @@ -0,0 +1,30 @@ +--- +description: "Vue/Vue3 专家顾问(10年经验)。当用户询问 Vue 相关问题、寻求最佳实践、代码评审、架构设计建议,或希望得到专业且详细的技术解释(包括为什么要这么做、好处是什么)时使用。触发词:vue、vue3、组合式API、setup、pinia、vue-router、vite、响应式、组件、性能优化、重构、最佳实践、为什么、原因、好处。" +name: "Vue 高级工程师" +tools: [read, search, web, edit, execute] +user-invocable: true +argument-hint: "描述你的 Vue 问题、需要评审的代码,或想了解的方案" +--- +你是一名拥有 10 年以上经验的 Vue 高级工程师,精通 Vue 2/Vue 3、Vite、Pinia、Vue Router、组合式 API(Composition API)与前端工程化。你同时是一名严谨的技术顾问:回答必须专业、深入,并且**对每个关键结论都详细解释「为什么要这么做」以及「这么做的好处」**。 + +## 核心职责 +- 解答 Vue 相关技术问题(响应式原理、组件设计、状态管理、路由、构建优化等)。 +- 评审与优化当前工作区(d:\vue_tickets,Vue 3 + Vite 项目)的代码。 +- 提供架构设计与最佳实践建议。 + +## 回答方式(务必遵循) +1. **直接给结论**:先用一两句话给出明确答案。 +2. **解释为什么**:讲清背后的技术原理、与其他方案的对比与权衡(trade-off)。 +3. **说明好处**:明确指出这样做带来的收益(可维护性、性能、可测试性、可扩展性、协作成本等)。 +4. **指出注意点**:说明边界条件、常见坑、何时不应采用。 +5. **给出示例**:提供可运行、符合项目实际结构的代码片段。 + +## 专业准则 +- 只推荐 Vue 官方认可、社区验证过的最佳实践,不推荐已废弃或反模式的做法。 +- 不确定的地方要明确说明,不臆造。 +- 引用项目内真实文件路径(如 src/views、src/components)使建议落地。 +- 使用简体中文回答,技术术语保留英文便于检索。 + +## 限制 +- 不要堆砌没有依据的「最佳实践」清单。 +- 若问题超出 Vue 范畴,先给出 Vue 侧最佳方案,再补充必要说明。 diff --git a/src/assets/main.css b/src/assets/main.css index 7d5dc37..8f5e20e 100644 --- a/src/assets/main.css +++ b/src/assets/main.css @@ -2,54 +2,86 @@ Global Design System — Refined Minimal ============================================ */ :root { - --color-bg: #fafbfc; - --color-surface: #ffffff; - --color-border: #e9eaed; - --color-border-light: #f0f1f3; + /* ===== 品牌主色(高饱和靛蓝 → 紫) ===== */ + --color-primary: #4f46e5; + --color-primary-deep: #4338ca; + --color-primary-soft: #eef0ff; + --brand-gradient: linear-gradient(135deg, #4f46e5 0%, #6d28d9 60%, #9333ea 100%); - --color-primary: #5b5fe3; - --color-primary-soft: #f0f0ff; - --color-primary-hover:#4a4ed1; + /* ===== 背景层次:深侧栏 → 浅内容 → 白卡片 ===== */ + --color-bg: #eef1f8; + --color-surface: #ffffff; + --color-surface-soft: #f6f8fd; - --color-success: #34c759; - --color-success-soft: #edfaf1; - --color-warning: #f59e0b; - --color-warning-soft: #fffcf0; - --color-danger: #ef4444; - --color-danger-soft: #fef2f2; + --color-border: #e3e8f2; + --color-border-light: #eef1f8; - --text-primary: #1c1c28; - --text-secondary: #6b6d7a; - --text-muted: #9a9ba7; - --text-inverse: #ffffff; + /* ===== 语义色(高饱和) ===== */ + --color-success: #16a34a; + --color-success-soft: #e7f6ed; + --color-warning: #f59e0b; + --color-warning-soft: #fff4e0; + --color-danger: #ef4444; + --color-danger-soft: #fdecec; + --color-info: #0ea5e9; + --color-info-soft: #e6f6fe; + /* ===== 文本层次 ===== */ + --text-primary: #17203f; + --text-secondary: #5b6478; + --text-muted: #98a0b5; + --text-inverse: #ffffff; + + /* ===== 圆角 ===== */ --radius-sm: 8px; --radius-md: 12px; - --radius-lg: 16px; + --radius-lg: 18px; - --shadow-xs: 0 1px 2px rgba(0,0,0,0.03); - --shadow-sm: 0 1px 3px rgba(0,0,0,0.04), 0 1px 2px rgba(0,0,0,0.02); - --shadow-md: 0 4px 12px rgba(0,0,0,0.04), 0 2px 4px rgba(0,0,0,0.02); - --shadow-lg: 0 8px 24px rgba(0,0,0,0.06), 0 2px 8px rgba(0,0,0,0.03); + /* ===== 阴影分级(层次感核心) ===== */ + --shadow-xs: 0 1px 2px rgba(23, 32, 63, 0.05); + --shadow-sm: 0 1px 3px rgba(23, 32, 63, 0.06), 0 1px 2px rgba(23, 32, 63, 0.04); + --shadow-md: 0 8px 20px rgba(79, 70, 229, 0.10), 0 2px 6px rgba(23, 32, 63, 0.05); + --shadow-lg: 0 18px 44px rgba(23, 32, 63, 0.16), 0 6px 16px rgba(23, 32, 63, 0.08); --font-sans: "PingFang SC", "Microsoft YaHei", -apple-system, "Helvetica Neue", sans-serif; --font-mono: "SF Mono", "JetBrains Mono", "Consolas", monospace; + /* ===== Element Plus 对齐 ===== */ --el-color-primary: var(--color-primary); - --el-color-primary-light-3: rgba(91,95,227,0.3); - --el-color-primary-light-5: rgba(91,95,227,0.15); - --el-color-primary-light-7: rgba(91,95,227,0.06); - --el-color-primary-light-9: rgba(91,95,227,0.02); + --el-color-primary-light-3: rgba(79, 70, 229, 0.30); + --el-color-primary-light-5: rgba(79, 70, 229, 0.16); + --el-color-primary-light-7: rgba(79, 70, 229, 0.07); + --el-color-primary-light-8: rgba(79, 70, 229, 0.04); + --el-color-primary-light-9: rgba(79, 70, 229, 0.02); + --el-color-primary-dark-2: var(--color-primary-deep); --el-color-success: var(--color-success); --el-color-warning: var(--color-warning); --el-color-danger: var(--color-danger); + --el-color-error: var(--color-danger); + --el-color-info: var(--color-info); + --el-border-radius-base: 8px; + --el-text-color-primary: var(--text-primary); + --el-text-color-regular: var(--text-secondary); + --el-border-color: var(--color-border); + --el-border-color-light: var(--color-border-light); + --el-fill-color-blank: var(--color-surface); + --el-bg-color: var(--color-surface); + --el-bg-color-page: var(--color-bg); } -*, *::before, *::after { box-sizing: border-box; } +/* ===== 全局基础 ===== */ +*, +*::before, +*::after { + box-sizing: border-box; +} -html, body { - margin: 0; padding: 0; - width: 100%; height: 100%; +html, +body { + margin: 0; + padding: 0; + width: 100%; + height: 100%; background: var(--color-bg); color: var(--text-primary); font-family: var(--font-sans); @@ -59,62 +91,226 @@ html, body { line-height: 1.5; } -#app { width: 100%; margin: 0; padding: 0; display: block; } +#app { + width: 100%; + margin: 0; + padding: 0; + display: block; +} -a { text-decoration: none; color: var(--color-primary); } +a { + text-decoration: none; + color: var(--color-primary); +} + +/* ===== Element Plus overrides ===== */ +/* ---- Button ---- */ +.el-button { + border-radius: 8px; + font-weight: 500; + letter-spacing: 0.01em; + transition: all 0.2s ease; +} -/* Element Plus overrides */ .el-button--primary { --el-button-bg-color: var(--color-primary); --el-button-border-color: var(--color-primary); - --el-button-hover-bg-color: var(--color-primary-hover); - --el-button-hover-border-color: var(--color-primary-hover); - font-weight: 500; - letter-spacing: 0.01em; + --el-button-hover-bg-color: var(--color-primary-deep); + --el-button-hover-border-color: var(--color-primary-deep); + --el-button-active-bg-color: #3730a3; + --el-button-active-border-color: #3730a3; + box-shadow: 0 2px 8px rgba(79, 70, 229, 0.28); } -.el-button { border-radius: var(--radius-sm); font-weight: 500; } +.el-button--primary:hover { + box-shadow: 0 4px 14px rgba(79, 70, 229, 0.36); + transform: translateY(-1px); +} -.el-input .el-input__wrapper { - border-radius: var(--radius-sm); +.el-button--primary:active { + transform: translateY(0); +} + +.el-button--success { + --el-button-bg-color: var(--color-success); + --el-button-border-color: var(--color-success); + --el-button-hover-bg-color: #15803d; + --el-button-hover-border-color: #15803d; + box-shadow: 0 2px 8px rgba(22, 163, 74, 0.24); +} + +/* ---- Input / Select ---- */ +.el-input .el-input__wrapper, +.el-select .el-input__wrapper { + border-radius: 8px; + background: var(--color-surface); box-shadow: 0 0 0 1px var(--color-border) inset; - transition: box-shadow 0.2s; -} -.el-input .el-input__wrapper:hover { box-shadow: 0 0 0 1px var(--color-primary) inset; } -.el-input .el-input__wrapper.is-focus { - box-shadow: 0 0 0 2px rgba(91,95,227,0.15), 0 0 0 1px var(--color-primary) inset; + transition: box-shadow 0.2s, background 0.2s; } -.el-select .el-input__wrapper { border-radius: var(--radius-sm); } +.el-input .el-input__wrapper:hover, +.el-select .el-input__wrapper:hover { + box-shadow: 0 0 0 1px rgba(79, 70, 229, 0.5) inset; +} +.el-input .el-input__wrapper.is-focus, +.el-select .el-input__wrapper.is-focus { + background: #fff; + box-shadow: 0 0 0 2px rgba(79, 70, 229, 0.16), 0 0 0 1px var(--color-primary) inset; +} + +/* ---- Table(层次感:表头深、斑马行、悬停抬升) ---- */ .el-table { --el-table-border-color: var(--color-border-light); + --el-table-header-bg-color: #f3f5fb; + --el-table-header-text-color: var(--text-secondary); + --el-table-row-hover-bg-color: #f6f8ff; + --el-table-current-row-bg-color: #eef0ff; + --el-table-tr-bg-color: var(--color-surface); border-radius: var(--radius-md); overflow: hidden; } +.el-table th.el-table__cell { + font-weight: 600; + letter-spacing: 0.02em; + background: #f3f5fb; +} + +.el-table__inner-wrapper::before { + display: none; +} + +/* ---- Card ---- */ +.el-card { + --el-card-border-color: var(--color-border-light); + border-radius: var(--radius-lg); + box-shadow: var(--shadow-sm); +} + +.el-card.is-always-shadow { + box-shadow: var(--shadow-sm); +} + +/* ---- Dialog ---- */ .el-dialog { --el-dialog-bg-color: var(--color-surface); border-radius: var(--radius-lg); overflow: hidden; box-shadow: var(--shadow-lg); } -.el-dialog__header { border-bottom: 1px solid var(--color-border-light); padding: 20px 24px; } -.el-dialog__body { padding: 24px; } -.el-dialog__footer { padding: 16px 24px; border-top: 1px solid var(--color-border-light); } + +.el-dialog__header { + border-bottom: 1px solid var(--color-border-light); + padding: 20px 24px; +} + +.el-dialog__body { + padding: 24px; +} + +.el-dialog__footer { + padding: 16px 24px; + border-top: 1px solid var(--color-border-light); +} .el-message-box { border-radius: var(--radius-lg); box-shadow: var(--shadow-lg); } +/* ---- Tag ---- */ .el-tag { --el-tag-border-radius: 6px; border: none; font-weight: 500; } +/* ---- Radio Button(筛选高亮) ---- */ +.el-radio-button__original-radio:checked+.el-radio-button__inner { + background: var(--color-primary); + border-color: var(--color-primary); + box-shadow: -1px 0 0 0 var(--color-primary); +} + +.el-radio-button__inner { + box-shadow: none; + border-radius: 0; +} + +.el-radio-group .el-radio-button:first-child .el-radio-button__inner { + border-radius: 8px 0 0 8px; +} + +.el-radio-group .el-radio-button:last-child .el-radio-button__inner { + border-radius: 0 8px 8px 0; +} + +/* ---- Progress ---- */ +.el-progress-bar__outer { + background: #e8ebf4; +} + +/* ---- Switch ---- */ +.el-switch.is-checked .el-switch__core { + background: var(--color-primary); + border-color: var(--color-primary); +} + +/* ---- Collapse ---- */ +.el-collapse { + --el-collapse-border-color: var(--color-border-light); + --el-collapse-header-bg-color: transparent; + --el-collapse-content-bg-color: transparent; +} + +/* ---- Pagination ---- */ .el-pagination { --el-pagination-button-bg-color: var(--color-surface); --el-pagination-hover-color: var(--color-primary); + --el-pagination-active-bg-color: var(--color-primary); + --el-pagination-active-color: #fff; + --el-pagination-button-color: var(--text-secondary); + --el-pagination-border-radius: 8px; } + +/* ---- Dropdown ---- */ +.el-dropdown-menu { + border-radius: 10px; + box-shadow: var(--shadow-lg); +} + +.el-dropdown-menu__item:not(.is-disabled):hover { + background: var(--color-primary-soft); + color: var(--color-primary); +} + +/* ---- Message / MessageBox ---- */ +.el-message { + border-radius: 10px; + box-shadow: var(--shadow-lg); +} + +/* ---- Empty ---- */ +.el-empty__description p { + color: var(--text-muted); +} + +/* ---- Scrollbar ---- */ +::-webkit-scrollbar { + width: 8px; + height: 8px; +} + +::-webkit-scrollbar-thumb { + background: #c6cce0; + border-radius: 8px; +} + +::-webkit-scrollbar-thumb:hover { + background: #aab3cf; +} + +::-webkit-scrollbar-track { + background: transparent; +} \ No newline at end of file diff --git a/src/components/ticket/TicketList.vue b/src/components/ticket/TicketList.vue index b0ddf0e..dd35a92 100644 --- a/src/components/ticket/TicketList.vue +++ b/src/components/ticket/TicketList.vue @@ -1,25 +1,12 @@