diff --git a/zhican/admin/src/mock/data.ts b/zhican/admin/src/mock/data.ts index 2864f57..63c8c35 100644 --- a/zhican/admin/src/mock/data.ts +++ b/zhican/admin/src/mock/data.ts @@ -575,6 +575,33 @@ export const dictItems: DictItem[] = [ { id: 'di33', typeCode: 'order_status', label: '已取消', value: 'cancelled', sort: 5, status: 'enabled', remark: '' }, ] +// ==================== 称重终端 ==================== +// 菜品基础库:用于称重终端的品名网格选择。emoji 仅作占位图标 +export const vegetableLibrary = [ + { id: 'v01', name: '白菜', emoji: '🥬' }, + { id: 'v02', name: '萝卜', emoji: '🥕' }, + { id: 'v03', name: '番茄', emoji: '🍅' }, + { id: 'v04', name: '黄瓜', emoji: '🥒' }, + { id: 'v05', name: '茄子', emoji: '🍆' }, + { id: 'v06', name: '青椒', emoji: '🫑' }, + { id: 'v07', name: '芹菜', emoji: '🌿' }, + { id: 'v08', name: '菠菜', emoji: '🥬' }, + { id: 'v09', name: '土豆', emoji: '🥔' }, + { id: 'v10', name: '胡萝卜', emoji: '🥕' }, + { id: 'v11', name: '豆角', emoji: '🫛' }, + { id: 'v12', name: '西兰花', emoji: '🥦' }, +] + +// 净菜规格(形状)枚举 +export const specOptions = [ + { code: 'whole', label: '整' }, + { code: 'dice', label: '丁' }, + { code: 'shred', label: '丝' }, + { code: 'slice', label: '片' }, + { code: 'segment', label: '段' }, + { code: 'chunk', label: '块' }, +] + // ==================== Dashboard ==================== export function genDashboardData() { return { diff --git a/zhican/admin/src/router/index.ts b/zhican/admin/src/router/index.ts index 81cf424..40fdbf7 100644 --- a/zhican/admin/src/router/index.ts +++ b/zhican/admin/src/router/index.ts @@ -64,6 +64,13 @@ const routes: RouteRecordRaw[] = [ name: 'login', component: () => import('@/views/login/index.vue'), }, + // 称重终端:触摸屏现场入口,不挂 MainLayout(无侧边栏/无顶栏,全屏),免登录 + { + path: '/weighing-terminal', + name: 'weighing-terminal', + meta: { title: '称重终端', public: true }, + component: () => import('@/views/weighing-terminal/index.vue'), + }, { path: '/', component: () => import('@/layouts/MainLayout.vue'), @@ -79,7 +86,9 @@ const router = createRouter({ router.beforeEach((to, _from, next) => { const token = localStorage.getItem('token') - if (to.name !== 'login' && !token) { + // 公开路由(如登录页、称重终端)免鉴权 + const isPublic = to.name === 'login' || to.meta.public === true + if (!isPublic && !token) { next({ name: 'login' }) } else { document.title = `${(to.meta.title as string) || ''} - 智能餐养` diff --git a/zhican/admin/src/stores/weighingTerminal.ts b/zhican/admin/src/stores/weighingTerminal.ts new file mode 100644 index 0000000..9e1b0fc --- /dev/null +++ b/zhican/admin/src/stores/weighingTerminal.ts @@ -0,0 +1,100 @@ +import { defineStore } from 'pinia' +import { ref } from 'vue' + +// 毛菜入库记录 +export interface RawVeggieRecord { + id: string + time: string // YYYY-MM-DD HH:mm:ss + name: string // 品名 + weight: number // 重量(g) +} + +// 净菜入库记录 +export interface CleanVeggieRecord { + id: string + time: string + name: string + spec: string // 规格(形状):整/丁/丝/片/段/块 + weight: number // 净菜重量(g) + operator: string | null // 加工人(预留人脸识别,当前为 null) + yieldRate: number | null // 出净率(%);无毛菜参照时为 null + refRawWeight: number | null // 参照的毛菜重量(g);用于在记录里追溯出净率算法 +} + +const genId = () => Date.now().toString(36) + Math.random().toString(36).slice(2, 6) + +const nowStr = () => { + const d = new Date() + const pad = (n: number) => String(n).padStart(2, '0') + return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}` +} + +/** + * 称重终端 store:负责毛菜/净菜两类入库流水的增删查 + * 设计要点: + * - 数据仅存活于本次会话内存(刷新即清空),原型阶段足够 + * - 出净率自动算 = 当前净菜重量 / 最近一条同品名毛菜重量 * 100% + * - 加工人字段保留 null 占位,留给后期人脸识别填充 + */ +export const useWeighingTerminalStore = defineStore('weighingTerminal', () => { + const rawVeggieRecords = ref([]) + const cleanVeggieRecords = ref([]) + + /** 新增一条毛菜入库记录 */ + function addRawRecord(name: string, weight: number): RawVeggieRecord { + const record: RawVeggieRecord = { + id: genId(), + time: nowStr(), + name, + weight, + } + rawVeggieRecords.value.unshift(record) + return record + } + + /** 取最近一条同品名毛菜记录的重量(g);找不到返回 null */ + function getLatestRawWeight(name: string): number | null { + const hit = rawVeggieRecords.value.find(r => r.name === name) + return hit ? hit.weight : null + } + + /** 取最近一条同品名毛菜记录(含时间,用于界面展示参照批次) */ + function getLatestRawRecord(name: string): RawVeggieRecord | null { + return rawVeggieRecords.value.find(r => r.name === name) ?? null + } + + /** 新增一条净菜入库记录;出净率根据最近一条同品名毛菜自动计算 */ + function addCleanRecord(payload: { + name: string + spec: string + weight: number + operator?: string | null + }): CleanVeggieRecord { + const refRaw = getLatestRawWeight(payload.name) + const yieldRate = refRaw && refRaw > 0 + ? +((payload.weight / refRaw) * 100).toFixed(1) + : null + + const record: CleanVeggieRecord = { + id: genId(), + time: nowStr(), + name: payload.name, + spec: payload.spec, + weight: payload.weight, + operator: payload.operator ?? null, + yieldRate, + refRawWeight: refRaw, + } + cleanVeggieRecords.value.unshift(record) + return record + } + + return { + rawVeggieRecords, + cleanVeggieRecords, + addRawRecord, + getLatestRawWeight, + getLatestRawRecord, + addCleanRecord, + } +}) diff --git a/zhican/admin/src/views/dashboard/trace/index.vue b/zhican/admin/src/views/dashboard/trace/index.vue index 72a4fef..04a57e0 100644 --- a/zhican/admin/src/views/dashboard/trace/index.vue +++ b/zhican/admin/src/views/dashboard/trace/index.vue @@ -102,7 +102,7 @@ const suppliers = ['集团种养公司', '集团净菜公司', '绿源农业', ' const lands = ['A01地块', 'B02地块', 'C03基地', 'D04养殖区'] const ingredients = ['白菜', '番茄', '猪里脊', '鸡胸肉', '青椒', '土豆'] -const queryDate = ref(dayjs()) +const queryDate = ref(dayjs()) const queryUser = ref() const queryMeal = ref() const searched = ref(false) diff --git a/zhican/admin/src/views/login/index.vue b/zhican/admin/src/views/login/index.vue index cb30700..1e4549b 100644 --- a/zhican/admin/src/views/login/index.vue +++ b/zhican/admin/src/views/login/index.vue @@ -15,6 +15,9 @@ + @@ -70,4 +73,18 @@ async function handleLogin() { color: #333; } } + +.terminal-link { + text-align: center; + margin-top: 8px; + font-size: 14px; + + a { + color: #888; + text-decoration: none; + transition: color 0.2s; + + &:hover { color: #4c8bf5; } + } +} diff --git a/zhican/admin/src/views/weighing-terminal/index.vue b/zhican/admin/src/views/weighing-terminal/index.vue new file mode 100644 index 0000000..3392987 --- /dev/null +++ b/zhican/admin/src/views/weighing-terminal/index.vue @@ -0,0 +1,682 @@ + + + + +