feat: 双主题系统 — 编辑风 + 极简亮色
前端: - 新增 Pinia theme store,localStorage 持久化,data-theme 切换 - App.vue: :root 新增 --font-*/--sidebar-* CSS 变量;新增 :root[data-theme=light] 完整配色(极简黑白金 + Noto Sans SC) - DesktopLayout: 侧边栏 15 个变量化 + 顶栏主题切换按钮 - MobileLayout: 装饰色变量化 - Settings: 新增「界面主题」卡片 - 21 个组件 font-family 统一替换为 var(--font-*) - 新增 utils/managerColor.ts — 12 色调色板 + 自适应文字色 + 后端自定义色优先 - WorkPlans/MiniBusiness/KeyVisits/CustomerManage: 客户经理标签色统一走共享工具 - UserManage: 编辑弹窗新增颜色选择器(仅 manager) - LightBoard: 去标题星标图标 - ManagerWorkspace/WorkPlans/MiniBusiness/KeyVisits: 删除按钮改为实心红底白字 后端: - User 模型新增 color 列 + lifespan 自动迁移 - users API 支持 color 字段读写 - UserOut schema 新增 color Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,11 +1,15 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import { useAuthStore } from '@/stores/auth'
|
||||
import { useThemeStore } from '@/stores/theme'
|
||||
import { customersApi } from '@/api/customers'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { getManagerColor as mgrColorFn, getMgrTextColor, loadManagerColors } from '@/utils/managerColor'
|
||||
import api from '@/api/index'
|
||||
|
||||
const auth = useAuthStore()
|
||||
const themeStore = useThemeStore()
|
||||
const isLight = computed(() => themeStore.currentTheme === 'light')
|
||||
const loading = ref(false)
|
||||
const search = ref('')
|
||||
const filterIndustry = ref('')
|
||||
@@ -43,7 +47,7 @@ const importLoading = ref(false)
|
||||
const importResult = ref<any>(null)
|
||||
|
||||
onMounted(async () => {
|
||||
await loadCustomers()
|
||||
await Promise.all([loadCustomers(), loadManagerColors()])
|
||||
try {
|
||||
const res = await api.get('/users/')
|
||||
managers.value = (res.data || []).filter((u: any) => u.role !== 'leader')
|
||||
@@ -193,11 +197,11 @@ async function removeExistingContact(contactId: string) {
|
||||
} catch (e: any) { if (e !== 'cancel') ElMessage.error('删除失败') }
|
||||
}
|
||||
|
||||
const mgrColors = ['#1C3738','#4A6741','#5B7FA5','#7B7568','#8B6F47','#6B5B4F','#3D5A5C','#5C4A3D']
|
||||
function mgrColor(name: string) {
|
||||
if (!name) return '#909399'
|
||||
let h = 0; for (let i=0;i<name.length;i++) h = name.charCodeAt(i) + ((h<<5)-h)
|
||||
return mgrColors[Math.abs(h) % mgrColors.length]
|
||||
return mgrColorFn(name, isLight.value)
|
||||
}
|
||||
function mgrTextColor(name: string) {
|
||||
return getMgrTextColor(mgrColor(name))
|
||||
}
|
||||
|
||||
async function openDetail(customer: any) {
|
||||
@@ -339,7 +343,7 @@ async function handleImport() {
|
||||
<el-table-column prop="in_use_services" label="在用业务" min-width="150" />
|
||||
<el-table-column label="客户经理" width="90">
|
||||
<template #default="{ row }">
|
||||
<el-tag :color="mgrColor(row.primary_manager_name)" effect="dark" size="small" style="border:none;color:#fff">{{ row.primary_manager_name || '-' }}</el-tag>
|
||||
<el-tag :color="mgrColor(row.primary_manager_name)" effect="dark" size="small" :style="{ border:'none', color: mgrTextColor(row.primary_manager_name) }">{{ row.primary_manager_name || '-' }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
@@ -410,7 +414,7 @@ async function handleImport() {
|
||||
<el-descriptions-item label="备注">{{ detailCustomer.remarks || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="客户经理">{{ detailCustomer.primary_manager_name || '-' }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
<h4 style="margin-top:16px; font-family: 'ZCOOL XiaoWei', STSong, serif; color: var(--ink)">联系人</h4>
|
||||
<h4 style="margin-top:16px; font-family: var(--font-heading); color: var(--ink)">联系人</h4>
|
||||
<div v-if="detailCustomer.contacts?.length">
|
||||
<el-tag v-for="c in detailCustomer.contacts" :key="c.id" style="margin:4px">
|
||||
{{ c.name }}{{ c.phone ? ' · '+c.phone : '' }}{{ c.role_desc ? ' ('+c.role_desc+')' : '' }}
|
||||
@@ -489,7 +493,7 @@ async function handleImport() {
|
||||
.page-head-row { display: flex; justify-content: space-between; align-items: center; }
|
||||
.page-title {
|
||||
margin: 0;
|
||||
font-family: 'ZCOOL XiaoWei', STSong, serif;
|
||||
font-family: var(--font-heading);
|
||||
font-size: 22px; font-weight: 400;
|
||||
color: var(--ink); letter-spacing: 0.06em;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user