ERP前端代码更新 2026-04-06

This commit is contained in:
贾维斯2号 2026-04-06 21:14:31 +08:00
parent 9f64a4d6f4
commit 118b547820
163 changed files with 140 additions and 19502 deletions

0
.env.development Normal file → Executable file
View File

0
.env.production Normal file → Executable file
View File

0
.gitignore vendored Normal file → Executable file
View File

0
.vscode/extensions.json vendored Normal file → Executable file
View File

View File

@ -1,102 +0,0 @@
# 登录页面测试指南
## 🎯 测试账号(模拟模式)
当前登录页面支持以下测试账号(当 `VITE_USE_MOCK=true` 时):
| 账号 | 密码 | 角色 | 描述 |
|------|------|------|------|
| `admin@erp.com` | `password123` | `admin` | 系统管理员,拥有所有权限 |
| `user@erp.com` | `user123456` | `user` | 普通用户,基础权限 |
| `test@erp.com` | `test123456` | `test` | 测试用户,受限权限 |
## 🚀 如何使用
### 1. 启动开发服务器
```bash
npm run dev
# 或
yarn dev
```
### 2. 访问登录页面
打开浏览器访问:`http://localhost:5173/login`
### 3. 识别模拟模式
- **页面右上角**显示黄色"模拟模式"标签
- **页脚**显示可用的模拟账号
- **登录过程**为模拟延迟800ms
### 4. 登录测试
1. 选择"密码登录"方式
2. 输入任一测试账号和密码
3. 点击"登录"按钮
4. 成功后将跳转到首页 (`/`)
## ⚙️ 环境配置
### 启用/禁用模拟模式
`.env.development` 文件中:
```env
# 启用模拟登录(默认)
VITE_USE_MOCK=true
# 禁用模拟登录使用真实API
VITE_USE_MOCK=false
```
### API配置
```env
# 后端API地址
VITE_API_BASE_URL=http://localhost:8080/api
```
## 🔧 模拟登录实现细节
### 前端模拟逻辑
- **位置**: `src/views/Auth/LoginEnhanced.vue` 中的 `mockLogin()` 函数
- **验证**: 检查账号密码是否匹配预设测试账号
- **用户数据**: 生成模拟用户信息ID、角色、权限等
- **状态存储**: 使用 Pinia store + localStorage模拟记住我
### 模拟用户权限
| 角色 | 权限 |
|------|------|
| `admin` | `['dashboard', 'goods', 'order', 'system']` |
| `user` | `['dashboard', 'goods']` |
| `test` | `['dashboard']` |
## 🎨 页面功能
### 登录方式
1. **密码登录** - 使用邮箱和密码
2. **短信登录** - 界面已完成API待实现
### 特色功能
- ✅ 明/暗色主题切换(自动记忆)
- ✅ 响应式设计(支持移动端)
- ✅ 表单实时验证
- ✅ 社交登录(微信、企业微信、钉钉)
- ✅ 记住我功能
- ✅ 协议声明
## 🐛 故障排除
### 常见问题
1. **登录失败**:检查是否输入了正确的测试账号密码
2. **页面样式异常**:确保安装了所有依赖 `npm install`
3. **路由问题**:检查 `src/router/complete-fixed.ts``complete.ts` 中的路由配置
### 开发建议
- 模拟模式仅用于前端开发和测试
- 对接真实API时设置 `VITE_USE_MOCK=false`
- 正式环境应使用 `.env.production` 配置文件
## 📁 相关文件
- `src/views/Auth/LoginEnhanced.vue` - 登录页面主文件
- `src/stores/user.ts` - 用户状态管理
- `src/api/auth.ts` - 登录相关API
- `.env.development` - 开发环境配置
---
*最后更新: 2026-03-24*

View File

