Commit a0aeefab12d97eb09bd4322c7c5d7f1f25f132b5
1 parent
940fb6ea
好了,设计现在需要给美国那边看,估计还有修改吧
Showing
14 changed files
with
471 additions
and
57 deletions
美国版/Food Labeling Management App UniApp/src/components/AppIcon.vue
| ... | ... | @@ -53,6 +53,8 @@ const icons: Record<string, string> = { |
| 53 | 53 | lock: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="11" width="18" height="11" rx="2" ry="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>', |
| 54 | 54 | chevronDown: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="6 9 12 15 18 9"/></svg>', |
| 55 | 55 | chevronUp: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="18 15 12 9 6 15"/></svg>', |
| 56 | + squares: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="7" height="7"/><rect x="14" y="3" width="7" height="7"/><rect x="14" y="14" width="7" height="7"/><rect x="3" y="14" width="7" height="7"/></svg>', | |
| 57 | + list: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/><line x1="3" y1="6" x2="3.01" y2="6"/><line x1="3" y1="12" x2="3.01" y2="12"/><line x1="3" y1="18" x2="3.01" y2="18"/></svg>', | |
| 56 | 58 | } |
| 57 | 59 | |
| 58 | 60 | const svgContent = computed(() => icons[props.name] || icons.food) | ... | ... |
美国版/Food Labeling Management App UniApp/src/locales/en.ts
| ... | ... | @@ -4,7 +4,7 @@ export default { |
| 4 | 4 | appName: 'Food Label System', |
| 5 | 5 | employeePortal: 'Employee Portal', |
| 6 | 6 | email: 'Email', |
| 7 | - emailPlaceholder: 'your.email@company.com', | |
| 7 | + emailPlaceholder: "your.email{'@'}company.com", | |
| 8 | 8 | password: 'Password', |
| 9 | 9 | passwordPlaceholder: 'Enter your password', |
| 10 | 10 | rememberMe: 'Remember me', | ... | ... |
美国版/Food Labeling Management App UniApp/src/locales/zh.ts
美国版/Food Labeling Management App UniApp/src/pages/labels/labels.vue
| ... | ... | @@ -103,7 +103,7 @@ |
| 103 | 103 | <text class="type-badge-text">{{ product.labelTypes.length }} Types</text> |
| 104 | 104 | </view> |
| 105 | 105 | </view> |
| 106 | - <text class="food-name">{{ product.name }}</text> | |
| 106 | + <text class="food-name">{{ getDisplayName(product) }}</text> | |
| 107 | 107 | <text class="food-desc">{{ product.templateName }}</text> |
| 108 | 108 | </view> |
| 109 | 109 | </view> |
| ... | ... | @@ -117,7 +117,7 @@ |
| 117 | 117 | <view v-if="showSubTypeModal" class="modal-mask" @click="showSubTypeModal = false"> |
| 118 | 118 | <view class="modal-body" @click.stop> |
| 119 | 119 | <text class="modal-title">Select Label Type</text> |
| 120 | - <text class="modal-desc">{{ selectedProduct ? selectedProduct.name : '' }}</text> | |
| 120 | + <text class="modal-desc">{{ selectedProduct ? getDisplayName(selectedProduct) : '' }}</text> | |
| 121 | 121 | <view class="subtype-list"> |
| 122 | 122 | <view |
| 123 | 123 | v-for="lt in currentLabelTypes" |
| ... | ... | @@ -396,6 +396,14 @@ const productCategoriesByLabel: Record<string, ProductCategory[]> = { |
| 396 | 396 | ], |
| 397 | 397 | } |
| 398 | 398 | |
| 399 | +// 按详情页规则:chicken→Chicken,2"x6"/2"x4"→Cheese Burger Deluxe,其余→Syrup(图片仍用产品图) | |
| 400 | +function getDisplayName(product: Product): string { | |
| 401 | + if (product.id === 'chicken') return 'Chicken' | |
| 402 | + const size = product.templateSize || '' | |
| 403 | + if (size.indexOf('2"x6"') >= 0 || size.indexOf('2"x4"') >= 0) return 'Cheese Burger Deluxe' | |
| 404 | + return 'Syrup' | |
| 405 | +} | |
| 406 | + | |
| 399 | 407 | const filteredProductCategories = computed(() => { |
| 400 | 408 | const cats = productCategoriesByLabel[selectedCategory.value] || [] |
| 401 | 409 | const s = searchTerm.value.toLowerCase() |
| ... | ... | @@ -405,7 +413,8 @@ const filteredProductCategories = computed(() => { |
| 405 | 413 | return { |
| 406 | 414 | ...cat, |
| 407 | 415 | products: cat.products.filter(function (p) { |
| 408 | - return p.name.toLowerCase().indexOf(s) >= 0 | |
| 416 | + const displayName = getDisplayName(p) | |
| 417 | + return p.name.toLowerCase().indexOf(s) >= 0 || displayName.toLowerCase().indexOf(s) >= 0 | |
| 409 | 418 | }), |
| 410 | 419 | } |
| 411 | 420 | }) | ... | ... |
美国版/Food Labeling Management App UniApp/src/pages/labels/preview.vue
| ... | ... | @@ -54,6 +54,10 @@ |
| 54 | 54 | |
| 55 | 55 | <view class="info-row"> |
| 56 | 56 | <view class="info-item"> |
| 57 | + <text class="info-label">Label ID</text> | |
| 58 | + <text class="info-value">{{ labelId }}</text> | |
| 59 | + </view> | |
| 60 | + <view class="info-item"> | |
| 57 | 61 | <text class="info-label">Last Edited</text> |
| 58 | 62 | <text class="info-value">{{ lastEdited }}</text> |
| 59 | 63 | </view> |
| ... | ... | @@ -94,6 +98,10 @@ |
| 94 | 98 | <view class="modal-label-inner"> |
| 95 | 99 | <image :src="labelImage" class="modal-label-img" mode="widthFix" /> |
| 96 | 100 | </view> |
| 101 | + <view class="modal-label-id"> | |
| 102 | + <text class="modal-label-id-label">Label ID</text> | |
| 103 | + <text class="modal-label-id-value">{{ labelId }}</text> | |
| 104 | + </view> | |
| 97 | 105 | </view> |
| 98 | 106 | </view> |
| 99 | 107 | </view> |
| ... | ... | @@ -109,6 +117,8 @@ import AppIcon from '../../components/AppIcon.vue' |
| 109 | 117 | import SideMenu from '../../components/SideMenu.vue' |
| 110 | 118 | import LocationPicker from '../../components/LocationPicker.vue' |
| 111 | 119 | import { getStatusBarHeight } from '../../utils/statusBar' |
| 120 | +import { generateNextLabelId } from '../../utils/printLog' | |
| 121 | +import chickenLabelImg from '../../static/chicken-lable.png' | |
| 112 | 122 | |
| 113 | 123 | const statusBarHeight = getStatusBarHeight() |
| 114 | 124 | const isPrinting = ref(false) |
| ... | ... | @@ -119,6 +129,7 @@ const showPreviewModal = ref(false) |
| 119 | 129 | const btConnected = ref(false) |
| 120 | 130 | const btDeviceName = ref('') |
| 121 | 131 | |
| 132 | +const productId = ref('chicken') | |
| 122 | 133 | const productName = ref('Chicken') |
| 123 | 134 | const productCategory = ref('Meat') |
| 124 | 135 | const labelTypeName = ref('') |
| ... | ... | @@ -126,8 +137,12 @@ const templateSize = ref('2"x2"') |
| 126 | 137 | const templateName = ref('Basic') |
| 127 | 138 | const lastEdited = ref('2025.12.03 11:45') |
| 128 | 139 | const locationName = ref('Location A') |
| 140 | +const labelId = ref('') | |
| 129 | 141 | |
| 130 | 142 | const labelImage = computed(() => { |
| 143 | + if (productId.value === 'chicken') { | |
| 144 | + return chickenLabelImg | |
| 145 | + } | |
| 131 | 146 | const size = templateSize.value |
| 132 | 147 | if (size.indexOf('2"x6"') >= 0 || size.indexOf('2"x4"') >= 0) { |
| 133 | 148 | return '/static/lable2.png' |
| ... | ... | @@ -135,10 +150,13 @@ const labelImage = computed(() => { |
| 135 | 150 | return '/static/lable1.png' |
| 136 | 151 | }) |
| 137 | 152 | |
| 138 | -// 产品名称按标签模板固定:lable1 → Syrup,lable2 → Cheese Burger Deluxe | |
| 139 | -const displayProductName = computed(() => | |
| 140 | - labelImage.value.includes('lable1') ? 'Syrup' : 'Cheese Burger Deluxe' | |
| 141 | -) | |
| 153 | +// 按详情规则与产品列表一致:chicken→Chicken,lable2→Cheese Burger Deluxe,lable1→Syrup | |
| 154 | +const displayProductName = computed(() => { | |
| 155 | + if (productId.value === 'chicken') return 'Chicken' | |
| 156 | + const size = templateSize.value | |
| 157 | + if (size.indexOf('2"x6"') >= 0 || size.indexOf('2"x4"') >= 0) return 'Cheese Burger Deluxe' | |
| 158 | + return 'Syrup' | |
| 159 | +}) | |
| 142 | 160 | |
| 143 | 161 | onShow(() => { |
| 144 | 162 | const name = uni.getStorageSync('btDeviceName') |
| ... | ... | @@ -178,6 +196,7 @@ onLoad((opts: any) => { |
| 178 | 196 | |
| 179 | 197 | const product = productMap[pid] |
| 180 | 198 | if (product) { |
| 199 | + productId.value = pid | |
| 181 | 200 | productName.value = product.name |
| 182 | 201 | productCategory.value = product.category |
| 183 | 202 | templateSize.value = product.templateSize |
| ... | ... | @@ -194,6 +213,7 @@ onLoad((opts: any) => { |
| 194 | 213 | |
| 195 | 214 | const storeId = uni.getStorageSync('storeId') || '001' |
| 196 | 215 | locationName.value = 'Location A' |
| 216 | + labelId.value = generateNextLabelId() | |
| 197 | 217 | }) |
| 198 | 218 | |
| 199 | 219 | const increment = () => { if (printQty.value < 99) printQty.value++ } |
| ... | ... | @@ -442,18 +462,22 @@ const handlePrint = () => { |
| 442 | 462 | |
| 443 | 463 | .info-row { |
| 444 | 464 | display: flex; |
| 445 | - gap: 16rpx; | |
| 446 | 465 | margin-bottom: 24rpx; |
| 447 | 466 | } |
| 448 | 467 | |
| 449 | 468 | .info-item { |
| 450 | 469 | flex: 1; |
| 470 | + min-width: 0; | |
| 451 | 471 | background: #fff; |
| 452 | 472 | padding: 20rpx 24rpx; |
| 453 | 473 | border-radius: 16rpx; |
| 454 | 474 | box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.04); |
| 455 | 475 | } |
| 456 | 476 | |
| 477 | +.info-item + .info-item { | |
| 478 | + margin-left: 10rpx; | |
| 479 | +} | |
| 480 | + | |
| 457 | 481 | .info-label { |
| 458 | 482 | font-size: 22rpx; |
| 459 | 483 | color: #9ca3af; |
| ... | ... | @@ -614,6 +638,28 @@ const handlePrint = () => { |
| 614 | 638 | padding: 24rpx; |
| 615 | 639 | } |
| 616 | 640 | |
| 641 | +.modal-label-id { | |
| 642 | + margin-top: 20rpx; | |
| 643 | + padding-top: 20rpx; | |
| 644 | + border-top: 1rpx solid #e5e7eb; | |
| 645 | + display: flex; | |
| 646 | + align-items: center; | |
| 647 | + justify-content: space-between; | |
| 648 | + gap: 16rpx; | |
| 649 | +} | |
| 650 | + | |
| 651 | +.modal-label-id-label { | |
| 652 | + font-size: 26rpx; | |
| 653 | + color: #6b7280; | |
| 654 | + font-weight: 500; | |
| 655 | +} | |
| 656 | + | |
| 657 | +.modal-label-id-value { | |
| 658 | + font-size: 28rpx; | |
| 659 | + color: #111827; | |
| 660 | + font-weight: 600; | |
| 661 | +} | |
| 662 | + | |
| 617 | 663 | .modal-top { |
| 618 | 664 | display: flex; |
| 619 | 665 | justify-content: space-between; | ... | ... |
美国版/Food Labeling Management App UniApp/src/pages/login/login.vue
| 1 | 1 | <template> |
| 2 | 2 | <view class="login-page"> |
| 3 | - <view class="header-hero" :style="{ paddingTop: (statusBarHeight + 40) + 'px' }"> | |
| 3 | + <view class="header-hero" :style="{ paddingTop: (statusBarHeight + 16) + 'px' }"> | |
| 4 | 4 | <view class="logo-section"> |
| 5 | 5 | <image class="login-logo" src="/static/logo_us.png" mode="aspectFit" /> |
| 6 | 6 | <text class="hero-sub">{{ t('login.employeePortal') }}</text> |
| ... | ... | @@ -14,6 +14,7 @@ |
| 14 | 14 | <input |
| 15 | 15 | v-model="email" |
| 16 | 16 | type="text" |
| 17 | + inputmode="email" | |
| 17 | 18 | class="input" |
| 18 | 19 | :placeholder="t('login.emailPlaceholder')" |
| 19 | 20 | placeholder-class="placeholder" |
| ... | ... | @@ -77,14 +78,14 @@ const handleLogin = () => { |
| 77 | 78 | .login-page { |
| 78 | 79 | min-height: 100vh; |
| 79 | 80 | background: #f9fafb; |
| 80 | - display: flex; | |
| 81 | - flex-direction: column; | |
| 81 | + padding-bottom: 48rpx; | |
| 82 | 82 | } |
| 83 | 83 | |
| 84 | 84 | .header-hero { |
| 85 | 85 | background: linear-gradient(135deg, var(--theme-primary), var(--theme-primary-dark)); |
| 86 | - padding: 0 48rpx 64rpx; | |
| 86 | + padding: 0 48rpx 24rpx; | |
| 87 | 87 | text-align: center; |
| 88 | + flex-shrink: 0; | |
| 88 | 89 | } |
| 89 | 90 | |
| 90 | 91 | .logo-section { |
| ... | ... | @@ -94,9 +95,9 @@ const handleLogin = () => { |
| 94 | 95 | } |
| 95 | 96 | |
| 96 | 97 | .login-logo { |
| 97 | - width: 420rpx; | |
| 98 | - height: 140rpx; | |
| 99 | - margin-bottom: 20rpx; | |
| 98 | + width: 360rpx; | |
| 99 | + height: 120rpx; | |
| 100 | + margin-bottom: 12rpx; | |
| 100 | 101 | background: rgba(255,255,255,0.92); |
| 101 | 102 | border-radius: 16rpx; |
| 102 | 103 | padding: 16rpx; |
| ... | ... | @@ -108,9 +109,7 @@ const handleLogin = () => { |
| 108 | 109 | } |
| 109 | 110 | |
| 110 | 111 | .form-wrap { |
| 111 | - flex: 1; | |
| 112 | - padding: 48rpx; | |
| 113 | - margin-top: -32rpx; | |
| 112 | + padding: 24rpx 48rpx 48rpx; | |
| 114 | 113 | } |
| 115 | 114 | |
| 116 | 115 | .form-card { |
| ... | ... | @@ -134,10 +133,14 @@ const handleLogin = () => { |
| 134 | 133 | |
| 135 | 134 | .input { |
| 136 | 135 | height: 96rpx; |
| 136 | + min-height: 48px; | |
| 137 | 137 | padding: 0 24rpx; |
| 138 | 138 | background: #f3f4f6; |
| 139 | 139 | border-radius: 16rpx; |
| 140 | 140 | font-size: 32rpx; |
| 141 | + display: block; | |
| 142 | + width: 100%; | |
| 143 | + box-sizing: border-box; | |
| 141 | 144 | } |
| 142 | 145 | |
| 143 | 146 | .placeholder { | ... | ... |
美国版/Food Labeling Management App UniApp/src/pages/more/label-report.vue
| ... | ... | @@ -15,6 +15,33 @@ |
| 15 | 15 | </view> |
| 16 | 16 | </view> |
| 17 | 17 | |
| 18 | + <view class="period-bar"> | |
| 19 | + <view | |
| 20 | + v-for="p in periodOptions" | |
| 21 | + :key="p.value" | |
| 22 | + class="period-btn" | |
| 23 | + :class="{ active: period === p.value }" | |
| 24 | + @click="selectPeriod(p.value)" | |
| 25 | + > | |
| 26 | + <text class="period-text">{{ p.label }}</text> | |
| 27 | + </view> | |
| 28 | + </view> | |
| 29 | + | |
| 30 | + <view v-if="period === 'custom'" class="custom-date-bar"> | |
| 31 | + <view class="date-field"> | |
| 32 | + <text class="date-label">Start</text> | |
| 33 | + <picker mode="date" :value="customStart" :end="customEnd || '2099-12-31'" @change="onStartChange"> | |
| 34 | + <view class="date-picker-btn">{{ customStart || 'Select' }}</view> | |
| 35 | + </picker> | |
| 36 | + </view> | |
| 37 | + <view class="date-field"> | |
| 38 | + <text class="date-label">End</text> | |
| 39 | + <picker mode="date" :value="customEnd" :start="customStart || '2000-01-01'" @change="onEndChange"> | |
| 40 | + <view class="date-picker-btn">{{ customEnd || 'Select' }}</view> | |
| 41 | + </picker> | |
| 42 | + </view> | |
| 43 | + </view> | |
| 44 | + | |
| 18 | 45 | <scroll-view class="content" scroll-y> |
| 19 | 46 | <!-- 指标卡 --> |
| 20 | 47 | <view class="metrics-grid"> |
| ... | ... | @@ -104,6 +131,42 @@ import { getStatusBarHeight } from '../../utils/statusBar' |
| 104 | 131 | |
| 105 | 132 | const statusBarHeight = getStatusBarHeight() |
| 106 | 133 | const isMenuOpen = ref(false) |
| 134 | +const period = ref('7d') | |
| 135 | +const customStart = ref('') | |
| 136 | +const customEnd = ref('') | |
| 137 | + | |
| 138 | +const periodOptions = [ | |
| 139 | + { value: '7d', label: 'Last 7 Days' }, | |
| 140 | + { value: '30d', label: 'Last 30 Days' }, | |
| 141 | + { value: '90d', label: 'Last 90 Days' }, | |
| 142 | + { value: 'custom', label: 'Custom' }, | |
| 143 | +] | |
| 144 | + | |
| 145 | +function selectPeriod(val: string) { | |
| 146 | + period.value = val | |
| 147 | + if (val === 'custom') { | |
| 148 | + const today = formatDate(new Date()) | |
| 149 | + const weekAgo = new Date() | |
| 150 | + weekAgo.setDate(weekAgo.getDate() - 7) | |
| 151 | + customStart.value = customStart.value || formatDate(weekAgo) | |
| 152 | + customEnd.value = customEnd.value || today | |
| 153 | + } | |
| 154 | +} | |
| 155 | + | |
| 156 | +function formatDate(d: Date): string { | |
| 157 | + const y = d.getFullYear() | |
| 158 | + const m = String(d.getMonth() + 1).padStart(2, '0') | |
| 159 | + const day = String(d.getDate()).padStart(2, '0') | |
| 160 | + return `${y}-${m}-${day}` | |
| 161 | +} | |
| 162 | + | |
| 163 | +function onStartChange(e: any) { | |
| 164 | + customStart.value = e.detail.value | |
| 165 | +} | |
| 166 | + | |
| 167 | +function onEndChange(e: any) { | |
| 168 | + customEnd.value = e.detail.value | |
| 169 | +} | |
| 107 | 170 | |
| 108 | 171 | const categoryDataRaw = [ |
| 109 | 172 | { name: 'Dairy', value: 450 }, |
| ... | ... | @@ -187,6 +250,67 @@ const goBack = () => { |
| 187 | 250 | color: #fff; |
| 188 | 251 | } |
| 189 | 252 | |
| 253 | +.period-bar { | |
| 254 | + display: flex; | |
| 255 | + gap: 12rpx; | |
| 256 | + padding: 16rpx 28rpx; | |
| 257 | + background: #fff; | |
| 258 | + border-bottom: 1rpx solid #e5e7eb; | |
| 259 | +} | |
| 260 | + | |
| 261 | +.period-btn { | |
| 262 | + flex: 1; | |
| 263 | + padding: 16rpx 24rpx; | |
| 264 | + border-radius: 12rpx; | |
| 265 | + background: #f3f4f6; | |
| 266 | + text-align: center; | |
| 267 | + transition: all 0.2s; | |
| 268 | +} | |
| 269 | + | |
| 270 | +.period-btn.active { | |
| 271 | + background: linear-gradient(135deg, #1F3A8A, #1447E6); | |
| 272 | +} | |
| 273 | + | |
| 274 | +.period-btn.active .period-text { | |
| 275 | + color: #fff; | |
| 276 | +} | |
| 277 | + | |
| 278 | +.period-text { | |
| 279 | + font-size: 26rpx; | |
| 280 | + font-weight: 500; | |
| 281 | + color: #6b7280; | |
| 282 | +} | |
| 283 | + | |
| 284 | +.custom-date-bar { | |
| 285 | + display: flex; | |
| 286 | + gap: 24rpx; | |
| 287 | + padding: 20rpx 28rpx; | |
| 288 | + background: #fff; | |
| 289 | + border-bottom: 1rpx solid #e5e7eb; | |
| 290 | +} | |
| 291 | + | |
| 292 | +.date-field { | |
| 293 | + flex: 1; | |
| 294 | + display: flex; | |
| 295 | + flex-direction: column; | |
| 296 | + gap: 8rpx; | |
| 297 | +} | |
| 298 | + | |
| 299 | +.date-label { | |
| 300 | + font-size: 24rpx; | |
| 301 | + color: #6b7280; | |
| 302 | + font-weight: 500; | |
| 303 | +} | |
| 304 | + | |
| 305 | +.date-picker-btn { | |
| 306 | + padding: 20rpx 24rpx; | |
| 307 | + background: #f3f4f6; | |
| 308 | + border-radius: 12rpx; | |
| 309 | + font-size: 28rpx; | |
| 310 | + color: #111827; | |
| 311 | + border: 2rpx solid #e5e7eb; | |
| 312 | +} | |
| 313 | + | |
| 190 | 314 | .content { |
| 191 | 315 | flex: 1; |
| 192 | 316 | padding: 24rpx 28rpx 40rpx; |
| ... | ... | @@ -378,10 +502,10 @@ const goBack = () => { |
| 378 | 502 | font-size: 24rpx; |
| 379 | 503 | } |
| 380 | 504 | |
| 381 | -.col-name { flex: 1; min-width: 0; } | |
| 382 | -.col-cat { flex: 0 0 140rpx; } | |
| 383 | -.col-total { flex: 0 0 120rpx; text-align: right; } | |
| 384 | -.col-pct { flex: 0 0 88rpx; text-align: right; } | |
| 505 | +.col-name { flex: 1; min-width: 0; text-align: left; } | |
| 506 | +.col-cat { flex: 0 0 140rpx; text-align: left; } | |
| 507 | +.col-total { flex: 0 0 120rpx; text-align: left; } | |
| 508 | +.col-pct { flex: 0 0 88rpx; text-align: left; } | |
| 385 | 509 | |
| 386 | 510 | .product-row:not(.header) .col-name { color: #111827; font-weight: 500; } |
| 387 | 511 | .product-row:not(.header) .col-cat { color: #6b7280; } | ... | ... |
美国版/Food Labeling Management App UniApp/src/pages/more/print-detail.vue
| ... | ... | @@ -27,6 +27,10 @@ |
| 27 | 27 | <text class="detail-section-title">Print Info</text> |
| 28 | 28 | <view class="info-card"> |
| 29 | 29 | <view class="info-row"> |
| 30 | + <text class="info-label">Label ID</text> | |
| 31 | + <text class="info-value">{{ record.labelId }}</text> | |
| 32 | + </view> | |
| 33 | + <view class="info-row"> | |
| 30 | 34 | <text class="info-label">Print Time</text> |
| 31 | 35 | <text class="info-value">{{ record.dateFull }} {{ record.time }}</text> |
| 32 | 36 | </view> |
| ... | ... | @@ -74,7 +78,8 @@ import AppIcon from '../../components/AppIcon.vue' |
| 74 | 78 | import SideMenu from '../../components/SideMenu.vue' |
| 75 | 79 | import LocationPicker from '../../components/LocationPicker.vue' |
| 76 | 80 | import { getStatusBarHeight } from '../../utils/statusBar' |
| 77 | -import { getRecordById } from '../../utils/printRecords' | |
| 81 | +import { getRecordByLabelId } from '../../utils/printLog' | |
| 82 | +import chickenLabelImg from '../../static/chicken-lable.png' | |
| 78 | 83 | |
| 79 | 84 | const statusBarHeight = getStatusBarHeight() |
| 80 | 85 | const isMenuOpen = ref(false) |
| ... | ... | @@ -83,6 +88,9 @@ const record = ref<any>(null) |
| 83 | 88 | const labelImage = computed(() => { |
| 84 | 89 | const r = record.value |
| 85 | 90 | if (!r) return '/static/lable1.png' |
| 91 | + if (r.productName === 'Chicken') { | |
| 92 | + return chickenLabelImg | |
| 93 | + } | |
| 86 | 94 | const size = r.templateSize || '' |
| 87 | 95 | if (size.indexOf('2"x6"') >= 0 || size.indexOf('2"x4"') >= 0) { |
| 88 | 96 | return '/static/lable2.png' |
| ... | ... | @@ -90,15 +98,20 @@ const labelImage = computed(() => { |
| 90 | 98 | return '/static/lable1.png' |
| 91 | 99 | }) |
| 92 | 100 | |
| 93 | -// 产品名称按标签模板固定:lable1 → Syrup,lable2 → Cheese Burger Deluxe | |
| 94 | -const displayProductName = computed(() => | |
| 95 | - labelImage.value.includes('lable1') ? 'Syrup' : 'Cheese Burger Deluxe' | |
| 96 | -) | |
| 101 | +// 与产品列表、详情一致:按标签图 Chicken/Syrup/Cheese Burger Deluxe | |
| 102 | +const displayProductName = computed(() => { | |
| 103 | + const r = record.value | |
| 104 | + if (!r) return '' | |
| 105 | + if (r.productName === 'Chicken') return 'Chicken' | |
| 106 | + const size = r.templateSize || '' | |
| 107 | + if (size.indexOf('2"x6"') >= 0 || size.indexOf('2"x4"') >= 0) return 'Cheese Burger Deluxe' | |
| 108 | + return 'Syrup' | |
| 109 | +}) | |
| 97 | 110 | |
| 98 | 111 | onLoad((opts: any) => { |
| 99 | - const id = opts && opts.id | |
| 100 | - if (id) { | |
| 101 | - record.value = getRecordById(id) | |
| 112 | + const labelId = opts && opts.labelId | |
| 113 | + if (labelId) { | |
| 114 | + record.value = getRecordByLabelId(labelId) | |
| 102 | 115 | } |
| 103 | 116 | }) |
| 104 | 117 | ... | ... |
美国版/Food Labeling Management App UniApp/src/pages/more/print-log.vue
| ... | ... | @@ -15,8 +15,28 @@ |
| 15 | 15 | </view> |
| 16 | 16 | </view> |
| 17 | 17 | |
| 18 | + <view class="view-toggle"> | |
| 19 | + <view | |
| 20 | + class="toggle-btn" | |
| 21 | + :class="{ active: viewMode === 'card' }" | |
| 22 | + @click="viewMode = 'card'" | |
| 23 | + > | |
| 24 | + <AppIcon name="squares" size="sm" :color="viewMode === 'card' ? 'white' : 'gray'" /> | |
| 25 | + <text class="toggle-text">Card</text> | |
| 26 | + </view> | |
| 27 | + <view | |
| 28 | + class="toggle-btn" | |
| 29 | + :class="{ active: viewMode === 'list' }" | |
| 30 | + @click="viewMode = 'list'" | |
| 31 | + > | |
| 32 | + <AppIcon name="list" size="sm" :color="viewMode === 'list' ? 'white' : 'gray'" /> | |
| 33 | + <text class="toggle-text">List</text> | |
| 34 | + </view> | |
| 35 | + </view> | |
| 36 | + | |
| 18 | 37 | <scroll-view class="content" scroll-y> |
| 19 | - <view class="log-list"> | |
| 38 | + <!-- 卡片视图 --> | |
| 39 | + <view v-if="viewMode === 'card'" class="log-list"> | |
| 20 | 40 | <view |
| 21 | 41 | v-for="row in printLogData" |
| 22 | 42 | :key="row.labelId" |
| ... | ... | @@ -56,6 +76,34 @@ |
| 56 | 76 | </view> |
| 57 | 77 | </view> |
| 58 | 78 | </view> |
| 79 | + | |
| 80 | + <!-- 列表视图 --> | |
| 81 | + <view v-else class="log-table-wrap"> | |
| 82 | + <view class="log-table"> | |
| 83 | + <view class="log-table-header"> | |
| 84 | + <text class="th th-product">Product</text> | |
| 85 | + <text class="th th-id">Label ID</text> | |
| 86 | + <text class="th th-printed">Printed At</text> | |
| 87 | + <text class="th th-expires">Expires</text> | |
| 88 | + <text class="th th-action">Action</text> | |
| 89 | + </view> | |
| 90 | + <view | |
| 91 | + v-for="row in printLogData" | |
| 92 | + :key="row.labelId" | |
| 93 | + class="log-table-row" | |
| 94 | + > | |
| 95 | + <text class="td td-product">{{ row.productName }}</text> | |
| 96 | + <text class="td td-id">{{ row.labelId }}</text> | |
| 97 | + <text class="td td-printed">{{ row.printedAt }}</text> | |
| 98 | + <text class="td td-expires">{{ row.expiryDate }}</text> | |
| 99 | + <view class="td td-action"> | |
| 100 | + <view class="reprint-btn-sm" @click="handleReprint(row)"> | |
| 101 | + <AppIcon name="printer" size="sm" color="white" /> | |
| 102 | + </view> | |
| 103 | + </view> | |
| 104 | + </view> | |
| 105 | + </view> | |
| 106 | + </view> | |
| 59 | 107 | </scroll-view> |
| 60 | 108 | |
| 61 | 109 | <SideMenu v-model="isMenuOpen" /> |
| ... | ... | @@ -68,20 +116,16 @@ import AppIcon from '../../components/AppIcon.vue' |
| 68 | 116 | import SideMenu from '../../components/SideMenu.vue' |
| 69 | 117 | import LocationPicker from '../../components/LocationPicker.vue' |
| 70 | 118 | import { getStatusBarHeight } from '../../utils/statusBar' |
| 119 | +import { printLogList } from '../../utils/printLog' | |
| 71 | 120 | |
| 72 | 121 | const statusBarHeight = getStatusBarHeight() |
| 73 | 122 | const isMenuOpen = ref(false) |
| 123 | +const viewMode = ref<'card' | 'list'>('card') | |
| 74 | 124 | |
| 75 | -const printLogData = ref([ | |
| 76 | - { labelId: '1-251201', productName: 'Whole Milk', category: 'Dairy', template: '2"x2" Basic', printedAt: '2024-03-20 09:30 AM', printedBy: 'Alice Johnson', location: 'Downtown Store (101)', expiryDate: '2024-03-27' }, | |
| 77 | - { labelId: '2-251201', productName: 'Ground Beef', category: 'Meat', template: '2"x2" Basic', printedAt: '2024-03-20 10:15 AM', printedBy: 'Bob Smith', location: 'Uptown Store (102)', expiryDate: '2024-03-23' }, | |
| 78 | - { labelId: '3-251201', productName: 'Croissant', category: 'Bakery', template: '2"x2" Basic', printedAt: '2024-03-19 14:00 PM', printedBy: 'Charlie Brown', location: 'Downtown Store (101)', expiryDate: '2024-03-20' }, | |
| 79 | - { labelId: '4-251201', productName: 'Caesar Salad', category: 'Deli', template: '2"x6" G\'n\'G !!!', printedAt: '2024-03-18 11:45 AM', printedBy: 'Alice Johnson', location: 'Downtown Store (101)', expiryDate: '2024-03-21' }, | |
| 80 | - { labelId: '5-251201', productName: 'Orange Juice', category: 'Beverage', template: '2"x2" Basic', printedAt: '2024-03-18 08:20 AM', printedBy: 'Bob Smith', location: 'Airport Kiosk (201)', expiryDate: '2024-03-25' }, | |
| 81 | -]) | |
| 125 | +const printLogData = ref(printLogList) | |
| 82 | 126 | |
| 83 | 127 | const handleReprint = (row: any) => { |
| 84 | - uni.showToast({ title: 'Reprint: ' + row.productName, icon: 'none' }) | |
| 128 | + uni.navigateTo({ url: `/pages/more/print-detail?labelId=${encodeURIComponent(row.labelId)}` }) | |
| 85 | 129 | } |
| 86 | 130 | |
| 87 | 131 | const goBack = () => { |
| ... | ... | @@ -250,4 +294,125 @@ const goBack = () => { |
| 250 | 294 | font-weight: 600; |
| 251 | 295 | color: #fff; |
| 252 | 296 | } |
| 297 | + | |
| 298 | +.view-toggle { | |
| 299 | + display: flex; | |
| 300 | + gap: 12rpx; | |
| 301 | + padding: 16rpx 28rpx; | |
| 302 | + background: #fff; | |
| 303 | + border-bottom: 1rpx solid #e5e7eb; | |
| 304 | +} | |
| 305 | + | |
| 306 | +.toggle-btn { | |
| 307 | + flex: 1; | |
| 308 | + display: flex; | |
| 309 | + align-items: center; | |
| 310 | + justify-content: center; | |
| 311 | + gap: 8rpx; | |
| 312 | + padding: 16rpx 24rpx; | |
| 313 | + border-radius: 12rpx; | |
| 314 | + background: #f3f4f6; | |
| 315 | + transition: all 0.2s; | |
| 316 | +} | |
| 317 | + | |
| 318 | +.toggle-btn.active { | |
| 319 | + background: linear-gradient(135deg, #1F3A8A, #1447E6); | |
| 320 | +} | |
| 321 | + | |
| 322 | +.toggle-btn.active .toggle-text { | |
| 323 | + color: #fff; | |
| 324 | +} | |
| 325 | + | |
| 326 | +.toggle-text { | |
| 327 | + font-size: 26rpx; | |
| 328 | + font-weight: 500; | |
| 329 | + color: #6b7280; | |
| 330 | +} | |
| 331 | + | |
| 332 | +.log-table-wrap { | |
| 333 | + background: #fff; | |
| 334 | + border-radius: 20rpx; | |
| 335 | + overflow-x: auto; | |
| 336 | + overflow-y: hidden; | |
| 337 | + -webkit-overflow-scrolling: touch; | |
| 338 | + box-shadow: 0 2rpx 16rpx rgba(0, 0, 0, 0.04); | |
| 339 | + border: 1rpx solid #e5e7eb; | |
| 340 | +} | |
| 341 | + | |
| 342 | +/* 确保横向滚动条可见(H5/浏览器) */ | |
| 343 | +.log-table-wrap::-webkit-scrollbar { | |
| 344 | + height: 6px; | |
| 345 | +} | |
| 346 | +.log-table-wrap::-webkit-scrollbar-thumb { | |
| 347 | + background: #d1d5db; | |
| 348 | + border-radius: 3px; | |
| 349 | +} | |
| 350 | +.log-table-wrap::-webkit-scrollbar-track { | |
| 351 | + background: #f3f4f6; | |
| 352 | +} | |
| 353 | + | |
| 354 | +.log-table { | |
| 355 | + width: max-content; | |
| 356 | + min-width: 100%; | |
| 357 | +} | |
| 358 | + | |
| 359 | +.log-table-header { | |
| 360 | + display: flex; | |
| 361 | + padding: 24rpx 28rpx; | |
| 362 | + gap: 16rpx; | |
| 363 | + background: #fafbfc; | |
| 364 | + border-bottom: 1rpx solid #e5e7eb; | |
| 365 | + font-size: 24rpx; | |
| 366 | + font-weight: 600; | |
| 367 | + color: #6b7280; | |
| 368 | +} | |
| 369 | + | |
| 370 | +.log-table-row { | |
| 371 | + display: flex; | |
| 372 | + padding: 24rpx 28rpx; | |
| 373 | + gap: 16rpx; | |
| 374 | + border-bottom: 1rpx solid #e5e7eb; | |
| 375 | + align-items: center; | |
| 376 | + font-size: 26rpx; | |
| 377 | +} | |
| 378 | + | |
| 379 | +.log-table-row:last-child { | |
| 380 | + border-bottom: none; | |
| 381 | +} | |
| 382 | + | |
| 383 | +.th, .td { | |
| 384 | + flex-shrink: 0; | |
| 385 | + white-space: nowrap; | |
| 386 | +} | |
| 387 | + | |
| 388 | +.th-product, .td-product { flex: 0 0 auto; min-width: 140rpx; } | |
| 389 | +.th-id, .td-id { flex: 0 0 auto; min-width: 140rpx; } | |
| 390 | +.th-printed, .td-printed { flex: 0 0 auto; min-width: 200rpx; } | |
| 391 | +.th-expires, .td-expires { flex: 0 0 auto; min-width: 200rpx; } | |
| 392 | +.th-action, .td-action { | |
| 393 | + flex: 0 0 80rpx; | |
| 394 | + width: 80rpx; | |
| 395 | + min-width: 80rpx; | |
| 396 | + display: flex; | |
| 397 | + align-items: center; | |
| 398 | + justify-content: center; | |
| 399 | +} | |
| 400 | + | |
| 401 | +.td-product { color: #111827; font-weight: 500; } | |
| 402 | +.td-id { color: #6b7280; font-size: 24rpx; } | |
| 403 | +.td-printed, .td-expires { color: #4b5563; } | |
| 404 | + | |
| 405 | +.reprint-btn-sm { | |
| 406 | + display: inline-flex; | |
| 407 | + align-items: center; | |
| 408 | + justify-content: center; | |
| 409 | + width: 64rpx; | |
| 410 | + height: 64rpx; | |
| 411 | + background: linear-gradient(135deg, #1F3A8A, #1447E6); | |
| 412 | + border-radius: 12rpx; | |
| 413 | +} | |
| 414 | + | |
| 415 | +.reprint-btn-sm:active { | |
| 416 | + opacity: 0.9; | |
| 417 | +} | |
| 253 | 418 | </style> | ... | ... |
美国版/Food Labeling Management App UniApp/src/pages/store-select/store-select.vue
| ... | ... | @@ -48,7 +48,7 @@ |
| 48 | 48 | </view> |
| 49 | 49 | </view> |
| 50 | 50 | |
| 51 | - <view class="bottom-bar" :style="{ paddingBottom: (bottomSafeArea + 20) + 'px' }"> | |
| 51 | + <view class="bottom-bar" :style="{ paddingBottom: (bottomSafeArea + 24) + 'px' }"> | |
| 52 | 52 | <view |
| 53 | 53 | class="confirm-btn" |
| 54 | 54 | :class="{ disabled: !selectedStore }" |
| ... | ... | @@ -96,10 +96,12 @@ const handleConfirm = () => { |
| 96 | 96 | .page { |
| 97 | 97 | min-height: 100vh; |
| 98 | 98 | background: #f9fafb; |
| 99 | - padding-bottom: 200rpx; | |
| 99 | + display: flex; | |
| 100 | + flex-direction: column; | |
| 100 | 101 | } |
| 101 | 102 | |
| 102 | 103 | .header-hero { |
| 104 | + flex-shrink: 0; | |
| 103 | 105 | background: linear-gradient(135deg, var(--theme-primary), var(--theme-primary-dark)); |
| 104 | 106 | padding: 16rpx 32rpx 32rpx; |
| 105 | 107 | } |
| ... | ... | @@ -136,7 +138,11 @@ const handleConfirm = () => { |
| 136 | 138 | } |
| 137 | 139 | |
| 138 | 140 | .list { |
| 141 | + flex: 1; | |
| 142 | + min-height: 0; | |
| 143 | + overflow-y: auto; | |
| 139 | 144 | padding: 32rpx; |
| 145 | + padding-bottom: 24rpx; | |
| 140 | 146 | } |
| 141 | 147 | |
| 142 | 148 | .card { |
| ... | ... | @@ -214,12 +220,8 @@ const handleConfirm = () => { |
| 214 | 220 | } |
| 215 | 221 | |
| 216 | 222 | .bottom-bar { |
| 217 | - position: fixed; | |
| 218 | - bottom: 0; | |
| 219 | - left: 0; | |
| 220 | - right: 0; | |
| 221 | - padding: 32rpx 48rpx; | |
| 222 | - padding-bottom: 48rpx; | |
| 223 | + flex-shrink: 0; | |
| 224 | + padding: 24rpx 48rpx; | |
| 223 | 225 | background: #ffffff; |
| 224 | 226 | border-top: 1rpx solid #e5e7eb; |
| 225 | 227 | } | ... | ... |
美国版/Food Labeling Management App UniApp/src/static/chicken lable.png
0 → 100644
14.5 KB
美国版/Food Labeling Management App UniApp/src/static/chicken-lable.png
0 → 100644
14.5 KB
美国版/Food Labeling Management App UniApp/src/utils/printLog.ts
0 → 100644
| 1 | +/** | |
| 2 | + * Print Log 为唯一数据源,labelId 格式: X-YYMMDD | |
| 3 | + */ | |
| 4 | +export interface PrintLogRecord { | |
| 5 | + labelId: string | |
| 6 | + productName: string | |
| 7 | + category: string | |
| 8 | + template: string | |
| 9 | + templateSize: string | |
| 10 | + templateName: string | |
| 11 | + printedAt: string | |
| 12 | + printedBy: string | |
| 13 | + location: string | |
| 14 | + expiryDate: string | |
| 15 | + qty: number | |
| 16 | + dateFull: string | |
| 17 | + time: string | |
| 18 | + labelType?: string | |
| 19 | + printer: string | |
| 20 | +} | |
| 21 | + | |
| 22 | +export const printLogList: PrintLogRecord[] = [ | |
| 23 | + { labelId: '1-251201', productName: 'Whole Milk', category: 'Dairy', template: '2"x2" Basic', templateSize: '2"x2"', templateName: 'Basic', printedAt: '2024-03-20 09:30 AM', printedBy: 'Alice Johnson', location: 'Downtown Store (101)', expiryDate: '2024-03-27 14:30', qty: 1, dateFull: 'Mar 20, 2024', time: '09:30 AM', printer: 'Zebra ZD421' }, | |
| 24 | + { labelId: '2-251201', productName: 'Ground Beef', category: 'Meat', template: '2"x2" Basic', templateSize: '2"x2"', templateName: 'Basic', printedAt: '2024-03-20 10:15 AM', printedBy: 'Bob Smith', location: 'Uptown Store (102)', expiryDate: '2024-03-23 09:45', qty: 1, dateFull: 'Mar 20, 2024', time: '10:15 AM', printer: 'Zebra ZD421' }, | |
| 25 | + { labelId: '3-251201', productName: 'Croissant', category: 'Bakery', template: '2"x2" Basic', templateSize: '2"x2"', templateName: 'Basic', printedAt: '2024-03-19 14:00 PM', printedBy: 'Charlie Brown', location: 'Downtown Store (101)', expiryDate: '2024-03-20 16:00', qty: 1, dateFull: 'Mar 19, 2024', time: '02:00 PM', printer: 'Zebra ZD421' }, | |
| 26 | + { labelId: '4-251201', productName: 'Caesar Salad', category: 'Deli', template: '2"x6" G\'n\'G !!!', templateSize: '2"x6"', templateName: "G'n'G", printedAt: '2024-03-18 11:45 AM', printedBy: 'Alice Johnson', location: 'Downtown Store (101)', expiryDate: '2024-03-21 11:30', qty: 1, dateFull: 'Mar 18, 2024', time: '11:45 AM', printer: 'Brother QL-820NWB' }, | |
| 27 | + { labelId: '5-251201', productName: 'Orange Juice', category: 'Beverage', template: '2"x2" Basic', templateSize: '2"x2"', templateName: 'Basic', printedAt: '2024-03-18 08:20 AM', printedBy: 'Bob Smith', location: 'Airport Kiosk (201)', expiryDate: '2024-03-25 08:00', qty: 1, dateFull: 'Mar 18, 2024', time: '08:20 AM', printer: 'Brother QL-820NWB' }, | |
| 28 | +] | |
| 29 | + | |
| 30 | +export function getRecordByLabelId(labelId: string): PrintLogRecord | undefined { | |
| 31 | + return printLogList.find(r => r.labelId === labelId) | |
| 32 | +} | |
| 33 | + | |
| 34 | +/** 生成下一个 labelId,格式与 print log 一致 X-YYMMDD */ | |
| 35 | +export function generateNextLabelId(): string { | |
| 36 | + const now = new Date() | |
| 37 | + const yy = String(now.getFullYear()).slice(-2) | |
| 38 | + const mm = String(now.getMonth() + 1).padStart(2, '0') | |
| 39 | + const dd = String(now.getDate()).padStart(2, '0') | |
| 40 | + const datePart = yy + mm + dd | |
| 41 | + const todayRecords = printLogList.filter(r => { | |
| 42 | + const parts = r.labelId.split('-') | |
| 43 | + return parts.length === 2 && parts[1] === datePart | |
| 44 | + }) | |
| 45 | + const maxSeq = todayRecords.length > 0 | |
| 46 | + ? Math.max(...todayRecords.map(r => parseInt(r.labelId.split('-')[0], 10))) | |
| 47 | + : 0 | |
| 48 | + return `${maxSeq + 1}-${datePart}` | |
| 49 | +} | ... | ... |
美国版/Food Labeling Management App UniApp/src/utils/printRecords.ts
| 1 | 1 | export interface PrintRecord { |
| 2 | 2 | id: string |
| 3 | + labelId: string | |
| 3 | 4 | productName: string |
| 4 | 5 | category: string |
| 5 | 6 | qty: number |
| ... | ... | @@ -14,14 +15,14 @@ export interface PrintRecord { |
| 14 | 15 | } |
| 15 | 16 | |
| 16 | 17 | export const printRecordsList: PrintRecord[] = [ |
| 17 | - { id: '1', productName: 'Chicken Sandwich', category: 'Sandwich', qty: 2, userName: 'John Smith', date: '12/04', dateFull: 'Dec 4, 2025', time: '10:45 AM', templateSize: '2"x6"', templateName: "G'n'G", printer: 'Zebra ZD421' }, | |
| 18 | - { id: '2', productName: 'Chicken', category: 'Meat', qty: 1, userName: 'John Smith', date: '12/04', dateFull: 'Dec 4, 2025', time: '10:32 AM', labelType: 'Defrost', templateSize: '2"x2"', templateName: 'Basic', printer: 'Zebra ZD421' }, | |
| 19 | - { id: '3', productName: 'Caesar Salad', category: 'Salads', qty: 3, userName: 'Jane Doe', date: '12/04', dateFull: 'Dec 4, 2025', time: '09:15 AM', templateSize: '2"x4"', templateName: "G'n'G", printer: 'Brother QL-820NWB' }, | |
| 20 | - { id: '4', productName: 'Beef', category: 'Meat', qty: 1, userName: 'John Smith', date: '12/03', dateFull: 'Dec 3, 2025', time: '4:20 PM', labelType: 'Heated', templateSize: '2"x2"', templateName: 'Basic', printer: 'Zebra ZD421' }, | |
| 21 | - { id: '5', productName: 'Cheese Burger', category: 'Sandwich', qty: 2, userName: 'Jane Doe', date: '12/03', dateFull: 'Dec 3, 2025', time: '3:45 PM', templateSize: '2"x6"', templateName: "G'n'G", printer: 'Brother QL-820NWB' }, | |
| 22 | - { id: '6', productName: 'Ice Cream', category: 'Frozen', qty: 1, userName: 'John Smith', date: '12/03', dateFull: 'Dec 3, 2025', time: '2:30 PM', labelType: 'Vanilla', templateSize: '2"x2"', templateName: 'Storage', printer: 'Epson TM-T88VI' }, | |
| 23 | - { id: '7', productName: 'Milk', category: 'Dairy', qty: 1, userName: 'Jane Doe', date: '12/03', dateFull: 'Dec 3, 2025', time: '11:00 AM', templateSize: '2"x2"', templateName: 'Basic', printer: 'Zebra ZD421' }, | |
| 24 | - { id: '8', productName: 'Turkey Club', category: 'Sandwich', qty: 1, userName: 'John Smith', date: '12/02', dateFull: 'Dec 2, 2025', time: '1:20 PM', templateSize: '2"x6"', templateName: "G'n'G", printer: 'Brother QL-820NWB' }, | |
| 18 | + { id: '1', labelId: '1-251204', productName: 'Chicken Sandwich', category: 'Sandwich', qty: 2, userName: 'John Smith', date: '12/04', dateFull: 'Dec 4, 2025', time: '10:45 AM', templateSize: '2"x6"', templateName: "G'n'G", printer: 'Zebra ZD421' }, | |
| 19 | + { id: '2', labelId: '2-251204', productName: 'Chicken', category: 'Meat', qty: 1, userName: 'John Smith', date: '12/04', dateFull: 'Dec 4, 2025', time: '10:32 AM', labelType: 'Defrost', templateSize: '2"x2"', templateName: 'Basic', printer: 'Zebra ZD421' }, | |
| 20 | + { id: '3', labelId: '3-251204', productName: 'Caesar Salad', category: 'Salads', qty: 3, userName: 'Jane Doe', date: '12/04', dateFull: 'Dec 4, 2025', time: '09:15 AM', templateSize: '2"x4"', templateName: "G'n'G", printer: 'Brother QL-820NWB' }, | |
| 21 | + { id: '4', labelId: '4-251203', productName: 'Beef', category: 'Meat', qty: 1, userName: 'John Smith', date: '12/03', dateFull: 'Dec 3, 2025', time: '4:20 PM', labelType: 'Heated', templateSize: '2"x2"', templateName: 'Basic', printer: 'Zebra ZD421' }, | |
| 22 | + { id: '5', labelId: '5-251203', productName: 'Cheese Burger', category: 'Sandwich', qty: 2, userName: 'Jane Doe', date: '12/03', dateFull: 'Dec 3, 2025', time: '3:45 PM', templateSize: '2"x6"', templateName: "G'n'G", printer: 'Brother QL-820NWB' }, | |
| 23 | + { id: '6', labelId: '6-251203', productName: 'Ice Cream', category: 'Frozen', qty: 1, userName: 'John Smith', date: '12/03', dateFull: 'Dec 3, 2025', time: '2:30 PM', labelType: 'Vanilla', templateSize: '2"x2"', templateName: 'Storage', printer: 'Epson TM-T88VI' }, | |
| 24 | + { id: '7', labelId: '7-251203', productName: 'Milk', category: 'Dairy', qty: 1, userName: 'Jane Doe', date: '12/03', dateFull: 'Dec 3, 2025', time: '11:00 AM', templateSize: '2"x2"', templateName: 'Basic', printer: 'Zebra ZD421' }, | |
| 25 | + { id: '8', labelId: '8-251202', productName: 'Turkey Club', category: 'Sandwich', qty: 1, userName: 'John Smith', date: '12/02', dateFull: 'Dec 2, 2025', time: '1:20 PM', templateSize: '2"x6"', templateName: "G'n'G", printer: 'Brother QL-820NWB' }, | |
| 25 | 26 | ] |
| 26 | 27 | |
| 27 | 28 | export function getRecordById(id: string): PrintRecord | undefined { | ... | ... |