From de59371f50991a0dbee997eb4a13fd3f5f415ffd Mon Sep 17 00:00:00 2001 From: baoshiwei <baoshiwei@shlanbao.cn> Date: 星期五, 21 三月 2025 09:45:21 +0800 Subject: [PATCH] feat(login): 添加 Keycloak 登录支持 --- src/views/qms/trend/quality.vue | 535 +++++++++++++++++++++++++++++++++++++++++++++++++++++ /dev/null | 6 src/lang/zh_CN.ts | 3 src/views/login.vue | 32 +- src/layout/components/SocialCallback/index.vue | 2 src/views/qms/sensorRetest/index.vue | 2 src/views/qms/sensor/index.vue | 3 7 files changed, 556 insertions(+), 27 deletions(-) diff --git a/src/lang/zh_CN.ts b/src/lang/zh_CN.ts index 3cc9872..a94a307 100644 --- a/src/lang/zh_CN.ts +++ b/src/lang/zh_CN.ts @@ -33,7 +33,8 @@ maxkey: 'MaxKey鐧诲綍', topiam: 'TopIam鐧诲綍', gitee: 'Gitee鐧诲綍', - github: 'Github鐧诲綍' + github: 'Github鐧诲綍', + keycloak: 'Keycloak鐧诲綍' } }, // 娉ㄥ唽椤甸潰鍥介檯鍖� diff --git a/src/layout/components/SocialCallback/index.vue b/src/layout/components/SocialCallback/index.vue index 746de20..84baf34 100644 --- a/src/layout/components/SocialCallback/index.vue +++ b/src/layout/components/SocialCallback/index.vue @@ -75,7 +75,7 @@ socialCode: code, socialState: state, tenantId: tenantId, - source: source, + source: 'keycloak', clientId: import.meta.env.VITE_APP_CLIENT_ID, grantType: 'social' }; diff --git a/src/views/login.vue b/src/views/login.vue index e5d7c23..50d0cb7 100644 --- a/src/views/login.vue +++ b/src/views/login.vue @@ -45,21 +45,21 @@ </el-form-item> <el-checkbox v-model="loginForm.rememberMe" style="margin: 0 0 25px 0">{{ proxy.$t('login.rememberPassword') }}</el-checkbox> <el-form-item style="float: right"> - <el-button circle :title="proxy.$t('login.social.wechat')" @click="doSocialLogin('wechat')"> - <svg-icon icon-class="wechat" /> +<!-- <el-button circle :title="proxy.$t('login.social.wechat')" @click="doSocialLogin('wechat')">--> +<!-- <svg-icon icon-class="wechat" />--> +<!-- </el-button>--> + <el-button circle :title="proxy.$t('login.social.keycloak')" @click="doSocialLogin('keycloak')"> + <svg-icon icon-class="keycloak" /> </el-button> - <el-button circle :title="proxy.$t('login.social.maxkey')" @click="doSocialLogin('maxkey')"> - <svg-icon icon-class="maxkey" /> - </el-button> - <el-button circle :title="proxy.$t('login.social.topiam')" @click="doSocialLogin('topiam')"> - <svg-icon icon-class="topiam" /> - </el-button> - <el-button circle :title="proxy.$t('login.social.gitee')" @click="doSocialLogin('gitee')"> - <svg-icon icon-class="gitee" /> - </el-button> - <el-button circle :title="proxy.$t('login.social.github')" @click="doSocialLogin('github')"> - <svg-icon icon-class="github" /> - </el-button> +<!-- <el-button circle :title="proxy.$t('login.social.topiam')" @click="doSocialLogin('topiam')">--> +<!-- <svg-icon icon-class="topiam" />--> +<!-- </el-button>--> +<!-- <el-button circle :title="proxy.$t('login.social.gitee')" @click="doSocialLogin('gitee')">--> +<!-- <svg-icon icon-class="gitee" />--> +<!-- </el-button>--> +<!-- <el-button circle :title="proxy.$t('login.social.github')" @click="doSocialLogin('github')">--> +<!-- <svg-icon icon-class="github" />--> +<!-- </el-button>--> </el-form-item> <el-form-item style="width: 100%"> <el-button :loading="loading" size="large" type="primary" style="width: 100%" @click.prevent="handleLogin"> @@ -223,9 +223,7 @@ }; onMounted(() => { - getCode(); - initTenantList(); - getLoginData(); + doSocialLogin('keycloak') }); </script> diff --git a/src/views/qms/sensor/index.vue b/src/views/qms/sensor/index.vue index c2a6750..815f919 100644 --- a/src/views/qms/sensor/index.vue +++ b/src/views/qms/sensor/index.vue @@ -171,7 +171,8 @@ <template #append>V</template> </el-input> </el-form-item> - </el-row> + </el-col> + </el-row> <el-row> <el-col :xs="24" :sm="12"> diff --git a/src/views/qms/sensorRetest/index.vue b/src/views/qms/sensorRetest/index.vue index eeaf1e7..28938b0 100644 --- a/src/views/qms/sensorRetest/index.vue +++ b/src/views/qms/sensorRetest/index.vue @@ -115,7 +115,7 @@ </template> <script setup name="SensorRetest" lang="ts"> -import { listSensorRetest, getSensorRetest, delSensorRetest, addSensorRetest, updateSensorRetest } from 'src/api/qms/sensorRetest'; +import { listSensorRetest, getSensorRetest, delSensorRetest, addSensorRetest, updateSensorRetest } from '@/api/qms/sensorRetest'; import { SensorRetestVO, SensorRetestQuery, SensorRetestForm } from '@/api/qms/sensorRetest/types'; const { proxy } = getCurrentInstance() as ComponentInternalInstance; diff --git a/src/views/qms/trend/quality.vue b/src/views/qms/trend/quality.vue new file mode 100644 index 0000000..e4560ec --- /dev/null +++ b/src/views/qms/trend/quality.vue @@ -0,0 +1,535 @@ +<template> + <div class="p-2"> + <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave"> + <div v-show="showSearch" class="mb-[10px]"> + <el-card shadow="hover"> + <el-form ref="queryFormRef" :model="queryParams" :inline="true"> + <el-form-item label="浜у搧鍨嬪彿" prop="prodModel"> + <el-select v-model="queryParams.prodModel" placeholder="璇烽�夋嫨浜у搧鍨嬪彿" clearable @keyup.enter="handleQuery"> + <el-option v-for="item in prodModelOptions" :key="item.value" :label="item.label" :value="item.value" /> + </el-select> + </el-form-item> + <el-form-item label="娴嬭瘯椤圭洰" prop="testItem"> + <el-select v-model="selectedTestItems" :multiple="false" placeholder="璇烽�夋嫨娴嬭瘯椤圭洰" clearable @keyup.enter="handleQuery"> + <el-option v-for="item in testItemsOptions" :key="item.value" :label="item.label" :value="item.value" /> + </el-select> + </el-form-item> + <el-form-item label="鎵规鍙�" prop="batchCode"> + <el-input v-model="queryParams.batchCode" placeholder="璇疯緭鍏ユ壒娆″彿" clearable @keyup.enter="handleQuery" /> + </el-form-item> + <el-form-item label="鍒涘缓鏃堕棿" style="width: 308px"> + <el-date-picker + v-model="dateRangeCreateTime" + value-format="YYYY-MM-DD" + type="daterange" + range-separator="-" + start-placeholder="寮�濮嬫棩鏈�" + end-placeholder="缁撴潫鏃ユ湡" + unlink-panels + :default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]" + /> + </el-form-item> + <el-form-item> + <el-button type="primary" icon="Search" @click="handleQuery">鎼滅储</el-button> + <el-button icon="Refresh" @click="resetQuery">閲嶇疆</el-button> + </el-form-item> + </el-form> + </el-card> + </div> + </transition> + + <el-card shadow="never"> + <template #header> + <el-row :gutter="10" class="mb8"> + <el-col :span="1.5"> + <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['qms:testResult:add']">鏂板</el-button> + </el-col> + <el-col :span="1.5"> + <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['qms:testResult:edit']">淇敼</el-button> + </el-col> + <el-col :span="1.5"> + <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['qms:testResult:remove']">鍒犻櫎</el-button> + </el-col> + <el-col :span="1.5"> + <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['qms:testResult:export']">瀵煎嚭</el-button> + </el-col> + <right-toolbar v-model:showSearch="showSearch" @queryTable="handleQuery"></right-toolbar> + </el-row> + </template> + + + <div ref="chartRef" style="width: 100%; height: 660px;"></div> + + <!-- <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />--> + </el-card> + <!-- 娣诲姞鎴栦慨鏀规祴璇曠粨鏋滃璇濇 --> + <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body> + <el-form ref="testResultFormRef" :model="form" :rules="rules" label-width="80px"> + <el-form-item label="鎵规鍙�" prop="batchCode"> + <el-input v-model="form.batchCode" placeholder="璇疯緭鍏ユ壒娆″彿" /> + </el-form-item> + <el-form-item label="娴嬭瘯搴忓彿" prop="testNum"> + <el-input v-model="form.testNum" placeholder="璇疯緭鍏ユ祴璇曞簭鍙�" /> + </el-form-item> + <el-form-item label="娴嬭瘯椤圭洰" prop="testItem"> + <el-select v-model="form.testItem" placeholder="璇烽�夋嫨娴嬭瘯椤圭洰"> + <el-option v-for="item in testItemsOptions" :key="item.value" :label="item.label" :value="item.value" /> + </el-select> + </el-form-item> + <el-form-item label="瀹為檯鐢靛帇" prop="voltage"> + <el-input v-model="form.voltage" placeholder="璇疯緭鍏ュ疄闄呯數鍘�" /> + </el-form-item> + <el-form-item label="瀹為檯鐢垫祦" prop="loadCurrent"> + <el-input v-model="form.loadCurrent" placeholder="璇疯緭鍏ュ疄闄呯數娴�" /> + </el-form-item> + <el-form-item label="鏍囧噯璺濈" prop="stdDistance"> + <el-input v-model="form.stdDistance" placeholder="璇疯緭鍏ユ爣鍑嗚窛绂�" /> + </el-form-item> + <el-form-item label="鎰熷簲鐗�" prop="inductor"> + <el-input v-model="form.inductor" placeholder="璇疯緭鍏ユ劅搴旂墿" /> + </el-form-item> + <el-form-item label="杈撳嚭寮曡剼" prop="output"> + <el-input v-model="form.output" placeholder="璇疯緭鍏ヨ緭鍑哄紩鑴�" /> + </el-form-item> + <el-form-item label="娴嬭瘯鏁版嵁" prop="testValue"> + <el-input v-model="form.testValue" placeholder="璇疯緭鍏ユ祴璇曟暟鎹�" /> + </el-form-item> + <el-form-item label="鍒ゆ柇鏉′欢" prop="judgeDetail"> + <el-input v-model="form.judgeDetail" placeholder="璇疯緭鍏ュ垽鏂潯浠�" /> + </el-form-item> + <el-form-item label="娴嬭瘯缁撴灉" prop="testResult"> + <el-input v-model="form.testResult" placeholder="璇疯緭鍏ユ祴璇曠粨鏋�" /> + </el-form-item> + <el-form-item label="澶囨敞" prop="remark"> + <el-input v-model="form.remark" placeholder="璇疯緭鍏ュ娉�" /> + </el-form-item> + </el-form> + <template #footer> + <div class="dialog-footer"> + <el-button :loading="buttonLoading" type="primary" @click="submitForm">纭� 瀹�</el-button> + <el-button @click="cancel">鍙� 娑�</el-button> + </div> + </template> + </el-dialog> + </div> +</template> + +<script setup name="TestResult" lang="ts"> +import { listTestResultAll, getTestResult, delTestResult, addTestResult, updateTestResult, listTestItem } from '@/api/qms/testResult'; +import { TestResultVO, TestResultQuery, TestResultForm } from '@/api/qms/testResult/types'; +import * as echarts from 'echarts'; +import { listProdModels} from '@/api/qms/batch'; + +const { proxy } = getCurrentInstance() as ComponentInternalInstance; + +const testResultList = ref<TestResultVO[]>([]); +const buttonLoading = ref(false); +const loading = ref(true); +const showSearch = ref(true); +const ids = ref<Array<string | number>>([]); +const single = ref(true); +const multiple = ref(true); +const total = ref(0); + +// 璁剧疆榛樿鏃堕棿涓烘渶杩戜竴涓湀 +const now = new Date(); +const dateRangeCreateTime = ref<[DateModelType, DateModelType]>([]); +const oneMonthAgo = new Date(now.getFullYear(), now.getMonth() - 1, now.getDate()); +dateRangeCreateTime.value = [oneMonthAgo.toISOString().split('T')[0], now.toISOString().split('T')[0]] as [DateModelType, DateModelType]; + +const queryFormRef = ref<ElFormInstance>(); +const testResultFormRef = ref<ElFormInstance>(); +const chartRef = ref<HTMLDivElement | null>(null); // 鏂板 chartRef 寮曠敤 + +const testItemsOptions = ref<{ label: string, value: string }[]>([]); // 鏂板娴嬭瘯椤圭洰閫夐」 +const selectedTestItems = ref<string | string[]>([]); // 淇敼涓哄吋瀹瑰崟閫夌殑绫诲瀷 + +const dialog = reactive<DialogOption>({ + visible: false, + title: '' +}); + +const initFormData: TestResultForm = { + id: undefined, + batchCode: undefined, + testNum: undefined, + testItem: undefined, + voltage: undefined, + loadCurrent: undefined, + stdDistance: undefined, + inductor: undefined, + output: undefined, + testValue: undefined, + judgeDetail: undefined, + testResult: undefined, + remark: undefined +} +const prodModelOptions = ref<{ label: string, value: string }[]>([]); + +const data = reactive<PageData<TestResultForm, TestResultQuery>>({ + form: {...initFormData}, + queryParams: { + batchCode: undefined, + testNum: undefined, + testItem: undefined, + voltage: undefined, + loadCurrent: undefined, + stdDistance: undefined, + inductor: undefined, + output: undefined, + testValue: undefined, + judgeDetail: undefined, + testResult: undefined, + startTime: undefined, // 鏂板 startTime 瀛楁 + endTime: undefined, // 鏂板 endTime 瀛楁 + prodModel: undefined, // 鏂板浜у搧鍨嬪彿瀛楁 + params: { + createTime: undefined, + } + }, + rules: { + id: [ + { required: true, message: "涓嶈兘涓虹┖", trigger: "blur" } + ], + batchCode: [ + { required: true, message: "鎵规鍙蜂笉鑳戒负绌�", trigger: "blur" } + ], + testNum: [ + { required: true, message: "娴嬭瘯搴忓彿涓嶈兘涓虹┖", trigger: "blur" } + ], + testItem: [ + { required: true, message: "娴嬭瘯椤圭洰涓嶈兘涓虹┖", trigger: "blur" } + ], + voltage: [ + { required: true, message: "瀹為檯鐢靛帇涓嶈兘涓虹┖", trigger: "blur" } + ], + loadCurrent: [ + { required: true, message: "瀹為檯鐢垫祦涓嶈兘涓虹┖", trigger: "blur" } + ], + stdDistance: [ + { required: true, message: "鏍囧噯璺濈涓嶈兘涓虹┖", trigger: "blur" } + ], + inductor: [ + { required: true, message: "鎰熷簲鐗╀笉鑳戒负绌�", trigger: "blur" } + ], + output: [ + { required: true, message: "杈撳嚭寮曡剼涓嶈兘涓虹┖", trigger: "blur" } + ], + testValue: [ + { required: true, message: "娴嬭瘯鏁版嵁涓嶈兘涓虹┖", trigger: "blur" } + ], + judgeDetail: [ + { required: true, message: "鍒ゆ柇鏉′欢涓嶈兘涓虹┖", trigger: "blur" } + ], + testResult: [ + { required: true, message: "娴嬭瘯缁撴灉涓嶈兘涓虹┖", trigger: "blur" } + ], + prodModel: [ + { required: true, message: "浜у搧鍨嬪彿涓嶈兘涓虹┖", trigger: "blur" } + ], + } +}); + +const { queryParams, form, rules } = toRefs(data); + +// 鑾峰彇鎵�鏈夋祴璇曢」鐩� +const fetchTestItems = async () => { + const res = await listTestItem(); + testItemsOptions.value = res.data.map(item => ({ label: item, value: item })); +} +// 鑾峰彇鎵�鏈変骇鍝佸瀷鍙� +const fetchProdModels = async () => { + const res = await listProdModels(); + prodModelOptions.value = res.data.map(item => ({ label: item, value: item })); +} + +/** 鏌ヨ娴嬭瘯缁撴灉鍒楄〃 */ +const getList = async () => { + loading.value = true; + queryParams.value.params = {}; + // 澶勭悊 selectedTestItems 鐨勫�硷紝鍏煎鍗曢�夊拰澶氶�� + if (Array.isArray(selectedTestItems.value)) { + queryParams.value.testItem = selectedTestItems.value.join(','); // 澶氶�夋ā寮� + } else { + queryParams.value.testItem = selectedTestItems.value; // 鍗曢�夋ā寮� + } + proxy?.addDateRange(queryParams.value, dateRangeCreateTime.value, 'CreateTime'); + const res = await listTestResultAll(queryParams.value); + testResultList.value = res.data; + loading.value = false; + updateChart(); // 鏇存柊鍥捐〃 +} + +// 鐩戝惉 testResultList 鐨勫彉鍖栵紝鍔ㄦ�佹洿鏂板浘琛� +watch(testResultList, () => { + updateChart(); +}); + +/** 鍙栨秷鎸夐挳 */ +const cancel = () => { + reset(); + dialog.visible = false; +} + +/** 琛ㄥ崟閲嶇疆 */ +const reset = () => { + form.value = {...initFormData}; + + testResultFormRef.value?.resetFields(); +} + +/** 鎼滅储鎸夐挳鎿嶄綔 */ +const handleQuery = () => { + // 鏍¢獙鏃堕棿鑼冨洿鏄惁瓒呰繃涓変釜鏈� + if (dateRangeCreateTime.value[0] && dateRangeCreateTime.value[1]) { + const startDate = new Date(dateRangeCreateTime.value[0]); + const endDate = new Date(dateRangeCreateTime.value[1]); + const timeDiff = endDate.getTime() - startDate.getTime(); + const maxDuration = 90 * 24 * 60 * 60 * 1000; // 涓変釜鏈堢殑姣鏁� + + if (timeDiff > maxDuration) { + proxy?.$modal.msgWarning("鏃堕棿鑼冨洿涓嶈兘瓒呰繃涓変釜鏈堬紝璇烽噸鏂伴�夋嫨锛�"); + return; + } + } + + // 鏍¢獙浜у搧鍨嬪彿鏄惁閫夋嫨 + if (!queryParams.value.prodModel) { + proxy?.$modal.msgWarning("璇烽�夋嫨浜у搧鍨嬪彿锛�"); + return; + } + + getList(); +} + +/** 閲嶇疆鎸夐挳鎿嶄綔 */ +const resetQuery = () => { + dateRangeCreateTime.value = ['', '']; + queryFormRef.value?.resetFields(); + selectedTestItems.value = []; // 閲嶇疆閫変腑鐨勬祴璇曢」鐩� + reset(); // 璋冪敤閲嶇疆鏂规硶浠ユ竻绌烘椂闂存瀛楁 +} + +/** 澶氶�夋閫変腑鏁版嵁 */ +const handleSelectionChange = (selection: TestResultVO[]) => { + ids.value = selection.map(item => item.id); + single.value = selection.length != 1; + multiple.value = !selection.length; +} + +/** 鏂板鎸夐挳鎿嶄綔 */ +const handleAdd = () => { + reset(); + dialog.visible = true; + dialog.title = "娣诲姞娴嬭瘯缁撴灉"; +} + +/** 淇敼鎸夐挳鎿嶄綔 */ +const handleUpdate = async (row?: TestResultVO) => { + reset(); + const _id = row?.id || ids.value[0] + const res = await getTestResult(_id); + Object.assign(form.value, res.data); + dialog.visible = true; + dialog.title = "淇敼娴嬭瘯缁撴灉"; +} + +/** 鎻愪氦鎸夐挳 */ +const submitForm = () => { + testResultFormRef.value?.validate(async (valid: boolean) => { + if (valid) { + buttonLoading.value = true; + if (form.value.id) { + await updateTestResult(form.value).finally(() => buttonLoading.value = false); + } else { + await addTestResult(form.value).finally(() => buttonLoading.value = false); + } + proxy?.$modal.msgSuccess("鎿嶄綔鎴愬姛"); + dialog.visible = false; + await handleQuery(); + } + }); +} + +/** 鍒犻櫎鎸夐挳鎿嶄綔 */ +const handleDelete = async (row?: TestResultVO) => { + const _ids = row?.id || ids.value; + await proxy?.$modal.confirm('鏄惁纭鍒犻櫎娴嬭瘯缁撴灉缂栧彿涓�"' + _ids + '"鐨勬暟鎹」锛�').finally(() => loading.value = false); + await delTestResult(_ids); + proxy?.$modal.msgSuccess("鍒犻櫎鎴愬姛"); + await handleQuery(); +} + +/** 瀵煎嚭鎸夐挳鎿嶄綔 */ +const handleExport = () => { + proxy?.download('qms/testResult/export', { + ...queryParams.value + }, `testResult_${new Date().getTime()}.xlsx`) +} + +// 鏇存柊鍥捐〃 +const updateChart = () => { + if (!chartRef.value) return; + // 閿�姣佸凡鏈夌殑鍥捐〃瀹炰緥 + const existingChart = echarts.getInstanceByDom(chartRef.value); + if (existingChart) { + existingChart.dispose(); + } + const chart = echarts.init(chartRef.value); + + // 瀹氫箟20涓笉閲嶅鐨勯鑹叉睜 + const colorPool = [ + '#5470c6', '#91cc75', '#fac858', '#ee6666', '#73c0de', + '#3ba272', '#fc8452', '#9a60b4', '#ea7ccc', '#5e7ce0', + '#f0c757', '#ff9f7f', '#d48265', '#7fb80e', '#b37feb', + '#4dc9b0', '#f47920', '#65b581', '#f08585', '#4a90e2', + // 鏂板棰滆壊浠ユ彁楂樺姣斿害 + '#ff6f61', '#ffd700', '#00ced1', '#da70d6', '#adff2f' + ]; + + // 浣跨敤Map鏇夸唬Object鏇撮珮鏁� + const seriesMap = new Map<string, [string, number][]>(); + testResultList.value.forEach(item => { + const key = item.testItem; + if (!seriesMap.has(key)) { + seriesMap.set(key, []); + } + seriesMap.get(key)?.push([item.createTime, item.testValue]); + }); + + // 瑙f瀽鏈�鍚庝竴鏉℃暟鎹殑鍒ゆ柇鏉′欢瀛楁 + let upperLimit: number | null = null; + let lowerLimit: number | null = null; + if (testResultList.value.length > 0) { + const lastItem = testResultList.value[testResultList.value.length - 1]; + const judgeDetail = lastItem.judgeDetail; + console.log('judgeDetail:', judgeDetail) + const regex = /(\d+\.\d+)\s*(V|mA|uA)\s*鈮s*result\s*鈮s*(\d+\.\d+)\s*(V|mA|uA)/; + const match = judgeDetail.match(regex); + console.log('match:', match) + if (match) { + lowerLimit = parseFloat(match[1]); + upperLimit = parseFloat(match[3]); + } + } + + console.log('upperLimit:', upperLimit, 'lowerLimit:', lowerLimit) + // 璁$畻鏂扮殑涓婁笅闄愬�硷紝澧炲姞20% + const paddingPercentage = 0.1; // 20%鐨刾adding + // 璁$畻涓婇檺鐨�20%鏄灏� + let padding = lowerLimit * paddingPercentage; + + console.log("padding",padding) + + let newLowerLimit = lowerLimit !== null ? (lowerLimit - padding) : undefined; + let newUpperLimit = upperLimit !== null ? (upperLimit + padding) : undefined; + + + const option = { + grid: { + top: '15%', + left: '5%', + right: '5%', + containLabel: true + }, + xAxis: { + type: 'time', + name: '鏃堕棿' + }, + yAxis: { + type: 'value', + name: '娴嬭瘯鏁版嵁', + min: newLowerLimit, // 浣跨敤鏂扮殑涓嬮檺鍊� + max: newUpperLimit, // 浣跨敤鏂扮殑涓婇檺鍊� + axisLabel: { + formatter: function (value: number) { + return value; + } + } + }, + legend: { + data: Array.from(seriesMap.keys()) + }, + series: Array.from(seriesMap).map(([name, data], index) => ({ + name: name, + data: data, + type: 'line', + animationDuration: 1000, + lineStyle: { + color: colorPool[index % colorPool.length], + width: 2 // 澧炲姞绾挎潯瀹藉害 + }, + itemStyle: { + color: colorPool[index % colorPool.length], + opacity: 0.8 // 娣诲姞閫忔槑搴� + }, + markLine: { + symbol: ['none', 'none'], + label: { + position: 'end', + align: 'center', // 娣诲姞 align 灞炴�т互瀹炵幇灞呬腑瀵归綈 + formatter: function (params: any) { + const name = params.name || ''; // 涓婇檺鎴栦笅闄愭爣璇� + const value = params.value || ''; // 瀵瑰簲鐨勬暟鍊� + return `${name}\n${value}`; // 鎹㈣鏄剧ず锛岀‘淇濅笂涓嬭鍐呭娓呮櫚 + } + }, + lineStyle: { + color: 'red', + type: 'dashed' + }, + data: [ + { + name: '涓嬮檺', + yAxis: lowerLimit !== null ? lowerLimit : undefined + }, + { + name: '涓婇檺', + yAxis: upperLimit !== null ? upperLimit : undefined + } + ] + }, + // markLine: { + // data: [{ type: 'average', name: 'Avg' }] + // } + })), + // 鏂板 dataZoom 閰嶇疆 + dataZoom: [ + { + type: 'slider', // X杞存粦鍔ㄦ潯 + xAxisIndex: 0, + start: 0, // 鍒濆鑼冨洿璧风偣鐧惧垎姣� + end: 100 // 鍒濆鑼冨洿缁堢偣鐧惧垎姣� + }, + { + type: 'slider', // Y杞存粦鍔ㄦ潯 + yAxisIndex: 0, + start: 0, // 鍒濆鑼冨洿璧风偣鐧惧垎姣� + end: 100 // 鍒濆鑼冨洿缁堢偣鐧惧垎姣� + }, + { + type: 'inside', // X杞村唴缃嫋鍔ㄥ拰妗嗛�� + xAxisIndex: 0, + start: 0, + end: 100 + }, + { + type: 'inside', // Y杞村唴缃嫋鍔ㄥ拰妗嗛�� + yAxisIndex: 0, + start: 0, + end: 100 + } + ] + }; + + chart.setOption(option, true); + window.addEventListener('resize', () => { + chart.resize(); + }); +} + +onMounted(() => { + fetchTestItems(); // 璋冪敤鑾峰彇娴嬭瘯椤圭洰鎺ュ彛 + fetchProdModels(); // 璋冪敤鑾峰彇浜у搧鍨嬪彿鎺ュ彛 +}); +</script> diff --git a/vite/plugins/i18n.ts b/vite/plugins/i18n.ts deleted file mode 100644 index 8777d1a..0000000 --- a/vite/plugins/i18n.ts +++ /dev/null @@ -1,6 +0,0 @@ -import VueI18nPlugin from '@intlify/unplugin-vue-i18n/vite'; -export default (path: any) => { - return VueI18nPlugin({ - include: [path.resolve(__dirname, '../../src/lang/**.json')] - }); -}; -- Gitblit v1.9.3