This commit is contained in:
2026-06-09 11:26:42 +08:00
parent 7d0fa506b6
commit 5d73a7d036
19 changed files with 35 additions and 248 deletions
-207
View File
@@ -384,11 +384,6 @@ select.form-input {
border: 1px solid rgba(239, 68, 68, 0.2);
}
.empty-state { text-align: center; padding: var(--space-12) 0; }
.empty-icon { width: 64px; height: 64px; margin: 0 auto var(--space-4); color: var(--text-muted); }
.empty-title { font-size: var(--text-lg); font-weight: var(--font-medium); color: var(--text-primary); margin-bottom: var(--space-2); }
.empty-desc { font-size: var(--text-sm); color: var(--text-tertiary); }
.text-center { text-align: center; }
.w-full { width: 100%; }
.hidden { display: none; }
@@ -1458,47 +1453,6 @@ optgroup {
margin-bottom: var(--space-8);
}
.stat-card {
background: var(--bg-primary);
border: 1px solid var(--border-light);
border-radius: var(--radius-xl);
padding: var(--space-5);
cursor: pointer;
transition: all var(--duration-fast) var(--ease-default);
display: flex;
align-items: center;
gap: var(--space-4);
}
.stat-card:hover {
border-color: var(--primary-200);
box-shadow: var(--shadow-md);
transform: translateY(-2px);
}
.stat-card .stat-icon {
font-size: var(--text-3xl);
line-height: 1;
flex-shrink: 0;
}
.stat-content { flex: 1; min-width: 0; }
.stat-value {
font-size: var(--text-2xl);
font-weight: var(--font-bold);
color: var(--text-primary);
line-height: 1.2;
margin-bottom: var(--space-1);
}
.stat-label { font-size: var(--text-sm); color: var(--text-tertiary); }
.stat-icon-big {
font-size: var(--text-2xl);
margin-bottom: var(--space-3);
}
.quick-actions { margin-top: var(--space-8); }
.section-title {
@@ -1562,49 +1516,8 @@ optgroup {
gap: var(--space-2);
}
.action-btns { display: flex; gap: var(--space-2); }
/* ================================
日期选择器
================================ */
.air-datetime-input {
appearance: none;
-webkit-appearance: none;
color: var(--text-primary);
min-height: 44px;
border: 1px solid var(--border-default);
border-radius: var(--radius-lg);
padding: var(--space-3) calc(var(--space-4) + 28px) var(--space-3) var(--space-4);
background: var(--bg-primary);
cursor: pointer;
}
.air-datetime-input:focus {
outline: none;
border-color: var(--primary-500);
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.12);
}
.datetime-field { position: relative; display: flex; align-items: center; }
.datetime-native {
position: absolute;
inset: 0;
opacity: 0;
width: 100%;
height: 100%;
cursor: pointer;
}
.air-datepicker { z-index: 2005 !important; }
.datetime-field-icon {
position: absolute;
right: var(--space-4);
color: var(--text-tertiary);
pointer-events: none;
}
/* ================================
登录页
================================ */
@@ -1726,54 +1639,6 @@ optgroup {
.markdown-preview a { color: var(--primary-700); text-decoration: underline; }
/* ================================
下拉菜单
================================ */
.dropdown { position: relative; display: inline-block; }
.dropdown-toggle { position: relative; padding-right: 24px; }
.dropdown-toggle::after {
content: '▼';
position: absolute;
right: 8px;
top: 50%;
transform: translateY(-50%);
font-size: 10px;
}
.dropdown-menu {
position: absolute;
top: 100%;
left: 0;
background: var(--bg-primary);
border: 1px solid var(--border-default);
border-radius: var(--radius-md);
box-shadow: var(--shadow-lg);
padding: var(--space-2);
min-width: 120px;
z-index: 1000;
display: none;
}
.dropdown:hover .dropdown-menu { display: block; }
.dropdown-item {
display: block;
width: 100%;
padding: var(--space-2) var(--space-3);
text-align: left;
background: none;
border: none;
border-radius: var(--radius-sm);
cursor: pointer;
font-size: var(--text-sm);
color: var(--text-primary);
transition: all var(--duration-fast) var(--ease-default);
}
.dropdown-item:hover { background: var(--bg-secondary); color: var(--primary-600); }
/* ================================
响应式
================================ */
@@ -1912,75 +1777,3 @@ optgroup {
.data-table td input[type="number"] { text-align: right; min-width: 150px; }
.data-table td input.form-input[placeholder*="备注"] { min-width: 250px; }
/* ================================
销售订单 / 采购订单表单
================================ */
.sales-order-table { width: 100%; border-collapse: collapse; margin-bottom: var(--space-4); }
.sales-order-table th, .sales-order-table td {
padding: var(--space-3) var(--space-3); text-align: left;
border-bottom: 1px solid var(--border-light); vertical-align: top;
}
.sales-order-table th {
font-size: var(--text-xs); font-weight: var(--font-medium); color: var(--text-tertiary);
background: var(--bg-secondary); text-transform: uppercase; letter-spacing: 0.05em;
}
.sales-order-item {
background: var(--bg-primary); border: 1px solid var(--border-light);
border-radius: var(--radius-lg); padding: var(--space-4); margin-bottom: var(--space-4);
}
.sales-order-item-header { display: flex; gap: var(--space-3); margin-bottom: var(--space-3); }
.sales-order-item-header button {
flex: 1; padding: var(--space-2) var(--space-3); font-size: var(--text-sm);
font-weight: var(--font-medium); border: 1px solid var(--border-default);
border-radius: var(--radius-md); background: var(--bg-secondary);
color: var(--text-primary); cursor: pointer;
transition: all var(--duration-fast) var(--ease-default);
}
.sales-order-item-header button.active { background: var(--primary-500); color: white; border-color: var(--primary-500); }
.sales-order-item-header button:hover { transform: translateY(-1px); box-shadow: var(--shadow-sm); }
.sales-order-item-content { display: flex; flex-direction: column; gap: var(--space-3); }
.sales-order-item-content input.form-input, .sales-order-item-content select.form-input {
width: 100%; padding: var(--space-3) var(--space-4); font-size: var(--text-sm);
border: 1px solid var(--border-default); border-radius: var(--radius-md);
transition: all var(--duration-fast) var(--ease-default);
}
.sales-order-item-content input.form-input:focus, .sales-order-item-content select.form-input:focus {
outline: none; border-color: var(--primary-500); box-shadow: 0 0 0 3px var(--primary-100);
}
.sales-order-item-row { display: flex; align-items: flex-start; gap: var(--space-4); }
.sales-order-item-column { flex: 1; min-width: 0; }
.sales-order-item-column input.form-input, .sales-order-item-column select.form-input { width: 100%; }
.sales-order-item-actions { display: flex; align-items: flex-start; padding-top: var(--space-3); }
.purchase-order-items { display: flex; flex-direction: column; gap: var(--space-4); }
.purchase-order-item {
background: var(--bg-primary); border: 1px solid var(--border-light);
border-radius: var(--radius-lg); padding: var(--space-4);
}
.purchase-order-item-content { display: flex; flex-direction: column; gap: var(--space-3); }
.purchase-order-item-row { display: flex; align-items: flex-start; gap: var(--space-4); }
.purchase-order-item-column { flex: 1; min-width: 0; }
.purchase-order-item-actions { display: flex; align-items: flex-start; padding-top: var(--space-3); }
/* ================================
物料消耗记录
================================ */
.material-consumption-list { border: 1px solid var(--border-default); border-radius: 4px; overflow: hidden; }
.material-consumption-header {
display: grid; grid-template-columns: 2fr 1fr 1fr 1fr;
background: var(--bg-secondary); padding: 12px 16px;
font-weight: 600; border-bottom: 1px solid var(--border-default);
}
.material-consumption-row {
display: grid; grid-template-columns: 2fr 1fr 1fr 1fr;
padding: 12px 16px; border-bottom: 1px solid var(--border-default);
}
.material-consumption-row:last-child { border-bottom: none; }
.material-consumption-total {
display: grid; grid-template-columns: 2fr 1fr 1fr 1fr;
padding: 12px 16px; background: var(--bg-secondary);
font-weight: 600; margin-top: 8px; border-radius: 4px;
}
.material-consumption-item { text-align: left; }
@@ -67,17 +67,16 @@ onUnmounted(() => {
</div>
</div>
<div v-if="!state.backendDbReady" class="inline-alert inline-alert-warning">
<div class="inline-alert-title">提示</div>
<div class="inline-alert-message">{{ state.backendDbMessage }}</div>
</div>
<el-alert
v-if="!state.backendDbReady"
:title="state.backendDbMessage"
type="warning"
show-icon
:closable="false"
style="margin-bottom: 16px;"
/>
<div v-if="state.loading" class="loading-state">
<div class="spinner"></div>
<span>加载中...</span>
</div>
<div v-else>
<div v-loading="state.loading">
<DashboardTab v-if="state.activeTab === 'dashboard'" />
<ProductsTab v-else-if="state.activeTab === 'products'" />
<MaterialsTab v-else-if="state.activeTab === 'materials'" />
@@ -109,15 +108,6 @@ onUnmounted(() => {
.inventory-breadcrumb .sep { margin: 0 var(--space-2); }
.inventory-breadcrumb .current { color: var(--text-primary); font-weight: var(--font-medium); }
.inline-alert { padding: var(--space-4); border-radius: var(--radius-md); margin-bottom: var(--space-4); }
.inline-alert-warning { background: var(--warning-bg); border: 1px solid var(--warning); }
.inline-alert-title { font-weight: var(--font-semibold); margin-bottom: var(--space-1); }
.inline-alert-message { font-size: var(--text-sm); }
.loading-state { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-8); justify-content: center; color: var(--text-tertiary); }
.spinner { width: 20px; height: 20px; border: 2px solid var(--border-default); border-top-color: var(--primary-500); border-radius: 50%; animation: spin 0.8s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }
.inventory-sidebar-wrapper :deep(.el-menu) {
border-right: none;
background: transparent;
@@ -1,7 +1,6 @@
<script setup lang="ts">
import { ref, computed, onMounted } from 'vue'
import { useInventory } from '../composables/useInventory'
import { handleApiError } from '@/shared/notification'
const {
state,
@@ -454,7 +454,7 @@ import { useRoute, useRouter } from 'vue-router'
import { useAppStore } from '@/stores/app'
import { apiRequest } from '@/shared/api'
import { handleApiError, addNotification } from '@/shared/notification'
import { formatFileSize, formatDateTime, formatNumber } from '@/shared/utils'
import { formatDateTime, formatNumber } from '@/shared/utils'
const route = useRoute()
const router = useRouter()
+10 -5
View File
@@ -45,11 +45,16 @@ export async function apiRequest<T = any>(url: string, options: RequestInit = {}
const response = await fetch(url, { ...options, headers })
if (response.status === 401) {
store.user = null
store.token = null
localStorage.removeItem('token')
localStorage.removeItem('user')
throw new Error('登录已过期,请重新登录')
// 登录接口返回 401 表示用户名/密码错误,不是 token 过期
const isLoginRequest = url.includes('/api/auth/login')
if (!isLoginRequest) {
store.user = null
store.token = null
localStorage.removeItem('token')
localStorage.removeItem('user')
}
const message = await parseErrorMessage(response)
throw new Error(isLoginRequest ? message : '登录已过期,请重新登录')
}
if (!response.ok) {
@@ -1 +1 @@
import{D as e,g as t,t as n,y as r}from"./index-Ck8PP4ML.js";var i={};function a(n,i){return e(),r(`div`,null,[...i[0]||=[t(`div`,{class:`page-header`},[t(`h1`,{class:`page-title`},`设计体系`),t(`p`,{class:`page-subtitle`},`迁移中...`)],-1)]])}var o=n(i,[[`render`,a]]);export{o as default};
import{D as e,g as t,t as n,y as r}from"./index-d9a4ZfZS.js";var i={};function a(n,i){return e(),r(`div`,null,[...i[0]||=[t(`div`,{class:`page-header`},[t(`h1`,{class:`page-title`},`设计体系`),t(`p`,{class:`page-subtitle`},`迁移中...`)],-1)]])}var o=n(i,[[`render`,a]]);export{o as default};
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
.inventory-tab[data-v-ac629843]{padding:0}.table-header[data-v-ac629843]{margin-bottom:16px}.suppliers-tab[data-v-9c9827fc]{padding:0}.table-header[data-v-9c9827fc]{margin-bottom:16px}.customers-tab[data-v-f6d9461f]{padding:0}.table-header[data-v-f6d9461f]{margin-bottom:16px}.movements-tab[data-v-d9f61c89],.page-container[data-v-c02cf723]{padding:0}.page-header[data-v-c02cf723]{margin-bottom:var(--space-6)}.page-header h1[data-v-c02cf723]{font-size:var(--text-2xl);font-weight:var(--font-bold);color:var(--text-primary);margin:0}.page-header p[data-v-c02cf723]{color:var(--text-tertiary);margin:var(--space-1) 0 0;font-size:var(--text-sm)}.inventory-layout[data-v-c02cf723]{gap:var(--space-6);min-height:calc(100vh - 200px);display:flex}.inventory-sidebar-wrapper[data-v-c02cf723]{flex-shrink:0;width:200px}.inventory-content[data-v-c02cf723]{flex:1;min-width:0}.inventory-content-header[data-v-c02cf723]{margin-bottom:var(--space-4)}.inventory-breadcrumb[data-v-c02cf723]{font-size:var(--text-sm);color:var(--text-tertiary)}.inventory-breadcrumb .sep[data-v-c02cf723]{margin:0 var(--space-2)}.inventory-breadcrumb .current[data-v-c02cf723]{color:var(--text-primary);font-weight:var(--font-medium)}.inventory-sidebar-wrapper[data-v-c02cf723] .el-menu{background:0 0;border-right:none}.inventory-sidebar-wrapper[data-v-c02cf723] .sidebar-group-title{padding:var(--space-3) var(--space-4);font-size:var(--text-xs);font-weight:var(--font-semibold);color:var(--text-tertiary);text-transform:uppercase;cursor:pointer;-webkit-user-select:none;user-select:none;justify-content:space-between;align-items:center;display:flex}.inventory-sidebar-wrapper[data-v-c02cf723] .el-menu-item{height:36px;line-height:36px;font-size:var(--text-sm);margin:2px var(--space-2);border-radius:var(--radius-md);padding:0 var(--space-4)}.inventory-sidebar-wrapper[data-v-c02cf723] .el-menu-item.is-active{background:var(--primary-50);color:var(--primary-600);font-weight:var(--font-medium)}.inventory-sidebar-wrapper[data-v-c02cf723] .el-menu-item:hover{background:var(--bg-tertiary)}
-1
View File
@@ -1 +0,0 @@
.inventory-tab[data-v-ac629843]{padding:0}.table-header[data-v-ac629843]{margin-bottom:16px}.suppliers-tab[data-v-9c9827fc]{padding:0}.table-header[data-v-9c9827fc]{margin-bottom:16px}.customers-tab[data-v-f6d9461f]{padding:0}.table-header[data-v-f6d9461f]{margin-bottom:16px}.movements-tab[data-v-d9f61c89],.page-container[data-v-cbcdda91]{padding:0}.page-header[data-v-cbcdda91]{margin-bottom:var(--space-6)}.page-header h1[data-v-cbcdda91]{font-size:var(--text-2xl);font-weight:var(--font-bold);color:var(--text-primary);margin:0}.page-header p[data-v-cbcdda91]{color:var(--text-tertiary);margin:var(--space-1) 0 0;font-size:var(--text-sm)}.inventory-layout[data-v-cbcdda91]{gap:var(--space-6);min-height:calc(100vh - 200px);display:flex}.inventory-sidebar-wrapper[data-v-cbcdda91]{flex-shrink:0;width:200px}.inventory-content[data-v-cbcdda91]{flex:1;min-width:0}.inventory-content-header[data-v-cbcdda91]{margin-bottom:var(--space-4)}.inventory-breadcrumb[data-v-cbcdda91]{font-size:var(--text-sm);color:var(--text-tertiary)}.inventory-breadcrumb .sep[data-v-cbcdda91]{margin:0 var(--space-2)}.inventory-breadcrumb .current[data-v-cbcdda91]{color:var(--text-primary);font-weight:var(--font-medium)}.inline-alert[data-v-cbcdda91]{padding:var(--space-4);border-radius:var(--radius-md);margin-bottom:var(--space-4)}.inline-alert-warning[data-v-cbcdda91]{background:var(--warning-bg);border:1px solid var(--warning)}.inline-alert-title[data-v-cbcdda91]{font-weight:var(--font-semibold);margin-bottom:var(--space-1)}.inline-alert-message[data-v-cbcdda91]{font-size:var(--text-sm)}.loading-state[data-v-cbcdda91]{align-items:center;gap:var(--space-3);padding:var(--space-8);color:var(--text-tertiary);justify-content:center;display:flex}.spinner[data-v-cbcdda91]{border:2px solid var(--border-default);border-top-color:var(--primary-500);border-radius:50%;width:20px;height:20px;animation:.8s linear infinite spin-cbcdda91}@keyframes spin-cbcdda91{to{transform:rotate(360deg)}}.inventory-sidebar-wrapper[data-v-cbcdda91] .el-menu{background:0 0;border-right:none}.inventory-sidebar-wrapper[data-v-cbcdda91] .sidebar-group-title{padding:var(--space-3) var(--space-4);font-size:var(--text-xs);font-weight:var(--font-semibold);color:var(--text-tertiary);text-transform:uppercase;cursor:pointer;-webkit-user-select:none;user-select:none;justify-content:space-between;align-items:center;display:flex}.inventory-sidebar-wrapper[data-v-cbcdda91] .el-menu-item{height:36px;line-height:36px;font-size:var(--text-sm);margin:2px var(--space-2);border-radius:var(--radius-md);padding:0 var(--space-4)}.inventory-sidebar-wrapper[data-v-cbcdda91] .el-menu-item.is-active{background:var(--primary-50);color:var(--primary-600);font-weight:var(--font-medium)}.inventory-sidebar-wrapper[data-v-cbcdda91] .el-menu-item:hover{background:var(--bg-tertiary)}
@@ -1 +1 @@
import{C as e,D as t,N as n,P as r,a as i,f as a,g as o,l as s,n as c,o as l,p as u,t as d,v as f,y as p,z as m}from"./index-Ck8PP4ML.js";var h={class:`login-container`},g={class:`login-card`},_={class:`form-group`},v={class:`form-group`},y={key:0,class:`form-error`},b=[`disabled`],x=d(e({__name:`LoginView`,setup(e){let d=s(),x=r({username:``,password:``,error:``,loading:!1}),S=async()=>{x.error=``,x.loading=!0;try{let e=await l(`/api/auth/login/json`,{method:`POST`,body:JSON.stringify({username:x.username,password:x.password})});i(e.access_token,e.user),c(`登录成功`,`success`),d.push(`/`)}catch(e){x.error=e.message||`登录失败`}finally{x.loading=!1}};return(e,r)=>(t(),p(`div`,h,[o(`div`,g,[r[4]||=o(`div`,{class:`login-header`},[o(`div`,{class:`login-logo`},`G`),o(`h1`,{class:`login-title`},`Gemold`),o(`p`,{class:`login-subtitle`},`模具制造管理系统`)],-1),o(`form`,{onSubmit:u(S,[`prevent`])},[o(`div`,_,[r[2]||=o(`label`,{class:`form-label`},`用户名`,-1),n(o(`input`,{"onUpdate:modelValue":r[0]||=e=>x.username=e,type:`text`,class:`form-input`,placeholder:`请输入用户名`,required:``},null,512),[[a,x.username]])]),o(`div`,v,[r[3]||=o(`label`,{class:`form-label`},`密码`,-1),n(o(`input`,{"onUpdate:modelValue":r[1]||=e=>x.password=e,type:`password`,class:`form-input`,placeholder:`请输入密码`,required:``},null,512),[[a,x.password]])]),x.error?(t(),p(`div`,y,m(x.error),1)):f(``,!0),o(`button`,{type:`submit`,class:`btn btn-primary w-full mt-4`,disabled:x.loading},m(x.loading?`登录中...`:`登录`),9,b)],32)])]))}}),[[`__scopeId`,`data-v-01da5b35`]]);export{x as default};
import{C as e,D as t,N as n,P as r,a as i,f as a,g as o,l as s,n as c,o as l,p as u,t as d,v as f,y as p,z as m}from"./index-d9a4ZfZS.js";var h={class:`login-container`},g={class:`login-card`},_={class:`form-group`},v={class:`form-group`},y={key:0,class:`form-error`},b=[`disabled`],x=d(e({__name:`LoginView`,setup(e){let d=s(),x=r({username:``,password:``,error:``,loading:!1}),S=async()=>{x.error=``,x.loading=!0;try{let e=await l(`/api/auth/login/json`,{method:`POST`,body:JSON.stringify({username:x.username,password:x.password})});i(e.access_token,e.user),c(`登录成功`,`success`),d.push(`/`)}catch(e){x.error=e.message||`登录失败`}finally{x.loading=!1}};return(e,r)=>(t(),p(`div`,h,[o(`div`,g,[r[4]||=o(`div`,{class:`login-header`},[o(`div`,{class:`login-logo`},`G`),o(`h1`,{class:`login-title`},`Gemold`),o(`p`,{class:`login-subtitle`},`模具制造管理系统`)],-1),o(`form`,{onSubmit:u(S,[`prevent`])},[o(`div`,_,[r[2]||=o(`label`,{class:`form-label`},`用户名`,-1),n(o(`input`,{"onUpdate:modelValue":r[0]||=e=>x.username=e,type:`text`,class:`form-input`,placeholder:`请输入用户名`,required:``},null,512),[[a,x.username]])]),o(`div`,v,[r[3]||=o(`label`,{class:`form-label`},`密码`,-1),n(o(`input`,{"onUpdate:modelValue":r[1]||=e=>x.password=e,type:`password`,class:`form-input`,placeholder:`请输入密码`,required:``},null,512),[[a,x.password]])]),x.error?(t(),p(`div`,y,m(x.error),1)):f(``,!0),o(`button`,{type:`submit`,class:`btn btn-primary w-full mt-4`,disabled:x.loading},m(x.loading?`登录中...`:`登录`),9,b)],32)])]))}}),[[`__scopeId`,`data-v-01da5b35`]]);export{x as default};
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
import{D as e,g as t,t as n,y as r}from"./index-Ck8PP4ML.js";var i={};function a(n,i){return e(),r(`div`,null,[...i[0]||=[t(`div`,{class:`page-header`},[t(`h1`,{class:`page-title`},`灰度发布与回滚`),t(`p`,{class:`page-subtitle`},`迁移中...`)],-1)]])}var o=n(i,[[`render`,a]]);export{o as default};
import{D as e,g as t,t as n,y as r}from"./index-d9a4ZfZS.js";var i={};function a(n,i){return e(),r(`div`,null,[...i[0]||=[t(`div`,{class:`page-header`},[t(`h1`,{class:`page-title`},`灰度发布与回滚`),t(`p`,{class:`page-subtitle`},`迁移中...`)],-1)]])}var o=n(i,[[`render`,a]]);export{o as default};
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+2 -2
View File
@@ -61,8 +61,8 @@
} catch (e) {}
})();
</script>
<script type="module" crossorigin src="/static/assets/index-Ck8PP4ML.js"></script>
<link rel="stylesheet" crossorigin href="/static/assets/index-O0fr6NFx.css">
<script type="module" crossorigin src="/static/assets/index-d9a4ZfZS.js"></script>
<link rel="stylesheet" crossorigin href="/static/assets/index-DBUUNurD.css">
</head>
<body>
<div id="app">