From bd129cfd7044a84e8b88082cae2c18b74600e6e1 Mon Sep 17 00:00:00 2001 From: fhm Date: Mon, 9 Jun 2025 19:20:11 +0700 Subject: [PATCH] add pinia and refactor some code --- .vscode/settings.json | 2 +- app.vue | 11 +- .../landing/demo/modalMakePrediction.vue | 2 +- components/landing/sidebar/index.vue | 3 - components/my/dashboard/sidebar/sidebar.vue | 22 +- .../my/predictions/prediction-card-list.vue | 12 + components/my/predictions/prediction-card.vue | 80 ++++++ .../my/predictions/prediction-table-list.vue | 87 ++++++ components/my/predictions/predictions.vue | 8 + .../ui/home/chart-session/chart-session.vue | 7 + .../home/chart-session/realVsPrediction.vue | 13 + components/my/ui/home/chart-session/trend.vue | 17 ++ .../my/ui/home/low-stock/fine-stock.vue | 88 ++++++ components/my/ui/home/low-stock/low-stock.vue | 86 ++++++ components/my/ui/home/modal-add-stock.vue | 253 ++++++++++++++++++ components/my/ui/home/stats-card.vue | 136 ++++++++++ composables/predictionTable.ts | 99 +++++++ composables/spreadsheetReader.ts | 69 +++++ composables/usePredictionFetch.ts | 2 +- composables/usePredictionTable.ts | 2 +- composables/useSpreadsheet.ts | 5 +- constants/dashboard-menu.ts | 5 + layouts/main.vue | 4 +- lib/utils.ts | 15 -- nuxt.config.ts | 2 +- package-lock.json | 82 ++++-- package.json | 2 + pages/dashboard/file-operation.vue | 2 +- pages/dashboard/home/index.vue | 174 +----------- pages/demo-old.vue | 147 ++++++++++ pages/demo.vue | 79 +++--- stores/file/record.ts | 28 ++ types/api-response/dashboard.ts | 10 + types/api-response/prediction.ts | 20 ++ types/api-response/product.ts | 9 +- types/api-response/py-prediction.ts | 11 - types/prediction/product-list.ts | 12 + types/table/prediction-input.ts | 7 + utils/math/percentage.ts | 9 + utils/spreadsheet/fileReader.ts | 4 +- utils/stringToSlug.ts | 10 + 41 files changed, 1352 insertions(+), 284 deletions(-) delete mode 100644 components/landing/sidebar/index.vue create mode 100644 components/my/predictions/prediction-card-list.vue create mode 100644 components/my/predictions/prediction-card.vue create mode 100644 components/my/predictions/prediction-table-list.vue create mode 100644 components/my/predictions/predictions.vue create mode 100644 components/my/ui/home/chart-session/chart-session.vue create mode 100644 components/my/ui/home/chart-session/realVsPrediction.vue create mode 100644 components/my/ui/home/chart-session/trend.vue create mode 100644 components/my/ui/home/low-stock/fine-stock.vue create mode 100644 components/my/ui/home/low-stock/low-stock.vue create mode 100644 components/my/ui/home/modal-add-stock.vue create mode 100644 components/my/ui/home/stats-card.vue create mode 100644 composables/predictionTable.ts create mode 100644 composables/spreadsheetReader.ts delete mode 100644 lib/utils.ts create mode 100644 pages/demo-old.vue create mode 100644 stores/file/record.ts create mode 100644 types/api-response/dashboard.ts create mode 100644 types/api-response/prediction.ts delete mode 100644 types/api-response/py-prediction.ts create mode 100644 types/prediction/product-list.ts create mode 100644 types/table/prediction-input.ts create mode 100644 utils/math/percentage.ts create mode 100644 utils/stringToSlug.ts diff --git a/.vscode/settings.json b/.vscode/settings.json index 79d57ec..ead227f 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,4 +1,4 @@ { - "iconify.annotations": false, + "iconify.annotations": true, "iconify.inplace": false } \ No newline at end of file diff --git a/app.vue b/app.vue index f1097ec..0f78df2 100644 --- a/app.vue +++ b/app.vue @@ -1,11 +1,12 @@ \ No newline at end of file + + \ No newline at end of file diff --git a/components/landing/demo/modalMakePrediction.vue b/components/landing/demo/modalMakePrediction.vue index 863fca4..84c9287 100644 --- a/components/landing/demo/modalMakePrediction.vue +++ b/components/landing/demo/modalMakePrediction.vue @@ -55,7 +55,7 @@ \ No newline at end of file diff --git a/components/my/predictions/prediction-card.vue b/components/my/predictions/prediction-card.vue new file mode 100644 index 0000000..b12f280 --- /dev/null +++ b/components/my/predictions/prediction-card.vue @@ -0,0 +1,80 @@ + + diff --git a/components/my/predictions/prediction-table-list.vue b/components/my/predictions/prediction-table-list.vue new file mode 100644 index 0000000..0a48e2a --- /dev/null +++ b/components/my/predictions/prediction-table-list.vue @@ -0,0 +1,87 @@ + + \ No newline at end of file diff --git a/components/my/predictions/predictions.vue b/components/my/predictions/predictions.vue new file mode 100644 index 0000000..d88fd00 --- /dev/null +++ b/components/my/predictions/predictions.vue @@ -0,0 +1,8 @@ + + \ No newline at end of file diff --git a/components/my/ui/home/chart-session/chart-session.vue b/components/my/ui/home/chart-session/chart-session.vue new file mode 100644 index 0000000..ad75169 --- /dev/null +++ b/components/my/ui/home/chart-session/chart-session.vue @@ -0,0 +1,7 @@ + \ No newline at end of file diff --git a/components/my/ui/home/chart-session/realVsPrediction.vue b/components/my/ui/home/chart-session/realVsPrediction.vue new file mode 100644 index 0000000..d3e978a --- /dev/null +++ b/components/my/ui/home/chart-session/realVsPrediction.vue @@ -0,0 +1,13 @@ + \ No newline at end of file diff --git a/components/my/ui/home/chart-session/trend.vue b/components/my/ui/home/chart-session/trend.vue new file mode 100644 index 0000000..dc7982f --- /dev/null +++ b/components/my/ui/home/chart-session/trend.vue @@ -0,0 +1,17 @@ + + \ No newline at end of file diff --git a/components/my/ui/home/low-stock/fine-stock.vue b/components/my/ui/home/low-stock/fine-stock.vue new file mode 100644 index 0000000..ef0f4d5 --- /dev/null +++ b/components/my/ui/home/low-stock/fine-stock.vue @@ -0,0 +1,88 @@ + \ No newline at end of file diff --git a/components/my/ui/home/low-stock/low-stock.vue b/components/my/ui/home/low-stock/low-stock.vue new file mode 100644 index 0000000..2c78b3e --- /dev/null +++ b/components/my/ui/home/low-stock/low-stock.vue @@ -0,0 +1,86 @@ + + \ No newline at end of file diff --git a/components/my/ui/home/modal-add-stock.vue b/components/my/ui/home/modal-add-stock.vue new file mode 100644 index 0000000..4ee9a31 --- /dev/null +++ b/components/my/ui/home/modal-add-stock.vue @@ -0,0 +1,253 @@ + + \ No newline at end of file diff --git a/components/my/ui/home/stats-card.vue b/components/my/ui/home/stats-card.vue new file mode 100644 index 0000000..982b430 --- /dev/null +++ b/components/my/ui/home/stats-card.vue @@ -0,0 +1,136 @@ + + \ No newline at end of file diff --git a/composables/predictionTable.ts b/composables/predictionTable.ts new file mode 100644 index 0000000..838daec --- /dev/null +++ b/composables/predictionTable.ts @@ -0,0 +1,99 @@ +import dayjs from '#build/dayjs.imports.mjs' +import type { TableColumn } from '#ui/types' +import type { TPredictionProductList } from '~/types/prediction/product-list' +import type { TRecordJSONResult } from '~/types/table/prediction-input' + +const mainColumns = [ + { label: 'Date', key: 'date', sortable: true, required: true }, + { label: 'Product Code', key: 'product_code', sortable: true, required: false }, + { label: 'Product Name', key: 'product_name', sortable: true, required: true }, + { label: 'Amount', key: 'amount', sortable: true, required: true } +] + +export function usePredictionInputTable(inputFile: Ref) { + const { + result, status: sheetReaderStatus + } = useSpreadSheetReader(inputFile) + const status = ref<'idle' | 'loading' | 'loaded'>('idle') + const loadingDetail = ref(); + const columns = ref(mainColumns) + const missingColumns = ref([]) + const mismatchDetail = ref([]) + const records = ref([]) + const products = ref([]) + + watch(sheetReaderStatus, newVal => { + if (newVal === 'idle' || newVal === 'error') + status.value = 'idle' + if (newVal === 'loading') + status.value = 'loading' + if (newVal === 'success') { + status.value = 'loading' + + if (!result.json.value) + return + + const requiredColumnKeys = mainColumns.map(v => v.key) + columns.value = [ + ...mainColumns, + ...result.jsonHeaders.value!.map(v => { + if (!requiredColumnKeys.includes(v.key)) + return { ...v, sortable: true } + return null + }).filter(v => !!v), + ] + records.value = result.json.value + + const jsonHeadersKeys = result.jsonHeaders.value!.map(v => v.key) + missingColumns.value = mainColumns.filter(v => !jsonHeadersKeys.includes(v.key) && v.required).map(v => v.label) + + let dateInvalidCounter = 0 + mismatchDetail.value = [] + const productsTemp: { + [key: string]: TPredictionProductList[number] + } = {} + result.json.value?.forEach((v, i) => { + if (!dayjs(v.date).isValid()) + dateInvalidCounter += 1 + const productKey = v.product_code || + stringToSlug(v.product_name) + + if ( + result.json.value && + result.json.value.length >= 1 && + !result.json.value[i].product_code + ) + result.json.value[i].product_code = productKey + if (!!productsTemp[productKey]) { + productsTemp[productKey].total += 1 + } else { + productsTemp[productKey] = { + product_code: productKey, + product_name: v.product_name, + total: 1, + status: 'unpredicted' + } + } + }) + if (dateInvalidCounter >= 1) + mismatchDetail.value.push(`${dateInvalidCounter} invalid date ${dateInvalidCounter === 1 ? 'value was' : 'values were'} found in the 'Date' column.`); + + products.value = Object.entries(productsTemp).map(v => v[1]) + + status.value = 'loaded' + } + }) + + const page = ref(1) + const pageCount = ref(10) + const rows = computed(() => { + return records.value.slice((page.value - 1) * pageCount.value, (page.value) * pageCount.value) + }) + + return { + inputFile, status, loadingDetail, result, + columns, missingColumns, mismatchDetail, + records, products, + page, pageCount, rows + } +} \ No newline at end of file diff --git a/composables/spreadsheetReader.ts b/composables/spreadsheetReader.ts new file mode 100644 index 0000000..a625538 --- /dev/null +++ b/composables/spreadsheetReader.ts @@ -0,0 +1,69 @@ +import type { TRecordJSONResult } from "~/types/table/prediction-input" +import { headerNRow2Sheet, sheet2HeaderNRow, sheet2JSON, spreadsheetReader } from "~/utils/spreadsheet/fileReader" + +export function useSpreadSheetReader(inputFile: Ref) { + const toast = useToast() + const status = ref<'idle' | 'loading' | 'error' | 'success'>('idle') + const error = ref() + const result = { + jsonHeaders: ref<{ + key: string, + label: string + }[]>(), + json: ref(), + } + + watch(inputFile, async (newVal) => { + try { + if (status.value === 'loading') + throw new Error('Please wait until the current file is fully loaded before uploading a new one.'); + if (!newVal) + return + + status.value = 'loading' + error.value = undefined + + const ws = await spreadsheetReader(newVal) + const { headers, rows } = sheet2HeaderNRow(ws) + result.jsonHeaders.value = [] + const validHeaders = headers.map((v: string) => { + const label = v.replaceAll(/\s+/g, ' ') + const key = v.toLowerCase().replaceAll(/\s+/g, '_').trim() + result.jsonHeaders.value?.push({ label, key }) + return key + }) + const newWs = headerNRow2Sheet(validHeaders, rows) + result.json.value = sheet2JSON(newWs) + } catch (e: unknown) { + setError(error.value?.message || 'Unknown Error', e as Error) + } finally { + if (status.value !== 'error') { + setSuccess() + } + } + }) + + function setError(msg: string, err?: Error) { + status.value = 'error' + error.value = err || new Error(msg) + toast.add({ + title: 'Error', + icon: 'i-heroicons-x-circle', + color: 'red', + description: msg + }) + } + function setSuccess() { + status.value = 'success' + toast.add({ + title: 'Success', + icon: 'i-heroicons-document-check', + color: 'green', + description: 'File Imported Successfully.' + }) + } + + return { + inputFile, status, result, error, + } +} \ No newline at end of file diff --git a/composables/usePredictionFetch.ts b/composables/usePredictionFetch.ts index e7afb51..54d0aed 100644 --- a/composables/usePredictionFetch.ts +++ b/composables/usePredictionFetch.ts @@ -1,7 +1,7 @@ import type { AsyncDataRequestStatus } from 'nuxt/app'; import type { TDurationType, TPredictionMode } from '~/types/landing-page/demo/modalMakePrediction'; import { z } from 'zod'; -import type { TPyPrediction } from '~/types/api-response/py-prediction'; +import type { TPyPrediction } from '~/types/api-response/prediction'; export function usePredictionFetch() { const config = useRuntimeConfig(); diff --git a/composables/usePredictionTable.ts b/composables/usePredictionTable.ts index 2fa8edd..30c3bff 100644 --- a/composables/usePredictionTable.ts +++ b/composables/usePredictionTable.ts @@ -5,7 +5,7 @@ const requiredColumn = [ { label: 'Date', key: 'date', sortable: true, }, { label: 'Product Code', key: 'product_code', sortable: true, }, { label: 'Product Name', key: 'product_name', sortable: true, }, - { label: 'Sold(qty)', key: 'sold(qty)', sortable: true, } + { label: 'Amount', key: 'amount', sortable: true, } ] export function usePredictionTable(inputFile: Ref) { diff --git a/composables/useSpreadsheet.ts b/composables/useSpreadsheet.ts index 3cb07a9..1d9574f 100644 --- a/composables/useSpreadsheet.ts +++ b/composables/useSpreadsheet.ts @@ -1,5 +1,6 @@ import { headerNRow2Sheet, sheet2CSV, sheet2HeaderNRow, sheet2JSON, spreadsheetReader } from "~/utils/spreadsheet/fileReader" import * as XLSX from 'xlsx' +import type { TRecordJSONResult } from "~/types/table/prediction-input" export function useSpreadSheet(inputFile: Ref) { const toast = useToast() @@ -12,7 +13,7 @@ export function useSpreadSheet(inputFile: Ref) { label: string }[]>(), csv: ref(), - json: ref[]>(), + json: ref(), } watch(inputFile, async (newVal) => { @@ -35,7 +36,7 @@ export function useSpreadSheet(inputFile: Ref) { return key }) const newWs = headerNRow2Sheet(validHeaders, rows) - result.json.value = sheet2JSON[]>(newWs) + result.json.value = sheet2JSON(newWs) result.csv.value = sheet2CSV(newWs) } catch (e: unknown) { setError(error.value?.message || 'Unknown Error', e as Error) diff --git a/constants/dashboard-menu.ts b/constants/dashboard-menu.ts index e343b17..1611ba2 100644 --- a/constants/dashboard-menu.ts +++ b/constants/dashboard-menu.ts @@ -15,6 +15,11 @@ export const sidebarItems = [ to: '/dashboard/restock', icon: 'i-heroicons-arrow-path-20-solid', }, + { + label: 'Prediction', + to: '/dashboard/prediction', + icon: 'i-heroicons-chart-bar-20-solid', + }, { label: 'Dataset', icon: 'i-heroicons-folder-20-solid', diff --git a/layouts/main.vue b/layouts/main.vue index b0dea04..9555af3 100644 --- a/layouts/main.vue +++ b/layouts/main.vue @@ -29,8 +29,8 @@
-
+
diff --git a/lib/utils.ts b/lib/utils.ts deleted file mode 100644 index 4c51992..0000000 --- a/lib/utils.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type { Updater } from '@tanstack/vue-table' -import type { Ref } from 'vue' -import { type ClassValue, clsx } from 'clsx' -import { twMerge } from 'tailwind-merge' - -export function cn(...inputs: ClassValue[]) { - return twMerge(clsx(inputs)) -} - -export function valueUpdater>(updaterOrValue: T, ref: Ref) { - ref.value - = typeof updaterOrValue === 'function' - ? updaterOrValue(ref.value) - : updaterOrValue -} diff --git a/nuxt.config.ts b/nuxt.config.ts index 8bfc825..84f7932 100644 --- a/nuxt.config.ts +++ b/nuxt.config.ts @@ -12,7 +12,7 @@ export default defineNuxtConfig({ }, compatibilityDate: '2024-11-01', devtools: { enabled: false }, - modules: ['@nuxt/image', '@nuxt/ui', 'dayjs-nuxt'], + modules: ['@nuxt/image', '@nuxt/ui', 'dayjs-nuxt', '@pinia/nuxt'], ui: { prefix: 'NuxtUi' }, diff --git a/package-lock.json b/package-lock.json index 368b6f6..7291db6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "@ngrok/ngrok": "^1.5.1", "@nuxt/image": "^1.10.0", "@nuxt/ui": "^2.21.1", + "@pinia/nuxt": "^0.11.1", "@vueuse/core": "^13.0.0", "@zxing/browser": "^0.1.5", "chart.js": "^4.4.9", @@ -21,6 +22,7 @@ "lucide-vue-next": "^0.485.0", "numeral": "^2.0.6", "nuxt": "^3.16.1", + "papaparse": "^5.5.3", "tailwind-merge": "^3.0.2", "tailwindcss-animate": "^1.0.7", "v-calendar": "^3.1.2", @@ -2464,6 +2466,21 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/@pinia/nuxt": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/@pinia/nuxt/-/nuxt-0.11.1.tgz", + "integrity": "sha512-tCD8ioWhhIHKwm8Y9VvyhBAV/kK4W5uGBIYbI5iM4N1t7duOqK6ECBUavrMxMolELayqqMLb9+evegrh3S7s2A==", + "license": "MIT", + "dependencies": { + "@nuxt/kit": "^3.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/posva" + }, + "peerDependencies": { + "pinia": "^3.0.3" + } + }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -3409,33 +3426,24 @@ } }, "node_modules/@vue/devtools-kit": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-7.7.2.tgz", - "integrity": "sha512-CY0I1JH3Z8PECbn6k3TqM1Bk9ASWxeMtTCvZr7vb+CHi+X/QwQm5F1/fPagraamKMAHVfuuCbdcnNg1A4CYVWQ==", + "version": "7.7.6", + "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-7.7.6.tgz", + "integrity": "sha512-geu7ds7tem2Y7Wz+WgbnbZ6T5eadOvozHZ23Atk/8tksHMFOFylKi1xgGlQlVn0wlkEf4hu+vd5ctj1G4kFtwA==", "license": "MIT", "dependencies": { - "@vue/devtools-shared": "^7.7.2", - "birpc": "^0.2.19", + "@vue/devtools-shared": "^7.7.6", + "birpc": "^2.3.0", "hookable": "^5.5.3", "mitt": "^3.0.1", "perfect-debounce": "^1.0.0", "speakingurl": "^14.0.1", - "superjson": "^2.2.1" - } - }, - "node_modules/@vue/devtools-kit/node_modules/birpc": { - "version": "0.2.19", - "resolved": "https://registry.npmjs.org/birpc/-/birpc-0.2.19.tgz", - "integrity": "sha512-5WeXXAvTmitV1RqJFppT5QtUiz2p1mRSYU000Jkft5ZUCLJIk4uQriYNO50HknxKwM6jd8utNc66K1qGIwwWBQ==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/antfu" + "superjson": "^2.2.2" } }, "node_modules/@vue/devtools-shared": { - "version": "7.7.2", - "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-7.7.2.tgz", - "integrity": "sha512-uBFxnp8gwW2vD6FrJB8JZLUzVb6PNRG0B0jBnHsOH8uKyva2qINY8PTF5Te4QlTbMDqU5K6qtJDr6cNsKWhbOA==", + "version": "7.7.6", + "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-7.7.6.tgz", + "integrity": "sha512-yFEgJZ/WblEsojQQceuyK6FzpFDx4kqrz2ohInxNj5/DnhoX023upTv4OD6lNPLAA5LLkbwPVb10o/7b+Y4FVA==", "license": "MIT", "dependencies": { "rfdc": "^1.4.1" @@ -8037,6 +8045,12 @@ "integrity": "sha512-Y8f9qUlBzW8qauJjd/eu6jlpJZsuPJm2ZAV0cDVd420o4EdpH5RPdoCv+60/TdJflGatr4sDfpAL6ArWZbM5tA==", "license": "MIT" }, + "node_modules/papaparse": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/papaparse/-/papaparse-5.5.3.tgz", + "integrity": "sha512-5QvjGxYVjxO59MGU2lHVYpRWBBtKHnlIAcSe1uNFCkkptUh63NFRj0FJQm7nR67puEruUci/ZkjmEFrjCAyP4A==", + "license": "MIT" + }, "node_modules/parse-path": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/parse-path/-/parse-path-7.0.1.tgz", @@ -8171,6 +8185,38 @@ "node": ">=0.10.0" } }, + "node_modules/pinia": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/pinia/-/pinia-3.0.3.tgz", + "integrity": "sha512-ttXO/InUULUXkMHpTdp9Fj4hLpD/2AoJdmAbAeW2yu1iy1k+pkFekQXw5VpC0/5p51IOR/jDaDRfRWRnMMsGOA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@vue/devtools-api": "^7.7.2" + }, + "funding": { + "url": "https://github.com/sponsors/posva" + }, + "peerDependencies": { + "typescript": ">=4.4.4", + "vue": "^2.7.0 || ^3.5.11" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/pinia/node_modules/@vue/devtools-api": { + "version": "7.7.6", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-7.7.6.tgz", + "integrity": "sha512-b2Xx0KvXZObePpXPYHvBRRJLDQn5nhKjXh7vUhMEtWxz1AYNFOVIsh5+HLP8xDGL7sy+Q7hXeUxPHB/KgbtsPw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@vue/devtools-kit": "^7.7.6" + } + }, "node_modules/pirates": { "version": "4.0.7", "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", diff --git a/package.json b/package.json index 7ec7142..bb23e0b 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "@ngrok/ngrok": "^1.5.1", "@nuxt/image": "^1.10.0", "@nuxt/ui": "^2.21.1", + "@pinia/nuxt": "^0.11.1", "@vueuse/core": "^13.0.0", "@zxing/browser": "^0.1.5", "chart.js": "^4.4.9", @@ -24,6 +25,7 @@ "lucide-vue-next": "^0.485.0", "numeral": "^2.0.6", "nuxt": "^3.16.1", + "papaparse": "^5.5.3", "tailwind-merge": "^3.0.2", "tailwindcss-animate": "^1.0.7", "v-calendar": "^3.1.2", diff --git a/pages/dashboard/file-operation.vue b/pages/dashboard/file-operation.vue index 5219601..30dd8ac 100644 --- a/pages/dashboard/file-operation.vue +++ b/pages/dashboard/file-operation.vue @@ -59,7 +59,7 @@ diff --git a/pages/demo.vue b/pages/demo.vue index 4787494..db9d3bc 100644 --- a/pages/demo.vue +++ b/pages/demo.vue @@ -20,9 +20,8 @@
- +
-