@ -1,5 +0,0 @@
# Vue 3 + Vite
This template should help get you started developing with Vue 3 in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
Learn more about IDE Support for Vue in the [Vue Docs Scaling up Guide](https://vuejs.org/guide/scaling-up/tooling.html#ide-support).

1
assets/Admin-BrBLLsD_.js Executable file

File diff suppressed because one or more lines are too long

1
assets/Admin-CGtBF8xn.css Executable file
View File

@ -0,0 +1 @@
.admin-container[data-v-b97571e9]{padding:20px}.search-card[data-v-b97571e9]{margin-bottom:20px}.card-header[data-v-b97571e9]{justify-content:space-between;align-items:center;display:flex}.pagination-wrapper[data-v-b97571e9]{justify-content:flex-end;margin-top:20px;display:flex}

View File

@ -0,0 +1 @@
.after-sale-container[data-v-e7704552]{background:#f8f9fa;min-height:100vh;padding:20px}.stats-row[data-v-e7704552]{margin-bottom:16px}.stat-card[data-v-e7704552]{text-align:center}.stat-item[data-v-e7704552]{flex-direction:column;align-items:center;padding:10px 0;display:flex}.stat-value[data-v-e7704552]{font-size:32px;font-weight:600}.stat-value.pending[data-v-e7704552]{color:#909399}.stat-value.processing[data-v-e7704552]{color:#e6a23c}.stat-value.completed[data-v-e7704552]{color:#67c23a}.stat-label[data-v-e7704552]{color:#909399;margin-top:4px;font-size:14px}.main-tabs[data-v-e7704552]{background:#fff;border-radius:8px;padding:16px}.main-card[data-v-e7704552]{border-radius:8px}.card-header[data-v-e7704552]{justify-content:space-between;align-items:center;display:flex}.filter-bar[data-v-e7704552]{flex-wrap:wrap;align-items:center;gap:12px;margin-bottom:16px;display:flex}.section[data-v-e7704552]{margin-top:24px}.section h4[data-v-e7704552]{color:#303133;margin-bottom:12px}.section h5[data-v-e7704552]{color:#606266;margin:12px 0 8px;font-size:14px}.selected-order-card[data-v-e7704552]{background:#f5f7fa}.order-info[data-v-e7704552]{flex-wrap:wrap;gap:20px;margin-bottom:12px;display:flex}.order-info span[data-v-e7704552]{color:#606266}.form-tip[data-v-e7704552]{color:#909399;margin-left:12px;font-size:12px}.detail-content[data-v-e7704552]{padding:0 10px}.pagination-wrapper[data-v-e7704552]{justify-content:flex-end;margin-top:16px;display:flex}

File diff suppressed because one or more lines are too long

1
assets/Config-Bf5OelgV.css Executable file
View File

@ -0,0 +1 @@
.config-container[data-v-48a34711]{padding:20px}.config-tabs[data-v-48a34711]{background:#fff}.suffix[data-v-48a34711]{color:#909399;margin-left:8px}

1
assets/Config-CHcKHtCr.js Executable file

File diff suppressed because one or more lines are too long

1
assets/Dashboard-TYKD7muw.css Executable file
View File

@ -0,0 +1 @@
.dashboard-container[data-v-3f0af19b]{padding:20px}.stats-row[data-v-3f0af19b]{margin-bottom:20px}.stat-card[data-v-3f0af19b]{background:#fff;border-radius:8px;align-items:center;padding:20px;display:flex;box-shadow:0 2px 12px #0000001a}.stat-icon[data-v-3f0af19b]{color:#fff;border-radius:8px;justify-content:center;align-items:center;width:60px;height:60px;margin-right:20px;font-size:28px;display:flex}.stat-card.tenant .stat-icon[data-v-3f0af19b]{background:linear-gradient(135deg,#667eea 0%,#764ba2 100%)}.stat-card.order .stat-icon[data-v-3f0af19b]{background:linear-gradient(135deg,#f093fb 0%,#f5576c 100%)}.stat-card.revenue .stat-icon[data-v-3f0af19b]{background:linear-gradient(135deg,#4facfe 0%,#00f2fe 100%)}.stat-card.pending .stat-icon[data-v-3f0af19b]{background:linear-gradient(135deg,#fa709a 0%,#fee140 100%)}.stat-content[data-v-3f0af19b]{flex:1}.stat-value[data-v-3f0af19b]{color:#303133;font-size:28px;font-weight:700}.stat-label[data-v-3f0af19b]{color:#909399;margin-top:4px;font-size:14px}.stat-trend[data-v-3f0af19b]{margin-top:8px;font-size:12px}.trend-value[data-v-3f0af19b]{font-weight:700}.trend-value.up[data-v-3f0af19b]{color:#67c23a}.trend-value.down[data-v-3f0af19b]{color:#f56c6c}.trend-label[data-v-3f0af19b]{color:#909399;margin-left:8px}.charts-row[data-v-3f0af19b]{margin-bottom:20px}.chart-card[data-v-3f0af19b]{height:350px}.chart-container[data-v-3f0af19b]{height:280px}.card-header[data-v-3f0af19b]{font-weight:700}.bottom-row .el-card[data-v-3f0af19b]{height:280px}.pending-list[data-v-3f0af19b]{flex-direction:column;gap:16px;display:flex}.pending-item[data-v-3f0af19b]{background:#f5f7fa;border-radius:8px;padding:12px}.pending-content[data-v-3f0af19b]{background:#fff;border-radius:4px;align-items:center;gap:8px;padding:8px 16px;display:flex}.status-list[data-v-3f0af19b]{flex-direction:column;gap:16px;display:flex}.status-item[data-v-3f0af19b]{background:#f5f7fa;border-radius:8px;justify-content:space-between;align-items:center;padding:12px;display:flex}.status-label[data-v-3f0af19b]{color:#606266}.status-value[data-v-3f0af19b]{color:#303133;font-weight:700}

39
assets/Dashboard-X5UFysZh.js Executable file

File diff suppressed because one or more lines are too long

1
assets/Edit-1Yow_gWs.css Executable file
View File

@ -0,0 +1 @@
.goods-edit-container[data-v-0d7a8ec1]{background:#f8f9fa;min-height:calc(100vh - 64px);padding:24px}.sub-items-toolbar[data-v-0d7a8ec1]{margin-bottom:12px}

1
assets/Edit-CeeIoUlF.js Executable file

File diff suppressed because one or more lines are too long

1
assets/List-ByaWNfBv.js Executable file

File diff suppressed because one or more lines are too long

1
assets/List-Djvd2WOK.css Executable file
View File

@ -0,0 +1 @@
.goods-list-container[data-v-2d0a0855]{background:#f8f9fa;min-height:calc(100vh - 64px);padding:24px}.card-header[data-v-2d0a0855]{color:#1a1a2e;justify-content:space-between;align-items:center;font-size:16px;font-weight:600;display:flex}.header-right[data-v-2d0a0855]{align-items:center;display:flex}

1
assets/Login-BESGi_b1.js Executable file

File diff suppressed because one or more lines are too long

1
assets/Login-Ch8cQwoZ.css Executable file

File diff suppressed because one or more lines are too long

1
assets/OrderList-Dg3_JjaG.css Executable file

File diff suppressed because one or more lines are too long

1
assets/OrderList-DhLSSK-m.js Executable file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
.order-pull-container[data-v-2e6e7b92]{padding:16px}.card-header[data-v-2e6e7b92]{justify-content:space-between;align-items:center;display:flex}.search-bar[data-v-2e6e7b92]{margin-bottom:16px}

File diff suppressed because one or more lines are too long

1
assets/Package-0Gwdjasn.css Executable file
View File

@ -0,0 +1 @@
.package-container[data-v-93d81e67]{padding:20px}.search-card[data-v-93d81e67]{margin-bottom:20px}.card-header[data-v-93d81e67]{justify-content:space-between;align-items:center;display:flex}.package-name[data-v-93d81e67]{align-items:center;gap:8px;display:flex}.price[data-v-93d81e67]{color:#f56c6c;font-weight:700}.features-list[data-v-93d81e67]{flex-wrap:wrap;gap:4px;display:flex}.more[data-v-93d81e67]{color:#909399;font-size:12px}.pagination-wrapper[data-v-93d81e67]{justify-content:flex-end;margin-top:20px;display:flex}

1
assets/Package-CFnVrxqs.js Executable file

File diff suppressed because one or more lines are too long

1
assets/Stock-BHXWC1pP.css Executable file
View File

@ -0,0 +1 @@
.stock-container[data-v-b66beaf0]{background:#f8f9fa;min-height:calc(100vh - 64px);padding:24px}.card-header[data-v-b66beaf0]{color:#1a1a2e;justify-content:space-between;align-items:center;font-size:16px;font-weight:600;display:flex}

1
assets/Stock-J2j7dkEc.js Executable file
View File

@ -0,0 +1 @@
import{B as e,F as t,Gt as n,H as r,R as i,U as a,a as o,b as s,d as c,et as l,f as u,m as d,t as f,tt as p,ut as m,v as h,y as g}from"./_plugin-vue_export-helper-BmDUjPB3.js";import{c as _,o as v,r as y}from"./index-BdquF2dM.js";import{t as b}from"./request-D2yY8ZUb.js";import{t as x}from"./warehouse-DjgOFCsD.js";function S(e){return b.get(`/stocks`,{params:e})}function C(e){return b.put(`/stocks/update-threshold`,e)}var w={class:`stock-container`},T={style:{"margin-bottom":`15px`,display:`flex`,gap:`10px`,"flex-wrap":`wrap`}},E=f(s({__name:`Stock`,setup(s){let f=v(),b=m([]),E=m(!1),D=m(1),O=m(10),k=m(0),A=m([]),j=m({warehouseId:``,keyword:``}),M=async()=>{let e=await x({pageSize:100});e.code===200&&(A.value=e.data.list)},N=async()=>{E.value=!0;try{let e=await S({warehouseId:j.value.warehouseId,keyword:j.value.keyword,currentPage:D.value,pageSize:O.value});e.code===200&&(b.value=e.data.list,k.value=e.data.total)}finally{E.value=!1}},P=()=>{j.value={warehouseId:``,keyword:``},D.value=1,N()},F=e=>e.quantity<=0?`danger`:e.quantity<=e.warningThreshold?`warning`:`success`,I=e=>e.quantity<=0?`缺货`:e.quantity<=e.warningThreshold?`预警`:`正常`,L=async(e,t)=>{let n=await C({skuCode:e.skuCode,warehouseId:e.warehouseId,threshold:t});n.code===200?y.success(`预警阈值更新成功`):y.error(n.message||`更新失败`)},R=e=>{f.push(`/warehouse/stock-detail/${e.id}`)};return t(()=>{M(),N()}),(t,s)=>{let f=r(`el-option`),m=r(`el-select`),v=r(`el-input`),y=r(`el-button`),x=r(`el-table-column`),S=r(`el-input-number`),C=r(`el-tag`),M=r(`el-table`),z=r(`el-pagination`),B=r(`el-card`),V=a(`loading`);return i(),d(`div`,w,[g(B,null,{header:l(()=>[...s[4]||=[c(`div`,{class:`card-header`},[c(`span`,null,`库存管理`)],-1)]]),default:l(()=>[c(`div`,T,[g(m,{modelValue:j.value.warehouseId,"onUpdate:modelValue":s[0]||=e=>j.value.warehouseId=e,placeholder:`选择仓库`,clearable:``,style:{width:`180px`}},{default:l(()=>[(i(!0),d(o,null,e(A.value,e=>(i(),u(f,{key:e.id,label:e.name,value:e.id},null,8,[`label`,`value`]))),128))]),_:1},8,[`modelValue`]),g(v,{modelValue:j.value.keyword,"onUpdate:modelValue":s[1]||=e=>j.value.keyword=e,placeholder:`商品名称/编码/条码`,style:{width:`250px`},clearable:``,onKeyup:_(N,[`enter`])},null,8,[`modelValue`]),g(y,{type:`primary`,onClick:N},{default:l(()=>[...s[5]||=[h(`查询`,-1)]]),_:1}),g(y,{onClick:P},{default:l(()=>[...s[6]||=[h(`重置`,-1)]]),_:1})]),p((i(),u(M,{data:b.value,border:``,style:{width:`100%`}},{default:l(()=>[g(x,{prop:`skuCode`,label:`商品编码`,width:`150`}),g(x,{prop:`skuName`,label:`商品名称`,"min-width":`200`}),g(x,{prop:`barcode`,label:`条码`,width:`130`}),g(x,{prop:`warehouseName`,label:`仓库`,width:`150`}),g(x,{prop:`quantity`,label:`实物库存`,width:`100`}),g(x,{prop:`lockedQuantity`,label:`锁定库存`,width:`100`}),g(x,{prop:`availableQuantity`,label:`可用库存`,width:`100`}),g(x,{prop:`warningThreshold`,label:`预警阈值`,width:`120`},{default:l(({row:e})=>[g(S,{modelValue:e.warningThreshold,"onUpdate:modelValue":t=>e.warningThreshold=t,min:0,size:`small`,style:{width:`100px`},onChange:t=>L(e,t)},null,8,[`modelValue`,`onUpdate:modelValue`,`onChange`])]),_:1}),g(x,{prop:`status`,label:`状态`,width:`100`},{default:l(({row:e})=>[g(C,{type:F(e)},{default:l(()=>[h(n(I(e)),1)]),_:2},1032,[`type`])]),_:1}),g(x,{label:`操作`,width:`120`,fixed:`right`},{default:l(({row:e})=>[g(y,{size:`small`,type:`primary`,onClick:t=>R(e)},{default:l(()=>[...s[7]||=[h(`详情`,-1)]]),_:1},8,[`onClick`])]),_:1})]),_:1},8,[`data`])),[[V,E.value]]),g(z,{"current-page":D.value,"onUpdate:currentPage":s[2]||=e=>D.value=e,"page-size":O.value,"onUpdate:pageSize":s[3]||=e=>O.value=e,"page-sizes":[10,20,50],total:k.value,layout:`total, sizes, prev, pager, next, jumper`,onSizeChange:N,onCurrentChange:N,style:{"margin-top":`20px`,"text-align":`right`}},null,8,[`current-page`,`page-size`,`total`])]),_:1})])}}}),[[`__scopeId`,`data-v-b66beaf0`]]);export{E as default};

1
assets/Tenant-Cm4txsEM.css Executable file
View File

@ -0,0 +1 @@
.tenant-container[data-v-cd1afe62]{padding:20px}.search-card[data-v-cd1afe62]{margin-bottom:20px}.card-header[data-v-cd1afe62]{justify-content:space-between;align-items:center;display:flex}.tenant-name[data-v-cd1afe62]{align-items:center;gap:8px;display:flex}.expired[data-v-cd1afe62]{color:#f56c6c}.pagination-wrapper[data-v-cd1afe62]{justify-content:flex-end;margin-top:20px;display:flex}

1
assets/Tenant-pWHhJhkV.js Executable file

File diff suppressed because one or more lines are too long

1
assets/Warehouse-CRSQRe3f.js Executable file
View File

@ -0,0 +1 @@
import{B as e,F as t,Gt as n,H as r,R as i,U as a,a as o,b as s,d as c,et as l,f as u,m as d,t as f,tt as p,ut as m,v as h,y as g}from"./_plugin-vue_export-helper-BmDUjPB3.js";import{n as _,o as v,r as y}from"./index-BdquF2dM.js";import"./request-D2yY8ZUb.js";import{t as b}from"./warehouse-DjgOFCsD.js";var x={class:`warehouse-container`},S={class:`card-header`},C={key:0},w={key:1},T={key:0},E={key:1},D=f(s({__name:`index`,setup(s){let f=v(),D=m([]),O=m(!1),k=m(1),A=m(10),j=m(0),M=e=>({qimen:`奇门`,jst:`聚水潭`,wdt:`旺店通`})[e]||e,N=e=>({common:`通用`,jd:`京东`,pdd:`拼多多`,taobao:`淘宝/天猫`})[e]||e,P=async()=>{O.value=!0;try{let e=await b({currentPage:k.value,pageSize:A.value});e.code===200&&(D.value=e.data.list,j.value=e.data.total)}finally{O.value=!1}},F=()=>{f.push(`/warehouse/edit`)},I=e=>{f.push(`/warehouse/edit/${e}`)},L=e=>{f.push(`/warehouse/bind-template/${e}`)},R=e=>{_.confirm(`确定删除该仓库吗?`,`提示`,{confirmButtonText:`确定`,cancelButtonText:`取消`,type:`warning`}).then(async()=>{let t=await R(e);t.code===200?(y.success(`删除成功`),P()):y.error(t.message||`删除失败`)}).catch(()=>{})};return t(()=>{P()}),(t,s)=>{let f=r(`el-button`),m=r(`el-table-column`),_=r(`el-tag`),v=r(`el-table`),y=r(`el-pagination`),b=r(`el-card`),z=a(`loading`);return i(),d(`div`,x,[g(b,null,{header:l(()=>[c(`div`,S,[s[3]||=c(`span`,null,`仓库列表`,-1),g(f,{type:`primary`,onClick:F},{default:l(()=>[...s[2]||=[h(`新增仓库`,-1)]]),_:1})])]),default:l(()=>[p((i(),u(v,{data:D.value,border:``,style:{width:`100%`}},{default:l(()=>[g(m,{prop:`name`,label:`仓库名称`,"min-width":`150`}),g(m,{prop:`type`,label:`仓库类型`,width:`120`},{default:l(({row:e})=>[g(_,{type:e.type===`erp`?`success`:`primary`},{default:l(()=>[h(n(e.type===`erp`?`ERP仓库`:`云仓`),1)]),_:2},1032,[`type`])]),_:1}),g(m,{prop:`cloudSystem`,label:`云仓系统`,width:`120`},{default:l(({row:e})=>[e.type===`cloud`?(i(),d(`span`,C,n(M(e.cloudSystem)),1)):(i(),d(`span`,w,`-`))]),_:1}),g(m,{prop:`ownerCode`,label:`货主编码`,width:`120`}),g(m,{prop:`cloudCode`,label:`云仓编码`,width:`120`}),g(m,{prop:`createdAt`,label:`创建时间`,width:`180`}),g(m,{label:`已绑平台`,width:`200`},{default:l(({row:t})=>[t.bindings&&t.bindings.length>0?(i(),d(`div`,T,[(i(!0),d(o,null,e(t.bindings,e=>(i(),u(_,{key:e.id,size:`small`,style:{"margin-right":`5px`,"margin-bottom":`3px`}},{default:l(()=>[h(n(N(e.platform))+`: `+n(e.templateName),1)]),_:2},1024))),128))])):(i(),d(`span`,E,`-`))]),_:1}),g(m,{label:`操作`,width:`300`,fixed:`right`},{default:l(({row:e})=>[g(f,{type:`primary`,size:`small`,onClick:t=>I(e.id)},{default:l(()=>[...s[4]||=[h(`编辑`,-1)]]),_:1},8,[`onClick`]),g(f,{type:`success`,size:`small`,onClick:t=>L(e.id)},{default:l(()=>[...s[5]||=[h(`绑定模板`,-1)]]),_:1},8,[`onClick`]),g(f,{type:`danger`,size:`small`,onClick:t=>R(e.id)},{default:l(()=>[...s[6]||=[h(`删除`,-1)]]),_:1},8,[`onClick`])]),_:1})]),_:1},8,[`data`])),[[z,O.value]]),g(y,{"current-page":k.value,"onUpdate:currentPage":s[0]||=e=>k.value=e,"page-size":A.value,"onUpdate:pageSize":s[1]||=e=>A.value=e,"page-sizes":[10,20,50],total:j.value,layout:`total, sizes, prev, pager, next, jumper`,onSizeChange:P,onCurrentChange:P,style:{"margin-top":`20px`,"text-align":`right`}},null,8,[`current-page`,`page-size`,`total`])]),_:1})])}}}),[[`__scopeId`,`data-v-4fb085e3`]]);export{D as default};

1
assets/Warehouse-ulTjVKJZ.css Executable file
View File

@ -0,0 +1 @@
.warehouse-container[data-v-4fb085e3]{background:#f8f9fa;min-height:calc(100vh - 64px);padding:24px}.card-header[data-v-4fb085e3]{color:#1a1a2e;justify-content:space-between;align-items:center;font-size:16px;font-weight:600;display:flex}

1
assets/Welcome-DnyaE-5Y.css Executable file
View File

@ -0,0 +1 @@
.welcome-container[data-v-b2b1d097]{background:#f8f9fa;min-height:calc(100vh - 120px);padding:24px}.welcome-card[data-v-b2b1d097]{background:#fff;border-radius:12px;max-width:1200px;margin:0 auto;padding:32px;box-shadow:0 4px 16px #00000014}.welcome-header[data-v-b2b1d097]{text-align:center;border-bottom:1px solid #e9ecef;margin-bottom:32px;padding-bottom:24px}.welcome-icon[data-v-b2b1d097]{margin-bottom:16px}.welcome-header h1[data-v-b2b1d097]{color:#1a1a2e;margin:0;font-size:24px;font-weight:600}.welcome-content[data-v-b2b1d097]{padding:0 12px}.welcome-text[data-v-b2b1d097]{color:#6c757d;text-align:center;margin-bottom:24px;font-size:15px}.user-tag[data-v-b2b1d097]{color:#1a1a2e;background:linear-gradient(135deg,#d4af37,#f5e6a3);border:none;margin:0 8px;padding:6px 14px;font-size:14px;font-weight:600}.user-info-card[data-v-b2b1d097]{background:#fafafa;border-radius:10px;margin-bottom:32px;padding:20px}.info-card-title[data-v-b2b1d097]{color:#1a1a2e;border-bottom:2px solid #d4af37;margin-bottom:16px;padding-bottom:10px;font-size:15px;font-weight:600;display:inline-block}.system-features[data-v-b2b1d097]{margin-bottom:32px}.section-title[data-v-b2b1d097]{color:#1a1a2e;border-bottom:2px solid #d4af37;margin-bottom:20px;padding-bottom:10px;font-size:15px;font-weight:600;display:inline-block}.feature-card[data-v-b2b1d097]{text-align:center;cursor:pointer;background:#fff;border:1px solid #e9ecef;border-radius:12px;height:100%;padding:24px 20px;transition:all .3s}.feature-card[data-v-b2b1d097]:hover{border-color:#d4af37;transform:translateY(-4px);box-shadow:0 8px 24px #0000001a}.feature-icon-wrap[data-v-b2b1d097]{border-radius:12px;justify-content:center;align-items:center;width:56px;height:56px;margin:0 auto 16px;display:flex}.feature-icon-wrap.gold[data-v-b2b1d097]{color:#d4af37;background:linear-gradient(135deg,#d4af3726,#d4af370d)}.feature-icon-wrap.blue[data-v-b2b1d097]{color:#1a1a2e;background:linear-gradient(135deg,#1a1a2e1a,#1a1a2e0d)}.feature-icon-wrap.green[data-v-b2b1d097]{color:#52c41a;background:linear-gradient(135deg,#52c41a1a,#52c41a0d)}.feature-card h4[data-v-b2b1d097]{color:#1a1a2e;margin:0 0 8px;font-size:15px;font-weight:600}.feature-card p[data-v-b2b1d097]{color:#6c757d;margin:0;font-size:13px;line-height:1.5}.quick-actions[data-v-b2b1d097]{margin-bottom:24px}.action-btn[data-v-b2b1d097]{border-radius:8px!important;justify-content:center!important;align-items:center!important;padding:10px 20px!important;font-weight:500!important;display:inline-flex!important}.gold-btn[data-v-b2b1d097]{color:#1a1a2e!important;background:linear-gradient(135deg,#d4af37,#f5e6a3)!important;border:none!important;box-shadow:0 4px 12px #d4af374d!important}.gold-btn[data-v-b2b1d097]:hover{transform:translateY(-2px);box-shadow:0 6px 16px #d4af3766!important}.white-btn[data-v-b2b1d097]{color:#1a1a2e!important;background:#fff!important;border:1px solid #e9ecef!important}.white-btn[data-v-b2b1d097]:hover{color:#d4af37!important;border-color:#d4af37!important}.welcome-footer[data-v-b2b1d097]{margin-top:32px}.footer-text[data-v-b2b1d097]{text-align:center;color:#adb5bd;justify-content:center;align-items:center;font-size:13px;display:flex}@media (width<=768px){.welcome-container[data-v-b2b1d097]{padding:12px}.welcome-card[data-v-b2b1d097]{padding:20px}.feature-card[data-v-b2b1d097]{margin-bottom:16px;padding:16px}}

1
assets/Welcome-DwFFMcoh.js Executable file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

1
assets/dist-CxIYsDur.js Executable file

File diff suppressed because one or more lines are too long

1
assets/goods-tPYeTpYk.js Executable file
View File

@ -0,0 +1 @@
import{t as e}from"./request-D2yY8ZUb.js";function t(t){return e.get(`/goods`,{params:t})}function n(t){return e.get(`/goods/${t}`)}function r(t){return e.post(`/goods`,t)}function i(t,n){return e.put(`/goods/${t}`,n)}function a(t){return e.delete(`/goods/${t}`)}function o(e){return Promise.resolve({code:200,message:`推送功能开发中`,data:null})}function s(){return e.get(`/goods/all`)}const c=s;export{t as a,n as i,a as n,o,c as r,i as s,r as t};

53
assets/index-BdquF2dM.js Executable file

File diff suppressed because one or more lines are too long

1
assets/index-DWQKLU3Q.css Executable file

File diff suppressed because one or more lines are too long

11
assets/request-D2yY8ZUb.js Executable file

File diff suppressed because one or more lines are too long

1
assets/superAdmin-DRegPzth.js Executable file
View File

@ -0,0 +1 @@
import{t as e}from"./request-D2yY8ZUb.js";function t(){return e({url:`/sa/dashboard`,method:`get`})}function n(t){return e({url:`/sa/tenants`,method:`get`,params:t})}function r(t){return e({url:`/sa/tenants`,method:`post`,data:t})}function i(t,n){return e({url:`/api/sa/tenants/${t}`,method:`put`,data:n})}function a(t){return e({url:`/api/sa/tenants/${t}`,method:`delete`})}function o(t){return e({url:`/api/sa/tenants/${t}/toggle-status`,method:`post`})}function s(t){return e({url:`/api/sa/tenants/${t}/suspend`,method:`post`})}function c(t){return e({url:`/sa/packages`,method:`get`,params:t})}function l(){return e({url:`/sa/packages/all`,method:`get`})}function u(t){return e({url:`/sa/packages`,method:`post`,data:t})}function d(t,n){return e({url:`/api/sa/packages/${t}`,method:`put`,data:n})}function f(t){return e({url:`/api/sa/packages/${t}`,method:`delete`})}function p(t){return e({url:`/api/sa/packages/${t}/set-default`,method:`post`})}function m(){return e({url:`/sa/configs`,method:`get`})}function h(t){return e({url:`/sa/configs`,method:`put`,data:t})}function g(t){return e({url:`/sa/admins`,method:`get`,params:t})}function _(t){return e({url:`/sa/admins`,method:`post`,data:t})}function v(t,n){return e({url:`/api/sa/admins/${t}`,method:`put`,data:n})}function y(t){return e({url:`/api/sa/admins/${t}`,method:`delete`})}function b(t){return e({url:`/api/sa/admins/${t}/toggle-status`,method:`post`})}function x(t,n){return e({url:`/api/sa/admins/${t}/reset-password`,method:`post`,data:{password:n}})}export{o as _,f as a,d as b,m as c,c as d,n as f,b as g,s as h,y as i,t as l,p as m,u as n,a as o,x as p,r,g as s,_ as t,l as u,v,i as x,h as y};

1
assets/warehouse-DjgOFCsD.js Executable file
View File

@ -0,0 +1 @@
import{t as e}from"./request-D2yY8ZUb.js";function t(t){return e.get(`/warehouses`,{params:t})}export{t};

0
public/diagnose-vue.html → diagnose-vue.html Normal file → Executable file
View File

0
public/diagnose.html → diagnose.html Normal file → Executable file
View File

View File

0
public/emergency-print.html → emergency-print.html Normal file → Executable file
View File

View File

@ -1,22 +0,0 @@
import js from '@eslint/js';
import globals from 'globals';
import pluginVue from 'eslint-plugin-vue';
import tseslint from 'typescript-eslint';
export default [
js.configs.recommended,
...tseslint.configs.recommended,
...pluginVue.configs['flat/recommended'],
{
languageOptions: {
ecmaVersion: 2020,
sourceType: 'module',
globals: {
...globals.browser,
},
},
rules: {
// 你可以在这里添加或覆盖规则
},
},
];

5
index.html Normal file → Executable file
View File

@ -5,9 +5,12 @@
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>new-erp</title>
<script type="module" crossorigin src="/assets/index-BdquF2dM.js"></script>
<link rel="modulepreload" crossorigin href="/assets/_plugin-vue_export-helper-BmDUjPB3.js">
<link rel="modulepreload" crossorigin href="/assets/dist-CxIYsDur.js">
<link rel="stylesheet" crossorigin href="/assets/index-DWQKLU3Q.css">
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>

0
public/login-fallback.html → login-fallback.html Normal file → Executable file
View File

0
npm
View File

View File

View File

View File

0
s.id
View File

0
public/simple-login.html → simple-login.html Normal file → Executable file
View File

View File

@ -1,3 +0,0 @@
<template>
<router-view />
</template>

View File

@ -1,58 +0,0 @@
// 售后管理 API
import request from '@/utils/request'
/**
*
*/
export function getAfterSalesList(params?: any) {
return request.get('/after-sales', { params })
}
/**
*
*/
export function getAfterSaleDetail(id: string) {
return request.get(`/after-sales/${id}`)
}
/**
*
*/
export function createAfterSale(data: any) {
return request.post('/after-sales', data)
}
/**
*
*/
export function updateAfterSaleStatus(id: string, data: any) {
return request.put(`/after-sales/${id}/status`, data)
}
/**
*
*/
export function deleteAfterSale(id: string) {
return request.delete(`/after-sales/${id}`)
}
/**
*
*/
export function getAvailableOrders(params?: any) {
return request.get('/after-sales/available-orders', { params })
}
/**
* 退
*/
export function getAllAvailableOrders(params?: any) {
return request.get('/after-sales/all-available-orders', { params })
}
/**
*
*/
export function getAfterSaleStats() {
return request.get('/after-sales/stats')
}

View File

@ -1,129 +0,0 @@
// AI 对话管理 API
import request from '@/utils/request'
/**
*
*/
export type MessageRole = 'user' | 'assistant' | 'system'
/**
*
*/
export interface Message {
id: string
role: MessageRole
content: string
createdAt: string
}
/**
*
*/
export interface Conversation {
id: string
title: string
messages: Message[]
model?: string
createdAt: string
updatedAt: string
}
/**
* AI
*/
export interface AIModel {
id: string
name: string
provider: string
description?: string
isActive?: boolean
}
/**
* AI
*/
export interface AICapability {
id: string
name: string
description: string
enabled: boolean
}
/**
*
*/
export interface ChatParams {
conversationId?: string
message: string
model?: string
}
/**
*
*/
export interface ExecuteTaskParams {
task: string
context?: Record<string, any>
options?: Record<string, any>
}
/**
*
*/
export function getConversations() {
return request.get('/ai/conversations')
}
/**
*
* @param id ID
*/
export function getConversationDetail(id: string) {
return request.get(`/ai/conversations/${id}`)
}
/**
*
* @param id ID
*/
export function deleteConversation(id: string) {
return request.delete(`/ai/conversations/${id}`)
}
/**
*
* @param params
*/
export function sendChatMessage(params: ChatParams) {
return request.post('/ai/chat', params)
}
/**
* AI
* @param params
*/
export function executeTask(params: ExecuteTaskParams) {
return request.post('/ai/execute-task', params)
}
/**
* AI
*/
export function getCapabilities() {
return request.get('/ai/capabilities')
}
/**
*
*/
export function getModels() {
return request.get('/ai/models')
}
/**
*
* @param data ID
*/
export function switchModel(data: { modelId: string }) {
return request.post('/ai/models/switch', data)
}

View File

@ -1,65 +0,0 @@
// src/api/brand.ts
import request from '@/utils/request'
/**
*
*/
export interface Brand {
id?: number
name: string
code?: string
logo?: string
status?: number
description?: string
created_at?: string
updated_at?: string
[key: string]: any
}
/**
*
* @param params page, limit, name, status
*/
export function getBrandList(params?: any) {
return request.get('/brands', { params })
}
/**
*
* @param id ID
*/
export function getBrandDetail(id: number) {
return request.get(`/brands/${id}`)
}
/**
*
* @param data
*/
export function createBrand(data: Brand) {
return request.post('/brands', data)
}
/**
*
* @param id ID
* @param data
*/
export function updateBrand(id: number, data: Partial<Brand>) {
return request.put(`/brands/${id}`, data)
}
/**
*
* @param id ID
*/
export function deleteBrand(id: number) {
return request.delete(`/brands/${id}`)
}
/**
*
*/
export function getAllBrands() {
return request.get('/brands/all')
}

View File

@ -1,151 +0,0 @@
import request from '@/utils/request'
// ==================== 类型定义 ====================
/** 配送单状态 */
export type DeliveryOrderStatus = 'pending' | 'printed' | 'shipped' | 'sync_failed' | 'completed'
/** 配送单商品项 */
export interface DeliveryOrderItem {
id?: string
skuCode: string
skuName?: string
quantity: number
}
/** 配送单 */
export interface DeliveryOrder {
id?: string
orderNo?: string
warehouseId: string
warehouseName?: string
platformOrderId?: string
platformOrderNo?: string
status: DeliveryOrderStatus
totalAmount?: number
expressCompany?: string
trackingNo?: string
items: DeliveryOrderItem[]
createTime?: string
updateTime?: string
printTime?: string
shipTime?: string
}
/** 待发货列表查询参数 */
export interface PendingDeliveryParams {
page?: number
pageSize?: number
warehouseId?: string
keyword?: string
}
/** 标记打印请求 */
export interface MarkPrintedDto {
orderIds: string[]
}
/** 重新打印请求 */
export interface ReprintDto {
orderIds: string[]
}
/** 发货请求 */
export interface ShipDto {
orderId: string
expressCompany: string
trackingNo: string
}
/** 打印日志 */
export interface PrintLog {
id?: string
orderId: string
orderNo?: string
printType: 'original' | 'reprint'
printedAt: string
printedBy?: string
printer?: string
}
/** 打印日志查询参数 */
export interface PrintLogParams {
page?: number
pageSize?: number
orderNo?: string
startDate?: string
endDate?: string
}
// ==================== API 函数 ====================
/**
*
* @param params
*/
export function getPendingDeliveryList(params?: PendingDeliveryParams) {
return request.get<PendingDeliveryResponse>('/delivery/pending-delivery', { params })
}
/**
*
* @param data ID列表
*/
export function markPrinted(data: MarkPrintedDto) {
return request.post<void>('/delivery/mark-printed', data)
}
/**
*
* @param data ID列表
*/
export function reprintDelivery(data: ReprintDto) {
return request.post<void>('/delivery/reprint', data)
}
/**
*
* @param params
*/
export function getPrintLogs(params?: PrintLogParams) {
return request.get<PrintLogResponse>('/delivery/print-logs', { params })
}
/**
*
* @param data
*/
export function shipDelivery(data: ShipDto) {
return request.post<void>('/delivery/ship', data)
}
/**
*
*/
export function syncFailedRetry() {
return request.post<void>('/delivery/sync-failed')
}
/**
*
* @param id ID
*/
export function retrySyncDelivery(id: string) {
return request.post<void>(`/delivery/retry-sync/${id}`)
}
// ==================== 响应类型 ====================
export interface PendingDeliveryResponse {
list: DeliveryOrder[]
total: number
page: number
pageSize: number
}
export interface PrintLogResponse {
list: PrintLog[]
total: number
page: number
pageSize: number
}

View File

@ -1,227 +0,0 @@
// src/api/goods.ts
import request from '@/utils/request'
// ============ 类型定义 ============
/** 商品类型 */
export type GoodsType = 'normal' | 'combo'
/** 商品状态 */
export type GoodsStatus = 'active' | 'inactive'
/** 商品 */
export interface Goods {
id: number
name: string
code: string
barcode?: string
type: GoodsType
type_label?: string
retail_price: string
cost_price: string
unit?: string
brand?: { id: number; name: string } | null
suppliers?: string
weight?: string
packaging_cost?: string
shipping_packaging_cost?: string
volume?: string
length?: string
width?: string
height?: string
batch_management: boolean
created_at: string
updated_at: string
}
/** 商品列表查询参数 */
export interface GoodsListParams {
keyword?: string
category?: string
type?: GoodsType
status?: GoodsStatus
page?: number
limit?: number
}
/** 商品列表响应 */
export interface GoodsListResponse {
list: Goods[]
total: number
current_page: number
last_page: number
}
/** 创建/更新商品请求 */
export interface GoodsFormData {
name: string
code: string
type: GoodsType
barcode?: string
retail_price?: number | string
cost_price?: number | string
unit?: string
brand_id?: number
weight?: number | string
packaging_cost?: number | string
}
/** SKU绑定请求 */
export interface BindSkuData {
goodsId: string
skuCode: string
}
/** 批量绑定请求 */
export interface BatchBindData {
goodsId: string
skuCodes: string[]
}
/** 自动匹配请求 */
export interface AutoMatchData {
warehouseId: string
}
/** 匹配结果查询参数 */
export interface MatchResultsParams {
warehouseId?: string
status?: string
page?: number
limit?: number
}
/** 匹配结果项 */
export interface MatchResult {
id: string
goodsId: string
goodsName: string
skuCode: string
warehouseId: string
warehouseName: string
matchStatus: 'matched' | 'unmatched' | 'pending'
matchType?: 'auto' | 'manual'
createdAt: string
}
// ============ API 函数 ============
/**
*
*/
export function getGoodsList(params?: GoodsListParams) {
return request.get<GoodsListResponse>('/goods', { params })
}
/**
*
*/
export function getGoodsDetail(id: string | number) {
return request.get<Goods>(`/goods/${id}`)
}
/**
*
*/
export function createGoods(data: GoodsFormData) {
return request.post<Goods>('/goods', data)
}
/**
*
*/
export function updateGoods(id: string | number, data: Partial<GoodsFormData>) {
return request.put<Goods>(`/goods/${id}`, data)
}
/**
*
*/
export function deleteGoods(id: string | number) {
return request.delete<void>(`/goods/${id}`)
}
/**
*
* 注意: 后端暂无此接口
*/
export function syncAllGoods() {
return Promise.resolve({
code: 200,
message: '同步功能开发中',
data: null
})
}
/**
* SKU
*/
export function bindSku(data: BindSkuData) {
return request.post<void>('/goods/bind-sku', data)
}
/**
* SKU绑定
*/
export function unbindSku(data: BindSkuData) {
return request.post<void>('/goods/unbind-sku', data)
}
/**
* SKU
*/
export function batchBindSku(data: BatchBindData) {
return request.post<void>('/goods/batch-bind', data)
}
/**
*
*/
export function autoMatchGoods(data: AutoMatchData) {
return request.post<void>('/goods/auto-match', data)
}
/**
*
*/
export function getMatchResults(params?: MatchResultsParams) {
return request.get<{ list: MatchResult[]; total: number }>('/goods/match-results', { params })
}
/**
*
* 注意: 后端暂无此接口
*/
export function pushGoodsToCloud(data: { goodsIds: number[]; warehouseId: number }) {
return Promise.resolve({
code: 200,
message: '推送功能开发中',
data: null
})
}
/**
*
* 注意: 后端暂无此接口
*/
export function getPushLogs(params?: { page?: number; pageSize?: number }) {
return Promise.resolve({
code: 200,
data: {
list: [],
total: 0,
page: params?.page || 1,
pageSize: params?.pageSize || 10
}
})
}
/**
*
*/
export function getAllGoods() {
return request.get('/goods/all')
}
// 别名兼容
export const getAllGoodsForSelect = getAllGoods

View File

@ -1,65 +0,0 @@
// 操作日志 API
import request from '@/utils/request'
/**
*
*/
export interface OperationLogItem {
id: number
operateTime: string
userName: string
operateType: string
operateDesc: string
result: number
ipAddress: string
userAgent: string
}
/**
*
*/
export interface OperationLogParams {
currentPage?: number
pageSize?: number
keyword?: string
operateType?: string
startDate?: string
endDate?: string
}
/**
*
* @param params
*/
export function getOperationLogs(params?: OperationLogParams) {
return request.get('/operation-logs', { params })
}
/**
*
* @param id ID
*/
export function getOperationLogDetail(id: number) {
return request.get(`/operation-logs/${id}`)
}
/**
*
* @param params
*/
export function exportLogs(params?: OperationLogParams) {
return request.get('/operation-logs/export', { params })
}
/**
*
*/
export function addOperationLog(data: {
operateType: string
operateDesc: string
result: number
userId?: number
userName?: string
}) {
return request.post('/operation-logs', data)
}

View File

@ -1,76 +0,0 @@
// src/api/platform-product.ts
import request from '@/utils/request'
/**
*
*/
export interface PlatformProduct {
id: number
platform_id: number
platform_name: string
platform_code: string
outer_id: string
num_iid: string
title: string
price: string
pic_url: string
seller_nick: string
approve_status: string
listed_time: string
unsale_time: string
stock: number
has_sync: boolean
bound_goods_id?: number
bound_goods_name?: string
bound_sku_code?: string
last_sync_at?: string
created_at: string
updated_at: string
}
/**
*
*/
export interface PlatformProductListParams {
platform_id?: number
keyword?: string
sync_status?: 'all' | 'synced' | 'unsynced'
page?: number
limit?: number
}
/**
*
*/
export function getPlatformProductList(params?: PlatformProductListParams) {
return request.get<{
list: PlatformProduct[]
total: number
page: number
last_page: number
}>('/platform-products', { params })
}
/**
*
*/
export function getPlatformProductDetail(id: number) {
return request.get<PlatformProduct>(`/platform-products/${id}`)
}
/**
*
*/
export function syncPlatformProducts(platformId: number) {
return request.post<{ synced_count: number }>('/platform-products/sync', { platform_id: platformId })
}
/**
* ERP商品
*/
export function bindPlatformProduct(platformProductId: number, goodsId: number, skuCode?: string) {
return request.post(`/platform-products/${platformProductId}/bind`, {
goods_id: goodsId,
sku_code: skuCode
})
}

View File

@ -1,113 +0,0 @@
// src/api/platform.ts
import request from '@/utils/request'
/**
*
*/
export interface Platform {
id?: number
name: string
code: string
status?: number
created_at?: string
updated_at?: string
[key: string]: any
}
/**
*
*/
export interface PlatformStats {
total: number
active: number
inactive: number
today_add: number
[key: string]: any
}
/**
*
* @param params page, limit, name, status
*/
export function getPlatformList(params?: any) {
return request.get('/platforms', { params })
}
/**
*
* @param id ID
*/
export function getPlatformDetail(id: number) {
return request.get(`/platforms/${id}`)
}
/**
*
* @param data
*/
export function createPlatform(data: Platform) {
return request.post('/platforms', data)
}
/**
*
* @param id ID
* @param data
*/
export function updatePlatform(id: number, data: Partial<Platform>) {
return request.put(`/platforms/${id}`, data)
}
/**
*
* @param id ID
*/
export function deletePlatform(id: number) {
return request.delete(`/platforms/${id}`)
}
/**
*
*/
export function syncPlatform() {
return request.post('/platforms/sync')
}
/**
*
* @param data
*/
export function batchUpdatePlatform(data: Partial<Platform>[]) {
return request.post('/platforms/batch-update', data)
}
/**
*
*/
export function getPlatformStats() {
return request.get('/platforms/stats')
}
/**
*
*/
export function getAllPlatforms() {
return request.get('/platforms/all')
}
/**
*
*/
export function getWaybillAccounts(platformId?: number) {
return Promise.resolve({
code: 200,
data: { list: [], total: 0 }
})
}
/**
*
*/
export function syncWaybillAccounts(platformId: number) {
return Promise.resolve({ code: 200, message: '功能开发中', data: null })
}

View File

@ -1,166 +0,0 @@
// src/api/platformGoods.ts
// 模拟店铺数据
const mockShops = {
taobao: [
{ id: 'tb1', name: '淘宝官方旗舰店' },
{ id: 'tb2', name: '淘宝专营店' }
],
jd: [
{ id: 'jd1', name: '京东自营店' },
{ id: 'jd2', name: '京东专营店' }
],
pdd: [
{ id: 'pdd1', name: '拼多多官方旗舰店' },
{ id: 'pdd2', name: '拼多多专营店' }
],
douyin: [
{ id: 'dy1', name: '抖音小店' },
{ id: 'dy2', name: '抖音专营店' }
]
}
// 模拟平台商品数据(按平台和店铺组织)
const mockPlatformGoods: Record<string, Record<string, any[]>> = {
taobao: {
tb1: [
{
id: 'tb_spu_1',
type: 'spu',
name: '连衣裙',
code: 'TB-SPU-001',
price: 199.0,
status: 'onsale',
bound: false,
skus: [
{
id: 'tb_sku_11',
spuId: 'tb_spu_1',
type: 'sku',
name: '红色-S',
code: 'TB-SKU-001-R-S',
price: 199.0,
status: 'onsale',
bound: false
},
{
id: 'tb_sku_12',
spuId: 'tb_spu_1',
type: 'sku',
name: '红色-M',
code: 'TB-SKU-001-R-M',
price: 199.0,
status: 'onsale',
bound: true
}
]
},
{
id: 'tb_spu_2',
type: 'spu',
name: '运动鞋',
code: 'TB-SPU-002',
price: 299.0,
status: 'onsale',
bound: false,
skus: [
{
id: 'tb_sku_21',
spuId: 'tb_spu_2',
type: 'sku',
name: '白色-42',
code: 'TB-SKU-002-W-42',
price: 299.0,
status: 'onsale',
bound: false
}
]
}
],
tb2: []
},
jd: {},
pdd: {},
douyin: {}
}
// 辅助函数:平台代码转中文名称
function getPlatformName(platform: string): string {
const map: Record<string, string> = {
taobao: '淘宝',
jd: '京东',
pdd: '拼多多',
douyin: '抖音'
}
return map[platform] || platform
}
/**
* -
*/
export function getPlatformShopTree() {
return new Promise<{ code: number; data: any[] }>((resolve) => {
setTimeout(() => {
const tree = Object.keys(mockShops).map(platform => ({
id: `platform-${platform}`,
label: getPlatformName(platform),
type: 'platform',
platform,
children: mockShops[platform].map(shop => ({
id: `shop-${shop.id}`,
label: shop.name,
type: 'shop',
platform,
shopId: shop.id,
leaf: true
}))
}))
resolve({ code: 200, data: tree })
}, 200)
})
}
// 获取店铺列表(兼容旧接口)
export function getShopsByPlatform(platform: string) {
return new Promise<{ code: number; data: any[] }>((resolve) => {
setTimeout(() => {
resolve({ code: 200, data: mockShops[platform] || [] })
}, 200)
})
}
// 下载平台商品
export function downloadPlatformGoods(params: {
platform: string
shopId: string
downloadType: string
specifyIds?: string
}) {
console.log('downloadPlatformGoods called with params:', params)
return new Promise<{ code: number; message?: string }>((resolve) => {
setTimeout(() => {
resolve({ code: 200, message: '下载任务已提交' })
}, 500)
})
}
// 获取已下载的平台商品列表
export function getPlatformGoodsList(params: { platform: string; shopId: string }) {
console.log('getPlatformGoodsList called with params:', params)
return new Promise<{ code: number; data: any[] }>((resolve) => {
setTimeout(() => {
const goods = mockPlatformGoods[params.platform]?.[params.shopId] || []
resolve({ code: 200, data: goods })
}, 300)
})
}
// 绑定ERP商品与平台SKU
export function bindErpSku(data: { skuId: string; erpGoodsId: string }) {
console.log('bindErpSku called with data:', data)
return new Promise<{ code: number; message?: string }>((resolve) => {
setTimeout(() => {
resolve({ code: 200, message: '绑定成功' })
}, 300)
})
}

View File

@ -1,119 +0,0 @@
// 打印任务 API
import request from '@/utils/request'
/**
*
*/
export function createJob(data: {
platform: string
plugin_code: string
order_id?: number
template_id?: number
print_data: Record<string, any>
priority?: number
}) {
return request.post('/print-jobs', data)
}
/**
*
*/
export function createBatchJobs(data: {
platform: string
plugin_code: string
template_id?: number
orders: Array<{
order_id?: number
priority?: number
print_data: Record<string, any>
}>
}) {
return request.post('/print-jobs/batch', data)
}
/**
*
*/
export function getQueue(params?: {
status?: string
platform?: string
page?: number
pageSize?: number
}) {
return request.get('/print-jobs/queue', { params })
}
/**
*
*/
export function getHistory(params?: {
page?: number
per_page?: number
}) {
return request.get('/print-jobs/history', { params })
}
/**
*
*/
export function getStats() {
return request.get('/print-jobs/stats')
}
/**
*
*/
export function batchQueue(jobIds: number[]) {
return request.post('/print-jobs/batch-queue', { job_ids: jobIds })
}
/**
*
*/
export function clearCompleted() {
return request.post('/print-jobs/clear-completed')
}
/**
*
*/
export function retryJob(jobId: number) {
return request.post(`/print-jobs/${jobId}/retry`)
}
/**
*
*/
export function cancelJob(jobId: number) {
return request.post(`/print-jobs/${jobId}/cancel`)
}
// ========== 设备端 API插件调用==========
/**
*
*/
export function getNextJob(deviceId: string) {
return request.get('/print-device/next-job', { params: { device_id: deviceId } })
}
/**
*
*/
export function claimJob(jobId: number, deviceId: string) {
return request.post('/print-device/claim', { job_id: jobId, device_id: deviceId })
}
/**
*
*/
export function completeJob(jobId: number, deviceId: string) {
return request.post('/print-device/complete', { job_id: jobId, device_id: deviceId })
}
/**
*
*/
export function failJob(jobId: number, error: string, deviceId?: string) {
return request.post('/print-device/fail', { job_id: jobId, error, device_id: deviceId })
}

View File

@ -1,78 +0,0 @@
// 打印插件管理 API
import request from '@/utils/request'
/**
*
*/
export function getPlugins(platform?: string) {
return request.get('/print-plugins', { params: { platform } })
}
/**
*
*/
export function getPlugin(code: string) {
return request.get(`/print-plugins/${code}`)
}
/**
*
*/
export function getLatestVersion(code: string) {
return request.get(`/print-plugins/${code}/version`)
}
/**
*
*/
export function downloadPlugin(code: string) {
return request.get(`/print-plugins/${code}/download`, { responseType: 'blob' })
}
/**
*
*/
export function getInstallations() {
return request.get('/print-plugins/auth/installations')
}
/**
*
*/
export function checkVersion(pluginCode: string, deviceId: string) {
return request.post('/print-plugins/auth/check-version', { plugin_code: pluginCode, device_id: deviceId })
}
/**
*
*/
export function registerPlugin(data: {
plugin_code: string
version: string
device_id: string
device_name?: string
os_version?: string
}) {
return request.post('/print-plugins/auth/register', data)
}
/**
*
*/
export function sendHeartbeat(deviceId: string) {
return request.post('/print-plugins/auth/heartbeat', { device_id: deviceId })
}
/**
*
*/
export function uninstall(pluginCode: string, deviceId: string) {
return request.post('/print-plugins/auth/uninstall', { plugin_code: pluginCode, device_id: deviceId })
}
/**
*
*/
export function getDeviceStatus(deviceId: string) {
return request.get(`/print-plugins/auth/device/${deviceId}/status`)
}

View File

@ -1,414 +0,0 @@
import request from '@/utils/request'
export interface OrderItem {
id: number
shortId: string
platformOrderSn: string
shopName: string
platformName: string
createTime: string
receiverName: string
receiverPhone: string
receiverAddress: string
goodsAmount: string
erpStatus: number
isBindErp: boolean
platformGoodsName: string
erpGoodsName: string
platformSku: string
erpSku: string
goodsName: string
bindStatusText: string
warehouseName?: string
warehouseType?: string
expressName?: string
expressId?: string
items?: any[]
printResult?: number
printLogs?: any[]
printError?: string
expressNo?: string
}
export interface PrintBatchItem {
id: number
batchNo: string
printTime: string
printUserId: number
printUserName: string
orderCount: number
status: number // 0:打印中,1:成功,2:部分成功,3:失败
remark: string
createdAt: string
}
export interface PrintBatchDetail extends PrintBatchItem {
orders: Array<OrderItem & { printSuccess?: boolean; errorMsg?: string; expressNo?: string }>
}
export interface CreateBatchParams {
orderIds: number[]
orders: Array<OrderItem & { printSuccess?: boolean; errorMsg?: string; expressNo?: string }>
remark?: string
printUserId: number
printUserName: string
}
export interface BatchListParams {
batchNo?: string
startDate?: string
endDate?: string
printUser?: string
status?: number
currentPage: number
pageSize: number
}
export interface ApiResponse<T> {
code: number
data: T
message?: string
}
export interface ExpressItem {
id: string
name: string
code: string
}
export interface TemplateItem {
id: string
name: string
expressId: string
}
export interface PrinterStatus {
type: 'idle' | 'printing' | 'error'
errorCode?: string
message?: string
}
export interface ExpressBalance {
expressId: string
expressName: string
platform: string
balance: number
warningThreshold?: number
status: 'normal' | 'low' | 'empty'
message?: string
}
// 模拟数据
const mockExpressList: ExpressItem[] = [
{ id: '1', name: '顺丰速运', code: 'SF' },
{ id: '2', name: '中通快递', code: 'ZTO' },
{ id: '3', name: '圆通速递', code: 'YTO' },
{ id: '4', name: '韵达快递', code: 'YD' }
]
const mockTemplateList: TemplateItem[] = [
{ id: '101', name: '标准模板', expressId: '1' },
{ id: '102', name: '生鲜模板', expressId: '1' },
{ id: '201', name: '标准模板', expressId: '2' },
{ id: '301', name: '标准模板', expressId: '3' }
]
const PRINT_BATCH_STORAGE_KEY = 'print_batches'
// 从 localStorage 加载批次
const loadPrintBatches = (): PrintBatchDetail[] => {
const stored = localStorage.getItem(PRINT_BATCH_STORAGE_KEY)
if (stored) {
try {
return JSON.parse(stored)
} catch (e) {
console.error('解析打印批次失败', e)
return []
}
}
return []
}
export function getPrintBatches(params: BatchListParams): Promise<ApiResponse<{ list: PrintBatchItem[]; total: number }>> {
return new Promise((resolve) => {
setTimeout(() => {
let list: PrintBatchItem[] = loadPrintBatches()
if (params.batchNo) {
list = list.filter(b => b.batchNo.includes(params.batchNo))
}
if (params.startDate && params.endDate) {
list = list.filter(b => b.printTime >= params.startDate && b.printTime <= params.endDate)
}
if (params.printUser) {
list = list.filter(b => b.printUserName === params.printUser)
}
if (params.status !== undefined) {
list = list.filter(b => b.status === params.status)
}
list.sort((a, b) => new Date(b.printTime).getTime() - new Date(a.printTime).getTime())
const total = list.length
const start = (params.currentPage - 1) * params.pageSize
const end = start + params.pageSize
list = list.slice(start, end)
resolve({ code: 200, data: { list, total } })
}, 300)
})
}
export function getPrintBatchDetail(id: string | number): Promise<ApiResponse<PrintBatchDetail>> {
return new Promise((resolve) => {
setTimeout(() => {
const batches = loadPrintBatches()
const batch = batches.find(b => b.id === Number(id))
if (!batch) {
// 动态生成模拟数据
const fakeBatch: PrintBatchDetail = {
id: Number(id),
batchNo: `PRT${String(id).padStart(12, '0')}`,
printTime: new Date().toLocaleString(),
printUserId: 1001,
printUserName: 'admin',
orderCount: 3,
status: 1,
remark: '动态生成的模拟批次(原批次不存在)',
createdAt: new Date().toLocaleString(),
orders: [
{
id: 1,
shortId: 'S001',
platformOrderSn: 'PDD123456',
shopName: '拼多多专营店',
platformName: '拼多多',
createTime: '2025-03-08 09:00:00',
receiverName: '张三',
receiverPhone: '13800138001',
receiverAddress: '北京市朝阳区xx路1号',
goodsAmount: '100.00',
erpStatus: 1,
isBindErp: true,
platformGoodsName: '商品A',
erpGoodsName: '商品A',
platformSku: 'SKU-A',
erpSku: 'SKU-A',
goodsName: '商品A',
bindStatusText: '已绑定',
warehouseName: '主仓',
warehouseType: 'erp',
expressName: '顺丰速运',
expressId: '1',
printSuccess: true,
expressNo: 'SF1234567890'
}
]
}
resolve({ code: 200, data: fakeBatch, message: '批次不存在,已返回模拟数据' })
return
}
resolve({ code: 200, data: batch })
}, 300)
})
}
export function reprintBatch(id: number): Promise<ApiResponse<null>> {
return new Promise((resolve) => {
setTimeout(() => {
resolve({ code: 200, data: null, message: '重新打印任务已提交' })
}, 300)
})
}
export function createPrintBatch(data: CreateBatchParams): Promise<ApiResponse<PrintBatchDetail>> {
return new Promise((resolve) => {
setTimeout(() => {
const batches = loadPrintBatches()
const successCount = data.orders.filter(o => o.printSuccess).length
let status: number
if (successCount === data.orders.length) status = 1
else if (successCount > 0) status = 2
else status = 3
const newBatch: PrintBatchDetail = {
id: Date.now(),
batchNo: `PRT${new Date().toISOString().slice(0,10).replace(/-/g,'')}${String(Math.floor(Math.random()*10000)).padStart(6,'0')}`,
printTime: new Date().toLocaleString(),
printUserId: data.printUserId,
printUserName: data.printUserName,
orderCount: data.orders.length,
status,
remark: data.remark || '',
createdAt: new Date().toLocaleString(),
orders: data.orders.map(order => ({ ...order }))
}
batches.unshift(newBatch)
localStorage.setItem(PRINT_BATCH_STORAGE_KEY, JSON.stringify(batches))
resolve({ code: 200, data: newBatch })
}, 300)
})
}
export function getExpressList(): Promise<ApiResponse<ExpressItem[]>> {
return new Promise((resolve) => {
setTimeout(() => resolve({ code: 200, data: mockExpressList }), 200)
})
}
export function getTemplateList(expressId?: string): Promise<ApiResponse<TemplateItem[]>> {
return new Promise((resolve) => {
setTimeout(() => {
let list = mockTemplateList
if (expressId) list = list.filter(t => t.expressId === expressId)
resolve({ code: 200, data: list })
}, 200)
})
}
export function generateWaybill(params: any): Promise<ApiResponse<{ html: string }>> {
return new Promise((resolve) => {
setTimeout(() => {
const express = mockExpressList.find(e => e.id === params.expressId)
const template = mockTemplateList.find(t => t.id === params.templateId)
const html = `
<html>
<head>
<title></title>
<style>
body { font-family: 'SimHei', sans-serif; margin: 20px; }
.waybill { border: 1px solid #333; padding: 20px; width: 300px; margin: 0 auto; position: relative; }
h3 { text-align: center; }
.info { margin: 10px 0; }
.seq { position: absolute; top: 10px; right: 10px; font-size: 20px; font-weight: bold; color: #f00; }
.tracking-number { font-size: 18px; font-weight: bold; color: #000; margin: 10px 0; }
.print-time { position: absolute; bottom: 10px; right: 10px; font-size: 12px; color: #999; }
.batch-no { position: absolute; bottom: 10px; left: 10px; font-size: 12px; color: #999; }
</style>
</head>
<body>
<div class="waybill">
<div class="seq">#${params.seq || 'N/A'}</div>
<h3></h3>
<div class="tracking-number">${params.expressNo || 'SF' + Date.now()}</div>
<div class="info">${express?.name || '未知'}</div>
<div class="info">${template?.name || '未知'}</div>
<div class="info">ID${params.orderId}</div>
<div class="info"></div>
<div class="info">xx路1号</div>
<div class="info">13800138001</div>
<div class="print-time">${params.printTime || new Date().toLocaleString()}</div>
<div class="batch-no">${params.batchNo || ''}</div>
</div>
</body>
</html>
`
resolve({ code: 200, data: { html } })
}, 300)
})
}
export function testPrinterConnection(port: number, path: string = ''): Promise<boolean> {
return Promise.resolve(true)
}
export function queryManualPrinterStatus(port: number, path: string = ''): Promise<{ ready: boolean; error?: string }> {
return Promise.resolve({ ready: true })
}
export function connectManualPrinterStatus(port: number, path: string = '') {}
export function disconnectPrinterStatus() {}
export function onPrinterStatus(callback: (status: PrinterStatus) => void) { return () => {} }
export function queryExpressBalance(expressIds?: string[]): Promise<ApiResponse<ExpressBalance[]>> {
return Promise.resolve({
code: 200,
data: [
{ expressId: '1', expressName: '顺丰速运', platform: 'all', balance: 150, status: 'normal' },
{ expressId: '2', expressName: '中通快递', platform: 'pdd', balance: 35, status: 'normal' }
]
})
}
export function fetchExpressNumbers(expressIds: string[]): Promise<ApiResponse<Array<{ expressId: string; expressName: string; success: boolean; message?: string }>>> {
return new Promise((resolve) => {
setTimeout(() => {
const results = expressIds.map(id => {
const express = mockExpressList.find(e => e.id === id)
const name = express?.name || '未知'
const success = Math.random() > 0.3
let message = ''
if (!success) {
const reasons = ['面单余额不足,请联系快递充值', '该区域不可达,请更换快递', '快递接口异常', '请稍后重试']
message = reasons[Math.floor(Math.random() * reasons.length)]
}
return { expressId: id, expressName: name, success, message }
})
resolve({ code: 200, data: results })
}, 800)
})
}
// 获取所有订单打印记录(扁平化)
export function getOrderPrintLogs(params: any): Promise<ApiResponse<{ list: any[]; total: number }>> {
return new Promise((resolve) => {
setTimeout(() => {
const batches = loadPrintBatches()
let orders: any[] = []
batches.forEach(batch => {
if (batch.orders && Array.isArray(batch.orders)) {
batch.orders.forEach(order => {
orders.push({
...order,
batchId: batch.id,
batchNo: batch.batchNo,
batchPrintTime: batch.printTime,
batchStatus: batch.status
})
})
}
})
// 如果没有订单数据,返回模拟数据以便测试
if (orders.length === 0) {
orders = [
{
id: 1001,
shortId: 'S001',
platformOrderSn: 'PDD123456789',
batchId: 999,
batchNo: 'PRT202603090001',
batchPrintTime: '2026-03-09 14:30:00',
receiverName: '张三',
goodsAmount: '199.00',
expressName: '顺丰速运',
expressId: '1',
expressNo: 'SF1234567890',
printSuccess: true,
errorMsg: undefined
},
{
id: 1002,
shortId: 'S002',
platformOrderSn: 'JD987654321',
batchId: 999,
batchNo: 'PRT202603090001',
batchPrintTime: '2026-03-09 14:30:00',
receiverName: '李四',
goodsAmount: '299.00',
expressName: '中通快递',
expressId: '2',
expressNo: 'ZTO987654321',
printSuccess: false,
errorMsg: '面单余额不足'
}
]
}
// 按打印时间倒序
orders.sort((a, b) => new Date(b.batchPrintTime).getTime() - new Date(a.batchPrintTime).getTime())
const total = orders.length
// 处理分页参数
const currentPage = params.currentPage || 1
const pageSize = params.pageSize || 10
const start = (currentPage - 1) * pageSize
const end = start + pageSize
const list = orders.slice(start, end)
resolve({ code: 200, data: { list, total } })
}, 300)
})
}

View File

@ -1,172 +0,0 @@
import request from '@/utils/request'
// ==================== 类型定义 ====================
/** 采购单状态 */
export type PurchaseOrderStatus = 'draft' | 'pending_review' | 'approved' | 'rejected' | 'pushed' | 'cancelled'
/** 采购单商品项 */
export interface PurchaseOrderItem {
id?: string
skuCode: string
skuName?: string
quantity: number
unitPrice?: number
totalPrice?: number
receivedQuantity?: number
}
/** 采购单 */
export interface PurchaseOrder {
id?: string
orderNo?: string
supplierId: string
supplierName?: string
warehouseId: string
warehouseName?: string
status: PurchaseOrderStatus
totalAmount?: number
remark?: string
items: PurchaseOrderItem[]
createTime?: string
updateTime?: string
reviewer?: string
reviewTime?: string
reviewComment?: string
cloudPushTime?: string
}
/** 采购单列表查询参数 */
export interface PurchaseListParams {
page?: number
pageSize?: number
status?: PurchaseOrderStatus
supplierId?: string
warehouseId?: string
keyword?: string
startDate?: string
endDate?: string
}
/** 创建采购单请求 */
export interface CreatePurchaseOrderDto {
supplierId: string
warehouseId: string
remark?: string
items: PurchaseOrderItem[]
}
/** 更新采购单请求 */
export interface UpdatePurchaseOrderDto {
supplierId?: string
warehouseId?: string
remark?: string
items?: PurchaseOrderItem[]
}
// ==================== API 函数 ====================
/**
*
* @param params
*/
export function getPurchaseList(params?: PurchaseListParams) {
return request.get<PurchaseListResponse>('/purchase-orders', { params })
}
/**
*
* @param id ID
*/
export function getPurchaseDetail(id: string) {
return request.get<PurchaseOrder>(`/purchase-orders/${id}`)
}
/**
*
* @param data
*/
export function createPurchaseOrder(data: CreatePurchaseOrderDto) {
return request.post<PurchaseOrder>('/purchase-orders', data)
}
/**
*
* @param id ID
* @param data
*/
export function updatePurchaseOrder(id: string, data: UpdatePurchaseOrderDto) {
return request.put<PurchaseOrder>(`/purchase-orders/${id}`, data)
}
/**
*
* @param id ID
*/
export function submitPurchaseReview(id: string) {
return request.post<void>(`/purchase-orders/${id}/submit-review`)
}
/**
*
* @param id ID
*/
export function approvePurchaseOrder(id: string) {
return request.post<void>(`/purchase-orders/${id}/approve`)
}
/**
*
* @param id ID
* @param comment
*/
export function rejectPurchaseOrder(id: string, comment: string) {
return request.post<void>(`/purchase-orders/${id}/reject`, { comment })
}
/**
*
* @param id ID
*/
export function pushPurchaseToCloud(id: string) {
return request.post<void>(`/purchase-orders/${id}/push-cloud`)
}
/**
*
* @param id ID
*/
export function cancelPushPurchase(id: string) {
return request.post<void>(`/purchase-orders/${id}/cancel-push`)
}
// 别名兼容
export const approvePurchase = approvePurchaseOrder
export const rejectPurchase = rejectPurchaseOrder
export const submitReview = submitPurchaseReview
export const createPurchase = createPurchaseOrder
export const updatePurchase = updatePurchaseOrder
export const getPurchase = getPurchaseDetail
/**
*
*/
export function deletePurchase(id: string) {
return request.delete<void>(`/purchase-orders/${id}`)
}
/**
* 稿
*/
export function createDraftPurchase(data: any) {
return Promise.resolve({ code: 200, message: '功能开发中', data: null })
}
// ==================== 响应类型 ====================
export interface PurchaseListResponse {
list: PurchaseOrder[]
total: number
page: number
pageSize: number
}

View File

@ -1,116 +0,0 @@
import request from '@/utils/request'
// ==================== 类型定义 ====================
/** 收货单状态 */
export type ReceivingOrderStatus = 'pending' | 'partial' | 'completed' | 'cancelled'
/** 收货单商品项 */
export interface ReceivingOrderItem {
id?: string
skuCode: string
skuName?: string
expectedQuantity: number
receivedQuantity: number
}
/** 收货单 */
export interface ReceivingOrder {
id?: string
orderNo?: string
purchaseOrderId?: string
purchaseOrderNo?: string
warehouseId: string
warehouseName?: string
supplierId?: string
supplierName?: string
status: ReceivingOrderStatus
totalAmount?: number
remark?: string
items: ReceivingOrderItem[]
createTime?: string
updateTime?: string
receiver?: string
receiveTime?: string
}
/** 收货单列表查询参数 */
export interface ReceivingListParams {
page?: number
pageSize?: number
status?: ReceivingOrderStatus
purchaseOrderId?: string
warehouseId?: string
keyword?: string
startDate?: string
endDate?: string
}
/** 创建收货单请求 */
export interface CreateReceivingOrderDto {
purchaseOrderId: string
warehouseId: string
remark?: string
}
/** 更新收货单请求 */
export interface UpdateReceivingOrderDto {
remark?: string
items?: ReceivingOrderItem[]
}
// ==================== API 函数 ====================
/**
*
* @param params
*/
export function getReceivingList(params?: ReceivingListParams) {
return request.get<ReceivingListResponse>('/receiving-orders', { params })
}
/**
*
* @param id ID
*/
export function getReceivingDetail(id: string) {
return request.get<ReceivingOrder>(`/receiving-orders/${id}`)
}
/**
*
* @param data
*/
export function createReceivingOrder(data: CreateReceivingOrderDto) {
return request.post<ReceivingOrder>('/receiving-orders', data)
}
/**
*
* @param id ID
* @param data
*/
export function updateReceivingOrder(id: string, data: UpdateReceivingOrderDto) {
return request.put<ReceivingOrder>(`/receiving-orders/${id}`, data)
}
/**
*
*/
export function receive(data: {
receivingId: string
items: { skuCode: string; receivedQuantity: number }[]
receiver?: string
remark?: string
}) {
return request.post('/receiving-orders/receive', data)
}
// ==================== 响应类型 ====================
export interface ReceivingListResponse {
list: ReceivingOrder[]
total: number
page: number
pageSize: number
}

View File

@ -1,64 +0,0 @@
import request from '@/utils/request'
/**
*
*/
export function getRoleList() {
return request.get('/roles')
}
/**
*
*/
export function getRoleDetail(id: string) {
return request.get(`/roles/${id}`)
}
/**
*
*/
export function createRole(data: any) {
return request.post('/roles', data)
}
/**
*
*/
export function updateRole(id: string, data: any) {
return request.put(`/roles/${id}`, data)
}
/**
*
*/
export function deleteRole(id: string) {
return request.delete(`/roles/${id}`)
}
/**
*
*/
export function getRolePermissions(id: string) {
return request.get(`/roles/${id}/permissions`)
}
/**
*
*/
export function assignRolePermissions(id: string, permissions: string[]) {
return request.put(`/roles/${id}/permissions`, { permissions })
}
/**
*
*/
export function getPermissionList() {
return request.get('/permissions')
}
/**
*
*/
export function getPermissionGroups() {
return request.get('/permissions/groups')
}

View File

View File

@ -1,93 +0,0 @@
// src/api/shop.ts
import request from '@/utils/request'
/**
*
*/
export interface Shop {
id?: number
name: string
platform_id?: number
platform_name?: string
shop_id?: string
app_key?: string
app_secret?: string
access_token?: string
refresh_token?: string
token_expires_at?: string
status?: number
created_at?: string
updated_at?: string
[key: string]: any
}
/**
*
*/
export function getShopList(params?: any) {
return request.get('/shops/platforms', { params })
}
/**
*
*/
export function getShopDetail(id: number) {
return request.get(`/shops/${id}`)
}
/**
* URL
*/
export function getAuthUrl(platformId: number) {
return request.post('/shops/auth-url', { platform_id: platformId })
}
/**
* Token
*/
export function refreshShopToken(id: number) {
return request.post(`/shops/${id}/refresh`)
}
/**
*
*/
export function deleteShop(id: number) {
return request.delete(`/shops/${id}`)
}
/**
*
*/
export function getAllShops() {
return request.get('/shops/all')
}
/**
* URL
*/
export function getPlatformAuthUrl(platformId: number) {
return getAuthUrl(platformId)
}
/**
*
*/
export function getPlatformConfig(platformId: number) {
return Promise.resolve({
code: 200,
message: '功能开发中',
data: null
})
}
/**
*
*/
export function handleAuthCallback(code: string) {
return Promise.resolve({
code: 200,
message: '功能开发中',
data: null
})
}

View File

@ -1,182 +0,0 @@
// src/api/stock.ts
import request from '@/utils/request'
// ============ 类型定义 ============
/** 库存记录 - 对应后端返回字段snake_case */
export interface Stock {
id: number
sku_code: string
sku_name: string
warehouse_id: number
warehouse_name: string
quantity: number
locked_quantity: number
available_quantity: number
defective_quantity: number
warning_threshold: number
is_low: boolean
created_at: string
updated_at: string
}
/** 库存列表查询参数 */
export interface StockListParams {
warehouse_id?: number
sku_code?: string
keyword?: string
low_stock?: boolean
page?: number
limit?: number
}
/** 库存列表响应 */
export interface StockListResponse {
list: Stock[]
total: number
current_page: number
last_page: number
}
/** 库存操作日志 */
export interface StockLog {
id: number
stock_id: number
type: 'inbound' | 'outbound' | 'adjust' | 'lock' | 'unlock' | 'defective_inbound' | 'defective_outbound'
quantity: number
before_quantity: number
after_quantity: number
reason?: string
operator?: string
created_at: string
}
/** 库存详情响应 */
export interface StockDetailResponse {
stock: Stock
logs: StockLog[]
}
/** 库存日志查询参数 */
export interface StockLogsParams {
stock_id?: number
sku_code?: string
warehouse_id?: number
type?: string
start_date?: string
end_date?: string
page?: number
limit?: number
}
/** 更新阈值请求 */
export interface UpdateThresholdData {
sku_code: string
warehouse_id: number
threshold: number
}
/** 手动入库请求 */
export interface InboundData {
sku_code: string
warehouse_id: number
quantity: number
reason?: string
}
/** 手动出库请求 */
export interface OutboundData {
sku_code: string
warehouse_id: number
quantity: number
reason?: string
}
/** 不良品入库请求 */
export interface DefectiveInboundData {
sku_code: string
warehouse_id: number
quantity: number
reason?: string
}
/** 库存调整请求 */
export interface AdjustData {
sku_code: string
warehouse_id: number
adjust_quantity: number
reason: string
}
// ============ API 函数 ============
/**
*
* @param params IDSKU
*/
export function getStockList(params?: StockListParams) {
return request.get<StockListResponse>('/stocks', { params })
}
/**
*
* @param params { sku_code, warehouse_id }
*/
export function getStockDetail(params: { sku_code: string; warehouse_id: number }) {
return request.get<StockDetailResponse>('/stocks/detail', { params })
}
/**
*
* @param params
*/
export function getStockLogs(params?: StockLogsParams) {
return request.get<{ list: StockLog[]; total: number }>('/stocks/logs', { params })
}
/**
*
* @param data { sku_code, warehouse_id, threshold }
*/
export function updateThreshold(data: UpdateThresholdData) {
return request.put<void>('/stocks/update-threshold', data)
}
/**
*
* @param data { sku_code, warehouse_id, quantity, reason }
*/
export function inbound(data: InboundData) {
return request.post<Stock>('/stocks/inbound', data)
}
/**
*
* @param data { sku_code, warehouse_id, quantity, reason }
*/
export function outbound(data: OutboundData) {
return request.post<Stock>('/stocks/outbound', data)
}
/**
*
* @param data { sku_code, warehouse_id, quantity, reason }
*/
export function defectiveInbound(data: DefectiveInboundData) {
return request.post<Stock>('/stocks/defective-inbound', data)
}
/**
*
* @param data { sku_code, warehouse_id, adjust_quantity, reason }
*/
export function adjustStock(data: AdjustData) {
return request.post<Stock>('/stocks/adjust', data)
}
/**
*
*/
export function updateWarningThreshold(data: { sku_code: string; warehouse_id: number; threshold: number }) {
return request.put('/stocks/update-threshold', data)
}

View File

@ -1,67 +0,0 @@
// src/api/supplier.ts
import request from '@/utils/request'
/**
*
*/
export interface Supplier {
id?: number
name: string
code?: string
contact?: string
phone?: string
email?: string
address?: string
status?: number
created_at?: string
updated_at?: string
[key: string]: any
}
/**
*
* @param params page, limit, name, status
*/
export function getSupplierList(params?: any) {
return request.get('/suppliers', { params })
}
/**
*
* @param id ID
*/
export function getSupplierDetail(id: number) {
return request.get(`/suppliers/${id}`)
}
/**
*
* @param data
*/
export function createSupplier(data: Supplier) {
return request.post('/suppliers', data)
}
/**
*
* @param id ID
* @param data
*/
export function updateSupplier(id: number, data: Partial<Supplier>) {
return request.put(`/suppliers/${id}`, data)
}
/**
*
* @param id ID
*/
export function deleteSupplier(id: number) {
return request.delete(`/suppliers/${id}`)
}
/**
*
*/
export function getAllSuppliers() {
return request.get('/suppliers/all')
}

View File

@ -1,70 +0,0 @@
// 模板管理 API
import request from '@/utils/request'
/**
*
*/
export interface Template {
id: string
name: string
platform: string
size: string
style: string
defaultExpress?: string
senderName: string
senderPhone: string
senderAddress: string
showProduct: boolean
remark?: string
updatedAt: string
}
/**
*
*/
export interface TemplateListParams {
currentPage?: number
pageSize?: number
keyword?: string
}
/**
*
* @param params
*/
export function getTemplateList(params?: TemplateListParams) {
return request.get('/templates', { params })
}
/**
*
* @param id ID
*/
export function getTemplateDetail(id: string) {
return request.get(`/templates/${id}`)
}
/**
*
* @param data
*/
export function createTemplate(data: Partial<Template>) {
return request.post('/templates', data)
}
/**
*
* @param id ID
* @param data
*/
export function updateTemplate(id: string, data: Partial<Template>) {
return request.put(`/templates/${id}`, data)
}
/**
*
* @param id ID
*/
export function deleteTemplate(id: string) {
return request.delete(`/templates/${id}`)
}

View File

@ -1,64 +0,0 @@
import request from '@/utils/request'
/**
*
*/
export function getThirdPartyConfigs() {
return request.get('/third-party-config', { params: { group: 'third_party' } })
}
/**
*
*/
export function saveThirdPartyConfigs(configs: any[]) {
return request.put('/third-party-config', { group: 'third_party', configs })
}
/**
*
*/
export function getConfig(key: string) {
return request.get(`/third-party-config/${key}`, { params: { group: 'third_party' } })
}
/**
*
*/
export function getMailConfig() {
return request.get('/third-party-config', { params: { group: 'mail' } })
}
/**
*
*/
export function saveMailConfig(configs: any[]) {
return request.put('/third-party-config', { group: 'mail', configs })
}
/**
*
*/
export function getSmsConfig() {
return request.get('/third-party-config', { params: { group: 'sms' } })
}
/**
*
*/
export function saveSmsConfig(configs: any[]) {
return request.put('/third-party-config', { group: 'sms', configs })
}
/**
*
*/
export function getWechatConfig() {
return request.get('/third-party-config', { params: { group: 'wechat' } })
}
/**
*
*/
export function saveWechatConfig(configs: any[]) {
return request.put('/third-party-config', { group: 'wechat', configs })
}

View File

@ -1,198 +0,0 @@
// 用户管理 API
import request from '@/utils/request'
/**
*
*/
export function getUserList(params?: any) {
return request.get('/users', { params })
}
/**
*
*/
export function getUserDetail(id: string) {
return request.get(`/users/${id}`)
}
/**
*
*/
export function createUser(data: any) {
return request.post('/users', data)
}
/**
*
*/
export function updateUser(id: string, data: any) {
return request.put(`/users/${id}`, data)
}
/**
*
*/
export function deleteUser(id: string) {
return request.delete(`/users/${id}`)
}
/**
*
*/
export function disableUser(id: string) {
return request.post(`/users/${id}/disable`)
}
/**
*
*/
export function enableUser(id: string) {
return request.post(`/users/${id}/enable`)
}
/**
*
*/
export function inviteUser(data: any) {
return request.post('/users/invite', data)
}
/**
*
*/
export function setUserPermissions(id: string, data: { permissions: string[], warehouseIds: number[] }) {
return request.put(`/users/${id}/permissions`, data)
}
/**
*
*/
export function getUserPermissions(id: string) {
return request.get(`/users/${id}/permissions`)
}
/**
*
*/
export function getUserLoginLogs(id: string, params?: any) {
if (id === 'me') {
return request.get('/user/login-logs', { params })
}
return request.get(`/users/${id}/login-logs`, { params })
}
/**
*
*/
export function getUserOperationLogs(id: string, params?: any) {
return request.get(`/users/${id}/operation-logs`, { params })
}
/**
*
*/
export function getCurrentUser() {
return request.get('/user/')
}
/**
*
*/
export function updateCurrentUser(data: any) {
return request.put('/user/profile', data)
}
/**
*
*/
export function changePassword(data: { oldPassword: string, newPassword: string, confirmPassword: string }) {
return request.put('/user/password', {
current_password: data.oldPassword,
new_password: data.newPassword,
new_password_confirmation: data.confirmPassword
})
}
/**
*
*/
export function resetPassword(id: string) {
return request.post(`/users/${id}/reset-password`)
}
/**
*
*/
export function sendPairCode(data: { username: string, expireHours: number }) {
return request.post('/auth/send-pair-code', data)
}
/**
*
*/
export function verifyPairCode(data: { code: string }) {
return request.post('/auth/verify-pair-code', data)
}
/**
*
*/
export function getTrustedDevices() {
return request.get('/user/devices')
}
/**
*
*/
export function revokeDevice(deviceId: string) {
return request.delete(`/user/devices/${deviceId}`)
}
/**
*
*/
export function approveDevice(deviceId: string) {
return request.post(`/user/devices/${deviceId}/approve`)
}
/**
*
*/
export function rejectDevice(deviceId: string) {
return request.post(`/users/devices/${deviceId}/reject`)
}
/**
*
*/
export function bindWechat(data: { code: string }) {
return request.post('/users/bind-wechat', data)
}
/**
*
*/
export function unbindWechat() {
return request.delete('/users/bind-wechat')
}
/**
*
*/
export function getWechatQRCode() {
return request.get('/users/wechat/qrcode')
}
/**
*
*/
export function checkWechatLogin(qrcodeId: string) {
return request.get(`/users/wechat/check/${qrcodeId}`)
}
/**
*
*/
export function sendEmailChangeCode(data: { email: string }) {
return request.post('/user/send-email-change-code', data)
}

View File

View File

@ -1,61 +0,0 @@
// src/utils/request.ts
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse, AxiosError } from 'axios';
import { ElMessage, ElMessageBox } from 'element-plus';
// import { useUserStore } from '@/stores/user'; // 后续引入
// 创建 axios 实例
const service: AxiosInstance = axios.create({
baseURL: import.meta.env.VITE_API_BASE_URL || '/api', // 环境变量配置
timeout: 15000, // 15秒超时
headers: { 'Content-Type': 'application/json;charset=UTF-8' }
});
// 请求拦截器
service.interceptors.request.use(
(config) => {
// TODO: 从 Pinia 获取 token 并注入 Header
// const userStore = useUserStore();
// if (userStore.token) {
// config.headers['Authorization'] = `Bearer ${userStore.token}`;
// }
return config;
},
(error) => {
console.error('Request Error:', error);
return Promise.reject(error);
}
);
// 响应拦截器
service.interceptors.response.use(
(response: AxiosResponse) => {
const res = response.data;
// 假设后端返回格式:{ code: 200, data: {}, msg: 'success' }
// 请根据实际后端接口调整判断逻辑
if (res.code !== 200 && res.code !== 0) {
ElMessage.error(res.msg || '系统错误');
// 特殊状态码处理401 未登录403 无权限
if (res.code === 401) {
// TODO: 跳转登录页
// userStore.logout();
}
return Promise.reject(new Error(res.msg || 'Error'));
}
return res;
},
(error: AxiosError) => {
console.error('Response Error:', error);
let msg = '网络异常,请稍后重试';
if (error.response?.status === 401) msg = '未授权,请重新登录';
if (error.response?.status === 403) msg = '拒绝访问';
if (error.response?.status === 404) msg = '资源不存在';
if (error.response?.status === 500) msg = '服务器内部错误';
ElMessage.error(msg);
return Promise.reject(error);
}
);
export default service;

View File

@ -1,130 +0,0 @@
// src/api/warehouse.ts
import request from '@/utils/request'
// ============ 类型定义 ============
/** 仓库类型 */
export type WarehouseType = 'erp' | 'cloud' | 'physical' | 'virtual'
/** 仓库状态 */
export type WarehouseStatus = 'active' | 'inactive'
/** 仓库 - 对应后端返回字段snake_case */
export interface Warehouse {
id: number
name: string
type: WarehouseType
cloud_system?: string | null
owner_code?: string | null
cloud_code?: string | null
app_key?: string | null
app_secret?: string | null
remark?: string | null
created_at: string
updated_at: string
}
/** 仓库列表查询参数 */
export interface WarehouseListParams {
keyword?: string
type?: WarehouseType
status?: WarehouseStatus
page?: number
limit?: number
}
/** 仓库列表响应 */
export interface WarehouseListResponse {
list: Warehouse[]
total: number
current_page: number
last_page: number
}
/** 创建仓库请求 */
export interface CreateWarehouseData {
name: string
type: WarehouseType
cloud_system?: string
owner_code?: string
cloud_code?: string
app_key?: string
app_secret?: string
remark?: string
}
/** 更新仓库请求 */
export interface UpdateWarehouseData {
name?: string
type?: WarehouseType
cloud_system?: string
owner_code?: string
cloud_code?: string
app_key?: string
app_secret?: string
remark?: string
}
// ============ API 函数 ============
/**
*
* @param params
*/
export function getWarehouseList(params?: WarehouseListParams) {
return request.get<WarehouseListResponse>('/warehouses', { params })
}
/**
*
* @param id ID
*/
export function getWarehouseDetail(id: string | number) {
return request.get<Warehouse>(`/warehouses/${id}`)
}
/**
*
* @param data
*/
export function createWarehouse(data: CreateWarehouseData) {
return request.post<Warehouse>('/warehouses', data)
}
/**
*
* @param id ID
* @param data
*/
export function updateWarehouse(id: string | number, data: UpdateWarehouseData) {
return request.put<Warehouse>(`/warehouses/${id}`, data)
}
/**
*
* @param id ID
*/
export function deleteWarehouse(id: string | number) {
return request.delete<void>(`/warehouses/${id}`)
}
/**
*
*/
export function getWarehouseBindings(warehouseId: string) {
return request.get(`/warehouse/bindings/${warehouseId}`)
}
/**
*
*/
export function addBinding(data: any) {
return request.post('/warehouse/bindings', data)
}
/**
*
*/
export function updateBinding(id: string, data: any) {
return request.put(`/warehouse/bindings/${id}`, data)
}

View File

View File

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="37.07" height="36" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 198"><path fill="#41B883" d="M204.8 0H256L128 220.8L0 0h97.92L128 51.2L157.44 0h47.36Z"></path><path fill="#41B883" d="m0 0l128 220.8L256 0h-51.2L128 132.48L50.56 0H0Z"></path><path fill="#35495E" d="M50.56 0L128 133.12L204.8 0h-47.36L128 51.2L97.92 0H50.56Z"></path></svg>

Before

Width:  |  Height:  |  Size: 496 B

View File

@ -1,41 +0,0 @@
<script setup lang="ts">
defineProps<{
msg: string
}>()
</script>
<template>
<div class="greetings">
<h1 class="green">{{ msg }}</h1>
<h3>
Youve successfully created a project with
<a href="https://vite.dev/" target="_blank" rel="noopener">Vite</a> +
<a href="https://vuejs.org/" target="_blank" rel="noopener">Vue 3</a>. What's next?
</h3>
</div>
</template>
<style scoped>
h1 {
font-weight: 500;
font-size: 2.6rem;
position: relative;
top: -10px;
}
h3 {
font-size: 1.2rem;
}
.greetings h1,
.greetings h3 {
text-align: center;
}
@media (min-width: 1024px) {
.greetings h1,
.greetings h3 {
text-align: left;
}
}
</style>

View File

@ -1,53 +0,0 @@
<template>
<el-dialog v-model="visible" title="批量打印" width="600px" :close-on-click-modal="false" @close="handleClose">
<div>
<p>这是一个独立的打印对话框组件</p>
<p>选中订单数{{ orderIds.length }}</p>
<p>环境模式{{ envMode }}</p>
<el-switch
v-model="envMode"
active-value="production"
inactive-value="simulate"
active-text="生产模式"
inactive-text="模拟模式"
/>
</div>
<template #footer>
<el-button @click="visible = false">取消</el-button>
<el-button type="primary" @click="handleConfirm">确定</el-button>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { ref, watch } from 'vue'
import { ElMessage } from 'element-plus'
const props = defineProps<{
modelValue: boolean
orderIds: number[]
orders: any[]
}>()
const emit = defineEmits(['update:modelValue'])
const visible = ref(props.modelValue)
const envMode = ref<'simulate' | 'production'>('simulate')
watch(() => props.modelValue, (val) => {
visible.value = val
})
watch(visible, (val) => {
emit('update:modelValue', val)
})
const handleClose = () => {
visible.value = false
}
const handleConfirm = () => {
ElMessage.success('打印功能待完善')
visible.value = false
}
</script>

View File

@ -1,95 +0,0 @@
<script setup lang="ts">
import WelcomeItem from './WelcomeItem.vue'
import DocumentationIcon from './icons/IconDocumentation.vue'
import ToolingIcon from './icons/IconTooling.vue'
import EcosystemIcon from './icons/IconEcosystem.vue'
import CommunityIcon from './icons/IconCommunity.vue'
import SupportIcon from './icons/IconSupport.vue'
const openReadmeInEditor = () => fetch('/__open-in-editor?file=README.md')
</script>
<template>
<WelcomeItem>
<template #icon>
<DocumentationIcon />
</template>
<template #heading>Documentation</template>
Vues
<a href="https://vuejs.org/" target="_blank" rel="noopener">official documentation</a>
provides you with all information you need to get started.
</WelcomeItem>
<WelcomeItem>
<template #icon>
<ToolingIcon />
</template>
<template #heading>Tooling</template>
This project is served and bundled with
<a href="https://vite.dev/guide/features.html" target="_blank" rel="noopener">Vite</a>. The
recommended IDE setup is
<a href="https://code.visualstudio.com/" target="_blank" rel="noopener">VSCode</a>
+
<a href="https://github.com/vuejs/language-tools" target="_blank" rel="noopener"
>Vue - Official</a
>. If you need to test your components and web pages, check out
<a href="https://vitest.dev/" target="_blank" rel="noopener">Vitest</a>
and
<a href="https://www.cypress.io/" target="_blank" rel="noopener">Cypress</a>
/
<a href="https://playwright.dev/" target="_blank" rel="noopener">Playwright</a>.
<br />
More instructions are available in
<a href="javascript:void(0)" @click="openReadmeInEditor"><code>README.md</code></a
>.
</WelcomeItem>
<WelcomeItem>
<template #icon>
<EcosystemIcon />
</template>
<template #heading>Ecosystem</template>
Get official tools and libraries for your project:
<a href="https://pinia.vuejs.org/" target="_blank" rel="noopener">Pinia</a>,
<a href="https://router.vuejs.org/" target="_blank" rel="noopener">Vue Router</a>,
<a href="https://test-utils.vuejs.org/" target="_blank" rel="noopener">Vue Test Utils</a>, and
<a href="https://github.com/vuejs/devtools" target="_blank" rel="noopener">Vue Dev Tools</a>. If
you need more resources, we suggest paying
<a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">Awesome Vue</a>
a visit.
</WelcomeItem>
<WelcomeItem>
<template #icon>
<CommunityIcon />
</template>
<template #heading>Community</template>
Got stuck? Ask your question on
<a href="https://chat.vuejs.org" target="_blank" rel="noopener">Vue Land</a>
(our official Discord server), or
<a href="https://stackoverflow.com/questions/tagged/vue.js" target="_blank" rel="noopener"
>StackOverflow</a
>. You should also follow the official
<a href="https://bsky.app/profile/vuejs.org" target="_blank" rel="noopener">@vuejs.org</a>
Bluesky account or the
<a href="https://x.com/vuejs" target="_blank" rel="noopener">@vuejs</a>
X account for latest news in the Vue world.
</WelcomeItem>
<WelcomeItem>
<template #icon>
<SupportIcon />
</template>
<template #heading>Support Vue</template>
As an independent project, Vue relies on community backing for its sustainability. You can help
us by
<a href="https://vuejs.org/sponsor/" target="_blank" rel="noopener">becoming a sponsor</a>.
</WelcomeItem>
</template>

View File

@ -1,87 +0,0 @@
<template>
<div class="item">
<i>
<slot name="icon"></slot>
</i>
<div class="details">
<h3>
<slot name="heading"></slot>
</h3>
<slot></slot>
</div>
</div>
</template>
<style scoped>
.item {
margin-top: 2rem;
display: flex;
position: relative;
}
.details {
flex: 1;
margin-left: 1rem;
}
i {
display: flex;
place-items: center;
place-content: center;
width: 32px;
height: 32px;
color: var(--color-text);
}
h3 {
font-size: 1.2rem;
font-weight: 500;
margin-bottom: 0.4rem;
color: var(--color-heading);
}
@media (min-width: 1024px) {
.item {
margin-top: 0;
padding: 0.4rem 0 1rem calc(var(--section-gap) / 2);
}
i {
top: calc(50% - 25px);
left: -26px;
position: absolute;
border: 1px solid var(--color-border);
background: var(--color-background);
border-radius: 8px;
width: 50px;
height: 50px;
}
.item:before {
content: ' ';
border-left: 1px solid var(--color-border);
position: absolute;
left: 0;
bottom: calc(50% + 25px);
height: calc(50% - 25px);
}
.item:after {
content: ' ';
border-left: 1px solid var(--color-border);
position: absolute;
left: 0;
top: calc(50% + 25px);
height: calc(50% - 25px);
}
.item:first-of-type:before {
display: none;
}
.item:last-of-type:after {
display: none;
}
}
</style>

View File

@ -1,11 +0,0 @@
import { describe, it, expect } from 'vitest'
import { mount } from '@vue/test-utils'
import HelloWorld from '../HelloWorld.vue'
describe('HelloWorld', () => {
it('renders properly', () => {
const wrapper = mount(HelloWorld, { props: { msg: 'Hello Vitest' } })
expect(wrapper.text()).toContain('Hello Vitest')
})
})

View File

@ -1,7 +0,0 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor">
<path
d="M15 4a1 1 0 1 0 0 2V4zm0 11v-1a1 1 0 0 0-1 1h1zm0 4l-.707.707A1 1 0 0 0 16 19h-1zm-4-4l.707-.707A1 1 0 0 0 11 14v1zm-4.707-1.293a1 1 0 0 0-1.414 1.414l1.414-1.414zm-.707.707l-.707-.707.707.707zM9 11v-1a1 1 0 0 0-.707.293L9 11zm-4 0h1a1 1 0 0 0-1-1v1zm0 4H4a1 1 0 0 0 1.707.707L5 15zm10-9h2V4h-2v2zm2 0a1 1 0 0 1 1 1h2a3 3 0 0 0-3-3v2zm1 1v6h2V7h-2zm0 6a1 1 0 0 1-1 1v2a3 3 0 0 0 3-3h-2zm-1 1h-2v2h2v-2zm-3 1v4h2v-4h-2zm1.707 3.293l-4-4-1.414 1.414 4 4 1.414-1.414zM11 14H7v2h4v-2zm-4 0c-.276 0-.525-.111-.707-.293l-1.414 1.414C5.42 15.663 6.172 16 7 16v-2zm-.707 1.121l3.414-3.414-1.414-1.414-3.414 3.414 1.414 1.414zM9 12h4v-2H9v2zm4 0a3 3 0 0 0 3-3h-2a1 1 0 0 1-1 1v2zm3-3V3h-2v6h2zm0-6a3 3 0 0 0-3-3v2a1 1 0 0 1 1 1h2zm-3-3H3v2h10V0zM3 0a3 3 0 0 0-3 3h2a1 1 0 0 1 1-1V0zM0 3v6h2V3H0zm0 6a3 3 0 0 0 3 3v-2a1 1 0 0 1-1-1H0zm3 3h2v-2H3v2zm1-1v4h2v-4H4zm1.707 4.707l.586-.586-1.414-1.414-.586.586 1.414 1.414z"
/>
</svg>
</template>

View File

@ -1,7 +0,0 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="17" fill="currentColor">
<path
d="M11 2.253a1 1 0 1 0-2 0h2zm-2 13a1 1 0 1 0 2 0H9zm.447-12.167a1 1 0 1 0 1.107-1.666L9.447 3.086zM1 2.253L.447 1.42A1 1 0 0 0 0 2.253h1zm0 13H0a1 1 0 0 0 1.553.833L1 15.253zm8.447.833a1 1 0 1 0 1.107-1.666l-1.107 1.666zm0-14.666a1 1 0 1 0 1.107 1.666L9.447 1.42zM19 2.253h1a1 1 0 0 0-.447-.833L19 2.253zm0 13l-.553.833A1 1 0 0 0 20 15.253h-1zm-9.553-.833a1 1 0 1 0 1.107 1.666L9.447 14.42zM9 2.253v13h2v-13H9zm1.553-.833C9.203.523 7.42 0 5.5 0v2c1.572 0 2.961.431 3.947 1.086l1.107-1.666zM5.5 0C3.58 0 1.797.523.447 1.42l1.107 1.666C2.539 2.431 3.928 2 5.5 2V0zM0 2.253v13h2v-13H0zm1.553 13.833C2.539 15.431 3.928 15 5.5 15v-2c-1.92 0-3.703.523-5.053 1.42l1.107 1.666zM5.5 15c1.572 0 2.961.431 3.947 1.086l1.107-1.666C9.203 13.523 7.42 13 5.5 13v2zm5.053-11.914C11.539 2.431 12.928 2 14.5 2V0c-1.92 0-3.703.523-5.053 1.42l1.107 1.666zM14.5 2c1.573 0 2.961.431 3.947 1.086l1.107-1.666C18.203.523 16.421 0 14.5 0v2zm3.5.253v13h2v-13h-2zm1.553 12.167C18.203 13.523 16.421 13 14.5 13v2c1.573 0 2.961.431 3.947 1.086l1.107-1.666zM14.5 13c-1.92 0-3.703.523-5.053 1.42l1.107 1.666C11.539 15.431 12.928 15 14.5 15v-2z"
/>
</svg>
</template>

View File

@ -1,7 +0,0 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="20" fill="currentColor">
<path
d="M11.447 8.894a1 1 0 1 0-.894-1.789l.894 1.789zm-2.894-.789a1 1 0 1 0 .894 1.789l-.894-1.789zm0 1.789a1 1 0 1 0 .894-1.789l-.894 1.789zM7.447 7.106a1 1 0 1 0-.894 1.789l.894-1.789zM10 9a1 1 0 1 0-2 0h2zm-2 2.5a1 1 0 1 0 2 0H8zm9.447-5.606a1 1 0 1 0-.894-1.789l.894 1.789zm-2.894-.789a1 1 0 1 0 .894 1.789l-.894-1.789zm2 .789a1 1 0 1 0 .894-1.789l-.894 1.789zm-1.106-2.789a1 1 0 1 0-.894 1.789l.894-1.789zM18 5a1 1 0 1 0-2 0h2zm-2 2.5a1 1 0 1 0 2 0h-2zm-5.447-4.606a1 1 0 1 0 .894-1.789l-.894 1.789zM9 1l.447-.894a1 1 0 0 0-.894 0L9 1zm-2.447.106a1 1 0 1 0 .894 1.789l-.894-1.789zm-6 3a1 1 0 1 0 .894 1.789L.553 4.106zm2.894.789a1 1 0 1 0-.894-1.789l.894 1.789zm-2-.789a1 1 0 1 0-.894 1.789l.894-1.789zm1.106 2.789a1 1 0 1 0 .894-1.789l-.894 1.789zM2 5a1 1 0 1 0-2 0h2zM0 7.5a1 1 0 1 0 2 0H0zm8.553 12.394a1 1 0 1 0 .894-1.789l-.894 1.789zm-1.106-2.789a1 1 0 1 0-.894 1.789l.894-1.789zm1.106 1a1 1 0 1 0 .894 1.789l-.894-1.789zm2.894.789a1 1 0 1 0-.894-1.789l.894 1.789zM8 19a1 1 0 1 0 2 0H8zm2-2.5a1 1 0 1 0-2 0h2zm-7.447.394a1 1 0 1 0 .894-1.789l-.894 1.789zM1 15H0a1 1 0 0 0 .553.894L1 15zm1-2.5a1 1 0 1 0-2 0h2zm12.553 2.606a1 1 0 1 0 .894 1.789l-.894-1.789zM17 15l.447.894A1 1 0 0 0 18 15h-1zm1-2.5a1 1 0 1 0-2 0h2zm-7.447-5.394l-2 1 .894 1.789 2-1-.894-1.789zm-1.106 1l-2-1-.894 1.789 2 1 .894-1.789zM8 9v2.5h2V9H8zm8.553-4.894l-2 1 .894 1.789 2-1-.894-1.789zm.894 0l-2-1-.894 1.789 2 1 .894-1.789zM16 5v2.5h2V5h-2zm-4.553-3.894l-2-1-.894 1.789 2 1 .894-1.789zm-2.894-1l-2 1 .894 1.789 2-1L8.553.106zM1.447 5.894l2-1-.894-1.789-2 1 .894 1.789zm-.894 0l2 1 .894-1.789-2-1-.894 1.789zM0 5v2.5h2V5H0zm9.447 13.106l-2-1-.894 1.789 2 1 .894-1.789zm0 1.789l2-1-.894-1.789-2 1 .894 1.789zM10 19v-2.5H8V19h2zm-6.553-3.894l-2-1-.894 1.789 2 1 .894-1.789zM2 15v-2.5H0V15h2zm13.447 1.894l2-1-.894-1.789-2 1 .894 1.789zM18 15v-2.5h-2V15h2z"
/>
</svg>
</template>

View File

@ -1,7 +0,0 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor">
<path
d="M10 3.22l-.61-.6a5.5 5.5 0 0 0-7.666.105 5.5 5.5 0 0 0-.114 7.665L10 18.78l8.39-8.4a5.5 5.5 0 0 0-.114-7.665 5.5 5.5 0 0 0-7.666-.105l-.61.61z"
/>
</svg>
</template>

View File

@ -1,19 +0,0 @@
<!-- This icon is from <https://github.com/Templarian/MaterialDesign>, distributed under Apache 2.0 (https://www.apache.org/licenses/LICENSE-2.0) license-->
<template>
<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
aria-hidden="true"
role="img"
class="iconify iconify--mdi"
width="24"
height="24"
preserveAspectRatio="xMidYMid meet"
viewBox="0 0 24 24"
>
<path
d="M20 18v-4h-3v1h-2v-1H9v1H7v-1H4v4h16M6.33 8l-1.74 4H7v-1h2v1h6v-1h2v1h2.41l-1.74-4H6.33M9 5v1h6V5H9m12.84 7.61c.1.22.16.48.16.8V18c0 .53-.21 1-.6 1.41c-.4.4-.85.59-1.4.59H4c-.55 0-1-.19-1.4-.59C2.21 19 2 18.53 2 18v-4.59c0-.32.06-.58.16-.8L4.5 7.22C4.84 6.41 5.45 6 6.33 6H7V5c0-.55.18-1 .57-1.41C7.96 3.2 8.44 3 9 3h6c.56 0 1.04.2 1.43.59c.39.41.57.86.57 1.41v1h.67c.88 0 1.49.41 1.83 1.22l2.34 5.39z"
fill="currentColor"
></path>
</svg>
</template>

View File

@ -1,40 +0,0 @@
<template>
<el-tag :type="tagType">
{{ statusText }}
</el-tag>
</template>
<script setup lang="ts">
import { computed } from 'vue'
const props = defineProps({
status: {
type: Number,
required: true
}
})
const statusText = computed(() => {
const statusMap = {
1: '待审核',
2: '已审核',
3: '待发货',
4: '已发货',
5: '已完成',
6: '已关闭'
}
return statusMap[props.status] || '未知状态'
})
const tagType = computed(() => {
const typeMap = {
1: 'warning',
2: 'success',
3: 'info',
4: 'primary',
5: 'success',
6: 'danger'
}
return typeMap[props.status] || 'info'
})
</script>

Some files were not shown because too many files have changed in this diff Show More