zengxi123 commited on
Commit
c8b2a0a
·
verified ·
1 Parent(s): 3c33f14

我需要你参考上面的页面设计一个程序,创建一个条形扫码uni-app+vue3应用程序,它是html文件+uvue文件的格式,主页名字为index。

Browse files

1.当它触发扫码时,发送POST请求,以将单号上传到数据库
2.创建一个存储十个条形码的数组,数组采用先进后出以确保最大只有十个,当扫码触发时将条形码数据加入这个数组中,当扫码得出的条形码数据已经在这个数组中时,应当发出提示说明单号已经扫描过,且不应该触发POST请求
3.它提供一个文本框,文本框放置需要注意的单号,以回车区分下一个,当扫码得出的条形码数据在文本框中时,应当给出提示
4.在编写代码时,你应该尽可能的去除耦合,以无数代码块的形式组成一个功能

Files changed (1) hide show
  1. index.uvue +356 -0
index.uvue ADDED
@@ -0,0 +1,356 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <template>
2
+ <view class="container">
3
+ <!-- Header -->
4
+ <view class="header">
5
+ <text class="title">Barcode Ninja</text>
6
+ <text class="subtitle">Scan, track, and manage barcodes efficiently</text>
7
+ </view>
8
+
9
+ <!-- Scanner Section -->
10
+ <view class="card">
11
+ <view class="card-header">
12
+ <text class="card-title">Barcode Scanner</text>
13
+ <button class="scan-btn" @click="initiateScan">
14
+ <text>Scan Now</text>
15
+ </button>
16
+ </view>
17
+
18
+ <view class="scanner-placeholder" :class="{ 'scan-animation': isScanning }">
19
+ <text v-if="!lastScanned">Ready to scan</text>
20
+ <text v-else class="last-scanned-code">{{ lastScanned }}</text>
21
+ </view>
22
+
23
+ <view class="last-scanned-container" v-if="lastScanned">
24
+ <text class="last-scanned-label">Last scanned:</text>
25
+ <text class="last-scanned-code">{{ lastScanned }}</text>
26
+ </view>
27
+ </view>
28
+
29
+ <!-- Watchlist Section -->
30
+ <view class="card">
31
+ <text class="card-title">Special Watchlist</text>
32
+ <textarea
33
+ class="watchlist-input"
34
+ v-model="watchlistInput"
35
+ placeholder="Enter barcodes to watch (one per line)"
36
+ @change="updateWatchlist"
37
+ />
38
+ <text class="watchlist-hint">Barcodes in this list will trigger special notifications when scanned.</text>
39
+ </view>
40
+
41
+ <!-- History Section -->
42
+ <view class="card">
43
+ <view class="card-header">
44
+ <text class="card-title">Recent Scans</text>
45
+ <button class="clear-btn" @click="clearHistory">
46
+ <text>Clear All</text>
47
+ </button>
48
+ </view>
49
+
50
+ <view v-if="scanHistory.length === 0" class="empty-history">
51
+ <text>No scans yet</text>
52
+ </view>
53
+
54
+ <view v-else class="history-list">
55
+ <view v-for="(item, index) in scanHistory" :key="index" class="history-item">
56
+ <text class="history-barcode">{{ item }}</text>
57
+ <text class="history-time">Just now</text>
58
+ </view>
59
+ </view>
60
+ </view>
61
+
62
+ <!-- Toast Notification -->
63
+ <view v-if="showToast" class="toast" :class="toastType">
64
+ <text>{{ toastMessage }}</text>
65
+ </view>
66
+ </view>
67
+ </template>
68
+
69
+ <script setup>
70
+ import { ref, reactive } from 'vue'
71
+
72
+ // State
73
+ const isScanning = ref(false)
74
+ const lastScanned = ref('')
75
+ const watchlistInput = ref('')
76
+ const showToast = ref(false)
77
+ const toastMessage = ref('')
78
+ const toastType = ref('info')
79
+ const scanHistory = reactive([])
80
+ const watchlist = reactive([])
81
+
82
+ // Constants
83
+ const MAX_HISTORY_SIZE = 10
84
+
85
+ // API Configuration
86
+ const API_ENDPOINT = 'https://your-api-endpoint.com/scans'
87
+
88
+ // Scan Functions
89
+ const initiateScan = () => {
90
+ isScanning.value = true
91
+ uni.scanCode({
92
+ success: (res) => {
93
+ handleScannedBarcode(res.result)
94
+ },
95
+ fail: () => {
96
+ showToastMessage('Scan failed', 'error')
97
+ },
98
+ complete: () => {
99
+ isScanning.value = false
100
+ }
101
+ })
102
+ }
103
+
104
+ const handleScannedBarcode = (barcode) => {
105
+ if (isBarcodeInHistory(barcode)) {
106
+ showToastMessage('This barcode has already been scanned!', 'warning')
107
+ return
108
+ }
109
+
110
+ addToHistory(barcode)
111
+
112
+ if (isBarcodeInWatchlist(barcode)) {
113
+ showToastMessage('⚠️ Special barcode detected!', 'warning')
114
+ }
115
+
116
+ sendToServer(barcode)
117
+ }
118
+
119
+ const isBarcodeInHistory = (barcode) => {
120
+ return scanHistory.includes(barcode)
121
+ }
122
+
123
+ const isBarcodeInWatchlist = (barcode) => {
124
+ return watchlist.includes(barcode)
125
+ }
126
+
127
+ // History Management
128
+ const addToHistory = (barcode) => {
129
+ if (scanHistory.length >= MAX_HISTORY_SIZE) {
130
+ scanHistory.pop()
131
+ }
132
+ scanHistory.unshift(barcode)
133
+ lastScanned.value = barcode
134
+ }
135
+
136
+ const clearHistory = () => {
137
+ scanHistory.splice(0, scanHistory.length)
138
+ lastScanned.value = ''
139
+ showToastMessage('Scan history cleared', 'info')
140
+ }
141
+
142
+ // Watchlist Management
143
+ const updateWatchlist = () => {
144
+ watchlist.splice(0, watchlist.length)
145
+ const barcodes = watchlistInput.value.split('\n')
146
+ .map(b => b.trim())
147
+ .filter(b => b !== '')
148
+ watchlist.push(...barcodes)
149
+ showToastMessage('Watchlist updated', 'success')
150
+ }
151
+
152
+ // API Communication
153
+ const sendToServer = async (barcode) => {
154
+ try {
155
+ const response = await uni.request({
156
+ url: API_ENDPOINT,
157
+ method: 'POST',
158
+ data: { barcode },
159
+ header: {
160
+ 'Content-Type': 'application/json'
161
+ }
162
+ })
163
+
164
+ if (response.statusCode === 200) {
165
+ showToastMessage(`Barcode "${barcode}" sent to server`, 'success')
166
+ } else {
167
+ throw new Error('Server error')
168
+ }
169
+ } catch (error) {
170
+ console.error('API Error:', error)
171
+ showToastMessage('Failed to send barcode', 'error')
172
+ }
173
+ }
174
+
175
+ // Toast Notification
176
+ const showToastMessage = (message, type = 'info') => {
177
+ toastMessage.value = message
178
+ toastType.value = type
179
+ showToast.value = true
180
+
181
+ setTimeout(() => {
182
+ showToast.value = false
183
+ }, 3000)
184
+ }
185
+ </script>
186
+
187
+ <style>
188
+ .container {
189
+ padding: 20px;
190
+ background-color: #f5f5f5;
191
+ min-height: 100vh;
192
+ }
193
+
194
+ .header {
195
+ margin-bottom: 20px;
196
+ text-align: center;
197
+ }
198
+
199
+ .title {
200
+ font-size: 24px;
201
+ font-weight: bold;
202
+ color: #4f46e5;
203
+ display: block;
204
+ margin-bottom: 5px;
205
+ }
206
+
207
+ .subtitle {
208
+ font-size: 14px;
209
+ color: #666;
210
+ }
211
+
212
+ .card {
213
+ background-color: white;
214
+ border-radius: 12px;
215
+ padding: 16px;
216
+ margin-bottom: 16px;
217
+ box-shadow: 0 2px 8px rgba(0,0,0,0.1);
218
+ }
219
+
220
+ .card-header {
221
+ display: flex;
222
+ justify-content: space-between;
223
+ align-items: center;
224
+ margin-bottom: 12px;
225
+ }
226
+
227
+ .card-title {
228
+ font-size: 18px;
229
+ font-weight: 600;
230
+ color: #333;
231
+ }
232
+
233
+ .scan-btn {
234
+ background-color: #4f46e5;
235
+ color: white;
236
+ padding: 8px 16px;
237
+ border-radius: 8px;
238
+ font-size: 14px;
239
+ }
240
+
241
+ .scanner-placeholder {
242
+ height: 200px;
243
+ background-color: #f0f0f0;
244
+ border-radius: 8px;
245
+ display: flex;
246
+ justify-content: center;
247
+ align-items: center;
248
+ margin-bottom: 12px;
249
+ border: 2px dashed #ccc;
250
+ }
251
+
252
+ .scan-animation {
253
+ animation: pulse 2s infinite;
254
+ }
255
+
256
+ @keyframes pulse {
257
+ 0% { box-shadow: 0 0 0 0 rgba(79, 70, 229, 0.4); }
258
+ 70% { box-shadow: 0 0 0 10px rgba(79, 70, 229, 0); }
259
+ 100% { box-shadow: 0 0 0 0 rgba(79, 70, 229, 0); }
260
+ }
261
+
262
+ .last-scanned-container {
263
+ background-color: #eef2ff;
264
+ padding: 12px;
265
+ border-radius: 8px;
266
+ }
267
+
268
+ .last-scanned-label {
269
+ font-size: 12px;
270
+ color: #666;
271
+ display: block;
272
+ margin-bottom: 4px;
273
+ }
274
+
275
+ .last-scanned-code {
276
+ font-family: monospace;
277
+ font-size: 16px;
278
+ font-weight: bold;
279
+ color: #4f46e5;
280
+ }
281
+
282
+ .watchlist-input {
283
+ width: 100%;
284
+ height: 100px;
285
+ border: 1px solid #ddd;
286
+ border-radius: 8px;
287
+ padding: 12px;
288
+ margin-bottom: 8px;
289
+ font-size: 14px;
290
+ }
291
+
292
+ .watchlist-hint {
293
+ font-size: 12px;
294
+ color: #666;
295
+ }
296
+
297
+ .empty-history {
298
+ padding: 20px 0;
299
+ text-align: center;
300
+ color: #999;
301
+ }
302
+
303
+ .history-list {
304
+ display: flex;
305
+ flex-direction: column;
306
+ gap: 8px;
307
+ }
308
+
309
+ .history-item {
310
+ display: flex;
311
+ justify-content: space-between;
312
+ align-items: center;
313
+ padding: 10px;
314
+ background-color: #f9f9f9;
315
+ border-radius: 8px;
316
+ }
317
+
318
+ .history-barcode {
319
+ font-family: monospace;
320
+ }
321
+
322
+ .history-time {
323
+ font-size: 12px;
324
+ color: #999;
325
+ }
326
+
327
+ .clear-btn {
328
+ color: #4f46e5;
329
+ font-size: 14px;
330
+ }
331
+
332
+ .toast {
333
+ position: fixed;
334
+ bottom: 40px;
335
+ left: 20px;
336
+ right: 20px;
337
+ padding: 12px 16px;
338
+ border-radius: 8px;
339
+ background-color: #333;
340
+ color: white;
341
+ text-align: center;
342
+ z-index: 1000;
343
+ }
344
+
345
+ .toast.success {
346
+ background-color: #10b981;
347
+ }
348
+
349
+ .toast.warning {
350
+ background-color: #f59e0b;
351
+ }
352
+
353
+ .toast.error {
354
+ background-color: #ef4444;
355
+ }
356
+ </style>