12 Commits

Author SHA1 Message Date
sjl
97d1f08bbe 正式检测闪变 2025-10-13 13:56:37 +08:00
sjl
7d0053eb71 被检设备监测点台账线路号占满不可新增 2025-10-11 14:12:15 +08:00
贾同学
666fb22c49 UPDATE: 优化客户端桌面窗口内容自适应 2025-10-10 15:29:54 +08:00
贾同学
b319a89501 UPDATE: 处理控制台警告问题 2025-10-10 13:23:40 +08:00
贾同学
8e0b3be438 Merge remote-tracking branch 'origin/master' 2025-10-10 08:24:55 +08:00
sjl
b0d92de738 微调 2025-10-09 15:51:45 +08:00
sjl
92b3e25989 冲突 2025-10-09 15:49:29 +08:00
sjl
43c75c96a7 录波数据 2025-10-09 15:47:00 +08:00
贾同学
da0aa0cd0f UPDATE: 调整超时时间到1200秒 2025-10-09 14:34:45 +08:00
贾同学
b0c88b9df2 UPDATE: 优化; 2025-09-30 08:42:45 +08:00
caozehui
7c0ec5844a 微调 2025-09-29 14:49:29 +08:00
贾同学
a4a64ef0f9 UPDATE: 优化; 2025-09-29 09:47:53 +08:00
56 changed files with 8245 additions and 8153 deletions

View File

@@ -25,10 +25,10 @@ module.exports = (appInfo) => {
*/ */
config.windowsOption = { config.windowsOption = {
title: '自动检测平台', title: '自动检测平台',
width: 1600, width: 1920 /1.5,
height: 950, height: 1080 /1.2,
minWidth: 1600, minWidth: 1920 /1.5,
minHeight: 950, minHeight: 1080 /1.2,
webPreferences: { webPreferences: {
//webSecurity: false, //webSecurity: false,
contextIsolation: false, // false -> 可在渲染进程中使用electron的apitrue->需要bridge.js(contextBridge) contextIsolation: false, // false -> 可在渲染进程中使用electron的apitrue->需要bridge.js(contextBridge)

View File

@@ -9,7 +9,7 @@ module.exports = (appInfo) => {
/** /**
* 开发者工具 * 开发者工具
*/ */
config.openDevTools = true; config.openDevTools = false;
/** /**
* 应用程序顶部菜单 * 应用程序顶部菜单

View File

@@ -17,6 +17,7 @@
"@types/event-source-polyfill": "^1.0.5", "@types/event-source-polyfill": "^1.0.5",
"@vue-flow/core": "^1.45.0", "@vue-flow/core": "^1.45.0",
"@vueuse/core": "^10.4.1", "@vueuse/core": "^10.4.1",
"autofit.js": "^3.2.8",
"axios": "^1.7.3", "axios": "^1.7.3",
"crypto-js": "^4.2.0", "crypto-js": "^4.2.0",
"dayjs": "^1.11.9", "dayjs": "^1.11.9",

View File

@@ -1,27 +1,25 @@
<template> <template>
<!--element-plus语言国际化全局修改为中文--> <!--element-plus语言国际化全局修改为中文-->
<el-config-provider <el-config-provider :locale="locale" :size="assemblySize" :button="buttonConfig">
:locale='locale' <router-view />
:size='assemblySize' </el-config-provider>
:button='buttonConfig'
>
<router-view />
</el-config-provider>
</template> </template>
<script lang='ts' setup> <script lang="ts" setup>
defineOptions({ import autofit from 'autofit.js'
name: 'App',
})
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import { getBrowserLang } from '@/utils' import { getBrowserLang } from '@/utils'
import { useTheme } from '@/hooks/useTheme' import { useTheme } from '@/hooks/useTheme'
import { ElConfigProvider } from 'element-plus' import { ElConfigProvider } from 'element-plus'
import { LanguageType } from './stores/interface' import { type LanguageType } from './stores/interface'
import { useGlobalStore } from '@/stores/modules/global' import { useGlobalStore } from '@/stores/modules/global'
import en from 'element-plus/es/locale/lang/en' import en from 'element-plus/es/locale/lang/en'
import zhCn from 'element-plus/es/locale/lang/zh-cn' import zhCn from 'element-plus/es/locale/lang/zh-cn'
defineOptions({
name: 'App'
})
const globalStore = useGlobalStore() const globalStore = useGlobalStore()
// init theme // init theme
@@ -31,16 +29,26 @@ initTheme()
// init language // init language
const i18n = useI18n() const i18n = useI18n()
onMounted(() => { onMounted(() => {
const language = globalStore.language ?? getBrowserLang() const language = globalStore.language ?? getBrowserLang()
i18n.locale.value = language i18n.locale.value = language
globalStore.setGlobalState('language', language as LanguageType) globalStore.setGlobalState('language', language as LanguageType)
// 自动适配
autofit.init({
el: '#app',
//dh: 720 * 1,
//dw: 1280 * 1.2,
dw: 1920 / 1.5,
dh: 1080 / 1.2,
resize: true,
limit: 0.1
})
}) })
// element language // element language
const locale = computed(() => { const locale = computed(() => {
if (globalStore.language == 'zh') return zhCn if (globalStore.language == 'zh') return zhCn
if (globalStore.language == 'en') return en if (globalStore.language == 'en') return en
return getBrowserLang() == 'zh' ? zhCn : en return getBrowserLang() == 'zh' ? zhCn : en
}) })
// element assemblySize // element assemblySize

View File

@@ -193,11 +193,13 @@ class RequestHttp {
* 针对excel的上传默认返回的是blob类型Excel没问题时返回json特殊处理 * 针对excel的上传默认返回的是blob类型Excel没问题时返回json特殊处理
*/ */
uploadExcel(url: string, params?: object, _object = {}): Promise<BlobPart> { uploadExcel(url: string, params?: object, _object = {}): Promise<BlobPart> {
return this.service.post(url, params, { return this.service
..._object, .post(url, params, {
headers: { 'Content-Type': 'multipart/form-data' }, ..._object,
responseType: 'blob' headers: { 'Content-Type': 'multipart/form-data' },
}).then(res => res.data) responseType: 'blob'
})
.then(res => res.data)
} }
// 添加SSE连接方法 // 添加SSE连接方法
@@ -220,8 +222,8 @@ class RequestHttp {
headers: { headers: {
Authorization: 'Bearer ' + userStore.accessToken Authorization: 'Bearer ' + userStore.accessToken
}, },
// 增加超时时间到120秒 // 增加超时时间到1200
heartbeatTimeout: 120000 heartbeatTimeout: 1200000
}) })
// 设置默认的Authorization头部 // 设置默认的Authorization头部

View File

@@ -1,19 +1,20 @@
<template> <template>
<div class="not-container"> <div class="not-container">
<img src="@/assets/images/403.png" class="not-img" alt="403" /> <img src="@/assets/images/403.png" class="not-img" alt="403" />
<div class="not-detail"> <div class="not-detail">
<h2>403</h2> <h2>403</h2>
<h4>抱歉您无权访问该页面~🙅🙅</h4> <h4>抱歉您无权访问该页面~🙅🙅</h4>
<el-button type="primary" @click="router.back"> 返回上一页 </el-button> <el-button type="primary" @click="router.back">返回上一页</el-button>
</div>
</div> </div>
</div>
</template> </template>
<script setup lang="ts" name="403"> <script setup lang="ts" name="403">
import { useRouter } from "vue-router"; import { useRouter } from 'vue-router'
const router = useRouter();
const router = useRouter()
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
@import "./index.scss"; @use './index.scss';
</style> </style>

View File

@@ -1,19 +1,20 @@
<template> <template>
<div class="not-container"> <div class="not-container">
<img src="@/assets/images/404.png" class="not-img" alt="404" /> <img src="@/assets/images/404.png" class="not-img" alt="404" />
<div class="not-detail"> <div class="not-detail">
<h2>404</h2> <h2>404</h2>
<h4>抱歉您访问的页面不存在~🤷🤷</h4> <h4>抱歉您访问的页面不存在~🤷🤷</h4>
<el-button type="primary" @click="router.back"> 返回上一页 </el-button> <el-button type="primary" @click="router.back">返回上一页</el-button>
</div>
</div> </div>
</div>
</template> </template>
<script setup lang="ts" name="404"> <script setup lang="ts" name="404">
import { useRouter } from "vue-router"; import { useRouter } from 'vue-router'
const router = useRouter();
const router = useRouter()
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
@import "./index.scss"; @use './index.scss';
</style> </style>

View File

@@ -1,19 +1,20 @@
<template> <template>
<div class="not-container"> <div class="not-container">
<img src="@/assets/images/500.png" class="not-img" alt="500" /> <img src="@/assets/images/500.png" class="not-img" alt="500" />
<div class="not-detail"> <div class="not-detail">
<h2>500</h2> <h2>500</h2>
<h4>抱歉您的网络不见了~🤦🤦</h4> <h4>抱歉您的网络不见了~🤦🤦</h4>
<el-button type="primary" @click="router.back"> 返回上一页 </el-button> <el-button type="primary" @click="router.back">返回上一页</el-button>
</div>
</div> </div>
</div>
</template> </template>
<script setup lang="ts" name="500"> <script setup lang="ts" name="500">
import { useRouter } from "vue-router"; import { useRouter } from 'vue-router'
const router = useRouter();
const router = useRouter()
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
@import "./index.scss"; @use './index.scss';
</style> </style>

View File

@@ -9,5 +9,5 @@
<script setup lang="ts" name="Loading"></script> <script setup lang="ts" name="Loading"></script>
<style scoped lang="scss"> <style scoped lang="scss">
@import "./index.scss"; @use "./index.scss";;
</style> </style>

View File

@@ -1,49 +1,49 @@
<template> <template>
<div class='icon-box' > <div class="icon-box">
<el-input <el-input
ref='inputRef' ref="inputRef"
v-model='valueIcon' v-model="valueIcon"
v-bind='$attrs' v-bind="$attrs"
:placeholder='placeholder' :placeholder="placeholder"
:clearable='clearable' :clearable="clearable"
@clear='clearIcon' @clear="clearIcon"
@click='openDialog' @click="openDialog"
> >
<template #append> <template #append>
<el-button :icon='customIcons[iconValue]' /> <el-button :icon="customIcons[iconValue]" />
</template> </template>
</el-input> </el-input>
<el-dialog v-model='dialogVisible' :title='placeholder' top='5%' width='30%' > <el-dialog v-model="dialogVisible" :title="placeholder" top="5%" width="30%">
<el-input v-model='inputValue' placeholder='搜索图标' size='large' :prefix-icon='Icons.Search' /> <el-input v-model="inputValue" placeholder="搜索图标" size="large" :prefix-icon="Icons.Search" />
<el-scrollbar v-if='Object.keys(iconsList).length'> <el-scrollbar v-if="Object.keys(iconsList).length">
<div class='icon-list'> <div class="icon-list">
<div v-for='item in iconsList' :key='item' class='icon-item' @click='selectIcon(item)'> <div v-for="item in iconsList" :key="item" class="icon-item" @click="selectIcon(item)">
<component :is='item'></component> <component :is="item"></component>
<span>{{ item.name }}</span> <span>{{ item.name }}</span>
</div> </div>
</div> </div>
</el-scrollbar> </el-scrollbar>
<el-empty v-else description='未搜索到您要找的图标~' /> <el-empty v-else description="未搜索到您要找的图标~" />
</el-dialog> </el-dialog>
</div> </div>
</template> </template>
<script lang='ts' setup name='SelectIcon'> <script lang="ts" setup name="SelectIcon">
import * as Icons from '@element-plus/icons-vue' import * as Icons from '@element-plus/icons-vue'
import { computed, ref } from 'vue'; import { computed, ref } from 'vue'
interface SelectIconProps { interface SelectIconProps {
iconValue: string| undefined; iconValue: string | undefined
title?: string; title?: string
clearable?: boolean; clearable?: boolean
placeholder?: string; placeholder?: string
} }
const props = withDefaults(defineProps<SelectIconProps>(), { const props = withDefaults(defineProps<SelectIconProps>(), {
iconValue: '', iconValue: '',
title: '请选择图标', title: '请选择图标',
clearable: true, clearable: true,
placeholder: '请选择图标', placeholder: '请选择图标'
}) })
// 重新接收一下,防止打包后 clearable 报错 // 重新接收一下,防止打包后 clearable 报错
@@ -55,37 +55,36 @@ const openDialog = () => (dialogVisible.value = true)
// 选择图标(触发更新父组件数据) // 选择图标(触发更新父组件数据)
const emit = defineEmits<{ const emit = defineEmits<{
'update:iconValue': [value: string]; 'update:iconValue': [value: string]
}>() }>()
const selectIcon = (item: any) => { const selectIcon = (item: any) => {
dialogVisible.value = false dialogVisible.value = false
valueIcon.value = item.name valueIcon.value = item.name
emit('update:iconValue', item.name) emit('update:iconValue', item.name)
setTimeout(() => inputRef.value.blur(), 0) setTimeout(() => inputRef.value.blur(), 0)
} }
// 清空图标 // 清空图标
const inputRef = ref() const inputRef = ref()
const clearIcon = () => { const clearIcon = () => {
valueIcon.value = '' valueIcon.value = ''
emit('update:iconValue', '') emit('update:iconValue', '')
setTimeout(() => inputRef.value.blur(), 0) setTimeout(() => inputRef.value.blur(), 0)
} }
// 监听搜索框值 // 监听搜索框值
const inputValue = ref('') const inputValue = ref('')
const customIcons: { [key: string]: any } = Icons const customIcons: { [key: string]: any } = Icons
const iconsList = computed((): { [key: string]: any } => { const iconsList = computed((): { [key: string]: any } => {
if (!inputValue.value) return Icons if (!inputValue.value) return Icons
let result: { [key: string]: any } = {} let result: { [key: string]: any } = {}
for (const key in customIcons) { for (const key in customIcons) {
if (key.toLowerCase().indexOf(inputValue.value.toLowerCase()) > -1) result[key] = customIcons[key] if (key.toLowerCase().indexOf(inputValue.value.toLowerCase()) > -1) result[key] = customIcons[key]
} }
return result return result
}) })
</script> </script>
<style scoped lang='scss'> <style scoped lang="scss">
@import "./index.scss"; @use './index.scss';
</style> </style>

View File

@@ -1,97 +1,84 @@
<template> <template>
<div class='time-control'> <div class="time-control">
<el-select <el-select class="select" v-model="timeUnit" placeholder="选择时间单位" @change="handleChange">
class='select' <!-- 采用 v-for 动态渲染 -->
v-model='timeUnit' <el-option v-for="unit in timeUnits" :key="unit.value" :label="unit.label" :value="unit.value"></el-option>
placeholder='选择时间单位' </el-select>
@change='handleChange'
>
<!-- 采用 v-for 动态渲染 -->
<el-option
v-for='unit in timeUnits'
:key='unit.value'
:label='unit.label'
:value='unit.value'
></el-option>
</el-select>
<!-- 禁用时间选择器 --> <!-- 禁用时间选择器 -->
<div class='date-display'> <div class="date-display">
<el-date-picker <el-date-picker
class='date-picker' class="date-picker"
v-model='startDate' v-model="startDate"
type='date' type="date"
placeholder='起始时间' placeholder="起始时间"
@change='emitDateChange' @change="emitDateChange"
:disabled-date='disableStartDate' :disabled-date="disableStartDate"
:readonly="timeUnit != '自定义'" :readonly="timeUnit != '自定义'"
></el-date-picker> ></el-date-picker>
<el-text>~</el-text> <el-text>~</el-text>
<el-date-picker <el-date-picker
class='date-picker' class="date-picker"
v-model='endDate' v-model="endDate"
type='date' type="date"
placeholder='结束时间' placeholder="结束时间"
@change='emitDateChange' @change="emitDateChange"
:disabled-date='disableEndDate' :disabled-date="disableEndDate"
:readonly="timeUnit !== '自定义'" :readonly="timeUnit !== '自定义'"
></el-date-picker> ></el-date-picker>
</div>
<div class="date-display" v-if="timeUnit !== '自定义'">
<el-button
style="width: 10px"
class="triangle-button"
type="primary"
@click="prevPeriod"
@change="emitDateChange"
>
<div class="left_triangle"></div>
</el-button>
<el-button class="triangle-button" type="primary" @click="goToCurrent">当前</el-button>
<el-button
style="width: 10px"
class="triangle-button"
type="primary"
@click="nextPeriod"
:disabled="isNextDisabled"
>
<div class="right_triangle"></div>
</el-button>
</div>
</div> </div>
<div class='date-display' v-if="timeUnit !== '自定义'">
<el-button
style='width: 10px;'
class='triangle-button'
type='primary'
@click='prevPeriod'
@change='emitDateChange'
>
<div class='left_triangle'></div>
</el-button>
<el-button class='triangle-button' type='primary' @click='goToCurrent'>
当前
</el-button>
<el-button
style='width: 10px;'
class='triangle-button'
type='primary'
@click='nextPeriod'
:disabled='isNextDisabled'
>
<div class='right_triangle'></div>
</el-button>
</div>
</div>
</template> </template>
<script setup lang="ts">
<script setup lang='ts'> import { onMounted, ref } from 'vue'
import { ref, onMounted, defineProps, defineEmits } from 'vue'
// 定义时间单位的类型 // 定义时间单位的类型
interface TimeUnit { interface TimeUnit {
label: string; label: string
value: string; value: string
} }
// 定义组件的props包含包括和排除的时间单位 // 定义组件的props包含包括和排除的时间单位
const props = defineProps({ const props = defineProps({
include: { include: {
type: Array as () => string[], type: Array as () => string[],
default: () => ['日', '周', '月', '季度', '年', '自定义'], default: () => ['日', '周', '月', '季度', '年', '自定义']
}, },
exclude: { exclude: {
type: Array as () => string[], type: Array as () => string[],
default: () => [], default: () => []
}, },
default: { default: {
type: String, type: String,
default: '月', default: '月'
}, }
}) })
// 定义事件 // 定义事件
const emit = defineEmits<{ const emit = defineEmits<{
(e: 'update-dates', startDate: string, endDate: string): void; (e: 'update-dates', startDate: string, endDate: string): void
}>() }>()
const timeUnit = ref<string>(props.default) // 默认选择 const timeUnit = ref<string>(props.default) // 默认选择
const startDate = ref<Date>(new Date()) // 起始日期 const startDate = ref<Date>(new Date()) // 起始日期
@@ -100,219 +87,206 @@ const isNextDisabled = ref<boolean>(false) // 控制下一周期按钮的禁用
const today = ref<Date>(new Date()) // 当前日期 const today = ref<Date>(new Date()) // 当前日期
// 过滤出可用的时间单位 // 过滤出可用的时间单位
const timeUnits = ref<TimeUnit[]>( const timeUnits = ref<TimeUnit[]>(
props.include.filter(unit => !props.exclude.includes(unit)).map(unit => ({ props.include
label: unit, .filter(unit => !props.exclude.includes(unit))
value: unit, .map(unit => ({
})), label: unit,
value: unit
}))
) )
// 发出日期变化事件 // 发出日期变化事件
const emitDateChange = () => { const emitDateChange = () => {
emit('update-dates', formatDate(startDate.value), formatDate(endDate.value)) emit('update-dates', formatDate(startDate.value), formatDate(endDate.value))
} }
// 在组件挂载时更新日期范围 // 在组件挂载时更新日期范围
onMounted(() => { onMounted(() => {
updateDateRange() updateDateRange()
}) })
const handleChange = (unit: string) => { const handleChange = (unit: string) => {
// 根据选择的时间单位处理日期变化 // 根据选择的时间单位处理日期变化
if (unit !== '自定义') { if (unit !== '自定义') {
updateDateRange() updateDateRange()
} else { } else {
// 自定义选项逻辑 // 自定义选项逻辑
startDate.value = new Date(new Date().setDate(new Date().getDate() - 1)) startDate.value = new Date(new Date().setDate(new Date().getDate() - 1))
endDate.value = new Date() endDate.value = new Date()
} }
timeUnit.value = unit timeUnit.value = unit
// 确保开始时间和结束时间不为空 // 确保开始时间和结束时间不为空
if (!startDate.value) { if (!startDate.value) {
startDate.value = new Date() startDate.value = new Date()
} }
if (!endDate.value) { if (!endDate.value) {
endDate.value = new Date() endDate.value = new Date()
} }
emitDateChange() // 变化时也发出更新事件 emitDateChange() // 变化时也发出更新事件
updateNextButtonStatus() updateNextButtonStatus()
} }
const updateDateRange = () => { const updateDateRange = () => {
// 根据选择的时间单位计算起始和结束日期
if (timeUnit.value === '日') {
startDate.value = today.value
endDate.value = today.value
} else if (timeUnit.value === '周') {
startDate.value = getStartOfWeek(today.value)
endDate.value = getEndOfWeek(today.value)
} else if (timeUnit.value === '月') {
// 获取本月的开始和结束日期
startDate.value = new Date(today.value.getFullYear(), today.value.getMonth(), 1)
endDate.value = new Date(today.value.getFullYear(), today.value.getMonth() + 1, 0)
// 根据选择的时间单位计算起始和结束日期 // // 确保结束日期不超过今天
if (timeUnit.value === '日') { // if (endDate.value > today.value) {
startDate.value = today.value // endDate.value = new Date(today.value);
endDate.value = today.value // endDate.value.setHours(23, 59, 59, 999); // 设置结束时间为今天的23:59:59.999
} else if (timeUnit.value === '周') { // }
startDate.value = getStartOfWeek(today.value) } else if (timeUnit.value === '季度') {
endDate.value = getEndOfWeek(today.value) const quarter = Math.floor(today.value.getMonth() / 3)
startDate.value = new Date(today.value.getFullYear(), quarter * 3, 1)
} else if (timeUnit.value === '月') { endDate.value = new Date(today.value.getFullYear(), quarter * 3 + 3, 0)
// 获取本月的开始和结束日期
startDate.value = new Date(today.value.getFullYear(), today.value.getMonth(), 1);
endDate.value = new Date(today.value.getFullYear(), today.value.getMonth() + 1, 0);
// // 确保结束日期不超过今天
// if (endDate.value > today.value) {
// endDate.value = new Date(today.value);
// endDate.value.setHours(23, 59, 59, 999); // 设置结束时间为今天的23:59:59.999
// }
} else if (timeUnit.value === '季度') { // // 确保结束日期不超过今天
const quarter = Math.floor(today.value.getMonth() / 3); // if (endDate.value > today.value) {
startDate.value = new Date(today.value.getFullYear(), quarter * 3, 1); // endDate.value = new Date(today.value);
endDate.value = new Date(today.value.getFullYear(), quarter * 3 + 3, 0); // endDate.value.setHours(23, 59, 59, 999); // 设置结束时间为今天的23:59:59.999
// }
} else if (timeUnit.value === '年') {
startDate.value = new Date(today.value.getFullYear(), 0, 1)
endDate.value = new Date(today.value.getFullYear(), 11, 31)
// // 确保结束日期不超过今天 // // 确保结束日期不超过今天
// if (endDate.value > today.value) { // if (endDate.value > today.value) {
// endDate.value = new Date(today.value);
// endDate.value.setHours(23, 59, 59, 999); // 设置结束时间为今天的23:59:59.999
// }
} else if (timeUnit.value === '年') { // endDate.value = new Date(today.value);
startDate.value = new Date(today.value.getFullYear(), 0, 1); // endDate.value.setHours(23, 59, 59, 999); // 设置结束时间为今天的23:59:59.999
endDate.value = new Date(today.value.getFullYear(), 11, 31); // }
}
// 确保开始时间和结束时间不为空
if (!startDate.value) {
startDate.value = new Date()
}
if (!endDate.value) {
endDate.value = new Date()
}
// // 确保结束日期不超过今天 updateNextButtonStatus()
// if (endDate.value > today.value) {
// endDate.value = new Date(today.value);
// endDate.value.setHours(23, 59, 59, 999); // 设置结束时间为今天的23:59:59.999
// }
}
// 确保开始时间和结束时间不为空
if (!startDate.value) {
startDate.value = new Date()
}
if (!endDate.value) {
endDate.value = new Date()
}
updateNextButtonStatus()
} }
const getStartOfWeek = (date: Date) => { const getStartOfWeek = (date: Date) => {
const startOfWeek = new Date(date) const startOfWeek = new Date(date)
const day = startOfWeek.getDay() const day = startOfWeek.getDay()
const diff = day === 0 ? -6 : 1 - day // 星期天的情况 const diff = day === 0 ? -6 : 1 - day // 星期天的情况
startOfWeek.setDate(startOfWeek.getDate() + diff) startOfWeek.setDate(startOfWeek.getDate() + diff)
return startOfWeek return startOfWeek
} }
const getEndOfWeek = (date: Date) => { const getEndOfWeek = (date: Date) => {
const endOfWeek = new Date(date) const endOfWeek = new Date(date)
const day = endOfWeek.getDay() const day = endOfWeek.getDay()
const diff = day === 0 ? 0 : 7 - day // 星期天的情况 const diff = day === 0 ? 0 : 7 - day // 星期天的情况
endOfWeek.setDate(endOfWeek.getDate() + diff) endOfWeek.setDate(endOfWeek.getDate() + diff)
// 获取今天的日期 // 获取今天的日期
const today = new Date(); const today = new Date()
today.setHours(23, 59, 59, 999); // 设置今天的结束时间23:59:59.999 today.setHours(23, 59, 59, 999) // 设置今天的结束时间23:59:59.999
// 返回不超过今天的结束时间 // 返回不超过今天的结束时间
//return endOfWeek > today ? today : endOfWeek; //return endOfWeek > today ? today : endOfWeek;
return endOfWeek return endOfWeek
} }
const prevPeriod = () => { const prevPeriod = () => {
const prevStartDate = new Date(startDate.value) const prevStartDate = new Date(startDate.value)
const prevEndDate = new Date(endDate.value) const prevEndDate = new Date(endDate.value)
if (timeUnit.value === '日') { if (timeUnit.value === '日') {
prevStartDate.setDate(prevStartDate.getDate() - 1) prevStartDate.setDate(prevStartDate.getDate() - 1)
prevEndDate.setDate(prevEndDate.getDate() - 1) prevEndDate.setDate(prevEndDate.getDate() - 1)
} else if (timeUnit.value === '周') { } else if (timeUnit.value === '周') {
prevStartDate.setDate(prevStartDate.getDate() - 7) prevStartDate.setDate(prevStartDate.getDate() - 7)
prevEndDate.setDate(prevEndDate.getDate() - 7) prevEndDate.setDate(prevEndDate.getDate() - 7)
} else if (timeUnit.value === '月') { } else if (timeUnit.value === '月') {
prevStartDate.setMonth(prevStartDate.getMonth() - 1)
prevEndDate.setMonth(prevEndDate.getMonth() - 1)
} else if (timeUnit.value === '季度') {
prevStartDate.setMonth(prevStartDate.getMonth() - 3)
prevEndDate.setMonth(prevEndDate.getMonth() - 3)
} else if (timeUnit.value === '年') {
prevStartDate.setFullYear(prevStartDate.getFullYear() - 1)
prevEndDate.setFullYear(prevEndDate.getFullYear() - 1)
}
startDate.value = prevStartDate
prevStartDate.setMonth(prevStartDate.getMonth() - 1) endDate.value = prevEndDate
prevEndDate.setMonth(prevEndDate.getMonth() - 1) updateNextButtonStatus()
} else if (timeUnit.value === '季度') {
prevStartDate.setMonth(prevStartDate.getMonth() - 3)
prevEndDate.setMonth(prevEndDate.getMonth() - 3)
} else if (timeUnit.value === '年') {
prevStartDate.setFullYear(prevStartDate.getFullYear() - 1)
prevEndDate.setFullYear(prevEndDate.getFullYear() - 1)
}
startDate.value = prevStartDate
endDate.value = prevEndDate
updateNextButtonStatus()
} }
const goToCurrent = () => { const goToCurrent = () => {
if (timeUnit.value !== '自定义') { if (timeUnit.value !== '自定义') {
updateDateRange() // 更新为当前选择时间单位的时间范围 updateDateRange() // 更新为当前选择时间单位的时间范围
} }
} }
const nextPeriod = () => { const nextPeriod = () => {
const nextStartDate = new Date(startDate.value) const nextStartDate = new Date(startDate.value)
const nextEndDate = new Date(endDate.value) const nextEndDate = new Date(endDate.value)
if (timeUnit.value === '日') { if (timeUnit.value === '日') {
nextStartDate.setDate(nextStartDate.getDate() + 1) nextStartDate.setDate(nextStartDate.getDate() + 1)
nextEndDate.setDate(nextEndDate.getDate() + 1) nextEndDate.setDate(nextEndDate.getDate() + 1)
} else if (timeUnit.value === '周') { } else if (timeUnit.value === '周') {
nextStartDate.setDate(nextStartDate.getDate() + 7) nextStartDate.setDate(nextStartDate.getDate() + 7)
nextEndDate.setDate(nextEndDate.getDate() + 7) nextEndDate.setDate(nextEndDate.getDate() + 7)
} else if (timeUnit.value === '月') { } else if (timeUnit.value === '月') {
nextStartDate.setMonth(nextStartDate.getMonth() + 1) nextStartDate.setMonth(nextStartDate.getMonth() + 1)
nextEndDate.setMonth(nextEndDate.getMonth() + 1) nextEndDate.setMonth(nextEndDate.getMonth() + 1)
} else if (timeUnit.value === '季度') { } else if (timeUnit.value === '季度') {
nextStartDate.setMonth(nextStartDate.getMonth() + 3) nextStartDate.setMonth(nextStartDate.getMonth() + 3)
nextEndDate.setMonth(nextStartDate.getMonth() + 3) nextEndDate.setMonth(nextStartDate.getMonth() + 3)
} else if (timeUnit.value === '年') { } else if (timeUnit.value === '年') {
nextStartDate.setFullYear(nextStartDate.getFullYear() + 1) nextStartDate.setFullYear(nextStartDate.getFullYear() + 1)
nextEndDate.setFullYear(nextEndDate.getFullYear() + 1) nextEndDate.setFullYear(nextEndDate.getFullYear() + 1)
} }
startDate.value = nextStartDate startDate.value = nextStartDate
endDate.value = nextEndDate endDate.value = nextEndDate
updateNextButtonStatus() updateNextButtonStatus()
} }
const updateNextButtonStatus = () => { const updateNextButtonStatus = () => {
// 更新下一个按钮的禁用状态
// 更新下一个按钮的禁用状态 const maxDate = new Date() // 假设最新日期为今天
const maxDate = new Date() // 假设最新日期为今天 // 将 maxDate 设置为当天的开始时间
// 将 maxDate 设置为当天的开始时间 maxDate.setHours(0, 0, 0, 0)
maxDate.setHours(0, 0, 0, 0) // 将 endDate 设置为当天的开始时间并进行比较
// 将 endDate 设置为当天的开始时间并进行比较 const endDateAdjusted = new Date(endDate.value)
const endDateAdjusted = new Date(endDate.value) endDateAdjusted.setHours(0, 0, 0, 0)
endDateAdjusted.setHours(0, 0, 0, 0) // 仅比较日期部分
// 仅比较日期部分 isNextDisabled.value = endDateAdjusted >= maxDate
isNextDisabled.value = endDateAdjusted >= maxDate emitDateChange() // 变化时也发出更新事件
emitDateChange() // 变化时也发出更新事件
} }
// 限制开始日期不能选择超过当前日期 // 限制开始日期不能选择超过当前日期
const disableStartDate = (date: Date) => { const disableStartDate = (date: Date) => {
return date > today.value return date > today.value
} }
// 限制结束日期不能超过当前日期且必须大于开始日期 // 限制结束日期不能超过当前日期且必须大于开始日期
const disableEndDate = (date: Date) => { const disableEndDate = (date: Date) => {
if (timeUnit.value !== '自定义') return false // 如果不是自定义时间单位,则不限制 if (timeUnit.value !== '自定义') return false // 如果不是自定义时间单位,则不限制
const start = new Date(startDate.value) const start = new Date(startDate.value)
return date > today.value || (start && date <= start) return date > today.value || (start && date <= start)
} }
// 格式化日期yyyy-mm-dd // 格式化日期yyyy-mm-dd
function formatDate(date: Date | null): string { function formatDate(date: Date | null): string {
if (!date) { if (!date) {
return ''; return ''
} }
const year = date.getFullYear(); const year = date.getFullYear()
const month = String(date.getMonth() + 1).padStart(2, '0'); const month = String(date.getMonth() + 1).padStart(2, '0')
const day = String(date.getDate()).padStart(2, '0'); const day = String(date.getDate()).padStart(2, '0')
return `${year}-${month}-${day}`; return `${year}-${month}-${day}`
} }
</script> </script>
<style scoped lang='scss'> <style scoped lang="scss">
@import "./index.scss"; @use './index.scss';
</style> </style>

View File

@@ -5,7 +5,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { onBeforeUnmount, onMounted, ref, defineExpose, watch, nextTick } from 'vue' import { onBeforeUnmount, onMounted, ref, watch } from 'vue'
// import echarts from './echarts' // import echarts from './echarts'
import * as echarts from 'echarts' // 全引入 import * as echarts from 'echarts' // 全引入
// import 'echarts/lib/component/dataZoom' // import 'echarts/lib/component/dataZoom'

View File

@@ -1,63 +1,62 @@
<!-- 经典布局 --> <!-- 经典布局 -->
<template> <template>
<el-container class="layout"> <el-container class="layout">
<el-header>
<el-header> <div class="header-lf mask-image">
<div class="header-lf mask-image"> <div class="logo flx-center">
<div class="logo flx-center"> <img class="logo-img" src="@/assets/images/logo.svg" alt="logo" />
<img class="logo-img" src="@/assets/images/logo.svg" alt="logo" /> <span class="logo-text">{{ title }}</span>
<span class="logo-text">{{ title }}</span> </div>
</div> <ToolBarLeft />
<ToolBarLeft /> </div>
</div> <div class="header-ri">
<div class="header-ri"> <ToolBarRight />
<ToolBarRight /> </div>
</div> </el-header>
</el-header> <el-container class="classic-content">
<el-container class="classic-content"> <el-aside>
<el-aside> <div class="aside-box" :style="{ width: isCollapse ? '65px' : '210px' }">
<div class="aside-box" :style="{ width: isCollapse ? '65px' : '210px' }"> <el-scrollbar>
<el-scrollbar> <el-menu
<el-menu :router="false"
:router="false" :default-active="activeMenu"
:default-active="activeMenu" :collapse="isCollapse"
:collapse="isCollapse" :unique-opened="accordion"
:unique-opened="accordion" :collapse-transition="false"
:collapse-transition="false" >
> <SubMenu :menu-list="menuList" />
<SubMenu :menu-list="menuList" /> </el-menu>
</el-menu> </el-scrollbar>
</el-scrollbar> </div>
</div> </el-aside>
</el-aside> <el-container class="classic-main">
<el-container class="classic-main"> <Main />
<Main /> </el-container>
</el-container> </el-container>
</el-container> </el-container>
</el-container>
</template> </template>
<script setup lang="ts" name="layoutClassic"> <script setup lang="ts" name="layoutClassic">
import { computed } from "vue"; import { computed } from 'vue'
import { useRoute } from "vue-router"; import { useRoute } from 'vue-router'
import { useAuthStore } from "@/stores/modules/auth"; import { useAuthStore } from '@/stores/modules/auth'
import { useGlobalStore } from "@/stores/modules/global"; import { useGlobalStore } from '@/stores/modules/global'
import Main from "@/layouts/components/Main/index.vue"; import Main from '@/layouts/components/Main/index.vue'
import SubMenu from "@/layouts/components/Menu/SubMenu.vue"; import SubMenu from '@/layouts/components/Menu/SubMenu.vue'
import ToolBarLeft from "@/layouts/components/Header/ToolBarLeft.vue"; import ToolBarLeft from '@/layouts/components/Header/ToolBarLeft.vue'
import ToolBarRight from "@/layouts/components/Header/ToolBarRight.vue"; import ToolBarRight from '@/layouts/components/Header/ToolBarRight.vue'
const title = import.meta.env.VITE_GLOB_APP_TITLE; const title = import.meta.env.VITE_GLOB_APP_TITLE
const route = useRoute(); const route = useRoute()
const authStore = useAuthStore(); const authStore = useAuthStore()
const globalStore = useGlobalStore(); const globalStore = useGlobalStore()
const accordion = computed(() => globalStore.accordion); const accordion = computed(() => globalStore.accordion)
const isCollapse = computed(() => globalStore.isCollapse); const isCollapse = computed(() => globalStore.isCollapse)
const menuList = computed(() => authStore.showMenuListGet); const menuList = computed(() => authStore.showMenuListGet)
const activeMenu = computed(() => (route.meta.activeMenu ? route.meta.activeMenu : route.path) as string); const activeMenu = computed(() => (route.meta.activeMenu ? route.meta.activeMenu : route.path) as string)
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
@import "./index.scss"; @use './index.scss';
</style> </style>

View File

@@ -1,103 +1,105 @@
<!-- 分栏布局 --> <!-- 分栏布局 -->
<template> <template>
<el-container class="layout"> <el-container class="layout">
<div class="aside-split"> <div class="aside-split">
<div class="logo flx-center"> <div class="logo flx-center">
<img class="logo-img" src="@/assets/images/logo.svg" alt="logo" /> <img class="logo-img" src="@/assets/images/logo.svg" alt="logo" />
</div> </div>
<el-scrollbar> <el-scrollbar>
<div class="split-list"> <div class="split-list">
<div <div
v-for="item in menuList" v-for="item in menuList"
:key="item.path" :key="item.path"
class="split-item" class="split-item"
:class="{ 'split-active': splitActive === item.path || `/${splitActive.split('/')[1]}` === item.path }" :class="{
@click="changeSubMenu(item)" 'split-active': splitActive === item.path || `/${splitActive.split('/')[1]}` === item.path
> }"
<el-icon> @click="changeSubMenu(item)"
<component :is="item.meta.icon"></component> >
</el-icon> <el-icon>
<span class="title">{{ item.meta.title }}</span> <component :is="item.meta.icon"></component>
</div> </el-icon>
<span class="title">{{ item.meta.title }}</span>
</div>
</div>
</el-scrollbar>
</div> </div>
</el-scrollbar> <el-aside :class="{ 'not-aside': !subMenuList.length }" :style="{ width: isCollapse ? '65px' : '210px' }">
</div> <div class="logo flx-center">
<el-aside :class="{ 'not-aside': !subMenuList.length }" :style="{ width: isCollapse ? '65px' : '210px' }"> <span v-show="subMenuList.length" class="logo-text">{{ isCollapse ? 'G' : title }}</span>
<div class="logo flx-center"> </div>
<span v-show="subMenuList.length" class="logo-text">{{ isCollapse ? "G" : title }}</span> <el-scrollbar>
</div> <el-menu
<el-scrollbar> :router="false"
<el-menu :default-active="activeMenu"
:router="false" :collapse="isCollapse"
:default-active="activeMenu" :unique-opened="accordion"
:collapse="isCollapse" :collapse-transition="false"
:unique-opened="accordion" >
:collapse-transition="false" <SubMenu :menu-list="subMenuList" />
> </el-menu>
<SubMenu :menu-list="subMenuList" /> </el-scrollbar>
</el-menu> </el-aside>
</el-scrollbar> <el-container>
</el-aside> <el-header>
<el-container> <ToolBarLeft />
<el-header> <ToolBarRight />
<ToolBarLeft /> </el-header>
<ToolBarRight /> <Main />
</el-header> </el-container>
<Main />
</el-container> </el-container>
</el-container>
</template> </template>
<script setup lang="ts" name="layoutColumns"> <script setup lang="ts" name="layoutColumns">
import { ref, computed, watch } from "vue"; import { computed, ref, watch } from 'vue'
import { useRoute, useRouter } from "vue-router"; import { useRoute, useRouter } from 'vue-router'
import { useAuthStore } from "@/stores/modules/auth"; import { useAuthStore } from '@/stores/modules/auth'
import { useGlobalStore } from "@/stores/modules/global"; import { useGlobalStore } from '@/stores/modules/global'
import Main from "@/layouts/components/Main/index.vue"; import Main from '@/layouts/components/Main/index.vue'
import ToolBarLeft from "@/layouts/components/Header/ToolBarLeft.vue"; import ToolBarLeft from '@/layouts/components/Header/ToolBarLeft.vue'
import ToolBarRight from "@/layouts/components/Header/ToolBarRight.vue"; import ToolBarRight from '@/layouts/components/Header/ToolBarRight.vue'
import SubMenu from "@/layouts/components/Menu/SubMenu.vue"; import SubMenu from '@/layouts/components/Menu/SubMenu.vue'
const title = import.meta.env.VITE_GLOB_APP_TITLE; const title = import.meta.env.VITE_GLOB_APP_TITLE
const route = useRoute(); const route = useRoute()
const router = useRouter(); const router = useRouter()
const authStore = useAuthStore(); const authStore = useAuthStore()
const globalStore = useGlobalStore(); const globalStore = useGlobalStore()
const accordion = computed(() => globalStore.accordion); const accordion = computed(() => globalStore.accordion)
const isCollapse = computed(() => globalStore.isCollapse); const isCollapse = computed(() => globalStore.isCollapse)
const menuList = computed(() => authStore.showMenuListGet); const menuList = computed(() => authStore.showMenuListGet)
const activeMenu = computed(() => (route.meta.activeMenu ? route.meta.activeMenu : route.path) as string); const activeMenu = computed(() => (route.meta.activeMenu ? route.meta.activeMenu : route.path) as string)
const subMenuList = ref<Menu.MenuOptions[]>([]); const subMenuList = ref<Menu.MenuOptions[]>([])
const splitActive = ref(""); const splitActive = ref('')
watch( watch(
() => [menuList, route], () => [menuList, route],
() => { () => {
// 当前菜单没有数据直接 return // 当前菜单没有数据直接 return
if (!menuList.value.length) return; if (!menuList.value.length) return
splitActive.value = route.path; splitActive.value = route.path
const menuItem = menuList.value.filter((item: Menu.MenuOptions) => { const menuItem = menuList.value.filter((item: Menu.MenuOptions) => {
return route.path === item.path || `/${route.path.split("/")[1]}` === item.path; return route.path === item.path || `/${route.path.split('/')[1]}` === item.path
}); })
if (menuItem[0].children?.length) return (subMenuList.value = menuItem[0].children); if (menuItem[0].children?.length) return (subMenuList.value = menuItem[0].children)
subMenuList.value = []; subMenuList.value = []
}, },
{ {
deep: true, deep: true,
immediate: true immediate: true
} }
); )
// change SubMenu // change SubMenu
const changeSubMenu = (item: Menu.MenuOptions) => { const changeSubMenu = (item: Menu.MenuOptions) => {
splitActive.value = item.path; splitActive.value = item.path
if (item.children?.length) return (subMenuList.value = item.children); if (item.children?.length) return (subMenuList.value = item.children)
subMenuList.value = []; subMenuList.value = []
router.push(item.path); router.push(item.path)
}; }
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
@import "./index.scss"; @use './index.scss';
</style> </style>

View File

@@ -1,85 +1,78 @@
<!-- 横向布局 --> <!-- 横向布局 -->
<template> <template>
<el-container class="layout"> <el-container class="layout">
<el-header> <el-header>
<div class="logo flx-center"> <div class="logo flx-center">
<!-- <img class="logo-img" src="@/assets/images/logo.svg" alt="logo" /> --> <!-- <img class="logo-img" src="@/assets/images/logo.svg" alt="logo" /> -->
<img <img class="logo-img" src="@/assets/images/cn_pms9100_logo.png" alt="logo" />
class="logo-img" <span class="logo-text">{{ title }}</span>
src="@/assets/images/cn_pms9100_logo.png" </div>
alt="logo" <el-menu v-if="showMenuFlag" trigger="click" mode="horizontal" :router="false" :default-active="activeMenu">
/> <!-- 不能直接使用 SubMenu 组件无法触发 el-menu 隐藏省略功能 -->
<span class="logo-text">{{ title }} </span> <template v-for="subItem in menuList" :key="subItem.path">
</div> <el-sub-menu
<el-menu v-if="showMenuFlag" trigger="click" mode="horizontal" :router="false" :default-active="activeMenu"> v-if="subItem.children?.length"
<!-- 不能直接使用 SubMenu 组件无法触发 el-menu 隐藏省略功能 --> :key="subItem.path"
<template v-for="subItem in menuList" :key="subItem.path"> :index="subItem.path + 'el-sub-menu'"
<el-sub-menu >
v-if="subItem.children?.length" <template #title>
:key="subItem.path" <el-icon>
:index="subItem.path + 'el-sub-menu'" <component :is="subItem.meta.icon"></component>
> </el-icon>
<template #title> <span>{{ subItem.meta.title }}</span>
<el-icon> </template>
<component :is="subItem.meta.icon"></component> <SubMenu :menu-list="subItem.children" />
</el-icon> </el-sub-menu>
<span>{{ subItem.meta.title }}</span> <el-menu-item
</template> v-else
<SubMenu :menu-list="subItem.children" /> :key="subItem.path + 'el-menu-item'"
</el-sub-menu> :index="subItem.path"
<el-menu-item @click="handleClickMenu(subItem)"
v-else >
:key="subItem.path + 'el-menu-item'" <el-icon>
:index="subItem.path" <component :is="subItem.meta.icon"></component>
@click="handleClickMenu(subItem)" </el-icon>
> <template #title>
<el-icon> <span>{{ subItem.meta.title }}</span>
<component :is="subItem.meta.icon"></component> </template>
</el-icon> </el-menu-item>
<template #title> </template>
<span>{{ subItem.meta.title }}</span> </el-menu>
</template> <ToolBarRight />
</el-menu-item> </el-header>
</template> <Main />
</el-menu> </el-container>
<ToolBarRight />
</el-header>
<Main />
</el-container>
</template> </template>
<script setup lang="ts" name="layoutTransverse"> <script setup lang="ts" name="layoutTransverse">
import { computed } from "vue"; import { computed } from 'vue'
import { useAuthStore } from "@/stores/modules/auth"; import { useAuthStore } from '@/stores/modules/auth'
import { useRoute, useRouter } from "vue-router"; import { useRoute, useRouter } from 'vue-router'
import Main from "@/layouts/components/Main/index.vue"; import Main from '@/layouts/components/Main/index.vue'
import ToolBarRight from "@/layouts/components/Header/ToolBarRight.vue"; import ToolBarRight from '@/layouts/components/Header/ToolBarRight.vue'
import SubMenu from "@/layouts/components/Menu/SubMenu.vue"; import SubMenu from '@/layouts/components/Menu/SubMenu.vue'
const title = import.meta.env.VITE_GLOB_APP_TITLE; const title = import.meta.env.VITE_GLOB_APP_TITLE
const route = useRoute(); const route = useRoute()
const router = useRouter(); const router = useRouter()
const authStore = useAuthStore(); const authStore = useAuthStore()
const menuList = computed(() => authStore.showMenuListGet); const menuList = computed(() => authStore.showMenuListGet)
const showMenuFlag=computed(()=>authStore.showMenuFlagGet) const showMenuFlag = computed(() => authStore.showMenuFlagGet)
const activeMenu = computed( const activeMenu = computed(() => (route.meta.activeMenu ? route.meta.activeMenu : route.path) as string)
() => (route.meta.activeMenu ? route.meta.activeMenu : route.path) as string
);
const handleClickMenu = (subItem: Menu.MenuOptions) => { const handleClickMenu = (subItem: Menu.MenuOptions) => {
if (subItem.meta.isLink) return window.open(subItem.meta.isLink, "_blank"); if (subItem.meta.isLink) return window.open(subItem.meta.isLink, '_blank')
router.push(subItem.path); router.push(subItem.path)
}; }
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
@import "./index.scss"; @use './index.scss';
.logo{ .logo {
margin-right: 0 !important; margin-right: 0 !important;
} }
.logo-text { .logo-text {
letter-spacing: 2px; letter-spacing: 2px;
} }
</style> </style>

View File

@@ -1,56 +1,56 @@
<!-- 纵向布局 --> <!-- 纵向布局 -->
<template> <template>
<el-container class="layout"> <el-container class="layout">
<el-aside> <el-aside>
<div class="aside-box" :style="{ width: isCollapse ? '65px' : '210px' }"> <div class="aside-box" :style="{ width: isCollapse ? '65px' : '210px' }">
<div class="logo flx-center"> <div class="logo flx-center">
<img class="logo-img" src="@/assets/images/logo.svg" alt="logo" /> <img class="logo-img" src="@/assets/images/logo.svg" alt="logo" />
<span v-show="!isCollapse" class="logo-text">{{ title }}</span> <span v-show="!isCollapse" class="logo-text">{{ title }}</span>
</div> </div>
<el-scrollbar> <el-scrollbar>
<el-menu <el-menu
:router="false" :router="false"
:default-active="activeMenu" :default-active="activeMenu"
:collapse="isCollapse" :collapse="isCollapse"
:unique-opened="accordion" :unique-opened="accordion"
:collapse-transition="false" :collapse-transition="false"
> >
<SubMenu :menu-list="menuList" /> <SubMenu :menu-list="menuList" />
</el-menu> </el-menu>
</el-scrollbar> </el-scrollbar>
</div> </div>
</el-aside> </el-aside>
<el-container> <el-container>
<el-header> <el-header>
<ToolBarLeft /> <ToolBarLeft />
<ToolBarRight /> <ToolBarRight />
</el-header> </el-header>
<Main /> <Main />
</el-container>
</el-container> </el-container>
</el-container>
</template> </template>
<script setup lang="ts" name="layoutVertical"> <script setup lang="ts" name="layoutVertical">
import { computed } from "vue"; import { computed } from 'vue'
import { useRoute } from "vue-router"; import { useRoute } from 'vue-router'
import { useAuthStore } from "@/stores/modules/auth"; import { useAuthStore } from '@/stores/modules/auth'
import { useGlobalStore } from "@/stores/modules/global"; import { useGlobalStore } from '@/stores/modules/global'
import Main from "@/layouts/components/Main/index.vue"; import Main from '@/layouts/components/Main/index.vue'
import ToolBarLeft from "@/layouts/components/Header/ToolBarLeft.vue"; import ToolBarLeft from '@/layouts/components/Header/ToolBarLeft.vue'
import ToolBarRight from "@/layouts/components/Header/ToolBarRight.vue"; import ToolBarRight from '@/layouts/components/Header/ToolBarRight.vue'
import SubMenu from "@/layouts/components/Menu/SubMenu.vue"; import SubMenu from '@/layouts/components/Menu/SubMenu.vue'
const title = import.meta.env.VITE_GLOB_APP_TITLE; const title = import.meta.env.VITE_GLOB_APP_TITLE
const route = useRoute(); const route = useRoute()
const authStore = useAuthStore(); const authStore = useAuthStore()
const globalStore = useGlobalStore(); const globalStore = useGlobalStore()
const accordion = computed(() => globalStore.accordion); const accordion = computed(() => globalStore.accordion)
const isCollapse = computed(() => globalStore.isCollapse); const isCollapse = computed(() => globalStore.isCollapse)
const menuList = computed(() => authStore.showMenuListGet); const menuList = computed(() => authStore.showMenuListGet)
const activeMenu = computed(() => (route.meta.activeMenu ? route.meta.activeMenu : route.path) as string); const activeMenu = computed(() => (route.meta.activeMenu ? route.meta.activeMenu : route.path) as string)
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
@import "./index.scss"; @use './index.scss';
</style> </style>

View File

@@ -1,115 +1,104 @@
<template> <template>
<div class="footer flx-align-center pl10"> <div class="footer flx-align-center pl10">
<el-dropdown> <el-dropdown>
<!-- <span class="el-dropdown-link"> <!-- <span class="el-dropdown-link">
{{ title }} {{ title }}
<el-icon class="el-icon--right"> <el-icon class="el-icon--right">
<arrow-down /> <arrow-down />
</el-icon> </el-icon>
</span> --> </span> -->
<!-- <el-button dictType="primary"> --> <!-- <el-button dictType="primary"> -->
<div class="change_mode"> <div class="change_mode">
{{ title }} {{ title }}
<el-icon class="el-icon--right change_mode_down" <el-icon class="el-icon--right change_mode_down"><arrow-down /></el-icon>
><arrow-down <el-icon class="el-icon--right change_mode_up"><arrow-up /></el-icon>
/></el-icon> </div>
<el-icon class="el-icon--right change_mode_up"><arrow-up /></el-icon> <!-- </el-button> -->
</div> <template #dropdown>
<!-- </el-button> --> <el-dropdown-menu>
<template #dropdown> <el-dropdown-item @click="handelOpen('模拟式')">模拟式模块</el-dropdown-item>
<el-dropdown-menu> <el-dropdown-item @click="handelOpen('数字式')">数字式模块</el-dropdown-item>
<el-dropdown-item @click="handelOpen('模拟式')" <el-dropdown-item @click="handelOpen('比对式')">比对式模块</el-dropdown-item>
>模拟式模块</el-dropdown-item </el-dropdown-menu>
> </template>
<el-dropdown-item @click="handelOpen('数字式')" </el-dropdown>
>数字式模块</el-dropdown-item <p style="margin: 0">
> <a href="http://www.shining-electric.com/" target="_blank">2024 © 南京灿能电力自动化股份有限公司</a>
<el-dropdown-item @click="handelOpen('比对式')" </p>
>比对式模块</el-dropdown-item </div>
>
</el-dropdown-menu>
</template>
</el-dropdown>
<p style="margin: 0;" >
<a href="http://www.shining-electric.com/" target="_blank">
2024 © 南京灿能电力自动化股份有限公司
</a>
</p>
</div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, reactive, computed, onMounted, watch } from "vue"; import { computed } from 'vue'
import { useAuthStore } from "@/stores/modules/auth"; import { useAuthStore } from '@/stores/modules/auth'
import { useModeStore } from '@/stores/modules/mode'; // 引入模式 store import { useModeStore } from '@/stores/modules/mode' // 引入模式 store
import { useRouter } from "vue-router"; import { useRouter } from 'vue-router'
const router = useRouter();
const authStore = useAuthStore(); const router = useRouter()
const modeStore = useModeStore(); const authStore = useAuthStore()
const modeStore = useModeStore()
const title = computed(() => { const title = computed(() => {
return modeStore.currentMode=== ''? '模拟式模块' : modeStore.currentMode+'模块'; return modeStore.currentMode === '' ? '模拟式模块' : modeStore.currentMode + '模块'
}); })
const handelOpen = async (item: string) => { const handelOpen = async (item: string) => {
await authStore.setShowMenu(); await authStore.setShowMenu()
modeStore.setCurrentMode(item); // 将模式code存入 store modeStore.setCurrentMode(item) // 将模式code存入 store
//if (router.currentRoute.value.path === '/home/index') {
// 强制刷新页面
window.location.reload();
//} else {
// router.push({ path: '/home/index' });
//}
};
//if (router.currentRoute.value.path === '/home/index') {
// 强制刷新页面
window.location.reload()
//} else {
// router.push({ path: '/home/index' });
//}
}
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
@import "./index.scss"; @use './index.scss';
.footer { .footer {
position: relative; position: relative;
background-color: var(--el-color-primary); background-color: var(--el-color-primary);
// .el-button:hover { // .el-button:hover {
// background-color: var(--el-color-primary) !important; // background-color: var(--el-color-primary) !important;
// border: none !important; // border: none !important;
// outline: none !important; // outline: none !important;
// } // }
.change_mode { .change_mode {
color: #fff; color: #fff;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: flex-start; justify-content: flex-start;
height: 100%; height: 100%;
width: auto; width: auto;
font-size: 14px; font-size: 14px;
.change_mode_down { .change_mode_down {
display: block; display: block;
}
.change_mode_up {
display: none;
}
} }
.change_mode_up { .change_mode:hover {
display: none; .change_mode_down {
display: none;
}
.change_mode_up {
display: block;
}
} }
} .el-dropdown {
.change_mode:hover { z-index: 1001;
.change_mode_down {
display: none;
} }
.change_mode_up { p {
display: block; position: absolute;
width: 100%;
height: 100%;
text-align: right;
line-height: 40px;
a {
color: #fff;
margin-right: 25px; // 增加右边距
}
} }
}
.el-dropdown {
z-index: 1001;
}
p {
position: absolute;
width: 100%;
height: 100%;
text-align: right;
line-height: 40px;
a {
color: #fff;
margin-right: 25px; // 增加右边距
}
}
} }
</style> </style>

View File

@@ -1,83 +1,81 @@
<template> <template>
<Maximize v-show="maximize" /> <Maximize v-show="maximize" />
<Tabs v-if="tabs && showMenuFlag" /> <Tabs v-if="tabs && showMenuFlag" />
<el-main> <el-main>
<router-view v-slot="{ Component, route }" style="height:100%;"> <router-view v-slot="{ Component, route }" style="height: 100%">
<!-- {{ keepAliveName}} --> <!-- {{ keepAliveName}} -->
<!-- <transition name="slide-right" mode="out-in"> --> <!-- <transition name="slide-right" mode="out-in"> -->
<keep-alive :include="tabsMenuList" > <keep-alive :include="tabsMenuList">
<component :is="Component" :key="route.fullPath" /> <component :is="Component" :key="route.fullPath" />
</keep-alive> </keep-alive>
<!-- </transition> --> <!-- </transition> -->
</router-view> </router-view>
</el-main> </el-main>
<el-footer> <el-footer>
<Footer /> <Footer />
</el-footer> </el-footer>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, onBeforeUnmount, provide, watch, computed } from "vue"; import { computed, onBeforeUnmount, provide, ref, watch } from 'vue'
import { storeToRefs } from "pinia"; import { storeToRefs } from 'pinia'
import { useDebounceFn } from "@vueuse/core"; import { useDebounceFn } from '@vueuse/core'
import { useGlobalStore } from "@/stores/modules/global"; import { useGlobalStore } from '@/stores/modules/global'
import { useKeepAliveStore } from "@/stores/modules/keepAlive"; import { useKeepAliveStore } from '@/stores/modules/keepAlive'
import Maximize from "./components/Maximize.vue"; import Maximize from './components/Maximize.vue'
import Tabs from "@/layouts/components/Tabs/index.vue"; import Tabs from '@/layouts/components/Tabs/index.vue'
import Footer from "@/layouts/components/Footer/index.vue"; import Footer from '@/layouts/components/Footer/index.vue'
import { useAuthStore } from "@/stores/modules/auth"; import { useAuthStore } from '@/stores/modules/auth'
import { useTabsStore } from '@/stores/modules/tabs' import { useTabsStore } from '@/stores/modules/tabs'
const tabStore = useTabsStore()
const globalStore = useGlobalStore(); const tabStore = useTabsStore()
const tabsMenuList = computed(() => tabStore.tabsMenuList.map(item => item.name)) const globalStore = useGlobalStore()
const authStore = useAuthStore(); const tabsMenuList = computed(() => tabStore.tabsMenuList.map(item => item.name))
const { maximize, isCollapse, layout, tabs, footer } = storeToRefs(globalStore); const authStore = useAuthStore()
const keepAliveStore = useKeepAliveStore(); const { maximize, isCollapse, layout, tabs, footer } = storeToRefs(globalStore)
const { keepAliveName } = storeToRefs(keepAliveStore); const keepAliveStore = useKeepAliveStore()
//是否显示导航栏 const { keepAliveName } = storeToRefs(keepAliveStore)
const showMenuFlag = computed(() => authStore.showMenuFlagGet); //是否显示导航栏
// 注入刷新页面方法 const showMenuFlag = computed(() => authStore.showMenuFlagGet)
const isRouterShow = ref(true); // 注入刷新页面方法
const refreshCurrentPage = (val: boolean) => (isRouterShow.value = val); const isRouterShow = ref(true)
provide("refresh", refreshCurrentPage); const refreshCurrentPage = (val: boolean) => (isRouterShow.value = val)
provide('refresh', refreshCurrentPage)
// 监听当前页面是否最大化,动态添加 class
watch( // 监听当前页面是否最大化,动态添加 class
() => maximize.value, watch(
() => { () => maximize.value,
const app = document.getElementById("app") as HTMLElement; () => {
if (maximize.value) app.classList.add("main-maximize"); const app = document.getElementById('app') as HTMLElement
else app.classList.remove("main-maximize"); if (maximize.value) app.classList.add('main-maximize')
}, else app.classList.remove('main-maximize')
{ immediate: true } },
); { immediate: true }
)
// 监听布局变化,在 body 上添加相对应的 layout class
watch( // 监听布局变化,在 body 上添加相对应的 layout class
() => layout.value, watch(
() => { () => layout.value,
const body = document.body as HTMLElement; () => {
body.setAttribute("class", layout.value); const body = document.body as HTMLElement
}, body.setAttribute('class', layout.value)
{ immediate: true } },
); { immediate: true }
)
// 监听窗口大小变化,折叠侧边栏 // 监听窗口大小变化,折叠侧边栏
const screenWidth = ref(0); const screenWidth = ref(0)
const listeningWindow = useDebounceFn(() => { const listeningWindow = useDebounceFn(() => {
screenWidth.value = document.body.clientWidth; screenWidth.value = document.body.clientWidth
if (!isCollapse.value && screenWidth.value < 1200) if (!isCollapse.value && screenWidth.value < 1200) globalStore.setGlobalState('isCollapse', true)
globalStore.setGlobalState("isCollapse", true); if (isCollapse.value && screenWidth.value > 1200) globalStore.setGlobalState('isCollapse', false)
if (isCollapse.value && screenWidth.value > 1200) }, 100)
globalStore.setGlobalState("isCollapse", false); window.addEventListener('resize', listeningWindow, false)
}, 100); onBeforeUnmount(() => {
window.addEventListener("resize", listeningWindow, false); window.removeEventListener('resize', listeningWindow)
onBeforeUnmount(() => { })
window.removeEventListener("resize", listeningWindow); </script>
});
</script> <style scoped lang="scss">
@use './index.scss';
<style scoped lang="scss"> </style>
@import "./index.scss";
</style>

View File

@@ -1,81 +1,88 @@
<template> <template>
<el-dropdown trigger="click" :teleported="false"> <el-dropdown trigger="click" :teleported="false">
<div class="more-button"> <div class="more-button">
<i :class="'iconfont icon-xiala'"></i> <i :class="'iconfont icon-xiala'"></i>
</div> </div>
<template #dropdown> <template #dropdown>
<el-dropdown-menu> <el-dropdown-menu>
<el-dropdown-item @click="refresh"> <el-dropdown-item @click="refresh">
<el-icon><Refresh /></el-icon>{{ $t("tabs.refresh") }} <el-icon><Refresh /></el-icon>
</el-dropdown-item> {{ $t('tabs.refresh') }}
<el-dropdown-item @click="maximize"> </el-dropdown-item>
<el-icon><FullScreen /></el-icon>{{ $t("tabs.maximize") }} <el-dropdown-item @click="maximize">
</el-dropdown-item> <el-icon><FullScreen /></el-icon>
<el-dropdown-item divided @click="closeCurrentTab"> {{ $t('tabs.maximize') }}
<el-icon><Remove /></el-icon>{{ $t("tabs.closeCurrent") }} </el-dropdown-item>
</el-dropdown-item> <el-dropdown-item divided @click="closeCurrentTab">
<el-dropdown-item @click="tabStore.closeTabsOnSide(route.fullPath, 'left')"> <el-icon><Remove /></el-icon>
<el-icon><DArrowLeft /></el-icon>{{ $t("tabs.closeLeft") }} {{ $t('tabs.closeCurrent') }}
</el-dropdown-item> </el-dropdown-item>
<el-dropdown-item @click="tabStore.closeTabsOnSide(route.fullPath, 'right')"> <el-dropdown-item @click="tabStore.closeTabsOnSide(route.fullPath, 'left')">
<el-icon><DArrowRight /></el-icon>{{ $t("tabs.closeRight") }} <el-icon><DArrowLeft /></el-icon>
</el-dropdown-item> {{ $t('tabs.closeLeft') }}
<el-dropdown-item divided @click="tabStore.closeMultipleTab(route.fullPath)"> </el-dropdown-item>
<el-icon><CircleClose /></el-icon>{{ $t("tabs.closeOther") }} <el-dropdown-item @click="tabStore.closeTabsOnSide(route.fullPath, 'right')">
</el-dropdown-item> <el-icon><DArrowRight /></el-icon>
<el-dropdown-item @click="closeAllTab"> {{ $t('tabs.closeRight') }}
<el-icon><FolderDelete /></el-icon>{{ $t("tabs.closeAll") }} </el-dropdown-item>
</el-dropdown-item> <el-dropdown-item divided @click="tabStore.closeMultipleTab(route.fullPath)">
</el-dropdown-menu> <el-icon><CircleClose /></el-icon>
</template> {{ $t('tabs.closeOther') }}
</el-dropdown> </el-dropdown-item>
<el-dropdown-item @click="closeAllTab">
<el-icon><FolderDelete /></el-icon>
{{ $t('tabs.closeAll') }}
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { inject, nextTick } from "vue"; import { inject, nextTick } from 'vue'
import { HOME_URL } from "@/config"; import { HOME_URL } from '@/config'
import { useTabsStore } from "@/stores/modules/tabs"; import { useTabsStore } from '@/stores/modules/tabs'
import { useGlobalStore } from "@/stores/modules/global"; import { useGlobalStore } from '@/stores/modules/global'
import { useKeepAliveStore } from "@/stores/modules/keepAlive"; import { useKeepAliveStore } from '@/stores/modules/keepAlive'
import { useRoute, useRouter } from "vue-router"; import { useRoute, useRouter } from 'vue-router'
const route = useRoute(); const route = useRoute()
const router = useRouter(); const router = useRouter()
const tabStore = useTabsStore(); const tabStore = useTabsStore()
const globalStore = useGlobalStore(); const globalStore = useGlobalStore()
const keepAliveStore = useKeepAliveStore(); const keepAliveStore = useKeepAliveStore()
// refresh current page // refresh current page
const refreshCurrentPage: Function = inject("refresh") as Function; const refreshCurrentPage: Function = inject('refresh') as Function
const refresh = () => { const refresh = () => {
setTimeout(() => { setTimeout(() => {
keepAliveStore.removeKeepAliveName(route.name as string); keepAliveStore.removeKeepAliveName(route.name as string)
refreshCurrentPage(false); refreshCurrentPage(false)
nextTick(() => { nextTick(() => {
keepAliveStore.addKeepAliveName(route.name as string); keepAliveStore.addKeepAliveName(route.name as string)
refreshCurrentPage(true); refreshCurrentPage(true)
}); })
}, 0); }, 0)
}; }
// maximize current page // maximize current page
const maximize = () => { const maximize = () => {
globalStore.setGlobalState("maximize", true); globalStore.setGlobalState('maximize', true)
}; }
// Close Current // Close Current
const closeCurrentTab = () => { const closeCurrentTab = () => {
if (route.meta.isAffix) return; if (route.meta.isAffix) return
tabStore.removeTabs(route.fullPath); tabStore.removeTabs(route.fullPath)
}; }
// Close All // Close All
const closeAllTab = () => { const closeAllTab = () => {
tabStore.closeMultipleTab(); tabStore.closeMultipleTab()
router.push(HOME_URL); router.push(HOME_URL)
}; }
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
@import "../index.scss"; @use '../index.scss';
</style> </style>

View File

@@ -1,121 +1,119 @@
<template> <template>
<div class="tabs-box"> <div class="tabs-box">
<div class="tabs-menu"> <div class="tabs-menu">
<el-tabs v-model="tabsMenuValue" type="card" @tab-click="tabClick" @tab-remove="tabRemove"> <el-tabs v-model="tabsMenuValue" type="card" @tab-click="tabClick" @tab-remove="tabRemove">
<el-tab-pane <el-tab-pane
v-for="item in tabsMenuList" v-for="item in tabsMenuList"
:key="item.path" :key="item.path"
:label="item.title" :label="item.title"
:name="item.path" :name="item.path"
:closable="item.close" :closable="item.close"
> >
<template #label> <template #label>
<el-icon v-show="item.icon && tabsIcon" class="tabs-icon"> <el-icon v-show="item.icon && tabsIcon" class="tabs-icon">
<component :is="item.icon"></component> <component :is="item.icon"></component>
</el-icon> </el-icon>
{{ item.title }} {{ item.title }}
</template> </template>
</el-tab-pane> </el-tab-pane>
</el-tabs> </el-tabs>
<MoreButton /> <MoreButton />
</div> </div>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import Sortable from 'sortablejs' import Sortable from 'sortablejs'
import { ref, computed, watch, onMounted } from 'vue' import { computed, onMounted, ref, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router' import { useRoute, useRouter } from 'vue-router'
import { useGlobalStore } from '@/stores/modules/global' import { useGlobalStore } from '@/stores/modules/global'
import { useTabsStore } from '@/stores/modules/tabs' import { useTabsStore } from '@/stores/modules/tabs'
import { useAuthStore } from '@/stores/modules/auth' import { useAuthStore } from '@/stores/modules/auth'
import { TabsPaneContext, TabPaneName } from 'element-plus' import { TabPaneName, TabsPaneContext } from 'element-plus'
import MoreButton from './components/MoreButton.vue' import MoreButton from './components/MoreButton.vue'
const route = useRoute() const route = useRoute()
const router = useRouter() const router = useRouter()
const tabStore = useTabsStore() const tabStore = useTabsStore()
const authStore = useAuthStore() const authStore = useAuthStore()
const globalStore = useGlobalStore() const globalStore = useGlobalStore()
const tabsMenuValue = ref(route.fullPath) const tabsMenuValue = ref(route.fullPath)
const tabsMenuList = computed(() => tabStore.tabsMenuList) const tabsMenuList = computed(() => tabStore.tabsMenuList)
const tabsIcon = computed(() => globalStore.tabsIcon) const tabsIcon = computed(() => globalStore.tabsIcon)
onMounted(() => { onMounted(() => {
tabsDrop() tabsDrop()
initTabs() initTabs()
}) })
// 监听路由的变化(防止浏览器后退/前进不变化 tabsMenuValue // 监听路由的变化(防止浏览器后退/前进不变化 tabsMenuValue
watch( watch(
() => route.fullPath, () => route.fullPath,
() => { () => {
if (route.meta.isFull) return if (route.meta.isFull) return
if (route.meta.hideTab) { if (route.meta.hideTab) {
tabsMenuValue.value = route.meta.parentPath as string tabsMenuValue.value = route.meta.parentPath as string
} else { } else {
tabsMenuValue.value = route.fullPath tabsMenuValue.value = route.fullPath
const tabsParams = { const tabsParams = {
icon: route.meta.icon as string, icon: route.meta.icon as string,
title: route.meta.title as string, title: route.meta.title as string,
path: route.fullPath, path: route.fullPath,
name: route.name as string, name: route.name as string,
close: !route.meta.isAffix, close: !route.meta.isAffix,
isKeepAlive: route.meta.isKeepAlive as boolean isKeepAlive: route.meta.isKeepAlive as boolean
} }
tabStore.addTabs(tabsParams) tabStore.addTabs(tabsParams)
} }
}, },
{ immediate: true } { immediate: true }
) )
// 初始化需要固定的 tabs // 初始化需要固定的 tabs
const initTabs = () => { const initTabs = () => {
authStore.flatMenuListGet.forEach(item => { authStore.flatMenuListGet.forEach(item => {
if (item.meta.isAffix && !item.meta.isHide && !item.meta.isFull) { if (item.meta.isAffix && !item.meta.isHide && !item.meta.isFull) {
const tabsParams = { const tabsParams = {
icon: item.meta.icon, icon: item.meta.icon,
title: item.meta.title, title: item.meta.title,
path: item.path, path: item.path,
name: item.name, name: item.name,
close: !item.meta.isAffix, close: !item.meta.isAffix,
isKeepAlive: item.meta.isKeepAlive, isKeepAlive: item.meta.isKeepAlive,
unshift: true unshift: true
} }
tabStore.addTabs(tabsParams) tabStore.addTabs(tabsParams)
} }
}) })
} }
// tabs 拖拽排序 // tabs 拖拽排序
const tabsDrop = () => { const tabsDrop = () => {
Sortable.create(document.querySelector('.el-tabs__nav') as HTMLElement, { Sortable.create(document.querySelector('.el-tabs__nav') as HTMLElement, {
draggable: '.el-tabs__item', draggable: '.el-tabs__item',
animation: 300, animation: 300,
onEnd({ newIndex, oldIndex }) { onEnd({ newIndex, oldIndex }) {
const tabsList = [...tabStore.tabsMenuList] const tabsList = [...tabStore.tabsMenuList]
const currRow = tabsList.splice(oldIndex as number, 1)[0] const currRow = tabsList.splice(oldIndex as number, 1)[0]
tabsList.splice(newIndex as number, 0, currRow) tabsList.splice(newIndex as number, 0, currRow)
tabStore.setTabs(tabsList) tabStore.setTabs(tabsList)
} }
}) })
} }
// Tab Click // Tab Click
const tabClick = (tabItem: TabsPaneContext) => { const tabClick = (tabItem: TabsPaneContext) => {
const fullPath = tabItem.props.name as string const fullPath = tabItem.props.name as string
router.push(fullPath) router.push(fullPath)
} }
// Remove Tab // Remove Tab
const tabRemove = (fullPath: TabPaneName) => { const tabRemove = (fullPath: TabPaneName) => {
tabStore.removeTabs(fullPath as string, fullPath == route.fullPath || '/machine/testScriptAdd' == route.fullPath)
}
tabStore.removeTabs(fullPath as string, fullPath == route.fullPath || '/machine/testScriptAdd' == route.fullPath) </script>
}
</script> <style scoped lang="scss">
@use './index.scss';
<style scoped lang="scss"> </style>
@import './index.scss';
</style>

View File

@@ -1,186 +1,198 @@
<template> <template>
<el-drawer v-model="drawerVisible" title="布局设置" size="290px"> <el-drawer v-model="drawerVisible" title="布局设置" size="290px">
<!-- 布局样式 --> <!-- 布局样式 -->
<el-divider class="divider" content-position="center"> <el-divider class="divider" content-position="center">
<el-icon><Notification /></el-icon> <el-icon><Notification /></el-icon>
布局样式 布局样式
</el-divider> </el-divider>
<div class="layout-box"> <div class="layout-box">
<el-tooltip effect="dark" content="纵向" placement="top" :show-after="200"> <el-tooltip effect="dark" content="纵向" placement="top" :show-after="200">
<div :class="['layout-item layout-vertical', { 'is-active': layout == 'vertical' }]" @click="setLayout('vertical')"> <div
<div class="layout-dark"></div> :class="['layout-item layout-vertical', { 'is-active': layout == 'vertical' }]"
<div class="layout-container"> @click="setLayout('vertical')"
<div class="layout-light"></div> >
<div class="layout-content"></div> <div class="layout-dark"></div>
</div> <div class="layout-container">
<el-icon v-if="layout == 'vertical'"> <div class="layout-light"></div>
<CircleCheckFilled /> <div class="layout-content"></div>
</el-icon> </div>
<el-icon v-if="layout == 'vertical'">
<CircleCheckFilled />
</el-icon>
</div>
</el-tooltip>
<el-tooltip effect="dark" content="经典" placement="top" :show-after="200">
<div
:class="['layout-item layout-classic', { 'is-active': layout == 'classic' }]"
@click="setLayout('classic')"
>
<div class="layout-dark"></div>
<div class="layout-container">
<div class="layout-light"></div>
<div class="layout-content"></div>
</div>
<el-icon v-if="layout == 'classic'">
<CircleCheckFilled />
</el-icon>
</div>
</el-tooltip>
<el-tooltip effect="dark" content="横向" placement="top" :show-after="200">
<div
:class="['layout-item layout-transverse', { 'is-active': layout == 'transverse' }]"
@click="setLayout('transverse')"
>
<div class="layout-dark"></div>
<div class="layout-content"></div>
<el-icon v-if="layout == 'transverse'">
<CircleCheckFilled />
</el-icon>
</div>
</el-tooltip>
<el-tooltip effect="dark" content="分栏" placement="top" :show-after="200">
<div
:class="['layout-item layout-columns', { 'is-active': layout == 'columns' }]"
@click="setLayout('columns')"
>
<div class="layout-dark"></div>
<div class="layout-light"></div>
<div class="layout-content"></div>
<el-icon v-if="layout == 'columns'">
<CircleCheckFilled />
</el-icon>
</div>
</el-tooltip>
</div> </div>
</el-tooltip> <div class="theme-item">
<el-tooltip effect="dark" content="经典" placement="top" :show-after="200"> <span>
<div :class="['layout-item layout-classic', { 'is-active': layout == 'classic' }]" @click="setLayout('classic')"> 侧边栏反转色
<div class="layout-dark"></div> <el-tooltip effect="dark" content="侧边栏颜色变为深色模式" placement="top">
<div class="layout-container"> <el-icon><QuestionFilled /></el-icon>
<div class="layout-light"></div> </el-tooltip>
<div class="layout-content"></div> </span>
</div> <el-switch v-model="asideInverted" @change="setAsideTheme" />
<el-icon v-if="layout == 'classic'">
<CircleCheckFilled />
</el-icon>
</div> </div>
</el-tooltip> <div class="theme-item mb50">
<el-tooltip effect="dark" content="横向" placement="top" :show-after="200"> <span>
<div :class="['layout-item layout-transverse', { 'is-active': layout == 'transverse' }]" @click="setLayout('transverse')"> 头部反转色
<div class="layout-dark"></div> <el-tooltip effect="dark" content="头部颜色变为深色模式" placement="top">
<div class="layout-content"></div> <el-icon><QuestionFilled /></el-icon>
<el-icon v-if="layout == 'transverse'"> </el-tooltip>
<CircleCheckFilled /> </span>
</el-icon> <el-switch v-model="headerInverted" @change="setHeaderTheme" />
</div> </div>
</el-tooltip>
<el-tooltip effect="dark" content="分栏" placement="top" :show-after="200">
<div :class="['layout-item layout-columns', { 'is-active': layout == 'columns' }]" @click="setLayout('columns')">
<div class="layout-dark"></div>
<div class="layout-light"></div>
<div class="layout-content"></div>
<el-icon v-if="layout == 'columns'">
<CircleCheckFilled />
</el-icon>
</div>
</el-tooltip>
</div>
<div class="theme-item">
<span>
侧边栏反转色
<el-tooltip effect="dark" content="侧边栏颜色变为深色模式" placement="top">
<el-icon><QuestionFilled /></el-icon>
</el-tooltip>
</span>
<el-switch v-model="asideInverted" @change="setAsideTheme" />
</div>
<div class="theme-item mb50">
<span>
头部反转色
<el-tooltip effect="dark" content="头部颜色变为深色模式" placement="top">
<el-icon><QuestionFilled /></el-icon>
</el-tooltip>
</span>
<el-switch v-model="headerInverted" @change="setHeaderTheme" />
</div>
<!-- 全局主题 --> <!-- 全局主题 -->
<el-divider class="divider" content-position="center"> <el-divider class="divider" content-position="center">
<el-icon><ColdDrink /></el-icon> <el-icon><ColdDrink /></el-icon>
全局主题 全局主题
</el-divider> </el-divider>
<div class="theme-item"> <div class="theme-item">
<span>主题颜色</span> <span>主题颜色</span>
<el-color-picker v-model="primary" :predefine="colorList" @change="changePrimary" /> <el-color-picker v-model="primary" :predefine="colorList" @change="changePrimary" />
</div> </div>
<div class="theme-item"> <div class="theme-item">
<span>暗黑模式</span> <span>暗黑模式</span>
<SwitchDark /> <SwitchDark />
</div> </div>
<div class="theme-item"> <div class="theme-item">
<span>灰色模式</span> <span>灰色模式</span>
<el-switch v-model="isGrey" @change="changeGreyOrWeak('grey', !!$event)" /> <el-switch v-model="isGrey" @change="changeGreyOrWeak('grey', !!$event)" />
</div> </div>
<div class="theme-item mb40"> <div class="theme-item mb40">
<span>色弱模式</span> <span>色弱模式</span>
<el-switch v-model="isWeak" @change="changeGreyOrWeak('weak', !!$event)" /> <el-switch v-model="isWeak" @change="changeGreyOrWeak('weak', !!$event)" />
</div> </div>
<!-- 界面设置 --> <!-- 界面设置 -->
<el-divider class="divider" content-position="center"> <el-divider class="divider" content-position="center">
<el-icon><Setting /></el-icon> <el-icon><Setting /></el-icon>
界面设置 界面设置
</el-divider> </el-divider>
<div class="theme-item"> <div class="theme-item">
<span>菜单折叠</span> <span>菜单折叠</span>
<el-switch v-model="isCollapse" /> <el-switch v-model="isCollapse" />
</div> </div>
<div class="theme-item"> <div class="theme-item">
<span>菜单手风琴</span> <span>菜单手风琴</span>
<el-switch v-model="accordion" /> <el-switch v-model="accordion" />
</div> </div>
<div class="theme-item"> <div class="theme-item">
<span>面包屑</span> <span>面包屑</span>
<el-switch v-model="breadcrumb" /> <el-switch v-model="breadcrumb" />
</div> </div>
<div class="theme-item"> <div class="theme-item">
<span>面包屑图标</span> <span>面包屑图标</span>
<el-switch v-model="breadcrumbIcon" /> <el-switch v-model="breadcrumbIcon" />
</div> </div>
<div class="theme-item"> <div class="theme-item">
<span>标签栏</span> <span>标签栏</span>
<el-switch v-model="tabs" /> <el-switch v-model="tabs" />
</div> </div>
<div class="theme-item"> <div class="theme-item">
<span>标签栏图标</span> <span>标签栏图标</span>
<el-switch v-model="tabsIcon" /> <el-switch v-model="tabsIcon" />
</div> </div>
<div class="theme-item"> <div class="theme-item">
<span>页脚</span> <span>页脚</span>
<el-switch v-model="footer" /> <el-switch v-model="footer" />
</div> </div>
</el-drawer> </el-drawer>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref } from "vue"; import { ref } from 'vue'
import { storeToRefs } from "pinia"; import { storeToRefs } from 'pinia'
import { useTheme } from "@/hooks/useTheme"; import { useTheme } from '@/hooks/useTheme'
import { useGlobalStore } from "@/stores/modules/global"; import { useGlobalStore } from '@/stores/modules/global'
import { LayoutType } from "@/stores/interface"; import { LayoutType } from '@/stores/interface'
import { DEFAULT_PRIMARY } from "@/config"; import { DEFAULT_PRIMARY } from '@/config'
import mittBus from "@/utils/mittBus"; import mittBus from '@/utils/mittBus'
import SwitchDark from "@/components/SwitchDark/index.vue"; import SwitchDark from '@/components/SwitchDark/index.vue'
const { changePrimary, changeGreyOrWeak, setAsideTheme, setHeaderTheme } = useTheme(); const { changePrimary, changeGreyOrWeak, setAsideTheme, setHeaderTheme } = useTheme()
const globalStore = useGlobalStore(); const globalStore = useGlobalStore()
const { const {
layout, layout,
primary, primary,
isGrey, isGrey,
isWeak, isWeak,
asideInverted, asideInverted,
headerInverted, headerInverted,
isCollapse, isCollapse,
accordion, accordion,
breadcrumb, breadcrumb,
breadcrumbIcon, breadcrumbIcon,
tabs, tabs,
tabsIcon, tabsIcon,
footer footer
} = storeToRefs(globalStore); } = storeToRefs(globalStore)
// 预定义主题颜色 // 预定义主题颜色
const colorList = [ const colorList = [
DEFAULT_PRIMARY, DEFAULT_PRIMARY,
"#daa96e", '#daa96e',
"#0c819f", '#0c819f',
"#409eff", '#409eff',
"#27ae60", '#27ae60',
"#ff5c93", '#ff5c93',
"#e74c3c", '#e74c3c',
"#fd726d", '#fd726d',
"#f39c12", '#f39c12',
"#9b59b6" '#9b59b6'
]; ]
// 设置布局方式 // 设置布局方式
const setLayout = (val: LayoutType) => { const setLayout = (val: LayoutType) => {
globalStore.setGlobalState("layout", val); globalStore.setGlobalState('layout', val)
setAsideTheme(); setAsideTheme()
}; }
// 打开主题设置 // 打开主题设置
const drawerVisible = ref(false); const drawerVisible = ref(false)
mittBus.on("openThemeDrawer", () => (drawerVisible.value = true)); mittBus.on('openThemeDrawer', () => (drawerVisible.value = true))
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
@import "./index.scss"; @use './index.scss';
</style> </style>

View File

@@ -1,222 +1,222 @@
<template> <template>
<el-dialog :title="dialogTitle" :model-value="dialogVisible" @close="close" v-bind="dialogMiddle" align-center> <el-dialog :title="dialogTitle" :model-value="dialogVisible" @close="close" v-bind="dialogMiddle" align-center>
<el-form :model="formContent" ref='dialogFormRef' :rules='rules' class="form-two"> <el-form :model="formContent" ref="dialogFormRef" :rules="rules" class="form-two">
<el-form-item label="上级菜单" prop="pid" :label-width="100"> <el-form-item label="上级菜单" prop="pid" :label-width="100">
<el-tree-select <el-tree-select
v-model="displayPid" v-model="displayPid"
:data="functionList" :data="functionList"
check-strictly check-strictly
:render-after-expand="false" :render-after-expand="false"
show-checkbox show-checkbox
check-on-click-node check-on-click-node
node-key="id" node-key="id"
:props="defaultProps" :props="defaultProps"
/> />
</el-form-item> </el-form-item>
<el-form-item label="名称" prop="name" :label-width="100"> <el-form-item label="名称" prop="name" :label-width="100">
<el-input v-model="formContent.name" maxlength="32" show-word-limit/> <el-input v-model="formContent.name" maxlength="32" show-word-limit />
</el-form-item> </el-form-item>
<el-form-item label="编码" prop="code" :label-width="100"> <el-form-item label="编码" prop="code" :label-width="100">
<el-input v-model="formContent.code" maxlength="32" show-word-limit/> <el-input v-model="formContent.code" maxlength="32" show-word-limit />
</el-form-item> </el-form-item>
<el-form-item v-if="!formContent.type" label="图标" prop="icon" :label-width="100"> <el-form-item v-if="!formContent.type" label="图标" prop="icon" :label-width="100">
<IconSelect <IconSelect
v-model="formContent.icon" v-model="formContent.icon"
:iconValue="formContent.icon" :iconValue="formContent.icon"
@update:icon-value="iconValue => formContent.icon = iconValue" @update:icon-value="iconValue => (formContent.icon = iconValue)"
placeholder="选择一个图标" placeholder="选择一个图标"
/> />
</el-form-item> </el-form-item>
<el-form-item v-if="!formContent.type" label="路由地址" prop="path" :label-width="100" > <el-form-item v-if="!formContent.type" label="路由地址" prop="path" :label-width="100">
<el-input v-model="formContent.path" maxlength="32" show-word-limit/> <el-input v-model="formContent.path" maxlength="32" show-word-limit />
</el-form-item> </el-form-item>
<el-form-item v-if="!formContent.type" label="组件地址" prop="component" :label-width="100"> <el-form-item v-if="!formContent.type" label="组件地址" prop="component" :label-width="100">
<el-input v-model="formContent.component" maxlength="32" show-word-limit/> <el-input v-model="formContent.component" maxlength="32" show-word-limit />
</el-form-item> </el-form-item>
<el-form-item label="排序" prop="sort" :label-width="100"> <el-form-item label="排序" prop="sort" :label-width="100">
<el-input-number v-model="formContent.sort" :min='1' :max='999' /> <el-input-number v-model="formContent.sort" :min="1" :max="999" />
</el-form-item> </el-form-item>
<el-form-item label='类型' prop='type' :label-width="100"> <el-form-item label="类型" prop="type" :label-width="100">
<el-select v-model="formContent.type" clearable placeholder="请选择资源类型"> <el-select v-model="formContent.type" clearable placeholder="请选择资源类型">
<el-option label="菜单" :value="0"></el-option> <el-option label="菜单" :value="0"></el-option>
<el-option label="按钮" :value="1"></el-option> <el-option label="按钮" :value="1"></el-option>
<!-- <el-option label="公共资源" :value="2"></el-option> <!-- <el-option label="公共资源" :value="2"></el-option>
<el-option label="服务间调用资源" :value="3"></el-option> --> <el-option label="服务间调用资源" :value="3"></el-option> -->
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="描述" prop="remark" :label-width="100"> <el-form-item label="描述" prop="remark" :label-width="100">
<el-input v-model="formContent.remark" :rows="2" type="textarea"/> <el-input v-model="formContent.remark" :rows="2" type="textarea" />
</el-form-item> </el-form-item>
</el-form> </el-form>
<template #footer> <template #footer>
<div class="dialog-footer"> <div class="dialog-footer">
<el-button @click="close()">取 消</el-button> <el-button @click="close()">取 消</el-button>
<el-button type="primary" @click="save()">确 定</el-button> <el-button type="primary" @click="save()">确 定</el-button>
</div> </div>
</template> </template>
</el-dialog> </el-dialog>
</template> </template>
<script lang="ts" setup name="ResourceDialog"> <script lang="ts" setup name="ResourceDialog">
import { defineProps, defineEmits,watch,ref, type Ref, computed } from 'vue'; import { computed, type Ref, ref, watch } from 'vue'
import { dialogMiddle } from '@/utils/elementBind' import { dialogMiddle } from '@/utils/elementBind'
import { ElMessage, type FormInstance, type FormItemRule } from 'element-plus' import { ElMessage, type FormInstance, type FormItemRule } from 'element-plus'
import { useDictStore } from '@/stores/modules/dict' import { useDictStore } from '@/stores/modules/dict'
import type { Function } from "@/api/user/interface/function" import type { Function } from '@/api/user/interface/function'
import {addFunction,updateFunction,getFunctionListNoButton} from '@/api/user/function/index' import { addFunction, getFunctionListNoButton, updateFunction } from '@/api/user/function/index'
import IconSelect from '@/components/SelectIcon/index.vue' import IconSelect from '@/components/SelectIcon/index.vue'
const value = ref()
// 树形节点配置 const value = ref()
const defaultProps = { // 树形节点配置
const defaultProps = {
children: 'children', children: 'children',
label: 'name', label: 'name',
value: 'id' value: 'id'
}; }
const functionList = ref<Function.ResFunction[]>([]) const functionList = ref<Function.ResFunction[]>([])
const dictStore = useDictStore() const dictStore = useDictStore()
// 定义弹出组件元信息 // 定义弹出组件元信息
const dialogFormRef = ref() const dialogFormRef = ref()
function useMetaInfo() { function useMetaInfo() {
const dialogVisible = ref(false) const dialogVisible = ref(false)
const titleType = ref('add') const titleType = ref('add')
const formContent = ref<Function.ResFunction>({ const formContent = ref<Function.ResFunction>({
id: '',//资源表Id id: '', //资源表Id
pid:'',//节点0为根节点 pid: '', //节点0为根节点
pids:'',//节点上层所有节点 pids: '', //节点上层所有节点
name: '',//名称 name: '', //名称
code:'',//资源标识 code: '', //资源标识
path:'',//路径 path: '', //路径
component:'', component: '',
icon:undefined as string | undefined, // 图标 icon: undefined as string | undefined, // 图标
sort:100,//排序 sort: 100, //排序
type:0,//资源类型0-菜单、1-按钮、2-公共资源、3-服务间调用资源 type: 0, //资源类型0-菜单、1-按钮、2-公共资源、3-服务间调用资源
remark: '',//权限资源描述 remark: '', //权限资源描述
state:1,//权限资源状态 state: 1 //权限资源状态
}) })
return { dialogVisible, titleType, formContent } return { dialogVisible, titleType, formContent }
} }
const { dialogVisible, titleType, formContent } = useMetaInfo() const { dialogVisible, titleType, formContent } = useMetaInfo()
// 清空formContent // 清空formContent
const resetFormContent = () => { const resetFormContent = () => {
formContent.value = { formContent.value = {
id: '',//资源表Id id: '', //资源表Id
pid:'',//节点0为根节点 pid: '', //节点0为根节点
pids:'',//节点上层所有节点 pids: '', //节点上层所有节点
name: '',//名称 name: '', //名称
code:'',//资源标识 code: '', //资源标识
path:'',//路径 path: '', //路径
component:'', component: '',
icon:undefined,//图标 icon: undefined, //图标
sort:100,//排序 sort: 100, //排序
type:0,//资源类型0-菜单、1-按钮、2-公共资源、3-服务间调用资源 type: 0, //资源类型0-菜单、1-按钮、2-公共资源、3-服务间调用资源
remark:'',//权限资源描述 remark: '', //权限资源描述
state:1,//权限资源状态 state: 1 //权限资源状态
} }
} }
let dialogTitle = computed(() => { let dialogTitle = computed(() => {
return titleType.value === 'add' ? '新增菜单' : '编辑菜单' return titleType.value === 'add' ? '新增菜单' : '编辑菜单'
}) })
// 定义规则
const formRuleRef = ref<FormInstance>()
const rules: Ref<Record<string, Array<FormItemRule>>> = ref({
name: [{ required: true, trigger: 'blur', message: '菜单名称必填!' }],
code: [{ required: true, trigger: 'blur', message: '编码必填!' }]
})
// 定义规则 watch(
const formRuleRef = ref<FormInstance>() () => formContent.value.type,
const rules : Ref<Record<string, Array<FormItemRule>>> = ref({ newVal => {
name :[{required:true,trigger:'blur',message:'菜单名称必填!'}], if (newVal === 1) {
code :[{required:true,trigger:'blur',message:'编码必填!'}] // 选择按钮时,路由地址和组件地址无需校验
}) rules.value.path = []
rules.value.component = []
} else {
// 其他情况下,路由地址和组件地址需要校验
rules.value.path = [{ required: true, trigger: 'blur', message: '路由地址必填!' }]
rules.value.component = [{ required: true, trigger: 'blur', message: '组件地址必填!' }]
}
}
)
watch(() => formContent.value.type, (newVal) => { // 关闭弹窗
if (newVal === 1) {
// 选择按钮时,路由地址和组件地址无需校验
rules.value.path = [];
rules.value.component = [];
} else {
// 其他情况下,路由地址和组件地址需要校验
rules.value.path = [{ required: true, trigger: 'blur', message: '路由地址必填!' }];
rules.value.component = [{ required: true, trigger: 'blur', message: '组件地址必填!' }];
}
});
// 关闭弹窗
const close = () => { const close = () => {
dialogVisible.value = false dialogVisible.value = false
// 清空dialogForm中的值 // 清空dialogForm中的值
resetFormContent() resetFormContent()
// 重置表单 // 重置表单
dialogFormRef.value?.resetFields() dialogFormRef.value?.resetFields()
} }
// 计算属性,用于控制显示的 pid // 计算属性,用于控制显示的 pid
const displayPid = computed({ const displayPid = computed({
get: () => { get: () => {
return formContent.value.pid === '0' ? '' : formContent.value.pid; return formContent.value.pid === '0' ? '' : formContent.value.pid
}, },
set: (value) => { set: value => {
formContent.value.pid = value; formContent.value.pid = value
} }
}); })
// 保存数据
// 保存数据 const save = () => {
const save = () => {
try { try {
dialogFormRef.value?.validate(async (valid: boolean) => { dialogFormRef.value?.validate(async (valid: boolean) => {
if (formContent.value.pid === undefined || formContent.value.pid === null || formContent.value.pid === '') {
if (formContent.value.pid === undefined || formContent.value.pid === null || formContent.value.pid === '') { formContent.value.pid = '0'
formContent.value.pid = '0'; }
} if (
if (formContent.value.pids === undefined || formContent.value.pids === null || formContent.value.pids === '') { formContent.value.pids === undefined ||
formContent.value.pids = '0'; formContent.value.pids === null ||
} formContent.value.pids === ''
if (valid) { ) {
if (formContent.value.id) { formContent.value.pids = '0'
await updateFunction(formContent.value); }
} else { if (valid) {
await addFunction(formContent.value); if (formContent.value.id) {
} await updateFunction(formContent.value)
ElMessage.success({ message: `${dialogTitle.value}成功!` }) } else {
close() await addFunction(formContent.value)
// 刷新表格 }
await props.refreshTable!() ElMessage.success({ message: `${dialogTitle.value}成功!` })
close()
} // 刷新表格
}) await props.refreshTable!()
}
})
} catch (err) { } catch (err) {
console.error('验证过程中出现错误', err) console.error('验证过程中出现错误', err)
} }
} }
// 打开弹窗,可能是新增,也可能是编辑 // 打开弹窗,可能是新增,也可能是编辑
const open = async (sign: string, data: Function.ResFunction) => { const open = async (sign: string, data: Function.ResFunction) => {
// 重置表单 // 重置表单
dialogFormRef.value?.resetFields() dialogFormRef.value?.resetFields()
const response = await getFunctionListNoButton() const response = await getFunctionListNoButton()
functionList.value = response.data as unknown as Function.ResFunction[] functionList.value = response.data as unknown as Function.ResFunction[]
titleType.value = sign titleType.value = sign
dialogVisible.value = true dialogVisible.value = true
rules.value.path = [{ required: true, trigger: 'blur', message: '路由地址必填!' }]; rules.value.path = [{ required: true, trigger: 'blur', message: '路由地址必填!' }]
rules.value.component = [{ required: true, trigger: 'blur', message: '组件地址必填!' }]; rules.value.component = [{ required: true, trigger: 'blur', message: '组件地址必填!' }]
if (formContent.value.pid ==='0') { if (formContent.value.pid === '0') {
formContent.value.pid = ''; formContent.value.pid = ''
} }
if (data.id) { if (data.id) {
formContent.value = { ...data } formContent.value = { ...data }
} else { } else {
resetFormContent() resetFormContent()
} }
} }
// 对外映射 // 对外映射
defineExpose({ open }) defineExpose({ open })
const props = defineProps<{ const props = defineProps<{
refreshTable: (() => Promise<void>) | undefined; refreshTable: (() => Promise<void>) | undefined
}>() }>()
</script> </script>

View File

@@ -1,348 +1,386 @@
<template> <template>
<div class="table-container table-main"> <div class="table-container table-main">
<el-table :data="tableData" <el-table
:header-cell-style="{ textAlign: 'center' } " :data="tableData"
:cell-style="{ textAlign: 'center' }" :header-cell-style="{ textAlign: 'center' }"
style="width: 100%" :cell-style="{ textAlign: 'center' }"
max-height="400px" style="width: 100%"
:span-method="objectSpanMethod"> max-height="400px"
<el-table-column prop="monitorNum" label="监测点序号" width="80"/> :span-method="objectSpanMethod"
<el-table-column prop="desc" label="描述" width="90"/> >
<el-table-column label="电压通道" > <el-table-column prop="monitorNum" label="监测点序号" width="80" />
<el-table-column prop="Ua" label="A相"> <el-table-column prop="desc" label="描述" width="90" />
<el-table-column prop="aVuData" label="被检值(V)" width="100px"> <el-table-column label="电压通道">
<template #default="scope"> <el-table-column prop="Ua" label="A相">
<el-icon v-if="scope.row.aVuData === '—'&& scope.row.loading" class="loading-box"> <el-table-column prop="aVuData" label="被检值(V)" width="100px">
<template #default="scope">
<el-icon v-if="scope.row.aVuData === '—' && scope.row.loading" class="loading-box">
<el-icon-loading /> <el-icon-loading />
</el-icon> </el-icon>
<span v-else> <span v-else>
{{ scope.row.aVuData }} {{ scope.row.aVuData }}
</span> </span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="aVuXi" label="检测结果" width="90px"> <el-table-column prop="aVuXi" label="检测结果" width="90px">
<template #default="scope"> <template #default="scope">
<el-tooltip <el-tooltip
v-if="scope.row.aVuXi === '不合格'" v-if="scope.row.aVuXi === '不合格'"
class="item" class="item"
effect="dark" effect="dark"
placement="bottom-start" placement="bottom-start"
> >
<template #content> <template #content>
误差范围 {{ (-0.001 * props.curV).toFixed(4) + 'V~' + (0.001 * props.curV).toFixed(4)+ 'V'}}<br/> 误差范围
误差值{{ scope.row.aV + 'V'}} {{
(-0.001 * props.curV).toFixed(4) + 'V~' + (0.001 * props.curV).toFixed(4) + 'V'
}}
<br />
误差值{{ scope.row.aV + 'V' }}
</template> </template>
<el-tag type="danger" class="tooltip-content"> <el-tag type="danger" class="tooltip-content">
{{ scope.row.aVuXi }} {{ scope.row.aVuXi }}
</el-tag> </el-tag>
</el-tooltip> </el-tooltip>
<el-tooltip <el-tooltip
v-else-if="scope.row.aVuXi === '合格'" v-else-if="scope.row.aVuXi === '合格'"
class="item" class="item"
effect="dark" effect="dark"
placement="bottom-start" placement="bottom-start"
> >
<template #content> <template #content>
误差范围 {{ (-0.001 * props.curV).toFixed(4) + 'V~' + (0.001 * props.curV).toFixed(4)+ 'V'}}<br/> 误差范围
误差值{{ scope.row.aV + 'V'}} {{
(-0.001 * props.curV).toFixed(4) + 'V~' + (0.001 * props.curV).toFixed(4) + 'V'
}}
<br />
误差值{{ scope.row.aV + 'V' }}
</template> </template>
<el-tag type="success" class="tooltip-content">{{ scope.row.aVuXi }}</el-tag> <el-tag type="success" class="tooltip-content">{{ scope.row.aVuXi }}</el-tag>
</el-tooltip> </el-tooltip>
<!-- <el-tag type="danger" v-if="scope.row.aVuXi === '不合格'"> <!-- <el-tag type="danger" v-if="scope.row.aVuXi === '不合格'">
{{ scope.row.aVuXi }} {{ scope.row.aVuXi }}
</el-tag> --> </el-tag> -->
<el-icon v-else-if="scope.row.aVuXi === '—'&& scope.row.loading" class="loading-box"> <el-icon v-else-if="scope.row.aVuXi === '—' && scope.row.loading" class="loading-box">
<el-icon-loading /> <el-icon-loading />
</el-icon> </el-icon>
<!-- <span v-else> <!-- <span v-else>
{{ scope.row.aVuXi }} {{ scope.row.aVuXi }}
</span> --> </span> -->
</template> </template>
</el-table-column> </el-table-column>
</el-table-column> </el-table-column>
<el-table-column prop="Ub" label="B相"> <el-table-column prop="Ub" label="B相">
<el-table-column prop="bVuData" label="被检值(V)" width="100px"> <el-table-column prop="bVuData" label="被检值(V)" width="100px">
<template #default="scope"> <template #default="scope">
<el-icon v-if="scope.row.bVuData === '—'&& scope.row.loading" class="loading-box"> <el-icon v-if="scope.row.bVuData === '—' && scope.row.loading" class="loading-box">
<el-icon-loading /> <el-icon-loading />
</el-icon> </el-icon>
<span v-else> <span v-else>
{{ scope.row.bVuData }} {{ scope.row.bVuData }}
</span> </span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="bVuXi" label="检测结果" width="90px"> <el-table-column prop="bVuXi" label="检测结果" width="90px">
<template #default="scope"> <template #default="scope">
<el-tooltip <el-tooltip
v-if="scope.row.bVuXi === '不合格'" v-if="scope.row.bVuXi === '不合格'"
class="item" class="item"
effect="dark" effect="dark"
placement="bottom-start" placement="bottom-start"
> >
<template #content> <template #content>
误差范围 {{ (-0.001 * props.curV).toFixed(4) + 'V~' + (0.001 * props.curV).toFixed(4)+ 'V'}}<br/> 误差范围
误差值{{ scope.row.bV + 'V'}} {{
(-0.001 * props.curV).toFixed(4) + 'V~' + (0.001 * props.curV).toFixed(4) + 'V'
}}
<br />
误差值{{ scope.row.bV + 'V' }}
</template> </template>
<el-tag type="danger" class="tooltip-content"> <el-tag type="danger" class="tooltip-content">
{{ scope.row.bVuXi }} {{ scope.row.bVuXi }}
</el-tag> </el-tag>
</el-tooltip> </el-tooltip>
<el-tooltip <el-tooltip
v-else-if="scope.row.bVuXi === '合格'" v-else-if="scope.row.bVuXi === '合格'"
class="item" class="item"
effect="dark" effect="dark"
placement="bottom-start" placement="bottom-start"
> >
<template #content> <template #content>
误差范围 {{ (-0.001 * props.curV).toFixed(4) + 'V~' + (0.001 * props.curV).toFixed(4)+ 'V'}}<br/> 误差范围
误差值{{ scope.row.bV + 'V'}} {{
(-0.001 * props.curV).toFixed(4) + 'V~' + (0.001 * props.curV).toFixed(4) + 'V'
}}
<br />
误差值{{ scope.row.bV + 'V' }}
</template> </template>
<el-tag type="success" class="tooltip-content">{{ scope.row.bVuXi }}</el-tag> <el-tag type="success" class="tooltip-content">{{ scope.row.bVuXi }}</el-tag>
</el-tooltip> </el-tooltip>
<el-icon v-else-if="scope.row.bVuXi === '—'&& scope.row.loading" class="loading-box"> <el-icon v-else-if="scope.row.bVuXi === '—' && scope.row.loading" class="loading-box">
<el-icon-loading /> <el-icon-loading />
</el-icon> </el-icon>
</template> </template>
</el-table-column> </el-table-column>
</el-table-column> </el-table-column>
<el-table-column prop="Uc" label="C相"> <el-table-column prop="Uc" label="C相">
<el-table-column prop="cVuData" label="被检值(V)" width="100px"> <el-table-column prop="cVuData" label="被检值(V)" width="100px">
<template #default="scope"> <template #default="scope">
<el-icon v-if="scope.row.cVuData === '—'&& scope.row.loading" class="loading-box"> <el-icon v-if="scope.row.cVuData === '—' && scope.row.loading" class="loading-box">
<el-icon-loading /> <el-icon-loading />
</el-icon> </el-icon>
<span v-else> <span v-else>
{{ scope.row.cVuData }} {{ scope.row.cVuData }}
</span> </span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="cVuXi" label="检测结果" width="90px"> <el-table-column prop="cVuXi" label="检测结果" width="90px">
<template #default="scope"> <template #default="scope">
<el-tooltip <el-tooltip
v-if="scope.row.cVuXi === '不合格'" v-if="scope.row.cVuXi === '不合格'"
class="item" class="item"
effect="dark" effect="dark"
placement="bottom-start" placement="bottom-start"
> >
<template #content> <template #content>
误差范围 {{ (-0.001 * props.curV).toFixed(4) + 'V~' + (0.001 * props.curV).toFixed(4)+ 'V'}}<br/> 误差范围
误差值{{ scope.row.cV + 'V'}} {{
(-0.001 * props.curV).toFixed(4) + 'V~' + (0.001 * props.curV).toFixed(4) + 'V'
}}
<br />
误差值{{ scope.row.cV + 'V' }}
</template> </template>
<el-tag type="danger" class="tooltip-content"> <el-tag type="danger" class="tooltip-content">
{{ scope.row.cVuXi }} {{ scope.row.cVuXi }}
</el-tag> </el-tag>
</el-tooltip> </el-tooltip>
<el-tooltip <el-tooltip
v-else-if="scope.row.cVuXi === '合格'" v-else-if="scope.row.cVuXi === '合格'"
class="item" class="item"
effect="dark" effect="dark"
placement="bottom-start" placement="bottom-start"
> >
<template #content> <template #content>
误差范围 {{ (-0.001 * props.curV).toFixed(4) + 'V~' + (0.001 * props.curV).toFixed(4) + 'V'}}<br/> 误差范围
误差值{{ scope.row.cV + 'V'}} {{
(-0.001 * props.curV).toFixed(4) + 'V~' + (0.001 * props.curV).toFixed(4) + 'V'
}}
<br />
误差值{{ scope.row.cV + 'V' }}
</template> </template>
<el-tag type="success" class="tooltip-content">{{ scope.row.cVuXi }}</el-tag> <el-tag type="success" class="tooltip-content">{{ scope.row.cVuXi }}</el-tag>
</el-tooltip> </el-tooltip>
<el-icon v-else-if="scope.row.cVuXi === '—'&& scope.row.loading" class="loading-box"> <el-icon v-else-if="scope.row.cVuXi === '—' && scope.row.loading" class="loading-box">
<el-icon-loading /> <el-icon-loading />
</el-icon> </el-icon>
</template> </template>
</el-table-column>
</el-table-column>
</el-table-column> </el-table-column>
<el-table-column label="电流通道" > </el-table-column>
<el-table-column prop="Ia" label="A相"> </el-table-column>
<el-table-column prop="aIeData" label="被检值(A)" width="100px"> <el-table-column label="电流通道">
<template #default="scope"> <el-table-column prop="Ia" label="A相">
<el-icon v-if="scope.row.aIeData === '—'&& scope.row.loading" class="loading-box"> <el-table-column prop="aIeData" label="被检值(A)" width="100px">
<template #default="scope">
<el-icon v-if="scope.row.aIeData === '—' && scope.row.loading" class="loading-box">
<el-icon-loading /> <el-icon-loading />
</el-icon> </el-icon>
<span v-else> <span v-else>
{{ scope.row.aIeData }} {{ scope.row.aIeData }}
</span> </span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="aIeXi" label="检测结果" width="90px"> <el-table-column prop="aIeXi" label="检测结果" width="90px">
<template #default="scope"> <template #default="scope">
<el-tooltip <el-tooltip
v-if="scope.row.aIeXi === '不合格'" v-if="scope.row.aIeXi === '不合格'"
class="item" class="item"
effect="dark" effect="dark"
placement="bottom-start" placement="bottom-start"
> >
<template #content> <template #content>
误差范围 {{-0.5 + "%~" +0.5 + "%" }}<br/> 误差范围 {{ -0.5 + '%~' + 0.5 + '%' }}
误差值{{ scope.row.aI + '%'}} <br />
误差值{{ scope.row.aI + '%' }}
</template> </template>
<el-tag type="danger" class="tooltip-content"> <el-tag type="danger" class="tooltip-content">
{{ scope.row.aIeXi }} {{ scope.row.aIeXi }}
</el-tag> </el-tag>
</el-tooltip> </el-tooltip>
<el-tooltip <el-tooltip
v-else-if="scope.row.aIeXi === '合格'" v-else-if="scope.row.aIeXi === '合格'"
class="item" class="item"
effect="dark" effect="dark"
placement="bottom-start" placement="bottom-start"
> >
<template #content> <template #content>
误差范围 {{ -0.5 + "%~" +0.5 + "%" }}<br/> 误差范围 {{ -0.5 + '%~' + 0.5 + '%' }}
误差值{{ scope.row.aI + '%'}} <br />
误差值{{ scope.row.aI + '%' }}
</template> </template>
<el-tag type="success" class="tooltip-content">{{ scope.row.aIeXi }}</el-tag> <el-tag type="success" class="tooltip-content">{{ scope.row.aIeXi }}</el-tag>
</el-tooltip> </el-tooltip>
<el-icon v-else-if="scope.row.aIeXi === '—'&& scope.row.loading" class="loading-box"> <el-icon v-else-if="scope.row.aIeXi === '—' && scope.row.loading" class="loading-box">
<el-icon-loading /> <el-icon-loading />
</el-icon> </el-icon>
</template> </template>
</el-table-column> </el-table-column>
</el-table-column> </el-table-column>
<el-table-column prop="Ib" label="B相"> <el-table-column prop="Ib" label="B相">
<el-table-column prop="bIeData" label="被检值(A)" width="100px"> <el-table-column prop="bIeData" label="被检值(A)" width="100px">
<template #default="scope"> <template #default="scope">
<el-icon v-if="scope.row.bIeData === '—'&& scope.row.loading" class="loading-box"> <el-icon v-if="scope.row.bIeData === '—' && scope.row.loading" class="loading-box">
<el-icon-loading /> <el-icon-loading />
</el-icon> </el-icon>
<span v-else> <span v-else>
{{ scope.row.bIeData }} {{ scope.row.bIeData }}
</span> </span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="bIeXi" label="检测结果" width="90px"> <el-table-column prop="bIeXi" label="检测结果" width="90px">
<template #default="scope"> <template #default="scope">
<el-tooltip <el-tooltip
v-if="scope.row.bIeXi === '不合格'" v-if="scope.row.bIeXi === '不合格'"
class="item" class="item"
effect="dark" effect="dark"
placement="bottom-start" placement="bottom-start"
> >
<template #content> <template #content>
误差范围 {{ -0.5 + "%~" +0.5 + "%" }}<br/> 误差范围 {{ -0.5 + '%~' + 0.5 + '%' }}
误差值{{ scope.row.bI + '%'}} <br />
误差值{{ scope.row.bI + '%' }}
</template> </template>
<el-tag type="danger" class="tooltip-content"> <el-tag type="danger" class="tooltip-content">
{{ scope.row.bIeXi }} {{ scope.row.bIeXi }}
</el-tag> </el-tag>
</el-tooltip> </el-tooltip>
<el-tooltip <el-tooltip
v-else-if="scope.row.bIeXi === '合格'" v-else-if="scope.row.bIeXi === '合格'"
class="item" class="item"
effect="dark" effect="dark"
placement="bottom-start" placement="bottom-start"
> >
<template #content> <template #content>
误差范围 {{ -0.5 + "%~" +0.5 + "%" }}<br/> 误差范围 {{ -0.5 + '%~' + 0.5 + '%' }}
误差值{{ scope.row.bI + '%'}} <br />
误差值{{ scope.row.bI + '%' }}
</template> </template>
<el-tag type="success" class="tooltip-content">{{ scope.row.bIeXi }}</el-tag> <el-tag type="success" class="tooltip-content">{{ scope.row.bIeXi }}</el-tag>
</el-tooltip> </el-tooltip>
<el-icon v-else-if="scope.row.bIeXi === '—'&& scope.row.loading" class="loading-box"> <el-icon v-else-if="scope.row.bIeXi === '—' && scope.row.loading" class="loading-box">
<el-icon-loading /> <el-icon-loading />
</el-icon> </el-icon>
</template> </template>
</el-table-column> </el-table-column>
</el-table-column> </el-table-column>
<el-table-column prop="Ic" label="C相"> <el-table-column prop="Ic" label="C相">
<el-table-column prop="cIeData" label="被检值(A)" width="100px"> <el-table-column prop="cIeData" label="被检值(A)" width="100px">
<template #default="scope"> <template #default="scope">
<el-icon v-if="scope.row.cIeData === '—'&& scope.row.loading" class="loading-box"> <el-icon v-if="scope.row.cIeData === '—' && scope.row.loading" class="loading-box">
<el-icon-loading /> <el-icon-loading />
</el-icon> </el-icon>
<span v-else> <span v-else>
{{ scope.row.cIeData }} {{ scope.row.cIeData }}
</span> </span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="cIeXi" label="检测结果" width="90px"> <el-table-column prop="cIeXi" label="检测结果" width="90px">
<template #default="scope"> <template #default="scope">
<el-tooltip <el-tooltip
v-if="scope.row.cIeXi === '不合格'" v-if="scope.row.cIeXi === '不合格'"
class="item" class="item"
effect="dark" effect="dark"
placement="bottom-start" placement="bottom-start"
> >
<template #content> <template #content>
误差范围 {{ -0.5 + "%~" +0.5 + "%" }}<br/> 误差范围 {{ -0.5 + '%~' + 0.5 + '%' }}
误差值{{ scope.row.cI + '%'}} <br />
误差值{{ scope.row.cI + '%' }}
</template> </template>
<el-tag type="danger" class="tooltip-content"> <el-tag type="danger" class="tooltip-content">
{{ scope.row.cIeXi }} {{ scope.row.cIeXi }}
</el-tag> </el-tag>
</el-tooltip> </el-tooltip>
<el-tooltip <el-tooltip
v-else-if="scope.row.cIeXi === '合格'" v-else-if="scope.row.cIeXi === '合格'"
class="item" class="item"
effect="dark" effect="dark"
placement="bottom-start" placement="bottom-start"
> >
<template #content> <template #content>
误差范围 {{ -0.5 + "%~" +0.5 + "%" }}<br/> 误差范围 {{ -0.5 + '%~' + 0.5 + '%' }}
误差值{{ scope.row.cI + '%'}} <br />
误差值{{ scope.row.cI + '%' }}
</template> </template>
<el-tag type="success" class="tooltip-content">{{ scope.row.cIeXi }}</el-tag> <el-tag type="success" class="tooltip-content">{{ scope.row.cIeXi }}</el-tag>
</el-tooltip> </el-tooltip>
<el-icon v-else-if="scope.row.cIeXi === '—'&& scope.row.loading" class="loading-box"> <el-icon v-else-if="scope.row.cIeXi === '—' && scope.row.loading" class="loading-box">
<el-icon-loading /> <el-icon-loading />
</el-icon> </el-icon>
</template> </template>
</el-table-column>
</el-table-column>
</el-table-column> </el-table-column>
</el-table> </el-table-column>
</div> </el-table-column>
</el-table>
</div>
</template> </template>
<script lang="ts" setup name="ErrorSystemDialog"> <script lang="ts" setup name="ErrorSystemDialog">
import { defineProps, type PropType } from 'vue'; import { ElIcon, ElTag } from 'element-plus'
import { ElIcon, ElLoading, ElTag } from 'element-plus'; import type { ChannelsTest } from '@/api/home/interface/channelsTest'
import type { ChannelsTest } from '@/api/home/interface/channelsTest';
import { number } from 'echarts';
interface Props { interface Props {
tableData: ChannelsTest.CoefficientVO[]; tableData: ChannelsTest.CoefficientVO[]
big_V_loading: boolean; big_V_loading: boolean
curV: number; curV: number
} }
const props = withDefaults(defineProps<Props>(), { const props = withDefaults(defineProps<Props>(), {
tableData: () => [], tableData: () => [],
big_V_loading: false, big_V_loading: false,
curV: 0, curV: 0
}); })
function objectSpanMethod({ row, column, rowIndex, columnIndex }: { row: any, column: any, rowIndex: number, columnIndex: number }) { function objectSpanMethod({
row,
column,
rowIndex,
columnIndex
}: {
row: any
column: any
rowIndex: number
columnIndex: number
}) {
if (columnIndex === 0) { if (columnIndex === 0) {
if (rowIndex % 4 === 0) { if (rowIndex % 4 === 0) {
return { return {
rowspan: 4, rowspan: 4,
colspan: 1, colspan: 1
}; }
} else { } else {
return { return {
rowspan: 0, rowspan: 0,
colspan: 0, colspan: 0
}; }
} }
} }
if (columnIndex === 1) { if (columnIndex === 1) {
if (rowIndex % 2 === 0) { if (rowIndex % 2 === 0) {
return { return {
rowspan: 2, rowspan: 2,
colspan: 1, colspan: 1
}; }
} else { } else {
return { return {
rowspan: 0, rowspan: 0,
colspan: 0, colspan: 0
}; }
} }
} }
} }
</script>
</script> <style scoped>
<style scoped>
.form-grid { .form-grid {
display: flex; display: flex;
flex-direction: row; /* 横向排列 */ flex-direction: row; /* 横向排列 */
@@ -364,40 +402,40 @@ const props = withDefaults(defineProps<Props>(), {
margin-bottom: 20px; /* 添加底部边距 */ margin-bottom: 20px; /* 添加底部边距 */
} }
.el-table th, .el-table td { .el-table th,
text-align: center; /* 所有单元格文字居中 */ .el-table td {
text-align: center; /* 所有单元格文字居中 */
} }
.table-container { .table-container {
max-height: 400px; /* 根据需要调整高度 */ max-height: 400px; /* 根据需要调整高度 */
overflow-y: auto; /* 允许垂直滚动 */ overflow-y: auto; /* 允许垂直滚动 */
overflow-x: hidden; /* 隐藏水平滚动条 */ overflow-x: hidden; /* 隐藏水平滚动条 */
} }
/* 确保 el-icon-loading 的动画效果没有被覆盖 */ /* 确保 el-icon-loading 的动画效果没有被覆盖 */
.loading-box { .loading-box {
animation: rotate 2s linear infinite; animation: rotate 2s linear infinite;
} }
.icon-margin { .icon-margin {
margin-left: 0px; margin-left: 0px;
} }
.icon-align { .icon-align {
vertical-align: 0px; vertical-align: 0px;
} }
.tooltip-content { .tooltip-content {
cursor: pointer; cursor: pointer;
} }
@keyframes rotate { @keyframes rotate {
from { from {
transform: rotate(0deg); transform: rotate(0deg);
} }
to { to {
transform: rotate(360deg); transform: rotate(360deg);
} }
} }
</style> </style>

View File

@@ -18,7 +18,7 @@
v-model="formContent.errorSysId" v-model="formContent.errorSysId"
placeholder="请选择误差体系" placeholder="请选择误差体系"
autocomplete="off" autocomplete="off"
@change="handleErrorSysChange" @change="handleErrorSysChange"
> >
<el-option <el-option
v-for="option in pqErrorList" v-for="option in pqErrorList"
@@ -39,8 +39,13 @@
<el-option v-for="item in chnList" :key="item" :label="item" :value="item" /> <el-option v-for="item in chnList" :key="item" :label="item" :value="item" />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="检测次数" > <el-form-item label="检测次数">
<el-select v-model="formContent.num" clearable @change="handleNumChange" :disabled="sourceKey == 1"> <el-select
v-model="formContent.num"
clearable
@change="handleNumChange"
:disabled="sourceKey == 1"
>
<el-option <el-option
v-for="item in chnMapList[formContent.chnNum]" v-for="item in chnMapList[formContent.chnNum]"
:key="item" :key="item"
@@ -67,48 +72,48 @@
node-key="id" node-key="id"
ref="treeRef" ref="treeRef"
@node-click="handleNodeClick" @node-click="handleNodeClick"
> ></el-tree>
</el-tree>
</div> </div>
<div class="content-right"> <div class="content-right">
<div class="content-right-title"> <div class="content-right-title">
<div style="width: 840px"> <div style="width: 840px">
<span class="content-right-title-text">当前检测项目</span> <span class="content-right-title-text">当前检测项目</span>
<!-- 当code为'wave_data'时显示下拉框 --> <!-- 当code为'wave_data'时显示下拉框 -->
<el-select <el-select
v-if="isWaveData" v-if="isWaveData"
v-model="selectedScriptName" v-model="selectedScriptName"
style="width: 200px" style="width: 200px"
@change="handleScriptNameChange" @change="handleScriptNameChange"
> >
<el-option <el-option
v-for="item in scriptNameOptions" v-for="item in scriptNameOptions"
:key="item.value" :key="item.value"
:label="item.label" :label="item.label"
:value="item.value" :value="item.value"
/> />
</el-select> </el-select>
<!-- 否则显示原来的文本 --> <!-- 否则显示原来的文本 -->
<span v-else style="color: var(--el-color-primary)">{{ rowList.scriptName }}</span> <span v-else style="color: var(--el-color-primary)">{{ rowList.scriptName }}</span>
</div> </div>
<el-form-item <el-form-item
style="margin: 0 auto; margin-bottom: 0px !important; width: 200px; position: absolute; left: 50%; transform: translateX(-50%);" style="
label="录波次数" margin: 0 auto;
margin-bottom: 0px !important;
width: 200px;
position: absolute;
left: 50%;
transform: translateX(-50%);
"
label="录波次数"
v-if="isWaveData" v-if="isWaveData"
> >
<el-select v-model="waveNumber" @change="handleWaveNumberChange"> <el-select v-model="waveNumber" @change="handleWaveNumberChange">
<el-option <el-option v-for="i in waveNumCount" :key="i" :label="i" :value="i" />
v-for="i in waveNumCount"
:key="i"
:label="i"
:value="i"
/>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item <el-form-item
style="margin-left: 280px; margin-bottom: 0px !important; width: 300px" style="margin-left: 280px; margin-bottom: 0px !important; width: 300px"
label="测试项" label="测试项"
> >
<el-select v-model="currentCheckItem"> <el-select v-model="currentCheckItem">
<el-option <el-option
@@ -128,7 +133,6 @@
:currentCheckItem="currentCheckItem" :currentCheckItem="currentCheckItem"
:currentScriptTypeName="currentScriptTypeName" :currentScriptTypeName="currentScriptTypeName"
v-if="activeTab === 'resultTab'" v-if="activeTab === 'resultTab'"
/> />
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="原始数据" name="rawDataTab"> <el-tab-pane label="原始数据" name="rawDataTab">
@@ -148,7 +152,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { dialogBig } from '@/utils/elementBind' import { dialogBig } from '@/utils/elementBind'
import { reactive, ref, watch, computed, nextTick } from 'vue' import { computed, reactive, ref } from 'vue'
import CompareDataCheckResultTable from './compareDataCheckResultTable.vue' import CompareDataCheckResultTable from './compareDataCheckResultTable.vue'
import CompareDataCheckRawDataTable from './compareDataCheckRawDataTable.vue' import CompareDataCheckRawDataTable from './compareDataCheckRawDataTable.vue'
import { CheckData } from '@/api/check/interface' import { CheckData } from '@/api/check/interface'
@@ -157,16 +161,20 @@ import { Histogram, Postcard } from '@element-plus/icons-vue'
import { getPqErrSysList } from '@/api/plan/plan' import { getPqErrSysList } from '@/api/plan/plan'
import { useModeStore } from '@/stores/modules/mode' // 引入模式 store import { useModeStore } from '@/stores/modules/mode' // 引入模式 store
import { useDictStore } from '@/stores/modules/dict' import { useDictStore } from '@/stores/modules/dict'
import { getContrastFormContent, getContrastResult, getScriptList,reCalculate ,changeErrorSystem,deleteTempTable} from '@/api/check/test' import {
changeErrorSystem,
deleteTempTable,
getContrastFormContent,
getContrastResult,
getScriptList,
reCalculate
} from '@/api/check/test'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import {ResultEnum} from "@/enums/httpEnum"; import { ResultEnum } from '@/enums/httpEnum'
const { appendToBody } = withDefaults( const { appendToBody = true } = defineProps<{
defineProps<{ appendToBody: boolean
appendToBody: boolean }>()
}>(),
{ appendToBody: true }
)
const checkStore = useCheckStore() const checkStore = useCheckStore()
const modeStore = useModeStore() const modeStore = useModeStore()
@@ -192,7 +200,7 @@ const selectedScriptName = ref('')
const pattern = ref('') const pattern = ref('')
// 添加以下内容 // 添加以下内容
const isWaveData = ref(false) const isWaveData = ref(false)
const scriptNameOptions = ref<{label: string, value: string}[]>([]) const scriptNameOptions = ref<{ label: string; value: string }[]>([])
// 表单数据 // 表单数据
const formContent = reactive<CheckData.DataCheck>({ const formContent = reactive<CheckData.DataCheck>({
@@ -230,10 +238,9 @@ const currentRawTableData = computed(() => {
return Array.isArray(data) ? data : [] return Array.isArray(data) ? data : []
}) })
const open = async (row: any, chnNum: string, deviceId: string | null, source: number) => { const open = async (row: any, chnNum: string, deviceId: string | null, source: number) => {
isWaveData.value = false isWaveData.value = false
pattern.value = dictStore.getDictData('Pattern').find(item => item.name === modeStore.currentMode)?.id ?? ''//获取数据字典中对应的id pattern.value = dictStore.getDictData('Pattern').find(item => item.name === modeStore.currentMode)?.id ?? '' //获取数据字典中对应的id
rowList.value = {} rowList.value = {}
formContent.deviceId = deviceId || '' formContent.deviceId = deviceId || ''
formContent.chnNum = chnNum formContent.chnNum = chnNum
@@ -241,14 +248,14 @@ const open = async (row: any, chnNum: string, deviceId: string | null, source: n
// 获取基本信息 // 获取基本信息
await getBasicInformation(row.scriptType) await getBasicInformation(row.scriptType)
if (source == 1) { if (source == 1) {
// 正式检测进入页面 - 创建新的对象避免引用共享 // 正式检测进入页面 - 创建新的对象避免引用共享
rowList.value = { rowList.value = {
scriptName: row.scriptName, scriptName: row.scriptName,
scriptType: row.scriptType, scriptType: row.scriptType,
// 复制其他需要的属性 // 复制其他需要的属性
devices: row.devices ? [...row.devices] : [] devices: row.devices ? [...row.devices] : []
} }
} }
// 检测数据查询进入---不区分检测数据查询和正式检测 // 检测数据查询进入---不区分检测数据查询和正式检测
await initScriptData() await initScriptData()
visible.value = true visible.value = true
@@ -259,16 +266,15 @@ const open = async (row: any, chnNum: string, deviceId: string | null, source: n
// 获取误差体系 // 获取误差体系
let { data: resPqErrorList } = await getPqErrSysList() let { data: resPqErrorList } = await getPqErrSysList()
Object.assign(pqErrorList, resPqErrorList) Object.assign(pqErrorList, resPqErrorList)
initGetResult() initGetResult()
} }
const initGetResult = async () => { const initGetResult = async () => {
// 判断是否为录波数据 // 判断是否为录波数据
const isLuoboData = (sourceKey.value == 1 && rowList.value.scriptName == "录波") || const isLuoboData =
(sourceKey.value == 2 && scriptData.value[0]?.code == "wave_data"); (sourceKey.value == 1 && rowList.value.scriptName == '录波数据') ||
(sourceKey.value == 2 && scriptData.value[0]?.code == 'wave_data')
if (isLuoboData) { if (isLuoboData) {
isWaveData.value = true isWaveData.value = true
// 设置录波数据相关的选项 // 设置录波数据相关的选项
@@ -276,7 +282,7 @@ const initGetResult = async () => {
label: item.scriptName, label: item.scriptName,
value: item.scriptName value: item.scriptName
})) }))
// 默认选中第一个选项 // 默认选中第一个选项
if (scriptNameOptions.value.length > 0) { if (scriptNameOptions.value.length > 0) {
selectedScriptName.value = scriptNameOptions.value[0].value selectedScriptName.value = scriptNameOptions.value[0].value
@@ -293,7 +299,6 @@ const initGetResult = async () => {
} }
} }
// 查询大项树 // 查询大项树
const initScriptData = async () => { const initScriptData = async () => {
let response: any = await getScriptList({ let response: any = await getScriptList({
@@ -301,7 +306,7 @@ const initScriptData = async () => {
chnNum: formContent.chnNum, chnNum: formContent.chnNum,
num: formContent.num num: formContent.num
}) })
// 格式化脚本数据 // 格式化脚本数据
let temp = response.data.map((item: any) => { let temp = response.data.map((item: any) => {
return { return {
@@ -314,11 +319,10 @@ const initScriptData = async () => {
scriptData.value = temp scriptData.value = temp
// 查找code为"录波"的项 // 查找code为"录波"的项
let luoboItem = response.data.find((item: any) => item.code === 'wave_data'); let luoboItem = response.data.find((item: any) => item.code === 'wave_data')
// 如果找到了"录波"项则使用其subitems否则使用空数组 // 如果找到了"录波"项则使用其subitems否则使用空数组
let temp2 = []; let temp2 = []
if (luoboItem && luoboItem.subItems) { if (luoboItem && luoboItem.subItems) {
// 格式化脚本数据 // 格式化脚本数据
temp2 = luoboItem.subItems.map((item: any) => { temp2 = luoboItem.subItems.map((item: any) => {
return { return {
@@ -329,10 +333,8 @@ const initScriptData = async () => {
} }
selectScript.value = temp2 selectScript.value = temp2
// 只有在sourceKey == 2时才设置rowList和tree相关属性 // 只有在sourceKey == 2时才设置rowList和tree相关属性
if (sourceKey.value === 2 && temp.length > 0) { if (sourceKey.value === 2 && temp.length > 0) {
rowList.value.scriptName = temp[0].scriptName rowList.value.scriptName = temp[0].scriptName
rowList.value.scriptType = temp[0].id rowList.value.scriptType = temp[0].id
selectedScriptName.value = temp[0].scriptName selectedScriptName.value = temp[0].scriptName
@@ -340,8 +342,6 @@ const initScriptData = async () => {
treeRef.value?.setCurrentKey(temp[0].id) treeRef.value?.setCurrentKey(temp[0].id)
}, 0) }, 0)
} }
} }
// 获取基本信息 // 获取基本信息
@@ -349,14 +349,14 @@ const getBasicInformation = async (scriptType: any) => {
checkResultData.value = [] checkResultData.value = []
rawTableData.value = [] rawTableData.value = []
const scriptType2 = ref('') const scriptType2 = ref('')
if(sourceKey.value == 1){
scriptType2.value = scriptType
}else{
scriptType2.value = ''
}
//确保scriptData已初始化 if (sourceKey.value == 1) {
scriptType2.value = scriptType
} else {
scriptType2.value = ''
}
//确保scriptData已初始化
// if (scriptData.value.length === 0) { // if (scriptData.value.length === 0) {
// await initScriptData() // await initScriptData()
// } // }
@@ -370,19 +370,19 @@ const getBasicInformation = async (scriptType: any) => {
num: formContent.num == '' ? null : parseInt(formContent.num), num: formContent.num == '' ? null : parseInt(formContent.num),
patternId: pattern.value patternId: pattern.value
}) })
formContent.dataRule = res.data.dataRule formContent.dataRule = res.data.dataRule
formContent.deviceName = res.data.deviceName formContent.deviceName = res.data.deviceName
formContent.errorSysId = res.data.errorSysId formContent.errorSysId = res.data.errorSysId
chnMapList.value = res.data.chnMap chnMapList.value = res.data.chnMap
let chnMap: string[] = [] let chnMap: string[] = []
for (let key in res.data.chnMap) { for (let key in res.data.chnMap) {
chnMap.push(key) chnMap.push(key)
} }
chnList.value = chnMap chnList.value = chnMap
formContent.chnNum = formContent.chnNum == null ? chnList.value[0] : formContent.chnNum formContent.chnNum = formContent.chnNum == null ? chnList.value[0] : formContent.chnNum
// 设置检测次数默认值为chnMap数组的最后一位 // 设置检测次数默认值为chnMap数组的最后一位
if (chnMapList.value[formContent.chnNum] && chnMapList.value[formContent.chnNum].length > 0) { if (chnMapList.value[formContent.chnNum] && chnMapList.value[formContent.chnNum].length > 0) {
// 获取当前通道号对应的检测次数数组,并设置为最后一个值(最大值) // 获取当前通道号对应的检测次数数组,并设置为最后一个值(最大值)
@@ -390,8 +390,6 @@ const getBasicInformation = async (scriptType: any) => {
formContent.num = numList[numList.length - 1] formContent.num = numList[numList.length - 1]
} }
waveNumCount.value = res.data.waveNumTotal waveNumCount.value = res.data.waveNumTotal
} catch (error) { } catch (error) {
console.error('获取基本信息失败:', error) console.error('获取基本信息失败:', error)
} }
@@ -415,7 +413,7 @@ const handleNumChange = async (value: string) => {
const handleCommonChange = async () => { const handleCommonChange = async () => {
// 重新初始化脚本数据(更新左侧树) // 重新初始化脚本数据(更新左侧树)
await initScriptData() await initScriptData()
// 触发当前选中节点的点击事件,保持界面状态一致 // 触发当前选中节点的点击事件,保持界面状态一致
if (sourceKey.value === 2 && scriptData.value.length > 0) { if (sourceKey.value === 2 && scriptData.value.length > 0) {
// 查找当前选中的节点 // 查找当前选中的节点
@@ -432,7 +430,7 @@ const handleCommonChange = async () => {
const tempNode = { const tempNode = {
scriptName: rowList.value.scriptName, scriptName: rowList.value.scriptName,
id: rowList.value.scriptType, id: rowList.value.scriptType,
code: rowList.value.scriptName === "录波" ? 'wave_data' : '' code: rowList.value.scriptName === '录波数据' ? 'wave_data' : ''
} }
handleNodeClick(tempNode) handleNodeClick(tempNode)
} }
@@ -451,7 +449,7 @@ const updateCheckNumForChn = (chnNum: string) => {
const handleNodeClick = (data: any) => { const handleNodeClick = (data: any) => {
rowList.value.scriptName = data.scriptName rowList.value.scriptName = data.scriptName
rowList.value.scriptType = data.id rowList.value.scriptType = data.id
// 判断是否为录波数据 // 判断是否为录波数据
if (data.code === 'wave_data') { if (data.code === 'wave_data') {
isWaveData.value = true isWaveData.value = true
@@ -465,19 +463,17 @@ const handleNodeClick = (data: any) => {
// 每次选中录波数据时都重置为第一个选项并触发getResults // 每次选中录波数据时都重置为第一个选项并触发getResults
if (scriptNameOptions.value.length > 0) { if (scriptNameOptions.value.length > 0) {
selectedScriptName.value = scriptNameOptions.value[0].value selectedScriptName.value = scriptNameOptions.value[0].value
// 更新rowList并触发getResults // 更新rowList并触发getResults
rowList.value.scriptName = selectedScriptName.value rowList.value.scriptName = selectedScriptName.value
const selectedItem = selectScript.value.find(item => item.scriptName === selectedScriptName.value) const selectedItem = selectScript.value.find(item => item.scriptName === selectedScriptName.value)
if (selectedItem) { if (selectedItem) {
rowList.value.scriptType = selectedItem.id rowList.value.scriptType = selectedItem.id
getResults('wave_data') getResults('wave_data')
} }
} }
} else { } else {
isWaveData.value = false isWaveData.value = false
getResults(data.code) getResults(data.code)
} }
@@ -489,15 +485,15 @@ const getResults = async (code: any) => {
// 判断是否为录波数据请求 // 判断是否为录波数据请求
const isWaveDataRequest = code === 'wave_data' || isWaveData.value const isWaveDataRequest = code === 'wave_data' || isWaveData.value
console.log('isWaveDataRequest:', rowList.value.scriptType)
getContrastResult({ getContrastResult({
planId: checkStore.plan.id, planId: checkStore.plan.id,
scriptType: rowList.value.scriptType, scriptType: rowList.value.scriptType,
deviceId: formContent.deviceId, deviceId: formContent.deviceId,
chnNum: formContent.chnNum, chnNum: formContent.chnNum,
num: formContent.num == '' ? null : formContent.num, num: formContent.num == '' ? null : formContent.num,
waveNum: isWaveDataRequest ? waveNumber.value : null, waveNum: isWaveDataRequest ? waveNumber.value : null,
isWave: isWaveDataRequest , isWave: isWaveDataRequest,
patternId: pattern.value patternId: pattern.value
}).then((res: any) => { }).then((res: any) => {
let list: string[] = [] let list: string[] = []
@@ -508,8 +504,6 @@ const getResults = async (code: any) => {
tesList.value = list tesList.value = list
checkResultData.value = res.data.resultMap checkResultData.value = res.data.resultMap
rawTableData.value = res.data.rawDataMap rawTableData.value = res.data.rawDataMap
}) })
} }
@@ -542,39 +536,35 @@ const close = async () => {
} }
const handleErrorSysChange = async () => { const handleErrorSysChange = async () => {
changeErrorSystem({ changeErrorSystem({
planId: checkStore.plan.id, planId: checkStore.plan.id,
scriptId: '', scriptId: '',
errorSysId: formContent.errorSysId, errorSysId: formContent.errorSysId,
deviceId: formContent.deviceId, deviceId: formContent.deviceId,
code: checkStore.plan.code + '', code: checkStore.plan.code + '',
patternId: dictStore.getDictData('Pattern').find(item => item.name === modeStore.currentMode)?.id ?? '', patternId: dictStore.getDictData('Pattern').find(item => item.name === modeStore.currentMode)?.id ?? ''
}).then((res) => { }).then(res => {
if (res.code === ResultEnum.SUCCESS) { if (res.code === ResultEnum.SUCCESS) {
ElMessage.success('切换误差体系成功') ElMessage.success('切换误差体系成功')
handleChnNumChange(formContent.chnNum) handleChnNumChange(formContent.chnNum)
} }
}) })
} }
const handleReCalculate = async () => { const handleReCalculate = async () => {
reCalculate({ reCalculate({
planId: checkStore.plan.id, planId: checkStore.plan.id,
scriptId: '', scriptId: '',
errorSysId: formContent.errorSysId, errorSysId: formContent.errorSysId,
deviceId: formContent.deviceId, deviceId: formContent.deviceId,
code: checkStore.plan.code + '', code: checkStore.plan.code + '',
patternId: dictStore.getDictData('Pattern').find(item => item.name === modeStore.currentMode)?.id ?? '', patternId: dictStore.getDictData('Pattern').find(item => item.name === modeStore.currentMode)?.id ?? ''
}).then((res) => { }).then(res => {
if (res.code === ResultEnum.SUCCESS) { if (res.code === ResultEnum.SUCCESS) {
ElMessage.success('重新计算成功!') ElMessage.success('重新计算成功!')
handleChnNumChange(formContent.chnNum) handleChnNumChange(formContent.chnNum)
}
} })
})
} }
defineExpose({ defineExpose({

View File

@@ -81,8 +81,8 @@
<RealTimeData ref="realTimeDataRef" /> <RealTimeData ref="realTimeDataRef" />
</template> </template>
<script lang="tsx" setup name="preTest"> <script lang="tsx" setup name="preTest">
import {ElMessage, ElMessageBox, StepProps} from "element-plus"; import { ElMessage, ElMessageBox, StepProps } from 'element-plus'
import {computed, defineExpose, PropType, ref, toRef, watch} from 'vue'; import { computed, PropType, ref, toRef, watch } from 'vue'
import RealTimeData from './realTimeDataAlign.vue' import RealTimeData from './realTimeDataAlign.vue'
const realTimeDataRef = ref() const realTimeDataRef = ref()
@@ -226,184 +226,161 @@ watch(webMsgSend, function (newValue, oldValue) {
} }
switch (newValue.requestId) { switch (newValue.requestId) {
case 'yjc_sbtxjy': case 'yjc_sbtxjy':
switch (newValue.operateCode) { if (newValue.code == 10200) {
case 'INIT_GATHER$02': step1InitLog.value.push({
if (newValue.code == 10200) { type: 'info',
step1InitLog.value.push({ log: newValue.data,
type: 'info', })
log: newValue.data, }
}) if (newValue.code == 10201) {
step1.value = 'process'
} else if (newValue.code == 10201) { step1InitLog.value = [{
step1.value = 'process' type: 'wait',
step1InitLog.value = [{ log: '正在进行设备通讯校验.....',
type: 'wait', }];
log: '正在进行设备通讯校验.....', }
}]; if (newValue.code == 10551) {
} else if (newValue.code == 10551) { step1InitLog.value.push({
step1InitLog.value.push({ type: 'error',
type: 'error', log: newValue.data + '设备触发报告异常!',
log: newValue.data + '设备触发报告异常!', })
}) step1.value = 'error'
step1.value = 'error' ts.value = 'error'
ts.value = 'error' step5.value = 'error'
step5.value = 'error' }
} else if (newValue.code == 10552) { if (newValue.code == 10552) {
step1InitLog.value = [{ step1InitLog.value = [{
type: 'error', type: 'error',
log: '存在已经初始化步骤,执行自动关闭,请重新发起检测!', log: '存在已经初始化步骤,执行自动关闭,请重新发起检测!',
}]; }];
step1.value = 'error' step1.value = 'error'
ts.value = 'error' ts.value = 'error'
step5.value = 'error' step5.value = 'error'
} else if (newValue.code == 25001) { }
activeIndex.value = 1 if (newValue.code == 25001) {
step1.value = 'success' step1InitLog.value.push({
step2.value = 'process' type: 'info',
} log: newValue.data,
break; })
case 'INIT_GATHER$03': activeIndex.value = 1
if (newValue.code == 10200) { step1.value = 'success'
step1InitLog.value.push({ step2.value = 'process'
type: 'info',
log: newValue.data,
})
}else if (newValue.code == 25001) {
step1InitLog.value.push({
type: 'info',
log: newValue.data,
})
activeIndex.value = 1
step1.value = 'success'
step2.value = 'process'
}
break;
case 'DATA_REQUEST$03':
if (newValue.code == 25001) {
activeIndex.value = 1
step1.value = 'success'
step2.value = 'process'
}
break;
} }
break; break;
case 'record_wave_step1': case 'record_wave_step1':
switch (newValue.operateCode) { if (newValue.code == 25002) { //某一路录波校验失败
case 'DATA_REQUEST$03': step1InitLog.value.push({
if (newValue.code == 25002) { //某一路录波校验失败 type: 'error',
step1InitLog.value.push({ log: newValue.data,
type: 'error', })
log: newValue.data , } else if (newValue.code == 25003) { //最终失败
}) step1.value = 'error'
}else if (newValue.code == 25003) { //最终失败 ts.value = 'error'
step1.value = 'error' step5.value = 'error'
ts.value = 'error'
step5.value = 'error'
}
} }
break; break;
case 'yjc_mxyzxjy': case 'yjc_mxyzxjy':
switch (newValue.operateCode){ if (newValue.code == 10200) { //单个监测点成功
case 'DATA_REQUEST$02': step2InitLog.value.push({
if (newValue.code == 10200) { //单个监测点成功 type: 'info',
step2InitLog.value.push({ log: newValue.data + '模型一致性检验成功!',
type: 'info', })
log: newValue.data + '模型一致性检验成功!',
})
}else if (newValue.code == 10201) {
step2.value = 'process'
step2InitLog.value = [{
type: 'wait',
log: '正在进行模型一致性校验.....',
}];
} else if (newValue.code == 25002) { //单个监测点失败
step2InitLog.value.push({
type: 'error',
log: newValue.data +'模型一致性检验失败!',
})
}else if (newValue.code == 25001) { //最终成功
step2.value = 'success'
step3.value = 'process'
activeIndex.value = 2
}else if (newValue.code == 25003) { //最终失败
step2.value = 'error'
ts.value = 'error'
step5.value = 'error'
}
break;
} }
break; if (newValue.code == 10201) {
step2.value = 'process'
step2InitLog.value = [{
type: 'wait',
log: '正在进行模型一致性校验.....',
}];
}
if (newValue.code == 25002) { //单个监测点失败
step2InitLog.value.push({
type: 'error',
log: newValue.data + '模型一致性检验失败!',
})
}
if (newValue.code == 25001) { //最终成功
step2.value = 'success'
step3.value = 'process'
activeIndex.value = 2
}
if (newValue.code == 25003) { //最终失败
step2.value = 'error'
ts.value = 'error'
step5.value = 'error'
}
break;
case 'yjc_align': case 'yjc_align':
switch (newValue.operateCode){ if (newValue.code == 10200) { //单个监测点成功
case 'DATA_REQUEST$02': step3InitLog.value.push({
if (newValue.code == 10200) { //单个监测点成功 type: 'info',
step3InitLog.value.push({ log: newValue.data + '数据对齐检验成功!',
type: 'info', })
log: newValue.data +'实时数据对齐检验成功!',
})
}else if (newValue.code == 10201) {
step3.value = 'process'
step3InitLog.value = [{
type: 'wait',
log: '正在进行实时数据对齐检验.....',
}];
}else if (newValue.code == 25002) { //单个监测点失败
step3InitLog.value.push({
type: 'error',
log: newValue.data + '实时数据对齐检验失败!',
})
}else if (newValue.code == 25001 && newValue.data) { //最终成功
isShowDialog.value = true
step3.value = 'success'
step4.value = 'process'
activeIndex.value = 3
testDataStructure.value = newValue.data
}else if (newValue.code == 25003) { //最终失败
isShowDialog.value = true
step3.value = 'error'
ts.value = 'error'
step5.value = 'error'
testDataStructure.value = newValue.data
}
break;
} }
break; if (newValue.code == 10201) {
step3.value = 'process'
step3InitLog.value = [{
type: 'wait',
log: '正在进行数据对齐检验.....',
}];
}
if (newValue.code == 25002) { //单个监测点失败
step3InitLog.value.push({
type: 'error',
log: newValue.data + '数据对齐检验失败!',
})
}
if (newValue.code == 25001 && newValue.data) { //最终成功
isShowDialog.value = true
step3.value = 'success'
step4.value = 'process'
activeIndex.value = 3
testDataStructure.value = newValue.data
}
if (newValue.code == 25003) { //最终失败
isShowDialog.value = true
step3.value = 'error'
ts.value = 'error'
step5.value = 'error'
testDataStructure.value = newValue.data
}
break;
case 'YJC_xujy': case 'YJC_xujy':
switch (newValue.operateCode) { if (newValue.code == 10200) {
case 'DATA_REQUEST$02': step4InitLog.value.push({
if (newValue.code == 10200) { type: 'info',
step4InitLog.value.push({ log: newValue.data,
type: 'info', })
log: newValue.data, }
}) if (newValue.code == 10201) {
}else if (newValue.code == 10201) { step4.value = 'process'
step4.value = 'process' step4InitLog.value = [{
step4InitLog.value = [{ type: 'wait',
type: 'wait', log: '正在进行相序性检.....',
log: '正在进行相序性检.....', }];
}]; }
} else if(newValue.code == 25002){ if (newValue.code == 25002) {
step4InitLog.value.push({ step4InitLog.value.push({
type: 'error', type: 'error',
log: newValue.data, log: newValue.data,
}) })
} else if (newValue.code == 25003) { }
step4InitLog.value.push({ if (newValue.code == 25003) {
type: 'error', step4InitLog.value.push({
log: newValue.data, type: 'error',
}) log: newValue.data,
step4.value = 'error' })
ts.value = 'error' step4.value = 'error'
step5.value = 'error' ts.value = 'error'
} else if (newValue.code == 25001) { step5.value = 'error'
step4.value = 'success' }
step5.value = 'success' if (newValue.code == 25001) {
ts.value = 'success' step4.value = 'success'
activeIndex.value = 4 step5.value = 'success'
} ts.value = 'success'
break activeIndex.value = 4
} }
break; break;
case 'quit': case 'quit':

View File

@@ -131,6 +131,7 @@ import {getBigTestItem} from '@/api/check/test'
import {getAutoGenerate} from '@/api/user/login' import {getAutoGenerate} from '@/api/user/login'
import {useModeStore} from '@/stores/modules/mode' // 引入模式 store import {useModeStore} from '@/stores/modules/mode' // 引入模式 store
import {useDictStore} from '@/stores/modules/dict' import {useDictStore} from '@/stores/modules/dict'
import { ca } from 'element-plus/es/locale'
const checkStore = useCheckStore() const checkStore = useCheckStore()
const modeStore = useModeStore() const modeStore = useModeStore()
@@ -352,6 +353,7 @@ watch(
} }
} }
break break
case 'connect': case 'connect':
switch (newValue.operateCode) { switch (newValue.operateCode) {
case 'Contrast_Dev': case 'Contrast_Dev':
@@ -394,31 +396,24 @@ watch(
setLogList('error', '设备主动关闭连接!') setLogList('error', '设备主动关闭连接!')
stopTimeCount() stopTimeCount()
break break
case 'yjc_xyjy' : case 'yjc_xyjy' :
switch (newValue.operateCode) { if (newValue.code == 10552) {
ElMessageBox.alert('重复的初始化操作!', '检测失败', {
case 'INIT_GATHER$03': confirmButtonText: '确定',
if (newValue.code == 10552) { type: 'error',
ElMessageBox.alert('重复的初始化操作!', '检测失败', { })
confirmButtonText: '确定', setLogList('error', '重复的初始化操作!')
type: 'error', stopTimeCount()
}) }
setLogList('error', '重复的初始化操作!') break;
stopTimeCount()
}
}
break;
case 'yjc_sbtxjy' : case 'yjc_sbtxjy' :
switch (newValue.operateCode) { ElMessageBox.alert('重复的初始化操作!', '检测失败', {
case 'INIT_GATHER$02': confirmButtonText: '确定',
ElMessageBox.alert('重复的初始化操作!', '检测失败', { type: 'error',
confirmButtonText: '确定', })
type: 'error', setLogList('error', '重复的初始化操作!')
}) stopTimeCount()
setLogList('error', '重复的初始化操作!') break;
stopTimeCount()
}
break;
} }
if (checkStore.selectTestItems.preTest == false && newValue.requestId != 'formal_real') { if (checkStore.selectTestItems.preTest == false && newValue.requestId != 'formal_real') {
if (testLogList[0].log == '正在检测,请稍等...' || testLogList[0].log == '暂无数据,等待检测开始') { if (testLogList[0].log == '正在检测,请稍等...' || testLogList[0].log == '暂无数据,等待检测开始') {
@@ -431,7 +426,7 @@ watch(
: newValue.requestId == 'yjc_mxyzxjy' : newValue.requestId == 'yjc_mxyzxjy'
? '模型一致性检验' ? '模型一致性检验'
: newValue.requestId == 'yjc_align' : newValue.requestId == 'yjc_align'
? '实时数据对齐检验' ? '数据对齐检验'
: newValue.requestId == 'YJC_xujy' : newValue.requestId == 'YJC_xujy'
? '相序校验' ? '相序校验'
: '' : ''
@@ -461,13 +456,18 @@ watch(
} }
switch (newValue.code) { switch (newValue.code) {
case 25001: case 25001:
case 25006:
case 25005: case 25005:
case 25007:// 添加闪变处理
{ {
let result: CheckData.ScriptChnItem[] = [] let result: CheckData.ScriptChnItem[] = []
let message = JSON.parse(newValue.data) let message = JSON.parse(newValue.data)
// 当收到 25005 消息时录波项目开始loading
if (newValue.code == 25005) {
// 当收到 25005/25006 消息时录波项目开始loading
if (newValue.code == 25005 || newValue.code == 25006) {
// 设置录波项目为LOADING状态 // 设置录波项目为LOADING状态
const waveResultItem = checkResult.find(item => item.code === 'wave_data') const waveResultItem = checkResult.find(item => item.code === 'wave_data')
@@ -478,6 +478,18 @@ watch(
} }
} }
if (newValue.code == 25007) {
// 设置闪变项目为LOADING状态
const flickerResultItem = checkResult.find(item => item.code === 'flicker_data')
if (flickerResultItem) {
flickerResultItem.devices.forEach(device => {
device.chnResult.fill(CheckData.ChnCheckResultEnum.LOADING)
})
}
}
scriptData.forEach(item => { scriptData.forEach(item => {
// 处理当前节点的数据 // 处理当前节点的数据
const temp: CheckData.ScriptChnItem = { const temp: CheckData.ScriptChnItem = {
@@ -487,12 +499,20 @@ watch(
} }
// 特殊处理录波项目 - 如果是25005消息且当前项目是录波项目则使用已设置的状态 // 特殊处理录波项目 - 如果是25005消息且当前项目是录波项目则使用已设置的状态
if (newValue.code == 25005 && item.code === 'wave_data') { if ((newValue.code == 25005 || newValue.code == 25006) && item.code === 'wave_data') {
const existingWaveItem = checkResult.find(checkItem => checkItem.scriptType === 'wave_data') const existingWaveItem = checkResult.find(checkItem => checkItem.scriptType === 'wave_data')
if (existingWaveItem) { if (existingWaveItem) {
temp.devices = [...existingWaveItem.devices] // 保留已设置的devices temp.devices = [...existingWaveItem.devices] // 保留已设置的devices
} }
} else { } // 特殊处理闪变项目 - 如果是25007消息且当前项目是闪变项目则使用已设置的状态
else if (newValue.code == 25007 && item.code === 'PST') {
const existingFlickerItem = checkResult.find(checkItem => checkItem.scriptType === 'PST')
if (existingFlickerItem) {
temp.devices = [...existingFlickerItem.devices] // 保留已设置的devices
}
}
else {
// 找到message中所有scriptName与当前item.code匹配的项 // 找到message中所有scriptName与当前item.code匹配的项
const matchedDevices = message const matchedDevices = message
.filter((msg: any) => msg.scriptName === item.code) .filter((msg: any) => msg.scriptName === item.code)
@@ -506,7 +526,7 @@ watch(
temp.devices.push(...matchedDevices) temp.devices.push(...matchedDevices)
// 对于未匹配到的设备,也要添加占位符(特别是录波项目) // 对于未匹配到的设备,也要添加占位符(特别是录波项目)
if (item.code === 'wave_data') { if (item.code === 'wave_data' || item.code === 'PST') {
deviceList.forEach(device => { deviceList.forEach(device => {
const isDeviceExist = matchedDevices.some((matchedDevice: any) => matchedDevice.deviceId === device.deviceId) const isDeviceExist = matchedDevices.some((matchedDevice: any) => matchedDevice.deviceId === device.deviceId)
if (!isDeviceExist) { if (!isDeviceExist) {
@@ -536,6 +556,9 @@ watch(
if(newValue.code == 25005){ if(newValue.code == 25005){
setLogList("error", '实时数据校验失败!开始录波校验...') setLogList("error", '实时数据校验失败!开始录波校验...')
} }
if(newValue.code == 25006){
setLogList("error", '统计数据校验失败!开始录波校验...')
}
break break
} }
@@ -686,7 +709,7 @@ const initCheckResult = (defaultValue: CheckData.ChnCheckResultEnum) => {
let tempChnResult: CheckData.ChnCheckResultEnum[] = [] let tempChnResult: CheckData.ChnCheckResultEnum[] = []
for (let j = 0; j < checkStore.chnNumList.length; j++) { for (let j = 0; j < checkStore.chnNumList.length; j++) {
// 录波项目初始化为UNKNOWN状态其他项目使用传入的默认值 // 录波项目初始化为UNKNOWN状态其他项目使用传入的默认值
if (item.code === 'wave_data' && checkTotal > 1) { if ((item.code === 'wave_data' || item.code === 'PST')&& checkTotal > 1) {
tempChnResult.push(CheckData.ChnCheckResultEnum.UNKNOWN) tempChnResult.push(CheckData.ChnCheckResultEnum.UNKNOWN)
} else { } else {
tempChnResult.push(defaultValue) tempChnResult.push(defaultValue)

View File

@@ -134,30 +134,17 @@
</template> </template>
<script lang="tsx" setup name="testPopup"> <script lang="tsx" setup name="testPopup">
import { nextTick, PropType, reactive, ref, watch } from 'vue' import { nextTick, reactive, ref, watch } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus' import { ElMessage, ElMessageBox } from 'element-plus'
import { import { Coin, Edit, Key, Refresh, Right, SuccessFilled, Switch, VideoPause, VideoPlay } from '@element-plus/icons-vue'
Coin,
Edit,
Key,
Switch,
Refresh,
Right,
SuccessFilled,
UploadFilled,
VideoPause,
VideoPlay
} from '@element-plus/icons-vue'
import ComparePreTest from './comparePreTest.vue' import ComparePreTest from './comparePreTest.vue'
import ChannelPairing from './channelPairing.vue' import ChannelPairing from './channelPairing.vue'
import { Device } from '@/api/device/interface/device'
import CompareTest from './compareTest.vue' import CompareTest from './compareTest.vue'
import socketClient from '@/utils/webSocketClient' import socketClient from '@/utils/webSocketClient'
import { useCheckStore } from '@/stores/modules/check' import { useCheckStore } from '@/stores/modules/check'
import { pauseTest, resumeTest, startPreTest, contrastTest } from '@/api/socket/socket' import { contrastTest, pauseTest, resumeTest, startPreTest } from '@/api/socket/socket'
import { useUserStore } from '@/stores/modules/user' import { useUserStore } from '@/stores/modules/user'
import { JwtUtil } from '@/utils/jwtUtil' import { JwtUtil } from '@/utils/jwtUtil'
import { StandardDevice } from '@/api/device/interface/standardDevice'
const userStore = useUserStore() const userStore = useUserStore()
const checkStore = useCheckStore() const checkStore = useCheckStore()
@@ -242,8 +229,8 @@ const standardDevIds = ref<[]>()
const pairs = ref<any>() const pairs = ref<any>()
const testAgain = ref(false) //重新检测按钮是否显示 const testAgain = ref(false) //重新检测按钮是否显示
const checkNumber = ref(0) //检测次数 const checkNumber = ref(0) //检测次数
const deviceMonitor2= ref<Map<string, any[]>>(); const deviceMonitor2 = ref<Map<string, any[]>>()
const onlyWave = ref(false);//计划数据源是否只有录波 const onlyWave = ref(false) //计划数据源是否只有录波
const open = async ( const open = async (
title: string, title: string,
mapping: any, mapping: any,
@@ -252,14 +239,14 @@ const open = async (
devIdsArray: [], devIdsArray: [],
standardDevIdsArray: [], standardDevIdsArray: [],
pair: any, pair: any,
deviceMonitor:Map<string, any[]>, deviceMonitor: Map<string, any[]>,
planIsOnlyWave: boolean planIsOnlyWave: boolean
) => { ) => {
if (checkStore.selectTestItems.preTest && !checkStore.selectTestItems.test) { if (checkStore.selectTestItems.preTest && !checkStore.selectTestItems.test) {
testAgain.value = true testAgain.value = true
} }
deviceMonitor2.value = deviceMonitor; deviceMonitor2.value = deviceMonitor
onlyWave.value = planIsOnlyWave; onlyWave.value = planIsOnlyWave
checkStore.setNodesConnectable(true) checkStore.setNodesConnectable(true)
dialogTitle.value = title dialogTitle.value = title
channelMapping.value = mapping channelMapping.value = mapping
@@ -588,7 +575,6 @@ const nextStep = () => {
} }
const handleStepClick = (step: number) => { const handleStepClick = (step: number) => {
if (step > stepsActive.value) { if (step > stepsActive.value) {
return return
} else { } else {
@@ -636,7 +622,7 @@ defineExpose({ open })
<style scoped lang="scss"> <style scoped lang="scss">
.test-head-steps { .test-head-steps {
::v-deep .el-step { :deep(.el-step) {
.el-step__head.is-success { .el-step__head.is-success {
color: #91cc75; color: #91cc75;
} }

View File

@@ -1,138 +1,144 @@
<template> <template>
<div class="table-main">
<el-table
v-if="tableData.length > 0"
:data="tableData"
height="357px"
:header-cell-style="{ textAlign: 'center' }"
:cell-style="{ textAlign: 'center' }"
>
<!-- <el-table-column prop="chnNum" label="通道号" width="80">-->
<!-- <template #default="{row}">-->
<!-- {{ '通道' + row.chnNum }}-->
<!-- </template>-->
<!-- </el-table-column>-->
<el-table-column label="A相" v-if="phaseA === 1">
<el-table-column prop="stdA" :label="'标准值' + (outerUnit == '' ? '' : '' + outerUnit + '')" />
<el-table-column prop="dataA" :label="'被检值' + (outerUnit == '' ? '' : '' + outerUnit + '')" />
<el-table-column prop="isDataA" label="检测结果">
<template #default="scope">
<el-tooltip effect="dark" placement="bottom">
<template #content>
误差范围{{ scope.row.maxErrorA }}
<br />
误差值{{ scope.row.errorA }} {{ scope.row.errorA !== '/' ? innerUnitA : '' }}
</template>
<el-tag type="success" v-if="scope.row.isDataA === 1">符合</el-tag>
<el-tag type="danger" v-if="scope.row.isDataA === 2">不符合</el-tag>
<el-tag type="warning" v-if="scope.row.isDataA === 4">/</el-tag>
<el-tag type="info" v-if="scope.row.isDataA === 5">-</el-tag>
</el-tooltip>
</template>
</el-table-column>
</el-table-column>
<el-table-column label="B相" v-if="phaseB === 1">
<el-table-column prop="stdB" :label="'标准值' + (outerUnit == '' ? '' : '' + outerUnit + '')" />
<el-table-column prop="dataB" :label="'被检值' + (outerUnit == '' ? '' : '' + outerUnit + '')" />
<el-table-column prop="isDataB" label="检测结果">
<template #default="scope">
<el-tooltip effect="dark" placement="bottom">
<template #content>
误差范围{{ scope.row.maxErrorB }}
<br />
误差值{{ scope.row.errorB }} {{ scope.row.errorB !== '/' ? innerUnitB : '' }}
</template>
<el-tag type="success" v-if="scope.row.isDataB === 1">符合</el-tag>
<el-tag type="danger" v-if="scope.row.isDataB === 2">不符合</el-tag>
<el-tag type="warning" v-if="scope.row.isDataB === 4">/</el-tag>
<el-tag type="info" v-if="scope.row.isDataA === 5">-</el-tag>
</el-tooltip>
</template>
</el-table-column>
</el-table-column>
<el-table-column label="C相" v-if="phaseC === 1">
<el-table-column prop="stdC" :label="'标准值' + (outerUnit == '' ? '' : '' + outerUnit + '')" />
<el-table-column prop="dataC" :label="'被检值' + (outerUnit == '' ? '' : '' + outerUnit + '')" />
<el-table-column prop="isDataC" label="检测结果">
<template #default="scope">
<el-tooltip effect="dark" placement="bottom">
<template #content>
误差范围 {{ scope.row.maxErrorC }}
<br />
误差值{{ scope.row.errorC }} {{ scope.row.errorC !== '/' ? innerUnitC : '' }}
</template>
<el-tag type="success" v-if="scope.row.isDataC === 1">符合</el-tag>
<el-tag type="danger" v-if="scope.row.isDataC === 2">不符合</el-tag>
<el-tag type="warning" v-if="scope.row.isDataC === 4">/</el-tag>
<el-tag type="info" v-if="scope.row.isDataA === 5">-</el-tag>
</el-tooltip>
</template>
</el-table-column>
</el-table-column>
<div class="table-main"> <el-table-column :label="tableHeader" v-if="phaseT === 1">
<el-table v-if="tableData.length > 0" :data="tableData" height="357px" :header-cell-style="{ textAlign: 'center' } " <el-table-column prop="stdT" :label="'标准值' + (outerUnit == '' ? '' : '' + outerUnit + '')" />
:cell-style="{ textAlign: 'center' }"> <el-table-column prop="dataT" :label="'被检值' + (outerUnit == '' ? '' : '' + outerUnit + '')" />
<!-- <el-table-column prop="chnNum" label="通道号" width="80">--> <el-table-column prop="isDataT" label="检测结果">
<!-- <template #default="{row}">--> <template #default="scope">
<!-- {{ '通道' + row.chnNum }}--> <el-tooltip effect="dark" placement="bottom">
<!-- </template>--> <template #content>
<!-- </el-table-column>--> 误差范围 {{ scope.row.maxErrorT }}
<el-table-column label="A相" v-if="phaseA === 1"> <br />
<el-table-column prop="stdA" :label="'标准值'+(outerUnit==''?'':''+outerUnit+'')"/> 误差值{{ scope.row.errorT }} {{ scope.row.errorT !== '/' ? innerUnitT : '' }}
<el-table-column prop="dataA" :label="'被检值'+(outerUnit==''?'':''+outerUnit+'')"/> </template>
<el-table-column prop="isDataA" label="检测结果"> <el-tag type="success" v-if="scope.row.isDataT === 1">符合</el-tag>
<template #default="scope"> <el-tag type="danger" v-if="scope.row.isDataT === 2">不符合</el-tag>
<el-tooltip effect="dark" placement="bottom"> <el-tag type="warning" v-if="scope.row.isDataT === 4">/</el-tag>
<template #content> <el-tag type="info" v-if="scope.row.isDataA === 5">-</el-tag>
误差范围{{ scope.row.maxErrorA }} <br/> </el-tooltip>
误差值{{ scope.row.errorA }} {{ scope.row.errorA !== '/' ? innerUnitA : '' }} </template>
</template> </el-table-column>
<el-tag type="success" v-if="scope.row.isDataA === 1">符合</el-tag> </el-table-column>
<el-tag type="danger" v-if="scope.row.isDataA === 2">不符合</el-tag> </el-table>
<el-tag type="warning" v-if="scope.row.isDataA === 4">/</el-tag> </div>
<el-tag type="info" v-if="scope.row.isDataA === 5">-</el-tag>
</el-tooltip>
</template>
</el-table-column>
</el-table-column>
<el-table-column label="B相" v-if="phaseB === 1">
<el-table-column prop="stdB" :label="'标准值'+(outerUnit==''?'':''+outerUnit+'')"/>
<el-table-column prop="dataB" :label="'被检值'+(outerUnit==''?'':''+outerUnit+'')"/>
<el-table-column prop="isDataB" label="检测结果">
<template #default="scope">
<el-tooltip effect="dark" placement="bottom">
<template #content>
误差范围{{ scope.row.maxErrorB }}<br/>
误差值{{ scope.row.errorB }} {{ scope.row.errorB !== '/' ? innerUnitB : '' }}
</template>
<el-tag type="success" v-if="scope.row.isDataB === 1">符合</el-tag>
<el-tag type="danger" v-if="scope.row.isDataB === 2">不符合</el-tag>
<el-tag type="warning" v-if="scope.row.isDataB === 4">/</el-tag>
<el-tag type="info" v-if="scope.row.isDataA === 5">-</el-tag>
</el-tooltip>
</template>
</el-table-column>
</el-table-column>
<el-table-column label="C相" v-if="phaseC === 1">
<el-table-column prop="stdC" :label="'标准值'+(outerUnit==''?'':''+outerUnit+'')"/>
<el-table-column prop="dataC" :label="'被检值'+(outerUnit==''?'':''+outerUnit+'')"/>
<el-table-column prop="isDataC" label="检测结果">
<template #default="scope">
<el-tooltip effect="dark" placement="bottom">
<template #content>
误差范围 {{ scope.row.maxErrorC }}<br/>
误差值{{ scope.row.errorC }} {{ scope.row.errorC !== '/' ? innerUnitC : '' }}
</template>
<el-tag type="success" v-if="scope.row.isDataC === 1">符合</el-tag>
<el-tag type="danger" v-if="scope.row.isDataC === 2">不符合</el-tag>
<el-tag type="warning" v-if="scope.row.isDataC === 4">/</el-tag>
<el-tag type="info" v-if="scope.row.isDataA === 5">-</el-tag>
</el-tooltip>
</template>
</el-table-column>
</el-table-column>
<el-table-column :label="tableHeader" v-if="phaseT === 1">
<el-table-column prop="stdT" :label="'标准值'+(outerUnit==''?'':''+outerUnit+'')"/>
<el-table-column prop="dataT" :label="'被检值'+(outerUnit==''?'':''+outerUnit+'')"/>
<el-table-column prop="isDataT" label="检测结果">
<template #default="scope">
<el-tooltip effect="dark" placement="bottom">
<template #content>
误差范围 {{ scope.row.maxErrorT }}<br/>
误差值{{ scope.row.errorT }} {{ scope.row.errorT !== '/' ? innerUnitT : '' }}
</template>
<el-tag type="success" v-if="scope.row.isDataT === 1">符合</el-tag>
<el-tag type="danger" v-if="scope.row.isDataT === 2">不符合</el-tag>
<el-tag type="warning" v-if="scope.row.isDataT === 4">/</el-tag>
<el-tag type="info" v-if="scope.row.isDataA === 5">-</el-tag>
</el-tooltip>
</template>
</el-table-column>
</el-table-column>
</el-table>
</div>
</template> </template>
<script lang="tsx" setup> <script lang="tsx" setup>
import {computed, defineProps} from 'vue'; import { computed } from 'vue'
import {CheckData} from "@/api/check/interface"; import { CheckData } from '@/api/check/interface'
const {tableData, currentScriptTypeName} = defineProps<{
tableData: CheckData.CheckResult[],
currentScriptTypeName: string
}>();
const { tableData, currentScriptTypeName } = defineProps<{
tableData: CheckData.CheckResult[]
currentScriptTypeName: string
}>()
const outerUnit = computed(() => { const outerUnit = computed(() => {
return tableData.length > 0 ? tableData[0].unit : ''; return tableData.length > 0 ? tableData[0].unit : ''
}) })
const innerUnitA = computed(() => { const innerUnitA = computed(() => {
return tableData.length > 0 ? tableData[0].unitA : ''; return tableData.length > 0 ? tableData[0].unitA : ''
}) })
const innerUnitB = computed(() => { const innerUnitB = computed(() => {
return tableData.length > 0 ? tableData[0].unitB : ''; return tableData.length > 0 ? tableData[0].unitB : ''
}) })
const innerUnitC = computed(() => { const innerUnitC = computed(() => {
return tableData.length > 0 ? tableData[0].unitC : ''; return tableData.length > 0 ? tableData[0].unitC : ''
}) })
const innerUnitT = computed(() => { const innerUnitT = computed(() => {
return tableData.length > 0 ? tableData[0].unitT : ''; return tableData.length > 0 ? tableData[0].unitT : ''
}) })
const phaseA = computed(() => { const phaseA = computed(() => {
return tableData.length <= 0 || tableData[0].dataA == null || tableData[0].dataA == "/" ? 0 : 1 return tableData.length <= 0 || tableData[0].dataA == null || tableData[0].dataA == '/' ? 0 : 1
}) })
const phaseB = computed(() => { const phaseB = computed(() => {
return tableData.length <= 0 || tableData[0].dataB == null || tableData[0].dataB == "/" ? 0 : 1 return tableData.length <= 0 || tableData[0].dataB == null || tableData[0].dataB == '/' ? 0 : 1
}) })
const phaseC = computed(() => { const phaseC = computed(() => {
return tableData.length <= 0 || tableData[0].dataC == null || tableData[0].dataC == "/" ? 0 : 1 return tableData.length <= 0 || tableData[0].dataC == null || tableData[0].dataC == '/' ? 0 : 1
}) })
const phaseT = computed(() => { const phaseT = computed(() => {
return tableData.length <= 0 || tableData[0].dataT == null || tableData[0].dataT == "/" ? 0 : 1 return tableData.length <= 0 || tableData[0].dataT == null || tableData[0].dataT == '/' ? 0 : 1
}) })
const tableHeader = computed(() => { const tableHeader = computed(() => {
if (phaseT.value === 1) { if (phaseT.value === 1) {
let index = currentScriptTypeName.indexOf('='); let index = currentScriptTypeName.indexOf('=')
return currentScriptTypeName.substring(0, index); return currentScriptTypeName.substring(0, index)
} }
return currentScriptTypeName return currentScriptTypeName
}) })
// const maxErrorStr = computed((data) => { // const maxErrorStr = computed((data) => {
@@ -143,38 +149,36 @@ const tableHeader = computed(() => {
// } // }
// return result; // return result;
// }) // })
</script> </script>
<style scoped> <style scoped>
.form-grid { .form-grid {
display: flex; display: flex;
flex-direction: row; /* 横向排列 */ flex-direction: row; /* 横向排列 */
flex-wrap: wrap; /* 允许换行 */ flex-wrap: wrap; /* 允许换行 */
} }
.form-grid .el-form-item { .form-grid .el-form-item {
flex: 1 1 30%; /* 控件宽度 */ flex: 1 1 30%; /* 控件宽度 */
margin-right: 20px; /* 控件间距 */ margin-right: 20px; /* 控件间距 */
} }
.form-grid .el-form-item:last-child { .form-grid .el-form-item:last-child {
margin-right: 0; /* 最后一个控件不需要右边距 */ margin-right: 0; /* 最后一个控件不需要右边距 */
} }
.dialog-footer { .dialog-footer {
display: flex; display: flex;
justify-content: flex-start; justify-content: flex-start;
margin-bottom: 10px; /* 调整这里的值以增加或减少间距 */ margin-bottom: 10px; /* 调整这里的值以增加或减少间距 */
} }
.el-tabs { .el-tabs {
margin-bottom: 20px; /* 添加底部边距 */ margin-bottom: 20px; /* 添加底部边距 */
} }
.el-table th, .el-table td { .el-table th,
text-align: center; /* 所有单元格文字居中 */ .el-table td {
text-align: center; /* 所有单元格文字居中 */
} }
</style> </style>

View File

@@ -74,8 +74,8 @@
* 3. 协议校验 - 进行ICD报告触发测试 * 3. 协议校验 - 进行ICD报告触发测试
* 4. 相序校验 - 判断装置接线是否正确 * 4. 相序校验 - 判断装置接线是否正确
*/ */
import {ElMessage, ElMessageBox} from "element-plus"; import { ElMessage, ElMessageBox } from 'element-plus'
import {defineExpose, ref, toRef, watch} from 'vue'; import { ref, toRef, watch } from 'vue'
// ==================== 日志数据存储 ==================== // ==================== 日志数据存储 ====================
// 各步骤的日志数据,用于在右侧折叠面板中显示实时日志 // 各步骤的日志数据,用于在右侧折叠面板中显示实时日志

View File

@@ -1,112 +1,111 @@
<template> <template>
<el-dialog title="检测结果" :model-value="visible" @close="handleCancel" v-bind="dialogBig" width="895px"> <el-dialog title="检测结果" :model-value="visible" @close="handleCancel" v-bind="dialogBig" width="895px">
<div class="result-dialog"> <div class="result-dialog">
<div class="result-title"> <div class="result-title">
<el-row> <el-row>
<el-form-item label="检测脚本" > <el-form-item label="检测脚本">
<el-input v-model='testScriptName' :disabled="true"/> <el-input v-model="testScriptName" :disabled="true" />
</el-form-item> </el-form-item>
<el-form-item label="误差体系" > <el-form-item label="误差体系">
<el-input v-model='errorSysName' :disabled="true"/> <el-input v-model="errorSysName" :disabled="true" />
</el-form-item> </el-form-item>
<el-form-item label="数据原则" > <el-form-item label="数据原则">
<el-input v-model='dataRule' :disabled="true"/> <el-input v-model="dataRule" :disabled="true" />
</el-form-item> </el-form-item>
</el-row> </el-row>
</div> </div>
<div class="result-content"> <div class="result-content">
<el-table :data="resultData" stripe max-height="350" :header-cell-style="{ textAlign: 'center' } " :cell-style="{ textAlign: 'center' }" style="width: 100%" border v-on:cell-click="handleClick"> <el-table
<el-table-column prop="deviceName" label="被检设备" /> :data="resultData"
<el-table-column prop="result_1" label="通道1" /> stripe
<el-table-column prop="result_2" label="通道2" /> max-height="350"
<el-table-column prop="result_3" label="通道3" /> :header-cell-style="{ textAlign: 'center' }"
<el-table-column prop="result_4" label="通道4" /> :cell-style="{ textAlign: 'center' }"
</el-table> style="width: 100%"
</div> border
<div class="result-footer"> v-on:cell-click="handleClick"
你可以停留在本页查看数据或返回首页进行复检报告生成和归档 >
</div> <el-table-column prop="deviceName" label="被检设备" />
</div> <el-table-column prop="result_1" label="通道1" />
<DataCheckPopup <el-table-column prop="result_2" label="通道2" />
:visible="DataCheckDialogVisible" <el-table-column prop="result_3" label="通道3" />
<el-table-column prop="result_4" label="通道4" />
</el-table>
</div>
<div class="result-footer">你可以停留在本页查看数据或返回首页进行复检报告生成和归档</div>
</div>
<DataCheckPopup
:visible="DataCheckDialogVisible"
@update:visible="DataCheckDialogVisible = $event" @update:visible="DataCheckDialogVisible = $event"
></DataCheckPopup> ></DataCheckPopup>
</el-dialog> </el-dialog>
</template> </template>
<script lang="ts" setup name="testPopup">
import{ElMessage, ElSelectV2, FormInstance,FormItemRule}from'element-plus'
import { defineProps, defineEmits, reactive,watch,ref, Ref } from 'vue';
import { dialogBig,dialogMiddle} from '@/utils/elementBind'
//import IndicatorTypeDialog from "@/views/machine/errorSystem/components/IndicatorTypeDialog.vue"; // 导入子组件
import {CirclePlus, Delete, EditPen,FolderOpened,CopyDocument,Edit, Picture, UploadFilled, SuccessFilled,VideoPlay,Right,Refresh,Close} from '@element-plus/icons-vue'
import { useDictStore } from '@/stores/modules/dict'
import preTest from './preTest.vue'
import timeTest from './timeTest.vue'
import DataCheckPopup from './dataCheckPopup.vue';
import { log } from 'console';
const props = defineProps<{ <script lang="ts" setup name="testPopup">
visible: boolean; import { ref } from 'vue'
}>(); import { dialogBig } from '@/utils/elementBind'
//import IndicatorTypeDialog from "@/views/machine/errorSystem/components/IndicatorTypeDialog.vue"; // 导入子组件
import DataCheckPopup from './dataCheckPopup.vue'
const emit = defineEmits<{ const props = defineProps<{
(e: 'update:visible', value: boolean): void; visible: boolean
(e: 'submit', data: any): void; }>()
}>();
const testScriptName = ref('Q/GDW 10650.4-2021 模拟式'); const emit = defineEmits<{
const errorSysName = ref('Q/GDW 10650.2-2021'); (e: 'update:visible', value: boolean): void
const dataRule = ref('所有值'); (e: 'submit', data: any): void
const DataCheckDialogVisible = ref(false); }>()
const testScriptName = ref('Q/GDW 10650.4-2021 模拟式')
const errorSysName = ref('Q/GDW 10650.2-2021')
const dataRule = ref('所有值')
const DataCheckDialogVisible = ref(false)
const resultData = ref([ const resultData = ref([
{ {
deviceName: "被检设备1", deviceName: '被检设备1',
result_1: "合格", result_1: '合格',
result_2: "合格", result_2: '合格',
result_3: "合格", result_3: '合格',
result_4: "合格", result_4: '合格'
}, },
{ {
deviceName: "被检设备2", deviceName: '被检设备2',
result_1: "合格", result_1: '合格',
result_2: "合格", result_2: '合格',
result_3: "—", result_3: '—',
result_4: "—", result_4: '—'
}, },
{ {
deviceName: "被检设备3", deviceName: '被检设备3',
result_1: "不合格", result_1: '不合格',
result_2: "合格", result_2: '合格',
result_3: "—", result_3: '—',
result_4: "—", result_4: '—'
}, }
]); ])
const handleClick = (row:any) => { const handleClick = (row: any) => {
console.log(111) console.log(111)
DataCheckDialogVisible.value = true; DataCheckDialogVisible.value = true
}; }
const handleCancel = () => {
emit('update:visible', false); // 关闭对话框
};
</script> const handleCancel = () => {
emit('update:visible', false) // 关闭对话框
<style scoped> }
.result-dialog{ </script>
<style scoped>
.result-dialog {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
.result-title{ .result-title {
/* display: flex; /* display: flex;
flex-direction: row; */ flex-direction: row; */
} }
.result-footer{ .result-footer {
text-align: right; text-align: right;
margin-top: 10px; margin-top: 10px;
} }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,76 +1,57 @@
<template> <template>
<el-form <el-form ref="loginFormRef" :model="loginForm" :rules="loginRules" size="large">
ref='loginFormRef' <el-form-item prop="username">
:model='loginForm' <el-input v-model="loginForm.username" placeholder="用户名">
:rules='loginRules' <template #prefix>
size='large' <el-icon class="el-input__icon">
> <user />
<el-form-item prop='username'> </el-icon>
<el-input v-model='loginForm.username' placeholder='用户名'> </template>
<template #prefix> </el-input>
<el-icon class='el-input__icon'> </el-form-item>
<user/> <el-form-item prop="password">
</el-icon> <el-input
</template> v-model="loginForm.password"
</el-input> type="password"
</el-form-item> placeholder="密码"
<el-form-item prop='password'> show-password
<el-input autocomplete="new-password"
v-model='loginForm.password' >
type='password' <template #prefix>
placeholder='密码' <el-icon class="el-input__icon">
show-password <lock />
autocomplete='new-password' </el-icon>
> </template>
<template #prefix> </el-input>
<el-icon class='el-input__icon'> </el-form-item>
<lock/> <el-form-item prop="checked">
</el-icon> <el-checkbox v-model="loginForm.checked">记住我</el-checkbox>
</template> </el-form-item>
</el-input> </el-form>
</el-form-item> <div class="login-btn">
<el-form-item prop='checked'> <el-button :icon="UserFilled" round size="large" type="primary" :loading="loading" @click="login(loginFormRef)">
<el-checkbox v-model="loginForm.checked">记住我</el-checkbox> 登录
</el-form-item> </el-button>
</el-form> <el-button :icon="CircleClose" round size="large" @click="resetForm(loginFormRef)">重置</el-button>
<div class='login-btn'> </div>
<el-button
:icon='UserFilled'
round
size='large'
type='primary'
:loading='loading'
@click='login(loginFormRef)'
>
登录
</el-button>
<el-button
:icon='CircleClose'
round
size='large'
@click='resetForm(loginFormRef)'
>
重置
</el-button>
</div>
</template> </template>
<script setup lang='ts'> <script setup lang="ts">
import {useRouter} from 'vue-router' import { useRouter } from 'vue-router'
import {HOME_URL} from '@/config' import { HOME_URL } from '@/config'
import {getTimeState} from '@/utils' import { getTimeState } from '@/utils'
import {type Dict} from '@/api/interface' import { type Dict } from '@/api/interface'
import {type Login} from '@/api/user/interface/user' import { type Login } from '@/api/user/interface/user'
import type {ElForm} from 'element-plus' import type { ElForm } from 'element-plus'
import {ElNotification} from 'element-plus' import { ElNotification } from 'element-plus'
import {getDictList, getPublicKey, loginApi} from '@/api/user/login' import { getDictList, getPublicKey, loginApi } from '@/api/user/login'
import {useUserStore} from '@/stores/modules/user' import { useUserStore } from '@/stores/modules/user'
import {useTabsStore} from '@/stores/modules/tabs' import { useTabsStore } from '@/stores/modules/tabs'
import {useKeepAliveStore} from '@/stores/modules/keepAlive' import { useKeepAliveStore } from '@/stores/modules/keepAlive'
import {initDynamicRouter} from '@/routers/modules/dynamicRouter' import { initDynamicRouter } from '@/routers/modules/dynamicRouter'
import {CircleClose, UserFilled} from '@element-plus/icons-vue' import { CircleClose, UserFilled } from '@element-plus/icons-vue'
import {useAuthStore} from '@/stores/modules/auth' import { useAuthStore } from '@/stores/modules/auth'
import {useDictStore} from "@/stores/modules/dict"; import { useDictStore } from '@/stores/modules/dict'
import forge from 'node-forge' import forge from 'node-forge'
const authStore = useAuthStore() const authStore = useAuthStore()
@@ -80,97 +61,97 @@ const tabsStore = useTabsStore()
const keepAliveStore = useKeepAliveStore() const keepAliveStore = useKeepAliveStore()
const dictStore = useDictStore() const dictStore = useDictStore()
let publicKey: any = null; let publicKey: any = null
type FormInstance = InstanceType<typeof ElForm>
type FormInstance = InstanceType<typeof ElForm>;
const loginFormRef = ref<FormInstance>() const loginFormRef = ref<FormInstance>()
const loginRules = reactive({ const loginRules = reactive({
username: [{required: true, message: '请输入用户名', trigger: 'blur'}], username: [{ required: true, message: '请输入用户名', trigger: 'blur' }],
password: [{required: true, message: '请输入密码', trigger: 'blur'}], password: [{ required: true, message: '请输入密码', trigger: 'blur' }]
}) })
const loading = ref(false) const loading = ref(false)
const loginForm = reactive<Login.ReqLoginForm>({ const loginForm = reactive<Login.ReqLoginForm>({
username: '', username: '',
password: '', password: '',
checked: false, checked: false
}) })
// login // login
const login = (formEl: FormInstance | undefined) => { const login = (formEl: FormInstance | undefined) => {
if (!formEl) return if (!formEl) return
formEl.validate(async (valid) => { formEl.validate(async valid => {
if (!valid) return if (!valid) return
loading.value = true loading.value = true
try { try {
let {data: publicKeyBase64}: { data: string } = await getPublicKey(loginForm.username) let { data: publicKeyBase64 }: { data: string } = await getPublicKey(loginForm.username)
//将base64格式的公钥转换为Forge可以使用的格式 //将base64格式的公钥转换为Forge可以使用的格式
const publicKeyDer = forge.util.decode64(publicKeyBase64); const publicKeyDer = forge.util.decode64(publicKeyBase64)
publicKey = forge.pki.publicKeyFromPem(forge.pki.publicKeyToPem(forge.pki.publicKeyFromAsn1(forge.asn1.fromDer(publicKeyDer)))); publicKey = forge.pki.publicKeyFromPem(
forge.pki.publicKeyToPem(forge.pki.publicKeyFromAsn1(forge.asn1.fromDer(publicKeyDer)))
)
// 1.执行登录接口 // 1.执行登录接口
const {data} = await loginApi({ const { data } = await loginApi({
username: forge.util.encode64(loginForm.username), username: forge.util.encode64(loginForm.username),
password: encryptPassword(loginForm.password), password: encryptPassword(loginForm.password)
}) })
userStore.setAccessToken(data.accessToken) userStore.setAccessToken(data.accessToken)
userStore.setRefreshToken(data.refreshToken) userStore.setRefreshToken(data.refreshToken)
userStore.setUserInfo(data.userInfo) userStore.setUserInfo(data.userInfo)
if(loginForm.checked){ if (loginForm.checked) {
userStore.setExp(Date.now() + 1000 * 60 * 60 * 24 * 30) userStore.setExp(Date.now() + 1000 * 60 * 60 * 24 * 30)
} }
const response = await getDictList() const response = await getDictList()
const dictData = response.data as unknown as Dict[] const dictData = response.data as unknown as Dict[]
await dictStore.initDictData(dictData) await dictStore.initDictData(dictData)
// 2.添加动态路由 // 2.添加动态路由
await initDynamicRouter() await initDynamicRouter()
// 3.清空 tabs、keepAlive 数据 // 3.清空 tabs、keepAlive 数据
tabsStore.setTabs([]) tabsStore.setTabs([])
keepAliveStore.setKeepAliveName([]) keepAliveStore.setKeepAliveName([])
// 4.跳转到首页 // 4.跳转到首页
router.push(HOME_URL) router.push(HOME_URL)
// 5.登录默认不显示菜单和导航栏 // 5.登录默认不显示菜单和导航栏
authStore.resetAuthStore() authStore.resetAuthStore()
ElNotification({ ElNotification({
title: getTimeState(), title: getTimeState(),
message: '登录成功', message: '登录成功',
type: 'success', type: 'success',
duration: 3000, duration: 3000
}) })
} finally { } finally {
loading.value = false loading.value = false
} }
}) })
} }
// resetForm // resetForm
const resetForm = (formEl: FormInstance | undefined) => { const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return if (!formEl) return
formEl.resetFields() formEl.resetFields()
} }
onMounted(() => { onMounted(() => {
// 监听 enter 事件(调用登录) // 监听 enter 事件(调用登录)
document.onkeydown = (e: KeyboardEvent) => { document.onkeydown = (e: KeyboardEvent) => {
e = (window.event as KeyboardEvent) || e e = (window.event as KeyboardEvent) || e
if (e.code === 'Enter' || e.code === 'enter' || e.code === 'NumpadEnter') { if (e.code === 'Enter' || e.code === 'enter' || e.code === 'NumpadEnter') {
if (loading.value) return if (loading.value) return
login(loginFormRef.value) login(loginFormRef.value)
}
} }
}
}) })
const encryptPassword = (password: string) => { const encryptPassword = (password: string) => {
const encrypted = publicKey.encrypt(password, 'RSAES-PKCS1-V1_5'); const encrypted = publicKey.encrypt(password, 'RSAES-PKCS1-V1_5')
// 将加密后的数据转换为base64格式以便传输 // 将加密后的数据转换为base64格式以便传输
return forge.util.encode64(encrypted); return forge.util.encode64(encrypted)
} }
</script> </script>
<style scoped lang='scss'> <style scoped lang="scss">
@import "../index.scss"; @use '../index.scss';
</style> </style>

View File

@@ -1,28 +1,28 @@
<template> <template>
<div class="login-container flx-center"> <div class="login-container flx-center">
<div class="login-box"> <div class="login-box">
<!-- <SwitchDark class="dark" /> --> <!-- <SwitchDark class="dark" /> -->
<div class="login-left"> <div class="login-left">
<img class="login-left-img" src="@/assets/images/login_left.png" alt="login" /> <img class="login-left-img" src="@/assets/images/login_left.png" alt="login" />
</div> </div>
<div class="login-form"> <div class="login-form">
<div class="login-logo"> <div class="login-logo">
<!-- <img class="login-icon" src="@/assets/images/logo.svg" alt="" /> --> <!-- <img class="login-icon" src="@/assets/images/logo.svg" alt="" /> -->
<img class="login-icon" src="@/assets/images/cn_pms9100_logo.png" alt="" /> <img class="login-icon" src="@/assets/images/cn_pms9100_logo.png" alt="" />
<h2 class="logo-text">{{ title }}</h2> <h2 class="logo-text">{{ title }}</h2>
</div>
<LoginForm />
</div>
</div> </div>
<LoginForm />
</div>
</div> </div>
</div>
</template> </template>
<script setup lang="ts" name="login"> <script setup lang="ts" name="login">
import LoginForm from "./components/LoginForm.vue"; import LoginForm from './components/LoginForm.vue'
const title = import.meta.env.VITE_GLOB_APP_TITLE;
const title = import.meta.env.VITE_GLOB_APP_TITLE
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
@import "./index.scss"; @use './index.scss';
</style> </style>

View File

@@ -6,7 +6,7 @@
</div> </div>
<div class="data-check-content"> <div class="data-check-content">
<div class="content-tree"> <div class="content-tree">
<Tree ref="treeRef" :treeData="treeData" @setTab="setTab" /> <MachineTree ref="treeRef" :treeData="treeData" @setTab="setTab" />
</div> </div>
<div class="content-right-Tabs" style="height: calc(100vh - 315px); width: 100px"> <div class="content-right-Tabs" style="height: calc(100vh - 315px); width: 100px">
@@ -204,33 +204,22 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { type PropType, ref, nextTick, onMounted, watch } from 'vue' import { nextTick, onMounted, type PropType, ref, watch } from 'vue'
import Tree from './tree.vue' import MachineTree from './machineTree.vue'
import Commun from '@/views/machine/testScript/components//communication.vue' import Commun from '@/views/machine/testScript/components//communication.vue'
import { type CascaderOption, ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import { getTreeData } from '@/api/check/test' import { getTreeData } from '@/api/check/test'
import { import { VideoPause, VideoPlay, View } from '@element-plus/icons-vue'
CirclePlus,
Delete,
Check,
CopyDocument,
View,
EditPen,
VideoPlay,
VideoPause,
Loading
} from '@element-plus/icons-vue'
import type { TestScript } from '@/api/device/interface/testScript' import type { TestScript } from '@/api/device/interface/testScript'
import TestProjectPopup from '@/views/machine/testScript/components/testProjectPopup.vue' import TestProjectPopup from '@/views/machine/testScript/components/testProjectPopup.vue'
import { CheckData } from '@/api/check/interface' import { CheckData } from '@/api/check/interface'
import { dlsDetails, deleteDtls, updateDtls, addScriptDtls, checkDataList } from '@/api/device/testScript' import { dlsDetails } from '@/api/device/testScript'
import { useDictStore } from '@/stores/modules/dict' import { useDictStore } from '@/stores/modules/dict'
import { useHandleData } from '@/hooks/useHandleData'
import { scriptDtlsCheckDataList } from '@/api/device/testScript/index'
import ViewRow from '@/views/machine/testScript/components/viewRow.vue' import ViewRow from '@/views/machine/testScript/components/viewRow.vue'
import { startSimulateTest, closeSimulateTest } from '@/api/device/controlSource/index.ts' import { closeSimulateTest, startSimulateTest } from '@/api/device/controlSource/index.ts'
import { controlSource } from '@/api/device/interface/controlSource' import { controlSource } from '@/api/device/interface/controlSource'
import {JwtUtil} from "@/utils/jwtUtil"; import { JwtUtil } from '@/utils/jwtUtil'
interface TabOption { interface TabOption {
label?: string label?: string
name?: string name?: string

View File

@@ -1,165 +1,165 @@
<template> <template>
<el-tree <el-tree
node-key="id" node-key="id"
default-expand-all default-expand-all
:data="props.treeData" :data="props.treeData"
:props="defaultProps" :props="defaultProps"
style="width: 100%" style="width: 100%"
:expand-on-click-node="false" :expand-on-click-node="false"
:highlight-current="true" :highlight-current="true"
@node-click="handleNodeClick" @node-click="handleNodeClick"
show-checkbox show-checkbox
:check-strictly="true" :check-strictly="true"
@check-change="handleCheckChange" @check-change="handleCheckChange"
ref="treeRef" ref="treeRef"
> >
<template #default="{ node, data }"> <template #default="{ node, data }">
<el-tooltip effect="dark" :content="data.sourceDesc || data.scriptTypeName" placement="top" :hide-after="0"> <el-tooltip effect="dark" :content="data.sourceDesc || data.scriptTypeName" placement="top" :hide-after="0">
<div class="custom-tree-node"> <div class="custom-tree-node">
{{ data.scriptTypeName || data.sourceDesc }} {{ data.scriptTypeName || data.sourceDesc }}
</div> </div>
</el-tooltip> </el-tooltip>
</template> </template>
</el-tree> </el-tree>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, reactive, onMounted, watch, nextTick } from 'vue' import { ref, reactive, onMounted, watch, nextTick } from 'vue'
import { CheckData } from '@/api/check/interface' import { CheckData } from '@/api/check/interface'
import { da } from 'element-plus/es/locale' import { da } from 'element-plus/es/locale'
import { on } from 'events' import { on } from 'events'
const props = defineProps({ const props = defineProps({
treeData: { treeData: {
type: Array, type: Array,
required: true required: true
} }
}) })
const emit = defineEmits(['setTab']) const emit = defineEmits(['setTab'])
const dataTree = ref<CheckData.TreeItem[]>([]) const dataTree = ref<CheckData.TreeItem[]>([])
const defaultProps = { const defaultProps = {
children: 'children', children: 'children',
label: 'scriptTypeName', label: 'scriptTypeName',
pid: 'pid' pid: 'pid'
} }
const activeName = ref('') const activeName = ref('')
const childActiveName = ref('') const childActiveName = ref('')
const activeIndex = ref() const activeIndex = ref()
const treeRef = ref() const treeRef = ref()
const handleNodeClick = (data, node) => { const handleNodeClick = (data, node) => {
if(data.index!= null){ if(data.index!= null){
let code = ['Base', 'VOL', 'Freq', 'Harm', 'Base_0_10', 'Base_20_85', 'Base_110_200'] let code = ['Base', 'VOL', 'Freq', 'Harm', 'Base_0_10', 'Base_20_85', 'Base_110_200']
const parents = getParentNodes(node, []) const parents = getParentNodes(node, [])
parents.pop() parents.pop()
parents.unshift(node.data) parents.unshift(node.data)
parents.reverse() parents.reverse()
let active = parents[0].scriptTypeCode let active = parents[0].scriptTypeCode
let childActive = findTargetCodes(parents, code)[0] || '' let childActive = findTargetCodes(parents, code)[0] || ''
// //
if (activeName.value != active || childActiveName.value != childActive || activeIndex.value != data.index) { if (activeName.value != active || childActiveName.value != childActive || activeIndex.value != data.index) {
activeName.value = active activeName.value = active
childActiveName.value = childActive childActiveName.value = childActive
emit('setTab', { emit('setTab', {
activeName: active, activeName: active,
childActiveName: childActive, childActiveName: childActive,
activeIndex:data.index activeIndex:data.index
}) })
} }
} }
} }
// //
const getParentNodes = (node, parents) => { const getParentNodes = (node, parents) => {
if (node.parent) { if (node.parent) {
// //
parents.push(node.parent.data) parents.push(node.parent.data)
// //
getParentNodes(node.parent, parents) getParentNodes(node.parent, parents)
} }
return parents return parents
} }
// childActiveName // childActiveName
function findTargetCodes(data: any[], targetCodes: string[]) { function findTargetCodes(data: any[], targetCodes: string[]) {
let result: string[] = [] let result: string[] = []
data.forEach(item => { data.forEach(item => {
if (item.scriptTypeCode != null) { if (item.scriptTypeCode != null) {
if (targetCodes.includes(item.scriptTypeCode)) { if (targetCodes.includes(item.scriptTypeCode)) {
result.push(item.scriptTypeCode) result.push(item.scriptTypeCode)
} }
} }
}) })
return result return result
// for (let item of data) { // for (let item of data) {
// // scriptTypeCode // // scriptTypeCode
// if (item.scriptTypeCode !=null && targetCodes.includes(item.scriptTypeCode)) { // if (item.scriptTypeCode !=null && targetCodes.includes(item.scriptTypeCode)) {
// result.push(item.scriptTypeCode) // result.push(item.scriptTypeCode)
// return result // return result
// } // }
// // children // // children
// if (item.children && item.children.length > 0) { // if (item.children && item.children.length > 0) {
// result = result.concat(findTargetCodes(item.children, targetCodes)) // result = result.concat(findTargetCodes(item.children, targetCodes))
// } // }
// } // }
// return result // return result
} }
function handleCheckChange(data,isChecked) { function handleCheckChange(data,isChecked) {
if (isChecked) if (isChecked)
{ {
// //
const checked = [data.id]; // idtreenode-key const checked = [data.id]; // idtreenode-key
treeRef.value?.setCheckedKeys(checked); treeRef.value?.setCheckedKeys(checked);
emit('setTab', { emit('setTab', {
activeName: data.scriptType, activeName: data.scriptType,
childActiveName: data.scriptTypeCode, childActiveName: data.scriptTypeCode,
activeIndex:data.index activeIndex:data.index
}) })
} }
} }
// //
function findFirstLeafNode(node: any): any { function findFirstLeafNode(node: any): any {
if (node.children && node.children.length > 0) { if (node.children && node.children.length > 0) {
return findFirstLeafNode(node.children[0]); return findFirstLeafNode(node.children[0]);
} }
return node; return node;
} }
const checkTree = () => { const checkTree = () => {
console.log('checkTree11') console.log('checkTree11')
console.log('checkTree22',props.treeData.length) console.log('checkTree22',props.treeData.length)
console.log('checkTree33',treeRef.value) console.log('checkTree33',treeRef.value)
if (props.treeData.length > 0 && treeRef.value) { if (props.treeData.length > 0 && treeRef.value) {
console.log('checkTree44') console.log('checkTree44')
const firstNode = props.treeData[0]; const firstNode = props.treeData[0];
const firstLeafNode = findFirstLeafNode(firstNode); const firstLeafNode = findFirstLeafNode(firstNode);
const firstLeafNodeId = firstLeafNode.id; const firstLeafNodeId = firstLeafNode.id;
treeRef.value.setCheckedKeys([firstLeafNodeId]); treeRef.value.setCheckedKeys([firstLeafNodeId]);
} }
} }
// //
onMounted(() => { onMounted(() => {
console.log('onMounted',props.treeData); console.log('onMounted',props.treeData);
nextTick(() => { nextTick(() => {
checkTree() checkTree()
}); });
}); });
// // // //
defineExpose({ checkTree }) defineExpose({ checkTree })
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.custom-tree-node { .custom-tree-node {
max-width: 230px; max-width: 230px;
overflow-x: hidden !important; overflow-x: hidden !important;
white-space: nowrap !important; white-space: nowrap !important;
text-overflow: ellipsis !important; text-overflow: ellipsis !important;
} }
</style> </style>

View File

@@ -1,199 +1,222 @@
<!-- components/MonitorPointTable.vue --> <!-- components/MonitorPointTable.vue -->
<template> <template>
<div class='table-box'> <div class="table-box">
<ProTable <ProTable
ref='proTable' ref="proTable"
:pagination="false" :pagination="false"
:toolButton="false" :toolButton="false"
:columns='columns' :columns="columns"
:data="tableData" :data="tableData"
:style="{ height: tableHeight + 'px',overflow:'hidden'}" :style="{ height: tableHeight + 'px', overflow: 'hidden' }"
> >
<!-- 表格 header 按钮 --> <!-- 表格 header 按钮 -->
<template #tableHeader='scope'> <template #tableHeader="scope">
<el-button type='primary' :icon='CirclePlus' @click="openDialog('add')" :disabled="props.DevFormContent.importFlag == 1">新增</el-button> <el-button
<el-button v-auth.device="'delete'" type='danger' :icon='Delete' plain :disabled='!scope.isSelected' type="primary"
@click='batchDelete(scope.selectedListIds)'> :icon="CirclePlus"
删除 @click="openDialog('add')"
</el-button> :disabled="props.DevFormContent.importFlag == 1"
</template> >
<!-- 表格操作 --> 新增
<template #operation="scope"> </el-button>
<el-button v-auth.device="'edit'" type='primary' link :icon='EditPen' :model-value='false' :disabled="props.DevFormContent.importFlag == 1" <el-button
@click="openDialog('edit', scope.row)">编辑 v-auth.device="'delete'"
</el-button> type="danger"
<el-button v-auth.device="'delete'" type='primary' link :icon='Delete' @click='handleDelete(scope.row.id)' >删除 :icon="Delete"
</el-button> plain
</template> :disabled="!scope.isSelected"
@click="batchDelete(scope.selectedListIds)"
>
删除
</el-button>
</template>
<!-- 表格操作 -->
<template #operation="scope">
<el-button
v-auth.device="'edit'"
type="primary"
link
:icon="EditPen"
:model-value="false"
:disabled="props.DevFormContent.importFlag == 1"
@click="openDialog('edit', scope.row)"
>
编辑
</el-button>
<el-button
v-auth.device="'delete'"
type="primary"
link
:icon="Delete"
@click="handleDelete(scope.row.id)"
>
删除
</el-button>
</template>
</ProTable> </ProTable>
</div> </div>
<MonitorPopup @getParameter="getParameter" ref='monitorPopup'/> <MonitorPopup @getParameter="getParameter" ref="monitorPopup" />
</template> </template>
<script setup lang="ts">
import { ref, defineProps, reactive, watch } from 'vue';
import ProTable from '@/components/ProTable/index.vue'; // 假设 ProTable 是自定义组件
import { CirclePlus, Delete, EditPen, MessageBox } from '@element-plus/icons-vue';
import MonitorPopup from '@/views/machine/device/components/monitorPopup.vue'
import { ProTableInstance, type ColumnProps } from '@/components/ProTable/interface'
import { type Monitor } from '@/api/device/interface/monitor'
import { useDictStore } from '@/stores/modules/dict';
import { useHandleData } from '@/hooks/useHandleData';
import { Device } from '@/api/device/interface/device';
import { ElMessage, ElMessageBox } from 'element-plus';
// 定义 props <script setup lang="ts">
const props = defineProps<{ import { reactive, ref, watch } from 'vue'
DevFormContent:Device.ResPqDev, import ProTable from '@/components/ProTable/index.vue' // 假设 ProTable 是自定义组件
tableHeight?: number, // 接收外部传入的高度 import { CirclePlus, Delete, EditPen } from '@element-plus/icons-vue'
selectOptions: Record<string, Device.SelectOption[]>, import MonitorPopup from '@/views/machine/device/components/monitorPopup.vue'
}>(); import { type ColumnProps, ProTableInstance } from '@/components/ProTable/interface'
import { type Monitor } from '@/api/device/interface/monitor'
import { useDictStore } from '@/stores/modules/dict'
import { Device } from '@/api/device/interface/device'
import { ElMessage, ElMessageBox } from 'element-plus'
// ProTable 实例 // 定义 props
const proTable = ref<ProTableInstance>() const props = defineProps<{
const dictStore = useDictStore() DevFormContent: Device.ResPqDev
const monitorPopup = ref() tableHeight?: number // 接收外部传入的高度
const tableData = ref<any[]>([]) selectOptions: Record<string, Device.SelectOption[]>
const title_Type = ref('add') }>()
// 表格配置项 // ProTable 实例
const proTable = ref<ProTableInstance>()
const dictStore = useDictStore()
const monitorPopup = ref()
const tableData = ref<any[]>([])
const title_Type = ref('add')
// 表格配置项
const columns = reactive<ColumnProps<Monitor.ResPqMon>[]>([ const columns = reactive<ColumnProps<Monitor.ResPqMon>[]>([
{ type: 'selection', fixed: 'left', width: 70 }, { type: 'selection', fixed: 'left', width: 70 },
{ type: 'index', fixed: 'left', width: 70, label: '序号' }, { type: 'index', fixed: 'left', width: 70, label: '序号' },
{ {
prop: 'name', prop: 'name',
label: '名称', label: '名称',
width: 200, width: 200
},
{
prop: 'busbar',
label: '所属母线',
width: 200,
},
{
prop: 'num',
label: '线路号',
width: 200,
},
{
prop: 'pt',
label: 'PT变比',
width: 110,
},
{
prop: 'ct',
label: 'CT变比',
width: 130,
},
{
prop: 'connection',
label: '接线方式',
enum: dictStore.getDictData('Dev_Connect'),
fieldNames: {label: 'name', value: 'id'},
width: 130,
},
{
prop: 'statInterval',
label: '统计间隔',
width: 130,
},
{
prop: 'checkFlag',
label: '是否参与检测',
render: (scope: any) => {
return scope.row.checkFlag === 1 ? '是' : '否'
}, },
width: 130, {
}, prop: 'busbar',
{ prop: 'operation', label: '操作', fixed: 'right', width: 200 }, label: '所属母线',
width: 200
},
{
prop: 'num',
label: '线路号',
width: 200
},
{
prop: 'pt',
label: 'PT变比',
width: 110
},
{
prop: 'ct',
label: 'CT变比',
width: 130
},
{
prop: 'connection',
label: '接线方式',
enum: dictStore.getDictData('Dev_Connect'),
fieldNames: { label: 'name', value: 'id' },
width: 130
},
{
prop: 'statInterval',
label: '统计间隔',
width: 130
},
{
prop: 'checkFlag',
label: '是否参与检测',
render: (scope: any) => {
return scope.row.checkFlag === 1 ? '是' : '否'
},
width: 130
},
{ prop: 'operation', label: '操作', fixed: 'right', width: 200 }
]) ])
const emit = defineEmits(['get-parameter']) const emit = defineEmits(['get-parameter'])
const getParameter = (data: Monitor.ResPqMon) => { const getParameter = (data: Monitor.ResPqMon) => {
console.log('data', data) console.log('data', data)
if (title_Type.value === 'edit') { if (title_Type.value === 'edit') {
// 编辑:替换已有的数据 // 编辑:替换已有的数据
const index = tableData.value.findIndex(item => item.id === data.id) const index = tableData.value.findIndex(item => item.id === data.id)
if (index > -1) { if (index > -1) {
tableData.value = [ tableData.value = [...tableData.value.slice(0, index), data, ...tableData.value.slice(index + 1)]
...tableData.value.slice(0, index), }
data, } else {
...tableData.value.slice(index + 1) // 新增:追加数据
] tableData.value = [...tableData.value, data]
} }
} else { emit('get-parameter', tableData.value)
// 新增:追加数据
tableData.value = [...tableData.value, data]
}
emit('get-parameter', tableData.value)
} }
// 打开 drawer(新增、编辑)
// 打开 drawer(新增、编辑) const openDialog = (titleType: string, row: Partial<Monitor.ResPqMon> = {}) => {
const openDialog = (titleType: string, row: Partial<Monitor.ResPqMon> = {}) => { if (props.DevFormContent.devType == '' || props.DevFormContent.devType == undefined) {
if(props.DevFormContent.devType == '' || props.DevFormContent.devType == undefined){ ElMessageBox.confirm('请先选择被检设备类型', '提示', {
ElMessageBox.confirm( confirmButtonText: '确定',
'请先选择被检设备类型', cancelButtonText: '取消',
'提示', type: 'warning'
{ })
confirmButtonText: '确定', return
cancelButtonText: '取消', }
type: 'warning', // 新增时检查线路号是否全部被占用
}, if (titleType === 'add') {
) if(props.DevFormContent.devChns == tableData.value.length){
ElMessageBox.confirm(`线路号已全部被占用,无法新增监测点`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
return return
} }
title_Type.value = titleType
monitorPopup.value?.open(titleType, row,props.DevFormContent,tableData.value,props.selectOptions) }
} title_Type.value = titleType
monitorPopup.value?.open(titleType, row, props.DevFormContent, tableData.value, props.selectOptions)
// 批量删除监测点台账
const batchDelete = (ids: string[]) => {
ElMessageBox.confirm(`是否批量删除监测点?`, "温馨提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
draggable: true
}).then(async () => {
tableData.value = tableData.value.filter(item => !ids.includes(item.id));
proTable.value?.clearSelection()
emit('get-parameter', tableData.value)
ElMessage({
type: "success",
message: `批量删除监测点成功!`
});
});
}
// 删除监测点台账
const handleDelete = (id: string) => {
ElMessageBox.confirm(`是否删除监测点?`, "温馨提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
draggable: true
}).then(async () => {
tableData.value = tableData.value.filter(item => item.id !== id)
proTable.value?.clearSelection()
emit('get-parameter', tableData.value)
ElMessage({
type: "success",
message: `删除监测点成功!`
});
});
} }
// 批量删除监测点台账
const batchDelete = (ids: string[]) => {
ElMessageBox.confirm(`是否批量删除监测点?`, '温馨提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
draggable: true
}).then(async () => {
tableData.value = tableData.value.filter(item => !ids.includes(item.id))
proTable.value?.clearSelection()
emit('get-parameter', tableData.value)
ElMessage({
type: 'success',
message: `批量删除监测点成功!`
})
})
}
// 删除监测点台账
const handleDelete = (id: string) => {
ElMessageBox.confirm(`是否删除监测点?`, '温馨提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
draggable: true
}).then(async () => {
tableData.value = tableData.value.filter(item => item.id !== id)
proTable.value?.clearSelection()
emit('get-parameter', tableData.value)
ElMessage({
type: 'success',
message: `删除监测点成功!`
})
})
}
watch( watch(
() => props.DevFormContent.monitorList, () => props.DevFormContent.monitorList,
(newVal) => { newVal => {
tableData.value = newVal|| [] tableData.value = newVal || []
}, },
{ immediate: true } { immediate: true }
) )
</script>
</script>

View File

@@ -1,8 +1,8 @@
<template> <template>
<el-dialog :title="dialogTitle" v-model="dialogVisible" @close="close" v-bind="dialogBig" align-center>
<el-dialog :title="dialogTitle" v-model='dialogVisible' @close="close" v-bind="dialogBig" align-center> <div class="table-container">
<div class="table-container"> <el-table
<el-table :data="errorData.value" :data="errorData.value"
height="500" height="500"
:header-cell-style="rowClass" :header-cell-style="rowClass"
:cell-style="{ textAlign: 'center' }" :cell-style="{ textAlign: 'center' }"
@@ -10,309 +10,374 @@
:span-method="spanMethod" :span-method="spanMethod"
:border="true" :border="true"
class="custom-table" class="custom-table"
> >
<el-table-column label="被测量"> <el-table-column label="被测量">
<el-table-column prop="col1" width="150"/> <el-table-column prop="col1" width="150" />
<el-table-column prop="col2" width="120"/> <el-table-column prop="col2" width="120" />
</el-table-column> </el-table-column>
<el-table-column prop="deviceLevel" label="检测装置级别" width="120"/> <el-table-column prop="deviceLevel" label="检测装置级别" width="120" />
<el-table-column prop="measurementType" label="测量类型"/> <el-table-column prop="measurementType" label="测量类型" />
<el-table-column prop="condition" label="测量条件"/> <el-table-column prop="condition" label="测量条件" />
<el-table-column prop="maxErrorValue" label="最大误差"/> <el-table-column prop="maxErrorValue" label="最大误差" />
</el-table> </el-table>
</div> </div>
<div> <div>
<label class="left-align-label">注1UN测量的标称电压IN测量仪器的标称电流Uh和Ih测量值h表示谐波次数</label> <label class="left-align-label">
</div> 注1UN测量的标称电压IN测量仪器的标称电流Uh和Ih测量值h表示谐波次数
<div> </label>
<label class="left-align-label">注2对于数字式接入监测终端与电能质量信号采集单元联合准确度需满足本表要求</label> </div>
</div> <div>
</el-dialog> <label class="left-align-label">
注2对于数字式接入监测终端与电能质量信号采集单元联合准确度需满足本表要求
</label>
</div>
</el-dialog>
</template> </template>
<script lang="ts" setup name="IndicatorTypeDialog"> <script lang="ts" setup name="IndicatorTypeDialog">
import {computed, type CSSProperties, defineProps, ref} from 'vue'; import { computed, type CSSProperties, ref } from 'vue'
import {dialogBig} from '@/utils/elementBind' import { dialogBig } from '@/utils/elementBind'
import type {ErrorSystem} from '@/api/device/interface/error' import type { ErrorSystem } from '@/api/device/interface/error'
import errorDataList from '@/api/device/error/errorData' import errorDataList from '@/api/device/error/errorData'
import type {TableColumnCtx} from 'element-plus' import type { TableColumnCtx } from 'element-plus'
import {useDictStore} from '@/stores/modules/dict' import { useDictStore } from '@/stores/modules/dict'
const dictStore = useDictStore() const dictStore = useDictStore()
const errorData = ref<ErrorSystem.Error_detail[]>([]); const errorData = ref<ErrorSystem.Error_detail[]>([])
const dialogTitle = ref() const dialogTitle = ref()
const devLevelName = ref<string>('') // 假设 devLevelName 是一个 ref const devLevelName = ref<string>('') // 假设 devLevelName 是一个 ref
function useMetaInfo() { function useMetaInfo() {
const dialogVisible = ref(false) const dialogVisible = ref(false)
const formContent = ref<ErrorSystem.ErrorSystemList>({ const formContent = ref<ErrorSystem.ErrorSystemList>({
id: '', id: '',
name: '', name: '',
standardName: '', standardName: '',
standardTime: '', standardTime: '',
devLevel: '', devLevel: '',
enable: 1, enable: 1,
state: 1, state: 1
}) })
return {dialogVisible, formContent} return { dialogVisible, formContent }
} }
const {dialogVisible, formContent} = useMetaInfo() const { dialogVisible, formContent } = useMetaInfo()
interface SpanMethodProps { interface SpanMethodProps {
row: ErrorSystem.ErrorSystemDetail row: ErrorSystem.ErrorSystemDetail
column: TableColumnCtx<ErrorSystem.ErrorSystemDetail> column: TableColumnCtx<ErrorSystem.ErrorSystemDetail>
rowIndex: number rowIndex: number
columnIndex: number columnIndex: number
} }
const rowClass = ({row, column, rowIndex, columnIndex}: { row: any; column: any; rowIndex: number; columnIndex: number }): CSSProperties => { const rowClass = ({
let res: CSSProperties = { row,
textAlign: 'center' as CSSProperties['textAlign'], column,
backgroundColor: 'var(--el-color-primary)', rowIndex,
color: '#fff' columnIndex
} }: {
if (rowIndex === 1) { row: any
res = {...res, display: 'none'} column: any
} rowIndex: number
return res columnIndex: number
}): CSSProperties => {
let res: CSSProperties = {
textAlign: 'center' as CSSProperties['textAlign'],
backgroundColor: 'var(--el-color-primary)',
color: '#fff'
}
if (rowIndex === 1) {
res = { ...res, display: 'none' }
}
return res
} }
const spanMethod = computed(() => { const spanMethod = computed(() => {
return devLevelName.value === 'A级' ? spanAMethod : spanSMethod return devLevelName.value === 'A级' ? spanAMethod : spanSMethod
}) })
const spanAMethod = ({ const spanAMethod = ({ row, column, rowIndex, columnIndex }: SpanMethodProps) => {
row, if (columnIndex === 0) {
column, if (rowIndex <= 1 || rowIndex === 7 || rowIndex == 20) {
rowIndex, //0电压偏差1频率偏差7闪变20功率简单的跨两列
columnIndex, return {
}: SpanMethodProps) => { rowspan: 1,
if (columnIndex === 0) { colspan: 2
if (rowIndex <= 1 || rowIndex === 7 || rowIndex == 20) {//0电压偏差1频率偏差7闪变20功率简单的跨两列 }
return { }
rowspan: 1, if (rowIndex === 2) {
colspan: 2, //2三相不平衡跨三行两列
} return {
rowspan: 3,
colspan: 2
}
}
if (
rowIndex === 3 ||
rowIndex === 4 ||
rowIndex === 6 ||
(rowIndex >= 9 && rowIndex <= 15) ||
(rowIndex >= 17 && rowIndex <= 19) ||
rowIndex === 22 ||
rowIndex === 24
) {
//这些行不显示
return {
rowspan: 0,
colspan: 0
}
}
if (rowIndex === 5 || rowIndex === 23) {
//5电压波动23电压暂降暂升中断跨两列
return {
rowspan: 2,
colspan: 1
}
}
if (rowIndex === 8) {
//谐波和间谐波跨八行两列
return {
rowspan: 8,
colspan: 2
}
}
if (rowIndex === 16) {
//高频次谐波跨八行两列
return {
rowspan: 4,
colspan: 2
}
}
if (rowIndex === 21 || rowIndex === 22) {
//电流跨两行两列
return {
rowspan: 2,
colspan: 2
}
}
} }
if (rowIndex === 2) {//2三相不平衡跨三行两列 if (columnIndex === 1) {
return { if (rowIndex <= 4 || (rowIndex >= 7 && rowIndex <= 22)) {
rowspan: 3, return {
colspan: 2, rowspan: 0,
} colspan: 0
}
}
} }
if (rowIndex === 3 || rowIndex === 4 || rowIndex === 6 || if (columnIndex === 2 || columnIndex === 3) {
rowIndex >= 9 && rowIndex <= 15 || if (
rowIndex >= 17 && rowIndex <= 19 || rowIndex === 2 ||
rowIndex === 22 || rowIndex === 24) {//这些行不显示 rowIndex === 8 ||
return { rowIndex === 10 ||
rowspan: 0, rowIndex === 12 ||
colspan: 0, rowIndex === 14 ||
} rowIndex === 16 ||
rowIndex === 18 ||
rowIndex === 21
) {
return {
rowspan: 2,
colspan: 1
}
}
if (
rowIndex === 3 ||
rowIndex === 9 ||
rowIndex === 11 ||
rowIndex === 13 ||
rowIndex === 15 ||
rowIndex === 17 ||
rowIndex === 19 ||
rowIndex === 22
) {
return {
rowspan: 0,
colspan: 0
}
}
} }
if (rowIndex === 5 || rowIndex === 23) {//5电压波动23电压暂降暂升中断跨两列 }
return {
rowspan: 2,
colspan: 1,
}
}
if (rowIndex === 8) {//谐波和间谐波跨八行两列
return {
rowspan: 8,
colspan: 2,
}
}
if (rowIndex === 16) {//高频次谐波跨八行两列
return {
rowspan: 4,
colspan: 2,
}
}
if (rowIndex === 21 || rowIndex === 22) {//电流跨两行两列
return {
rowspan: 2,
colspan: 2,
}
}
}
if (columnIndex === 1) {
if (rowIndex <= 4 || rowIndex >= 7 && rowIndex <= 22) {
return {
rowspan: 0,
colspan: 0,
}
}
}
if (columnIndex === 2 || columnIndex === 3) {
if (rowIndex === 2 || rowIndex === 8 || rowIndex === 10 ||
rowIndex === 12 || rowIndex === 14 || rowIndex === 16 ||
rowIndex === 18 || rowIndex === 21) {
return {
rowspan: 2,
colspan: 1,
}
}
if (rowIndex === 3 || rowIndex === 9 || rowIndex === 11 ||
rowIndex === 13 || rowIndex === 15 || rowIndex === 17 ||
rowIndex === 19 || rowIndex === 22) {
return {
rowspan: 0,
colspan: 0,
}
}
}
};
const spanSMethod = ({ row, column, rowIndex, columnIndex }: SpanMethodProps) => {
const spanSMethod = ({ if (columnIndex === 0) {
row, if (rowIndex <= 1 || rowIndex === 8 || rowIndex == 17) {
column, //0电压偏差1频率偏差7闪变20功率简单的跨两列
rowIndex, return {
columnIndex, rowspan: 1,
}: SpanMethodProps) => { colspan: 2
if (columnIndex === 0) { }
if (rowIndex <= 1 || rowIndex === 8 || rowIndex == 17) {//0电压偏差1频率偏差7闪变20功率简单的跨两列 }
return { if (rowIndex === 2) {
rowspan: 1, //2三相不平衡跨三行两列
colspan: 2, return {
} rowspan: 3,
colspan: 2
}
}
if (
rowIndex === 3 ||
rowIndex === 4 ||
rowIndex === 6 ||
rowIndex === 7 ||
(rowIndex >= 10 && rowIndex <= 12) ||
(rowIndex >= 14 && rowIndex <= 16) ||
rowIndex === 19 ||
rowIndex === 21 ||
rowIndex === 22
) {
//这些行不显示
return {
rowspan: 0,
colspan: 0
}
}
if (rowIndex === 5 || rowIndex === 20) {
//5电压波动23电压暂降暂升中断跨两行
return {
rowspan: 3,
colspan: 1
}
}
if (rowIndex === 9 || rowIndex === 13) {
//谐波和间谐波跨八行两列
return {
rowspan: 4,
colspan: 2
}
}
if (rowIndex === 18) {
//电流跨两行两列
return {
rowspan: 2,
colspan: 2
}
}
} }
if (rowIndex === 2) {//2三相不平衡跨三行两列 if (columnIndex === 1) {
return { if (rowIndex === 6 || rowIndex === 21) {
rowspan: 3, return {
colspan: 2, rowspan: 2,
} colspan: 1
}
}
if (rowIndex <= 4 || (rowIndex >= 7 && rowIndex <= 19) || rowIndex === 22) {
return {
rowspan: 0,
colspan: 0
}
}
} }
if (rowIndex === 3 || rowIndex === 4 || rowIndex === 6 || rowIndex === 7 || if (columnIndex === 2) {
rowIndex >= 10 && rowIndex <= 12 || if (
rowIndex >= 14 && rowIndex <= 16 || rowIndex === 2 ||
rowIndex === 19 || rowIndex === 21 || rowIndex === 22) {//这些行不显示 rowIndex === 6 ||
return { rowIndex === 9 ||
rowspan: 0, rowIndex === 11 ||
colspan: 0, rowIndex === 13 ||
} rowIndex === 15 ||
rowIndex === 18 ||
rowIndex === 21
) {
return {
rowspan: 2,
colspan: 1
}
}
if (
rowIndex === 3 ||
rowIndex === 7 ||
rowIndex === 10 ||
rowIndex === 12 ||
rowIndex === 14 ||
rowIndex === 16 ||
rowIndex === 19 ||
rowIndex === 22
) {
return {
rowspan: 0,
colspan: 0
}
}
} }
if (rowIndex === 5 || rowIndex === 20) {//5电压波动23电压暂降暂升中断跨两行 if (columnIndex === 3) {
return { if (
rowspan: 3, rowIndex === 2 ||
colspan: 1, rowIndex === 6 ||
} rowIndex === 9 ||
rowIndex === 11 ||
rowIndex === 13 ||
rowIndex === 15 ||
rowIndex === 18 ||
rowIndex === 21
) {
return {
rowspan: 2,
colspan: 1
}
}
if (
rowIndex === 3 ||
rowIndex === 7 ||
rowIndex === 10 ||
rowIndex === 12 ||
rowIndex === 14 ||
rowIndex === 16 ||
rowIndex === 19 ||
rowIndex === 22
) {
return {
rowspan: 0,
colspan: 0
}
}
} }
if (rowIndex === 9 || rowIndex === 13) {//谐波和间谐波跨八行两列 }
return {
rowspan: 4,
colspan: 2,
}
}
if (rowIndex === 18) {//电流跨两行两列
return {
rowspan: 2,
colspan: 2,
}
}
}
if (columnIndex === 1) {
if (rowIndex === 6 || rowIndex === 21) {
return {
rowspan: 2,
colspan: 1,
}
}
if (rowIndex <= 4 || rowIndex >= 7 && rowIndex <= 19 || rowIndex === 22) {
return {
rowspan: 0,
colspan: 0,
}
}
}
if (columnIndex === 2) {
if (rowIndex === 2 || rowIndex === 6 || rowIndex === 9 ||
rowIndex === 11 || rowIndex === 13 || rowIndex === 15 ||
rowIndex === 18 || rowIndex === 21) {
return {
rowspan: 2,
colspan: 1,
}
}
if (rowIndex === 3 || rowIndex === 7 ||
rowIndex === 10 || rowIndex === 12 ||
rowIndex === 14 || rowIndex === 16 ||
rowIndex === 19 || rowIndex === 22) {
return {
rowspan: 0,
colspan: 0,
}
}
}
if (columnIndex === 3) {
if (rowIndex === 2 || rowIndex === 6 || rowIndex === 9 ||
rowIndex === 11 || rowIndex === 13 || rowIndex === 15 ||
rowIndex === 18 || rowIndex === 21) {
return {
rowspan: 2,
colspan: 1,
}
}
if (rowIndex === 3 || rowIndex === 7 || rowIndex === 10 ||
rowIndex === 12 || rowIndex === 14 || rowIndex === 16 ||
rowIndex === 19 || rowIndex === 22) {
return {
rowspan: 0,
colspan: 0,
}
}
}
};
// 关闭弹窗 // 关闭弹窗
const close = () => { const close = () => {
dialogVisible.value = false dialogVisible.value = false
} }
// 打开弹窗,可能是新增,也可能是编辑 // 打开弹窗,可能是新增,也可能是编辑
const open = async (sign: string, data: ErrorSystem.ErrorSystemList) => { const open = async (sign: string, data: ErrorSystem.ErrorSystemList) => {
dialogTitle.value = sign + ' 误差体系' dialogTitle.value = sign + ' 误差体系'
dialogVisible.value = true dialogVisible.value = true
if (data.id) { if (data.id) {
formContent.value = data as ErrorSystem.ErrorSystemList; formContent.value = data as ErrorSystem.ErrorSystemList
devLevelName.value = dictStore.getDictData('Dev_Level').find(item => item.id === data.devLevel)?.name || ''; devLevelName.value = dictStore.getDictData('Dev_Level').find(item => item.id === data.devLevel)?.name || ''
if (devLevelName.value === 'A级' || data.devLevel === 'A级') { if (devLevelName.value === 'A级' || data.devLevel === 'A级') {
errorData.value = errorDataList.errorADetail as unknown as ErrorSystem.Error_detail[]; errorData.value = errorDataList.errorADetail as unknown as ErrorSystem.Error_detail[]
} else { } else {
errorData.value = errorDataList.errorSDetail as unknown as ErrorSystem.Error_detail[]; errorData.value = errorDataList.errorSDetail as unknown as ErrorSystem.Error_detail[]
}
} }
}
} }
// 对外映射 // 对外映射
defineExpose({open}) defineExpose({ open })
const props = defineProps<{ const props = defineProps<{
refreshTable: (() => Promise<void>) | undefined; refreshTable: (() => Promise<void>) | undefined
}>() }>()
</script> </script>
<style> <style>
.table-container { .table-container {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
} }
.custom-table { .custom-table {
margin-bottom: 20px; /* 调整表格和注释之间的间距 */ margin-bottom: 20px; /* 调整表格和注释之间的间距 */
} }
.notes-container { .notes-container {
text-align: center; text-align: center;
width: 100%; /* 确保注释容器宽度与表格一致 */ width: 100%; /* 确保注释容器宽度与表格一致 */
} }
.notes-container label { .notes-container label {
display: block; /* 使每个label标签上下排列 */ display: block; /* 使每个label标签上下排列 */
margin-bottom: 10px; /* 调整两个label之间的间距 */ margin-bottom: 10px; /* 调整两个label之间的间距 */
} }
</style> </style>

View File

@@ -1,350 +1,372 @@
<template> <template>
<div class="dialog-footer"> <div class="dialog-footer">
<el-button :icon='CirclePlus' type="primary" @click="openAddDialog">新增</el-button> <el-button :icon="CirclePlus" type="primary" @click="openAddDialog">新增</el-button>
<el-button :icon='Delete' type="danger" plain :disabled='!multipleSelection.length' @click="deleteSelectedRows">删除</el-button> <el-button :icon="Delete" type="danger" plain :disabled="!multipleSelection.length" @click="deleteSelectedRows">
</div> 删除
<div class="table-container"> </el-button>
<el-table :data="tableData" </div>
:header-cell-style="{ textAlign: 'center',backgroundColor: 'var(--el-color-primary)',color: '#fff' } " <div class="table-container">
:cell-style="{ textAlign: 'center' }" <el-table
style="width: 100%" :data="tableData"
:style="{ height: '400px',maxHeight: '400px',overflow:'hidden'}" :header-cell-style="{ textAlign: 'center', backgroundColor: 'var(--el-color-primary)', color: '#fff' }"
@selection-change="handleSelectionChange"> :cell-style="{ textAlign: 'center' }"
<el-table-column type="selection" width="55"/> style="width: 100%"
<el-table-column prop="sort" label="序号" width="60"/> :style="{ height: '400px', maxHeight: '400px', overflow: 'hidden' }"
<el-table-column prop="type" label="误差类型" min-width="180"> @selection-change="handleSelectionChange"
<template #default="{ row }"> >
<el-cascader style="min-width: 180px;" <el-table-column type="selection" width="55" />
:options="errorOptions" <el-table-column prop="sort" label="序号" width="60" />
v-model="row.errorType" <el-table-column prop="type" label="误差类型" min-width="180">
:props="{ checkStrictly: false, emitPath: false }" <template #default="{ row }">
placeholder="请选择误差类型" <el-cascader
@change="handleErrorTypeChange($event, row)"/> style="min-width: 180px"
</template> :options="errorOptions"
</el-table-column> v-model="row.errorType"
<el-table-column prop="type" label="脚本类型" min-width="230"> :props="{ checkStrictly: false, emitPath: false }"
<template #default="{ row }"> placeholder="请选择误差类型"
<el-cascader style="min-width: 230px;" @change="handleErrorTypeChange($event, row)"
:options="scriptOptions" />
v-model="row.scriptType" </template>
:props="{ checkStrictly: false, emitPath: false }" </el-table-column>
placeholder="请选择脚本类型" <el-table-column prop="type" label="脚本类型" min-width="230">
@change="handleScriptTypeChange(row)"/> <template #default="{ row }">
</template> <el-cascader
</el-table-column> style="min-width: 230px"
<el-table-column label="起止范围"> :options="scriptOptions"
<el-table-column label="起始" width="150"> v-model="row.scriptType"
<template #default="{ row }"> :props="{ checkStrictly: false, emitPath: false }"
<el-row type="flex" :gutter="24"> placeholder="请选择脚本类型"
<el-col :span="12"> @change="handleScriptTypeChange(row)"
<el-select v-model="row.startFlag" placeholder="选择起始值" style="width: 70px;" @change="(value) => handleStartFlagChange(row, value)"> />
<el-option label="无" :value="2"></el-option> </template>
<el-option label=">=" :value="1"></el-option> </el-table-column>
<el-option label=">" :value="0"></el-option> <el-table-column label="起止范围">
</el-select> <el-table-column label="起始" width="150">
</el-col> <template #default="{ row }">
<el-col :span="12"> <el-row type="flex" :gutter="24">
<el-input v-model="row.startValue" style="width: 60px;" :disabled="isStartValueDisabled[row.sort]" <el-col :span="12">
/> <el-select
</el-col> v-model="row.startFlag"
</el-row> placeholder="选择起始值"
</template> style="width: 70px"
</el-table-column> @change="value => handleStartFlagChange(row, value)"
<el-table-column label="结束" width="150"> >
<template #default="{ row }"> <el-option label="无" :value="2"></el-option>
<el-row type="flex" :gutter="24"> <el-option label=">=" :value="1"></el-option>
<el-col :span="12"> <el-option label=">" :value="0"></el-option>
<el-select v-model="row.endFlag" placeholder="选择结束值" style="width: 70px;" @change="(value) => handleEndFlagChange(row, value)"> </el-select>
<el-option label="无" :value="2"></el-option> </el-col>
<el-option label="<=" :value="1"></el-option> <el-col :span="12">
<el-option label="<" :value="0"></el-option> <el-input
</el-select> v-model="row.startValue"
</el-col> style="width: 60px"
<el-col :span="12"> :disabled="isStartValueDisabled[row.sort]"
<el-input v-model="row.endValue" style="width: 60px;" :disabled="isEndValueDisabled[row.sort]"/> />
</el-col> </el-col>
</el-row> </el-row>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="单位" width="130"> <el-table-column label="结束" width="150">
<template #default="{ row }"> <template #default="{ row }">
<el-select v-model="row.conditionType" placeholder="选择单位"> <el-row type="flex" :gutter="24">
<el-option <el-col :span="12">
v-for="item in conditionTypes" <el-select
:key="item.id" v-model="row.endFlag"
:label="item.name" placeholder="选择结束值"
:value="Number(item.value)" style="width: 70px"
/> @change="value => handleEndFlagChange(row, value)"
</el-select> >
</template> <el-option label="无" :value="2"></el-option>
</el-table-column> <el-option label="<=" :value="1"></el-option>
</el-table-column> <el-option label="<" :value="0"></el-option>
<el-table-column label="最大误差"> </el-select>
<el-table-column prop="maxErrorValue" label="最大误差值" width="100"> </el-col>
<template #default="{ row }"> <el-col :span="12">
<el-input v-model="row.maxErrorValue" style="width: 70px;"/> <el-input
</template> v-model="row.endValue"
</el-table-column> style="width: 60px"
<el-table-column label="误差类型" width="170"> :disabled="isEndValueDisabled[row.sort]"
<template #default="{ row }"> />
<el-cascader :options="errorValueTypeOptions" </el-col>
v-model="row.errorValueType" </el-row>
@change="handleErrorValueTypeChange(row)"/> </template>
</template> </el-table-column>
</el-table-column> <el-table-column label="单位" width="130">
<el-table-column label="误差单位" width="100" prop="errorUnit"> <template #default="{ row }">
<template #default="{ row }"> <el-select v-model="row.conditionType" placeholder="选择单位">
<span>{{ row.errorUnit }}</span> <el-option
</template> v-for="item in conditionTypes"
</el-table-column> :key="item.id"
</el-table-column> :label="item.name"
<el-table-column label="操作" min-width="150"> :value="Number(item.value)"
<template #default="{ row }"> />
<el-button type="primary" link :icon='CopyDocument' @click="copyRow(row)">复制</el-button> </el-select>
<el-button type='primary' link :icon='Delete' @click="deleteRow(row)">删除</el-button> </template>
</template> </el-table-column>
</el-table-column> </el-table-column>
</el-table> <el-table-column label="最大误差">
</div> <el-table-column prop="maxErrorValue" label="最大误差值" width="100">
<template #default="{ row }">
<el-input v-model="row.maxErrorValue" style="width: 70px" />
</template>
</el-table-column>
<el-table-column label="误差类型" width="170">
<template #default="{ row }">
<el-cascader
:options="errorValueTypeOptions"
v-model="row.errorValueType"
@change="handleErrorValueTypeChange(row)"
/>
</template>
</el-table-column>
<el-table-column label="误差单位" width="100" prop="errorUnit">
<template #default="{ row }">
<span>{{ row.errorUnit }}</span>
</template>
</el-table-column>
</el-table-column>
<el-table-column label="操作" min-width="150">
<template #default="{ row }">
<el-button type="primary" link :icon="CopyDocument" @click="copyRow(row)">复制</el-button>
<el-button type="primary" link :icon="Delete" @click="deleteRow(row)">删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import {type ErrorSystem} from '@/api/device/interface/error'; import { type ErrorSystem } from '@/api/device/interface/error'
import {useDictStore,} from '@/stores/modules/dict' import { useDictStore } from '@/stores/modules/dict'
import {CirclePlus, CopyDocument, Delete} from '@element-plus/icons-vue' import { CirclePlus, CopyDocument, Delete } from '@element-plus/icons-vue'
import {type CascaderOption} from 'element-plus'; import { type CascaderOption } from 'element-plus'
import {defineEmits, type PropType, reactive, ref, watch} from 'vue'; import { type PropType, reactive, ref, watch } from 'vue'
const emit = defineEmits(['updateTableData']); const emit = defineEmits(['updateTableData'])
const multipleSelection = ref<number[]>([]) const multipleSelection = ref<number[]>([])
const dictStore = useDictStore() const dictStore = useDictStore()
const isStartValueDisabled = ref<{ [key: number]: boolean }>({}); const isStartValueDisabled = ref<{ [key: number]: boolean }>({})
const isEndValueDisabled = ref<{ [key: number]: boolean }>({}); const isEndValueDisabled = ref<{ [key: number]: boolean }>({})
const props = defineProps({ const props = defineProps({
errorOptions: { errorOptions: {
type: Array as PropType<CascaderOption[]>, type: Array as PropType<CascaderOption[]>,
required: true required: true
}, },
scriptOptions: { scriptOptions: {
type: Array as PropType<CascaderOption[]>, type: Array as PropType<CascaderOption[]>,
required: true required: true
}, },
tableData: { tableData: {
type: Array as PropType<ErrorSystem.ErrorSystemDetail[]>, type: Array as PropType<ErrorSystem.ErrorSystemDetail[]>,
default: () => [] default: () => []
} }
}); })
const errorValueTypeOptions = reactive<{ value: number, label: string, children: { value: number, label: string }[] }[]>([]) const errorValueTypeOptions = reactive<
{ value: number; label: string; children: { value: number; label: string }[] }[]
>([])
const conditionTypes = dictStore.getDictData('Condition_Type') const conditionTypes = dictStore.getDictData('Condition_Type')
const errorValueTypes = dictStore.getDictData('Error_Value_Type') const errorValueTypes = dictStore.getDictData('Error_Value_Type')
const valueTypes = dictStore.getDictData('Script_Value_Type') const valueTypes = dictStore.getDictData('Script_Value_Type')
onBeforeMount(() => { onBeforeMount(() => {
valueTypes.forEach(item1 => { valueTypes.forEach(item1 => {
let children = [] let children = []
for (let i = 0; i < errorValueTypes.length; i++) { for (let i = 0; i < errorValueTypes.length; i++) {
if (item1.value === '2' && errorValueTypes[i].value === '2') { if (item1.value === '2' && errorValueTypes[i].value === '2') {
continue continue
} }
children.push({label: errorValueTypes[i].name, value: Number(errorValueTypes[i].value)}) children.push({ label: errorValueTypes[i].name, value: Number(errorValueTypes[i].value) })
} }
errorValueTypeOptions.push({label: item1.name, value: Number(item1.value), children: children}) errorValueTypeOptions.push({ label: item1.name, value: Number(item1.value), children: children })
}) })
}) })
const handleErrorTypeChange = (value: any, row: any) => { const handleErrorTypeChange = (value: any, row: any) => {
// const matchedRow = findRowById(row.errorType, props.errorOptions);//选中误差id找对应结构中的含chilren的code
// const matchedRow = findRowById(row.errorType, props.errorOptions);//选中误差id找对应结构中的含chilren的code // console.log('matchedRow.code',matchedRow.code)
// console.log('matchedRow.code',matchedRow.code) // const code = errSysAndScriptMap.get(matchedRow?.code || '') || ''; // 确保 code 不为 undefined
// const code = errSysAndScriptMap.get(matchedRow?.code || '') || ''; // 确保 code 不为 undefined // console.log('code',code)
// console.log('code',code) // if (code) {
// if (code) { // const matchedRow2 = findRowByCode(code, props.scriptOptions);//误差code映射脚本code找对应脚本结构中含children的id
// const matchedRow2 = findRowByCode(code, props.scriptOptions);//误差code映射脚本code找对应脚本结构中含children的id // console.log('matchedRow2',matchedRow2)
// console.log('matchedRow2',matchedRow2) // if (matchedRow2) {
// if (matchedRow2) { // row.scriptType = matchedRow2.value;
// row.scriptType = matchedRow2.value; // }else{
// }else{ // row.scriptType = '';//如果没有找到匹配的脚本,置空
// row.scriptType = '';//如果没有找到匹配的脚本,置空 // }
// } // }else{
// }else{ // row.scriptType = '';//如果没有找到匹配的脚本,置空
// row.scriptType = '';//如果没有找到匹配的脚本,置空 // }
// }
} }
const handleScriptTypeChange = (row: any) => { const handleScriptTypeChange = (row: any) => {
handleErrorValueTypeChange(row) handleErrorValueTypeChange(row)
} }
const handleErrorValueTypeChange = (row: any) => { const handleErrorValueTypeChange = (row: any) => {
let scriptType = findRowById(row.scriptType, props.scriptOptions) let scriptType = findRowById(row.scriptType, props.scriptOptions)
if (scriptType) { if (scriptType) {
const errorValueType = row.errorValueType const errorValueType = row.errorValueType
let level1 = errorValueType[0] let level1 = errorValueType[0]
switch (level1) { switch (level1) {
case 1: // 绝对值 case 1: // 绝对值
row.valueType = 1 row.valueType = 1
row.errorUnit = scriptType.remark row.errorUnit = scriptType.remark
break; break
case 2: // 相对值 case 2: // 相对值
row.valueType = 2 row.valueType = 2
row.errorUnit = "%" row.errorUnit = '%'
break; break
default: default:
break; break
}
} }
}
} }
// 假设 props.errorOptions 是一个数组,每个元素可能包含 children 属性 // 假设 props.errorOptions 是一个数组,每个元素可能包含 children 属性
const findRowById = (id: string, options: any[]): any | null => { const findRowById = (id: string, options: any[]): any | null => {
for (const option of options) { for (const option of options) {
if (option.value === id) { if (option.value === id) {
return option; return option
}
if (option.children && option.children.length > 0) {
const result = findRowById(id, option.children)
if (result) {
return result
}
}
} }
if (option.children && option.children.length > 0) { return null
const result = findRowById(id, option.children); }
if (result) {
return result;
}
}
}
return null;
};
// 假设 props.errorOptions 是一个数组,每个元素可能包含 children 属性 // 假设 props.errorOptions 是一个数组,每个元素可能包含 children 属性
const findRowByCode = (code: string, options: any[]): any | null => { const findRowByCode = (code: string, options: any[]): any | null => {
for (const option of options) { for (const option of options) {
if (option.code === code) { if (option.code === code) {
return option; return option
}
if (option.children && option.children.length > 0) {
const result = findRowByCode(code, option.children)
if (result) {
return result
}
}
} }
if (option.children && option.children.length > 0) { return null
const result = findRowByCode(code, option.children); }
if (result) {
return result;
}
}
}
return null;
};
// 监听 props.tableData 的变化,确保每次数据变化时都重新设置 sort // 监听 props.tableData 的变化,确保每次数据变化时都重新设置 sort
watch(() => props.tableData, async (newTableData) => { watch(
for (let i = 0; i < newTableData.length; i++) { () => props.tableData,
newTableData[i].sort = i + 1; async newTableData => {
if (newTableData[i].startFlag === 2) { for (let i = 0; i < newTableData.length; i++) {
newTableData[i].startValue = null; // 设置 startValue 为 null newTableData[i].sort = i + 1
} if (newTableData[i].startFlag === 2) {
if (newTableData[i].endFlag === 2) { newTableData[i].startValue = null // 设置 startValue 为 null
newTableData[i].endValue = null; // 设置 endValue 为 null }
} if (newTableData[i].endFlag === 2) {
} newTableData[i].endValue = null // 设置 endValue 为 null
// 重新设置 isStartValueDisabled 和 isEndValueDisabled,并清空输入框 }
props.tableData.forEach(row => { }
isStartValueDisabled.value[row.sort] = row.startFlag === 2; // 重新设置 isStartValueDisabled 和 isEndValueDisabled,并清空输入框
props.tableData.forEach(row => {
}); isStartValueDisabled.value[row.sort] = row.startFlag === 2
props.tableData.forEach(row => { })
isEndValueDisabled.value[row.sort] = row.endFlag === 2; props.tableData.forEach(row => {
}); isEndValueDisabled.value[row.sort] = row.endFlag === 2
}, {immediate: true}); })
},
{ immediate: true }
)
// 处理 startFlag 变化的方法 // 处理 startFlag 变化的方法
const handleStartFlagChange = (row: ErrorSystem.ErrorSystemDetail, value: number) => { const handleStartFlagChange = (row: ErrorSystem.ErrorSystemDetail, value: number) => {
if (value === 2) { if (value === 2) {
row.startValue = null; // 清空输入框 row.startValue = null // 清空输入框
isStartValueDisabled.value[row.sort] = true; // 禁用输入框 isStartValueDisabled.value[row.sort] = true // 禁用输入框
} else { } else {
isStartValueDisabled.value[row.sort] = false; // 启用输入框 isStartValueDisabled.value[row.sort] = false // 启用输入框
} }
}; }
// 处理 endFlag 变化的方法 // 处理 endFlag 变化的方法
const handleEndFlagChange = (row: ErrorSystem.ErrorSystemDetail, value: number) => { const handleEndFlagChange = (row: ErrorSystem.ErrorSystemDetail, value: number) => {
if (value === 2) { if (value === 2) {
row.endValue = null; // 清空输入框 row.endValue = null // 清空输入框
isEndValueDisabled.value[row.sort] = true; // 禁用输入框 isEndValueDisabled.value[row.sort] = true // 禁用输入框
} else { } else {
isEndValueDisabled.value[row.sort] = false; // 启用输入框 isEndValueDisabled.value[row.sort] = false // 启用输入框
} }
}; }
//选中 //选中
const handleSelectionChange = (selection: ErrorSystem.ErrorSystemDetail[]) => { const handleSelectionChange = (selection: ErrorSystem.ErrorSystemDetail[]) => {
multipleSelection.value = selection.map(row => row.sort); // 更新选中的行 multipleSelection.value = selection.map(row => row.sort) // 更新选中的行
}; }
//新增 //新增
const openAddDialog = () => { const openAddDialog = () => {
// 获取字典数据 // 获取字典数据
const newRow = {
sort: props.tableData.length + 1,
id: '',
startFlag: 2,
endFlag: 2,
conditionType: conditionTypes.length > 0 ? Number(conditionTypes[0].value) : 0, // 设置默认值为第一个选项的值
valueType: valueTypes.length > 0 ? Number(valueTypes[0].value) : 1,
errorValueType: [errorValueTypeOptions[0].value, errorValueTypeOptions[0].children[0].value],
errorSysId: '',
errorType: '',
scriptType: '',
maxErrorValue: 0
}
const newRow = { emit('updateTableData', [...props.tableData, newRow])
sort: props.tableData.length + 1, }
id: '',
startFlag: 2,
endFlag: 2,
conditionType: conditionTypes.length > 0 ? Number(conditionTypes[0].value) : 0, // 设置默认值为第一个选项的值
valueType: valueTypes.length > 0 ? Number(valueTypes[0].value) : 1,
errorValueType: [errorValueTypeOptions[0].value, errorValueTypeOptions[0].children[0].value],
errorSysId: "",
errorType: "",
scriptType: "",
maxErrorValue: 0
};
emit('updateTableData', [...props.tableData, newRow]);
};
const copyRow = (row: ErrorSystem.ErrorSystemDetail) => { const copyRow = (row: ErrorSystem.ErrorSystemDetail) => {
// 深拷贝行数据 // 深拷贝行数据
const newRow = {...row}; const newRow = { ...row }
const maxNextId = Math.max(...props.tableData.map(item => item.sort), 0); const maxNextId = Math.max(...props.tableData.map(item => item.sort), 0)
newRow.sort = maxNextId + 1; newRow.sort = maxNextId + 1
emit('updateTableData', [...props.tableData, newRow]); emit('updateTableData', [...props.tableData, newRow])
}; }
//删除行 //删除行
const deleteRow = (row: ErrorSystem.ErrorSystemDetail) => { const deleteRow = (row: ErrorSystem.ErrorSystemDetail) => {
const index = props.tableData.indexOf(row); const index = props.tableData.indexOf(row)
if (index !== -1) { if (index !== -1) {
const newTableData = [...props.tableData]; const newTableData = [...props.tableData]
newTableData.splice(index, 1); newTableData.splice(index, 1)
emit('updateTableData', newTableData); emit('updateTableData', newTableData)
} }
}; }
//批量删除选中行 //批量删除选中行
const deleteSelectedRows = () => { const deleteSelectedRows = () => {
const newTableData = props.tableData.filter(row => !multipleSelection.value.includes(row.sort)); const newTableData = props.tableData.filter(row => !multipleSelection.value.includes(row.sort))
multipleSelection.value = []; // 清空已选择的行 multipleSelection.value = [] // 清空已选择的行
emit('updateTableData', newTableData); emit('updateTableData', newTableData)
}; }
</script> </script>
<style scoped> <style scoped>
.dialog-footer { .dialog-footer {
display: flex; display: flex;
justify-content: flex-start; justify-content: flex-start;
margin-bottom: 10px; /* 调整这里的值以增加或减少间距 */ margin-bottom: 10px; /* 调整这里的值以增加或减少间距 */
margin-top: 10px; margin-top: 10px;
} }
.el-table th, .el-table td { .el-table th,
text-align: center; /* 所有单元格文字居中 */ .el-table td {
text-align: center; /* 所有单元格文字居中 */
} }
.table-container { .table-container {
max-height: 400px; /* 根据需要调整高度 */ max-height: 400px; /* 根据需要调整高度 */
overflow-y: auto; /* 允许垂直滚动 */ overflow-y: auto; /* 允许垂直滚动 */
overflow-x: hidden; /* 隐藏水平滚动条 */ overflow-x: hidden; /* 隐藏水平滚动条 */
} }
</style> </style>

View File

@@ -1,30 +1,49 @@
<template> <template>
<el-dialog :title="dialogTitle" v-model='dialogVisible' @close="close" v-bind="dialogBig" width="1660px" align-center> <el-dialog
:title="dialogTitle"
v-model="dialogVisible"
@close="close"
v-bind="dialogBig"
width="1660px"
align-center
>
<el-tabs type="border-card"> <el-tabs type="border-card">
<el-tab-pane label="基础信息"> <el-tab-pane label="基础信息">
<div> <div>
<el-form :model="formContent" ref='dialogFormRef' :rules='rules' label-width="auto" class="form-four"> <el-form
<el-form-item label="标准号" prop="standardName" > :model="formContent"
<el-input v-model='formContent.standardName' placeholder="请填写标准号" maxlength="32" show-word-limit/> ref="dialogFormRef"
:rules="rules"
label-width="auto"
class="form-four"
>
<el-form-item label="标准号" prop="standardName">
<el-input
v-model="formContent.standardName"
placeholder="请填写标准号"
maxlength="32"
show-word-limit
/>
</el-form-item> </el-form-item>
<el-form-item label="标准推行年份" prop="standardTime" > <el-form-item label="标准推行年份" prop="standardTime">
<el-date-picker <el-date-picker
v-model="formContent.standardTime" v-model="formContent.standardTime"
type="year" type="year"
placeholder="请选择标准推行年份" placeholder="请选择标准推行年份"
/> />
</el-form-item> </el-form-item>
<el-form-item label="适用设备等级" prop="devLevel" > <el-form-item label="适用设备等级" prop="devLevel">
<el-select v-model='formContent.devLevel' placeholder="请选择设备等级"> <el-select v-model="formContent.devLevel" placeholder="请选择设备等级">
<el-option <el-option
v-for="item in dictStore.getDictData('Dev_Level')" v-for="item in dictStore.getDictData('Dev_Level')"
:key="item.id" :key="item.id"
:label="item.name" :label="item.name"
:value="item.id"/> :value="item.id"
</el-select> />
</el-select>
</el-form-item> </el-form-item>
<el-form-item label="状态" prop="enable" > <el-form-item label="状态" prop="enable">
<el-select v-model='formContent.enable' placeholder="请选择状态"> <el-select v-model="formContent.enable" placeholder="请选择状态">
<el-option label="启用" :value="1"></el-option> <el-option label="启用" :value="1"></el-option>
<el-option label="停用" :value="0"></el-option> <el-option label="停用" :value="0"></el-option>
</el-select> </el-select>
@@ -33,44 +52,45 @@
</div> </div>
</el-tab-pane> </el-tab-pane>
</el-tabs> </el-tabs>
<ErrorSystemDetailTable
<ErrorSystemDetailTable :tableData="tableData" :errorOptions="errorOptions" :scriptOptions="scriptOptions" @updateTableData="handleTableDataUpdate" /> :tableData="tableData"
:errorOptions="errorOptions"
:scriptOptions="scriptOptions"
@updateTableData="handleTableDataUpdate"
/>
<template #footer> <template #footer>
<div > <div>
<el-button @click='close()'> </el-button> <el-button @click="close()"> </el-button>
<el-button type="primary" @click='save()'>保存</el-button> <el-button type="primary" @click="save()">保存</el-button>
</div> </div>
</template> </template>
</el-dialog> </el-dialog>
</template> </template>
<script lang="ts" setup name="ErrorSystemDialog">
import{type CascaderOption, ElMessage, type FormInstance,type FormItemRule}from'element-plus'
import { defineProps, defineEmits, reactive,watch,ref, type Ref, computed } from 'vue';
import { dialogBig} from '@/utils/elementBind'
import { addPqErrSys,updatePqErrSys,getPqErrSysListById} from '@/api/device/error/index'
import {CirclePlus, Delete, EditPen,FolderOpened,CopyDocument} from '@element-plus/icons-vue'
import { useDictStore } from '@/stores/modules/dict'
import { type ErrorSystem } from '@/api/device/interface/error';
import ErrorSystemDetailTable from '@/views/machine/errorSystem/components/errorSystemDetailTable.vue';
import {getDictTreeByCode} from '@/api/system/dictionary/dictTree'
import { type Dict } from '@/api/system/dictionary/interface';
// 定义弹出组件元信息
const dialogFormRef = ref()
const dictStore = useDictStore()
const tableData = ref<ErrorSystem.ErrorSystemDetail[]>([]);
const errorOptions: Ref<CascaderOption[]> = ref([]); // 修改这里
const scriptOptions: Ref<CascaderOption[]> = ref([]); // 修改这里
const handleTableDataUpdate = (newTableData: ErrorSystem.ErrorSystemDetail[]) => {
tableData.value = newTableData;
};
function useMetaInfo() { <script lang="ts" setup name="ErrorSystemDialog">
import { type CascaderOption, ElMessage, type FormItemRule } from 'element-plus'
import { computed, type Ref, ref } from 'vue'
import { dialogBig } from '@/utils/elementBind'
import { addPqErrSys, getPqErrSysListById, updatePqErrSys } from '@/api/device/error/index'
import { useDictStore } from '@/stores/modules/dict'
import { type ErrorSystem } from '@/api/device/interface/error'
import ErrorSystemDetailTable from '@/views/machine/errorSystem/components/errorSystemDetailTable.vue'
import { getDictTreeByCode } from '@/api/system/dictionary/dictTree'
import { type Dict } from '@/api/system/dictionary/interface'
// 定义弹出组件元信息
const dialogFormRef = ref()
const dictStore = useDictStore()
const tableData = ref<ErrorSystem.ErrorSystemDetail[]>([])
const errorOptions: Ref<CascaderOption[]> = ref([]) // 修改这里
const scriptOptions: Ref<CascaderOption[]> = ref([]) // 修改这里
const handleTableDataUpdate = (newTableData: ErrorSystem.ErrorSystemDetail[]) => {
tableData.value = newTableData
}
function useMetaInfo() {
const dialogVisible = ref(false) const dialogVisible = ref(false)
const titleType = ref('add') const titleType = ref('add')
const formContent = ref<ErrorSystem.ErrorSystemList>({ const formContent = ref<ErrorSystem.ErrorSystemList>({
@@ -80,15 +100,15 @@ const handleTableDataUpdate = (newTableData: ErrorSystem.ErrorSystemDetail[]) =>
standardTime: '', standardTime: '',
devLevel: '', devLevel: '',
enable: 1, enable: 1,
state:1, state: 1,
pqErrSysDtlsList:[] pqErrSysDtlsList: []
}) })
return { dialogVisible, titleType, formContent } return { dialogVisible, titleType, formContent }
} }
const { dialogVisible, titleType, formContent } = useMetaInfo() const { dialogVisible, titleType, formContent } = useMetaInfo()
// 清空formContent // 清空formContent
const resetFormContent = () => { const resetFormContent = () => {
formContent.value = { formContent.value = {
id: '', id: '',
name: '', name: '',
@@ -96,164 +116,154 @@ const handleTableDataUpdate = (newTableData: ErrorSystem.ErrorSystemDetail[]) =>
standardTime: '', standardTime: '',
devLevel: '', devLevel: '',
enable: 1, enable: 1,
state:1, state: 1,
pqErrSysDtlsList:[] pqErrSysDtlsList: []
} }
tableData.value =[] tableData.value = []
} }
let dialogTitle = computed(() => {
return titleType.value === 'add' ? '新增误差体系' : '编辑误差体系'
})
// 定义规则 let dialogTitle = computed(() => {
const rules: Ref<Record<string, Array<FormItemRule>>> = ref({ return titleType.value === 'add' ? '新增误差体系' : '编辑误差体系'
})
// 定义规则
const rules: Ref<Record<string, Array<FormItemRule>>> = ref({
name: [{ required: true, message: '误差体系名称必填!', trigger: 'blur' }], name: [{ required: true, message: '误差体系名称必填!', trigger: 'blur' }],
standardName: [{ required: true, message: '参照标准名称必填!', trigger: 'blur' }], standardName: [{ required: true, message: '参照标准名称必填!', trigger: 'blur' }],
standardTime: [{ required: true, message: '标准推行年份必选!', trigger: 'blur' }], standardTime: [{ required: true, message: '标准推行年份必选!', trigger: 'blur' }],
devLevel:[{ required: true, message: '请选择一项设备等级', trigger: 'change' },], devLevel: [{ required: true, message: '请选择一项设备等级', trigger: 'change' }],
enable:[{ required: true, message: '请选择一项状态', trigger: 'change '},] enable: [{ required: true, message: '请选择一项状态', trigger: 'change ' }]
}); })
// 关闭弹窗
const close = () => {
dialogVisible.value = false
// 清空dialogForm中的值
resetFormContent()
// 重置表单
dialogFormRef.value?.resetFields()
}
// 关闭弹窗 // 保存数据
const close = () => { const save = () => {
dialogVisible.value = false try {
// 清空dialogForm中的值 dialogFormRef.value?.validate(async (valid: boolean) => {
resetFormContent()
// 重置表单
dialogFormRef.value?.resetFields()
}
// 保存数据
const save = () => {
try {
dialogFormRef.value?.validate(async (valid: boolean) => {
if (valid) { if (valid) {
// 确保 standardTime 是 Date 对象 // 确保 standardTime 是 Date 对象
if (formContent.value.standardTime) { if (formContent.value.standardTime) {
const date = new Date(formContent.value.standardTime); const date = new Date(formContent.value.standardTime)
formContent.value.standardTime = date.getFullYear().toString(); formContent.value.standardTime = date.getFullYear().toString()
} }
formContent.value.pqErrSysDtlsList = tableData.value formContent.value.pqErrSysDtlsList = tableData.value
formContent.value.pqErrSysDtlsList.forEach((item) => { formContent.value.pqErrSysDtlsList.forEach(item => {
item.errorValueType=item.errorValueType[1] item.errorValueType = item.errorValueType[1]
}) })
if (formContent.value.id) { if (formContent.value.id) {
await updatePqErrSys(formContent.value); await updatePqErrSys(formContent.value)
ElMessage.success({ message: `${dialogTitle.value}成功!` }) ElMessage.success({ message: `${dialogTitle.value}成功!` })
} else { } else {
await addPqErrSys(formContent.value); await addPqErrSys(formContent.value)
ElMessage.success({ message: `${dialogTitle.value}成功!` }) ElMessage.success({ message: `${dialogTitle.value}成功!` })
} }
close() close()
// 刷新表格 // 刷新表格
await props.refreshTable!() await props.refreshTable!()
} }
}) })
} catch (err) { } catch (err) {
console.error('验证过程中出现错误', err) console.error('验证过程中出现错误', err)
} }
} }
// 封装提取第二层节点的逻辑 // 封装提取第二层节点的逻辑
const loadSecondLevelOptions = async () => { const loadSecondLevelOptions = async () => {
const dictCode = 'Err_Sys_Items'; // 替换为实际需要的字典代码 const dictCode = 'Err_Sys_Items' // 替换为实际需要的字典代码
const dictCode2 = 'Script_Error'; // 替换为实际需要的字典代码 const dictCode2 = 'Script_Error' // 替换为实际需要的字典代码
const resDictTree: Dict.ResDictTree = { const resDictTree: Dict.ResDictTree = {
name: '', name: '',
id: '', id: '',
pid: '', pid: '',
pids: '', pids: '',
code: dictCode, code: dictCode,
sort: 0 sort: 0
};
const resDictTree2: Dict.ResDictTree = {
name: '',
id: '',
pid: '',
pids: '',
code: dictCode2,
sort: 0
};
// 并行请求两个字典树列表
const [result, result2] = await Promise.all([
getDictTreeByCode(resDictTree),
getDictTreeByCode(resDictTree2)
]);
const allOptions = convertToOptions(result.data as Dict.ResDictTree[]);
const allOptions2 = convertToOptions(result2.data as Dict.ResDictTree[]);
// 提取第二层节点
const secondLevelOptions: any[] = [];
allOptions.forEach(option => {
if (option.children && option.children.length > 0) {
secondLevelOptions.push(...option.children);
} }
});
const secondLevelOptions2: any[] = []; const resDictTree2: Dict.ResDictTree = {
allOptions2.forEach(option => { name: '',
if (option.children && option.children.length > 0) { id: '',
secondLevelOptions2.push(...option.children); pid: '',
pids: '',
code: dictCode2,
sort: 0
} }
});
// 将第二层节点赋值给 options.value // 并行请求两个字典树列表
errorOptions.value = secondLevelOptions; const [result, result2] = await Promise.all([getDictTreeByCode(resDictTree), getDictTreeByCode(resDictTree2)])
scriptOptions.value = secondLevelOptions2;
};
// 转换函数 const allOptions = convertToOptions(result.data as Dict.ResDictTree[])
const convertToOptions = (dictTree: Dict.ResDictTree[]): CascaderOption[] => { const allOptions2 = convertToOptions(result2.data as Dict.ResDictTree[])
// 提取第二层节点
const secondLevelOptions: any[] = []
allOptions.forEach(option => {
if (option.children && option.children.length > 0) {
secondLevelOptions.push(...option.children)
}
})
const secondLevelOptions2: any[] = []
allOptions2.forEach(option => {
if (option.children && option.children.length > 0) {
secondLevelOptions2.push(...option.children)
}
})
// 将第二层节点赋值给 options.value
errorOptions.value = secondLevelOptions
scriptOptions.value = secondLevelOptions2
}
// 转换函数
const convertToOptions = (dictTree: Dict.ResDictTree[]): CascaderOption[] => {
return dictTree.map(item => ({ return dictTree.map(item => ({
value: item.id, value: item.id,
label: item.name, label: item.name,
code: item.code, code: item.code,
children: item.children ? convertToOptions(item.children) : undefined, children: item.children ? convertToOptions(item.children) : undefined,
remark: item.remark remark: item.remark
})); }))
}; }
// 打开弹窗,可能是新增,也可能是编辑
// 打开弹窗,可能是新增,也可能是编辑
const open = async (sign: string, data: ErrorSystem.ErrorSystemList) => { const open = async (sign: string, data: ErrorSystem.ErrorSystemList) => {
titleType.value = sign; titleType.value = sign
// 并行执行两个异步操作 // 并行执行两个异步操作
const loadOptionsPromise = loadSecondLevelOptions(); const loadOptionsPromise = loadSecondLevelOptions()
const fetchDataPromise = data.id ? getPqErrSysListById(data) : Promise.resolve(null); const fetchDataPromise = data.id ? getPqErrSysListById(data) : Promise.resolve(null)
const [_, result] = await Promise.all([loadOptionsPromise, fetchDataPromise]); const [_, result] = await Promise.all([loadOptionsPromise, fetchDataPromise])
if (result && result.data) { if (result && result.data) {
formContent.value = result.data as ErrorSystem.ErrorSystemList; formContent.value = result.data as ErrorSystem.ErrorSystemList
tableData.value = formContent.value.pqErrSysDtlsList || []; tableData.value = formContent.value.pqErrSysDtlsList || []
tableData.value.forEach((item) => { tableData.value.forEach(item => {
item.errorValueType=[item.valueType,item.errorValueType] item.errorValueType = [item.valueType, item.errorValueType]
}) })
} else { } else {
resetFormContent(); resetFormContent()
} }
// 重置表单
dialogFormRef.value?.resetFields();
dialogVisible.value = true;
};
// 重置表单
dialogFormRef.value?.resetFields()
dialogVisible.value = true
}
// 对外映射 // 对外映射
defineExpose({ open }) defineExpose({ open })
const props = defineProps<{ const props = defineProps<{
refreshTable: (() => Promise<void>) | undefined; refreshTable: (() => Promise<void>) | undefined
}>() }>()
</script> </script>
<style> <style></style>
</style>

View File

@@ -7,7 +7,7 @@
</div> </div>
<div class="data-check-content"> <div class="data-check-content">
<div class="content-tree" :style="{ height: `calc(100vh - ${props.shrink ? '370px' : '315px'})` }"> <div class="content-tree" :style="{ height: `calc(100vh - ${props.shrink ? '370px' : '315px'})` }">
<Tree :treeData="treeData" @setTab="setTab" /> <TestScriptTree :treeData="treeData" @setTab="setTab" />
</div> </div>
<div <div
@@ -19,17 +19,18 @@
<el-tab-pane v-for="tab in tabData" :key="tab.value" :label="tab.label" :name="tab.value"> <el-tab-pane v-for="tab in tabData" :key="tab.value" :label="tab.label" :name="tab.value">
<div v-if="activeName == tab.value"> <div v-if="activeName == tab.value">
<div class="dialog-footer"> <div class="dialog-footer">
<el-switch v-model="value1" <el-switch
inline-prompt v-model="value1"
:active-value="1" inline-prompt
:inactive-value="0" :active-value="1"
active-text="禁用" :inactive-value="0"
inactive-text="" active-text=""
@change="enableScript" inactive-text="启用"
size="large" @change="enableScript"
width="80px" size="large"
style="margin-right: 10px;" width="80px"
/> style="margin-right: 10px"
/>
<el-button :icon="CirclePlus" type="primary" @click="openDialog('add')">新增</el-button> <el-button :icon="CirclePlus" type="primary" @click="openDialog('add')">新增</el-button>
</div> </div>
<div style="display: flex"> <div style="display: flex">
@@ -41,7 +42,7 @@
:formContent="props.formContent" :formContent="props.formContent"
:options="props.options" :options="props.options"
style="width: 360px" style="width: 360px"
:shrink="props.shrink" :shrink="props.shrink"
:disabled="tab.children.length == 0 ? false : true" :disabled="tab.children.length == 0 ? false : true"
ref="communRef" ref="communRef"
/> />
@@ -215,20 +216,21 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { type PropType, ref, nextTick } from 'vue' import { type PropType, ref } from 'vue'
import Tree from './tree.vue' import TestScriptTree from './testScriptTree.vue'
import Commun from './communication.vue' import Commun from './communication.vue'
import { type CascaderOption, ElMessageBox } from 'element-plus' import { ElMessageBox } from 'element-plus'
import { getTreeData } from '@/api/check/test' import { getTreeData } from '@/api/check/test'
import { CirclePlus, Delete, Check, CopyDocument, View, EditPen } from '@element-plus/icons-vue' import { CirclePlus, CopyDocument, Delete, EditPen, View } from '@element-plus/icons-vue'
import type { TestScript } from '@/api/device/interface/testScript' import type { TestScript } from '@/api/device/interface/testScript'
import TestProjectPopup from '@/views/machine/testScript/components/testProjectPopup.vue' import TestProjectPopup from '@/views/machine/testScript/components/testProjectPopup.vue'
import { CheckData } from '@/api/check/interface' import { CheckData } from '@/api/check/interface'
import { dlsDetails, deleteDtls, updateDtls, addScriptDtls, checkDataList } from '@/api/device/testScript' import { addScriptDtls, deleteDtls, dlsDetails, updateDtls } from '@/api/device/testScript'
import { useDictStore } from '@/stores/modules/dict' import { useDictStore } from '@/stores/modules/dict'
import { useHandleData } from '@/hooks/useHandleData' import { useHandleData } from '@/hooks/useHandleData'
import { scriptDtlsCheckDataList } from '@/api/device/testScript/index' import { scriptDtlsCheckDataList } from '@/api/device/testScript/index'
import ViewRow from '@/views/machine/testScript/components/viewRow.vue' import ViewRow from '@/views/machine/testScript/components/viewRow.vue'
interface TabOption { interface TabOption {
label?: string label?: string
name?: string name?: string
@@ -280,7 +282,7 @@ const column = ref([
]) ])
// 获取树 // 获取树
const getTree = () => { const getTree = () => {
// console.log('props.formContent.id', props.formContent.id) // console.log('props.formContent.id', props.formContent.id)
getTreeData({ getTreeData({
scriptId: props.formContent.id scriptId: props.formContent.id
}).then(res => { }).then(res => {
@@ -370,8 +372,6 @@ const inquireTable = () => {
value1.value = tableData.value.some(item => item.enable === 1) ? 1 : 0 value1.value = tableData.value.some(item => item.enable === 1) ? 1 : 0
} }
}) })
} }
// 打开 drawer(新增、编辑) // 打开 drawer(新增、编辑)
const openDialog = (titleType: string, row: Partial<TestScript.ResTestScript> = {}) => { const openDialog = (titleType: string, row: Partial<TestScript.ResTestScript> = {}) => {
@@ -420,7 +420,7 @@ const copyRow = async (row: any) => {
// 查看 // 查看
const view = (row: Partial<TestScript.ResTestScript> = {}) => { const view = (row: Partial<TestScript.ResTestScript> = {}) => {
getCommunication() getCommunication()
// console.log('communicationList', communicationList.value) // console.log('communicationList', communicationList.value)
//当前点击的一级tab //当前点击的一级tab
const parentTabName = communicationList.value.find(t => t.id === activeName.value)?.name || '未找到对应名称' const parentTabName = communicationList.value.find(t => t.id === activeName.value)?.name || '未找到对应名称'
//当前点击的二级tab //当前点击的二级tab
@@ -466,7 +466,6 @@ const enableRow = async (row: any) => {
}) })
} }
// 启用/禁用脚本的方法 // 启用/禁用脚本的方法
const enableScript = async () => { const enableScript = async () => {
const willEnable = value1.value === 1 const willEnable = value1.value === 1
@@ -496,7 +495,6 @@ const enableScript = async () => {
} }
} }
// 获取左边树数据 // 获取左边树数据
// 新增保存 // 新增保存
const addTab = (row: any) => { const addTab = (row: any) => {
@@ -537,7 +535,6 @@ onMounted(() => {
overflow-x: hidden; overflow-x: hidden;
} }
/* 确保 el-tree 内容可以超出容器宽度 */ /* 确保 el-tree 内容可以超出容器宽度 */
.el-tree { .el-tree {
width: fit-content; /* 根据内容自适应宽度 */ width: fit-content; /* 根据内容自适应宽度 */
@@ -553,7 +550,6 @@ onMounted(() => {
margin-bottom: 10px; margin-bottom: 10px;
} }
.divider-container { .divider-container {
display: flex; display: flex;
} }

View File

@@ -1,106 +1,106 @@
<template> <template>
<el-tree <el-tree
node-key="id" node-key="id"
default-expand-all default-expand-all
:data="props.treeData" :data="props.treeData"
:props="defaultProps" :props="defaultProps"
style="width: 100%" style="width: 100%"
:expand-on-click-node="false" :expand-on-click-node="false"
@node-click="handleNodeClick" @node-click="handleNodeClick"
> >
<template #default="{ node, data }"> <template #default="{ node, data }">
<el-tooltip effect="dark" :content="data.sourceDesc || data.scriptTypeName" placement="top" :hide-after="0"> <el-tooltip effect="dark" :content="data.sourceDesc || data.scriptTypeName" placement="top" :hide-after="0">
<div class="custom-tree-node"> <div class="custom-tree-node">
{{ data.scriptTypeName || data.sourceDesc }} {{ data.scriptTypeName || data.sourceDesc }}
</div> </div>
</el-tooltip> </el-tooltip>
</template> </template>
</el-tree> </el-tree>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, reactive } from 'vue' import { ref, reactive } from 'vue'
import { CheckData } from '@/api/check/interface' import { CheckData } from '@/api/check/interface'
const props = defineProps({ const props = defineProps({
treeData: { treeData: {
type: Array, type: Array,
required: true required: true
} }
}) })
const emit = defineEmits(['setTab']) const emit = defineEmits(['setTab'])
const dataTree = ref<CheckData.TreeItem[]>([]) const dataTree = ref<CheckData.TreeItem[]>([])
const defaultProps = { const defaultProps = {
children: 'children', children: 'children',
label: 'scriptTypeName', label: 'scriptTypeName',
pid: 'pid' pid: 'pid'
} }
const activeName = ref('') const activeName = ref('')
const childActiveName = ref('') const childActiveName = ref('')
const handleNodeClick = (data, node) => { const handleNodeClick = (data, node) => {
console.log('handleNodeClick', data, node) console.log('handleNodeClick', data, node)
let code = ['Base', 'VOL', 'Freq', 'Harm', 'Base_0_10', 'Base_20_85', 'Base_110_200'] let code = ['Base', 'VOL', 'Freq', 'Harm', 'Base_0_10', 'Base_20_85', 'Base_110_200']
const parents = getParentNodes(node, []) const parents = getParentNodes(node, [])
parents.pop() parents.pop()
parents.unshift(node.data) parents.unshift(node.data)
parents.reverse() parents.reverse()
let active = parents[0].scriptTypeCode let active = parents[0].scriptTypeCode
let childActive = findTargetCodes(parents, code)[0] || '' let childActive = findTargetCodes(parents, code)[0] || ''
// //
if (activeName.value != active || childActiveName.value != childActive) { if (activeName.value != active || childActiveName.value != childActive) {
activeName.value = active activeName.value = active
childActiveName.value = childActive childActiveName.value = childActive
emit('setTab', { emit('setTab', {
activeName: active, activeName: active,
childActiveName: childActive childActiveName: childActive
}) })
} }
} }
// //
const getParentNodes = (node, parents) => { const getParentNodes = (node, parents) => {
if (node.parent) { if (node.parent) {
// //
parents.push(node.parent.data) parents.push(node.parent.data)
// //
getParentNodes(node.parent, parents) getParentNodes(node.parent, parents)
} }
return parents return parents
} }
// childActiveName // childActiveName
function findTargetCodes(data: any[], targetCodes: string[]) { function findTargetCodes(data: any[], targetCodes: string[]) {
let result: string[] = [] let result: string[] = []
data.forEach(item => { data.forEach(item => {
if (item.scriptTypeCode != null) { if (item.scriptTypeCode != null) {
if (targetCodes.includes(item.scriptTypeCode)) { if (targetCodes.includes(item.scriptTypeCode)) {
result.push(item.scriptTypeCode) result.push(item.scriptTypeCode)
} }
} }
}) })
return result return result
// for (let item of data) { // for (let item of data) {
// // scriptTypeCode // // scriptTypeCode
// if (item.scriptTypeCode !=null && targetCodes.includes(item.scriptTypeCode)) { // if (item.scriptTypeCode !=null && targetCodes.includes(item.scriptTypeCode)) {
// result.push(item.scriptTypeCode) // result.push(item.scriptTypeCode)
// return result // return result
// } // }
// // children // // children
// if (item.children && item.children.length > 0) { // if (item.children && item.children.length > 0) {
// result = result.concat(findTargetCodes(item.children, targetCodes)) // result = result.concat(findTargetCodes(item.children, targetCodes))
// } // }
// } // }
// return result // return result
} }
onMounted(() => {}) onMounted(() => {})
// // // //
// defineExpose({ init }) // defineExpose({ init })
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.custom-tree-node { .custom-tree-node {
max-width: 230px; max-width: 230px;
overflow-x: hidden !important; overflow-x: hidden !important;
white-space: nowrap !important; white-space: nowrap !important;
text-overflow: ellipsis !important; text-overflow: ellipsis !important;
} }
</style> </style>

View File

@@ -1,101 +1,100 @@
<template> <template>
<el-dialog v-model="dialogVisible" :title="dialogTitle" <el-dialog v-model="dialogVisible" :title="dialogTitle" v-bind="dialogSmall" @close="close" align-center>
v-bind="dialogSmall" @close="close" align-center> <div>
<div> <el-form :model="formContent" ref="dialogFormRef" :rules="rules">
<el-form :model="formContent" ref="dialogFormRef" :rules="rules"> <el-form-item label="参数所属" prop="pId" :label-width="100">
<el-form-item label="参数所属" prop="pId" :label-width="100"> <el-tree-select
<el-tree-select v-model="displayPid"
v-model="displayPid" :data="tableData"
:data="tableData" check-strictly
check-strictly :render-after-expand="false"
:render-after-expand="false" show-checkbox
show-checkbox check-on-click-node
check-on-click-node node-key="id"
node-key="id" :props="defaultProps"
:props="defaultProps" />
/> </el-form-item>
</el-form-item> <el-form-item label="源参数描述" :label-width="100" prop="desc">
<el-form-item label="源参数描述" :label-width="100" prop="desc"> <el-input v-model="formContent.desc" autocomplete="off" maxlength="32" show-word-limit />
<el-input v-model="formContent.desc" autocomplete="off" maxlength="32" show-word-limit/> </el-form-item>
</el-form-item> <el-form-item label="源参数类型" :label-width="100" prop="type">
<el-form-item label="源参数类型" :label-width="100" prop="type"> <el-input v-model="formContent.type" autocomplete="off" maxlength="32" show-word-limit />
<el-input v-model="formContent.type" autocomplete="off" maxlength="32" show-word-limit/> </el-form-item>
</el-form-item> <el-form-item label="源参数值" :label-width="100" prop="value">
<el-form-item label="源参数值" :label-width="100" <el-input v-model="formContent.value" autocomplete="off" />
prop="value"> </el-form-item>
<el-input v-model="formContent.value" autocomplete="off"/> <el-form-item label="排序" :label-width="100">
</el-form-item> <el-input-number v-model="formContent.sort" :min="1" :max="999" />
<el-form-item label="排序" :label-width="100"> </el-form-item>
<el-input-number v-model="formContent.sort" :min='1' :max='999'/> </el-form>
</el-form-item> </div>
</el-form> <template #footer>
</div> <div class="dialog-footer">
<template #footer> <el-button @click="close()">取消</el-button>
<div class="dialog-footer"> <el-button type="primary" @click="save()">保存</el-button>
<el-button @click="close()">取消</el-button> </div>
<el-button type="primary" @click="save()"> </template>
保存 </el-dialog>
</el-button>
</div>
</template>
</el-dialog>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import {computed, defineEmits, reactive, watch} from 'vue' import { computed, reactive } from 'vue'
import {dialogSmall} from "@/utils/elementBind" import { dialogSmall } from '@/utils/elementBind'
import {TestSource} from "@/api/device/interface/testSource" import { type TestSource } from '@/api/device/interface/testSource'
import {ElMessage, FormItemRule} from "element-plus" import { type FormItemRule } from 'element-plus'
defineProps<{ defineProps<{
tableData: TestSource.ParameterType[] tableData: TestSource.ParameterType[]
}>() }>()
const emit = defineEmits(['get-parameter']) const emit = defineEmits(['get-parameter'])
// 计算属性,用于控制显示的 pid // 计算属性,用于控制显示的 pid
const displayPid = computed({ const displayPid = computed({
get: () => { get: () => {
return formContent.pId === '0' ? '' : formContent.pId
return formContent.pId === '0' ? '' : formContent.pId; },
}, set: value => {
set: (value) => { formContent.pId = value
}
formContent.pId = value; })
}
});
// 树形节点配置 // 树形节点配置
const defaultProps = { const defaultProps = {
children: 'children', children: 'children',
label: 'desc', label: 'desc',
value: 'id' value: 'id'
}; }
const dialogFormRef = ref() const dialogFormRef = ref()
const {dialogVisible, titleType, formContent} = useMetaInfo() const { dialogVisible, titleType, formContent } = useMetaInfo()
function useMetaInfo() { function useMetaInfo() {
const dialogVisible = ref(false) const dialogVisible = ref(false)
const titleType = ref('add') const titleType = ref('add')
const formContent = reactive<TestSource.ParameterType>({ const formContent = reactive<TestSource.ParameterType>({
id: "", id: '',
type: "", type: '',
value: null, value: null,
desc: "", desc: '',
sort: 100, sort: 100,
pId: "0", pId: '0'
}) })
return {dialogVisible, titleType, formContent} return { dialogVisible, titleType, formContent }
} }
const rules: reactive<Record<string, Array<FormItemRule>>> = reactive({ const rules: reactive<Record<string, Array<FormItemRule>>> = reactive({
desc: [{required: true, message: '源参数描述必填!', trigger: 'blur'},{min: 1, max: 32, message: '长度为1~32个字符', trigger: 'blur'}], desc: [
type: [{required: true, message: '源参数类型必填!', trigger: 'blur'},{min: 1, max: 32, message: '长度为1~32个字符', trigger: 'blur'}], { required: true, message: '源参数描述必填!', trigger: 'blur' },
sort: [{required: true, message: '排序必填!', trigger: 'blur'}] { min: 1, max: 32, message: '长度为1~32个字符', trigger: 'blur' }
],
type: [
{ required: true, message: '源参数类型必填!', trigger: 'blur' },
{ min: 1, max: 32, message: '长度为1~32个字符', trigger: 'blur' }
],
sort: [{ required: true, message: '排序必填!', trigger: 'blur' }]
}) })
// watch(() => formContent.pId, (newVal, oldVal) => { // watch(() => formContent.pId, (newVal, oldVal) => {
@@ -108,54 +107,52 @@ const rules: reactive<Record<string, Array<FormItemRule>>> = reactive({
// }) // })
let dialogTitle = computed(() => { let dialogTitle = computed(() => {
return titleType.value === 'add' ? '新增源参数' : '编辑源参数' return titleType.value === 'add' ? '新增源参数' : '编辑源参数'
}) })
const resetFormContent = () => { const resetFormContent = () => {
Object.assign(formContent, { Object.assign(formContent, {
id: "", id: '',
type: "", type: '',
value: null, value: null,
desc: "", desc: '',
sort: 100, sort: 100,
pId: "0", pId: '0'
}) })
} }
const open = (sign: string, data: TestSource.ParameterType) => { const open = (sign: string, data: TestSource.ParameterType) => {
// 重置表单 // 重置表单
dialogFormRef.value?.resetFields() dialogFormRef.value?.resetFields()
resetFormContent() resetFormContent()
titleType.value = sign titleType.value = sign
dialogVisible.value = true dialogVisible.value = true
if (data.id) { if (data.id) {
Object.assign(formContent, data) Object.assign(formContent, data)
} }
} }
const save = () => { const save = () => {
try { try {
dialogFormRef.value?.validate(async (valid: boolean) => { dialogFormRef.value?.validate(async (valid: boolean) => {
if (valid) { if (valid) {
let newUpdateParameter = toRaw({...formContent}) let newUpdateParameter = toRaw({ ...formContent })
delete newUpdateParameter.children delete newUpdateParameter.children
emit('get-parameter', newUpdateParameter) emit('get-parameter', newUpdateParameter)
close() close()
} }
}) })
} catch (err) { } catch (err) {
console.error('验证过程中出现错误', err) console.error('验证过程中出现错误', err)
} }
} }
const close = () => { const close = () => {
dialogVisible.value = false dialogVisible.value = false
resetFormContent() resetFormContent()
dialogFormRef.value?.resetFields() dialogFormRef.value?.resetFields()
} }
defineExpose({open}) defineExpose({ open })
</script> </script>
<style scoped> <style scoped></style>
</style>

View File

@@ -1,280 +1,298 @@
<template> <template>
<div class='table-box' > <div class="table-box">
<ProTable <ProTable
ref='proTable' ref="proTable"
:columns='columns' :columns="columns"
:pagination="false" :pagination="false"
:toolButton="false" :toolButton="false"
:data="tableData" :data="tableData"
row-key="id" row-key="id"
:style="{ height: '250px',maxHeight: '400px',overflow:'hidden'}" :style="{ height: '250px', maxHeight: '400px', overflow: 'hidden' }"
:expand-row-keys="defaultExpandRowKeys" :expand-row-keys="defaultExpandRowKeys"
> >
<!-- 表格 header 按钮 --> <!-- 表格 header 按钮 -->
<template #tableHeader='scope'> <template #tableHeader="scope">
<el-button :disabled="isDisable" v-auth.testSource="'add'" type='primary' :icon='CirclePlus' @click="openDialog('add')">新增 <el-button
</el-button> :disabled="isDisable"
<el-button v-auth.testSource="'delete'" type='danger' :icon='Delete' v-auth.testSource="'add'"
plain :disabled='isDisable || !scope.isSelected' @click='batchDelete(scope.selectedListIds)'> type="primary"
删除 :icon="CirclePlus"
</el-button> @click="openDialog('add')"
</template> >
<!-- 表格操作 --> 新增
<template #operation='scope'> </el-button>
<!-- <el-button type="primary" link :icon='CopyDocument' @click="copyRow(scope.row)">复制</el-button> --> <el-button
<el-button :disabled="isDisable" type='primary' link :icon='EditPen' @click="openDialog('edit', scope.row)">编辑</el-button> v-auth.testSource="'delete'"
<el-button :disabled="isDisable" type='primary' link :icon='Delete' @click='handleDelete(scope.row.id)'>删除</el-button> type="danger"
</template> :icon="Delete"
</ProTable> plain
:disabled="isDisable || !scope.isSelected"
</div> @click="batchDelete(scope.selectedListIds)"
<ParameterPopup @getParameter="getParameter" ref='parameterPopup' :tableData="tableData"/> >
删除
</el-button>
</template>
<!-- 表格操作 -->
<template #operation="scope">
<!-- <el-button type="primary" link :icon='CopyDocument' @click="copyRow(scope.row)">复制</el-button> -->
<el-button
:disabled="isDisable"
type="primary"
link
:icon="EditPen"
@click="openDialog('edit', scope.row)"
>
编辑
</el-button>
<el-button :disabled="isDisable" type="primary" link :icon="Delete" @click="handleDelete(scope.row.id)">
删除
</el-button>
</template>
</ProTable>
</div>
<ParameterPopup @getParameter="getParameter" ref="parameterPopup" :tableData="tableData" />
</template> </template>
<script setup lang='tsx' name='useRole'> <script setup lang="tsx" name="useRole">
import {type TestSource} from '@/api/device/interface/testSource' import { type TestSource } from '@/api/device/interface/testSource'
import ProTable from '@/components/ProTable/index.vue' import ProTable from '@/components/ProTable/index.vue'
import type {ColumnProps, ProTableInstance} from '@/components/ProTable/interface' import type { ColumnProps, ProTableInstance } from '@/components/ProTable/interface'
import {CirclePlus, CopyDocument, Delete, EditPen} from '@element-plus/icons-vue' import { CirclePlus, Delete, EditPen } from '@element-plus/icons-vue'
import {useDictStore} from '@/stores/modules/dict' import ParameterPopup from '@/views/machine/testSource/components/parameterPopup.vue'
import ParameterPopup from '@/views/machine/testSource/components/parameterPopup.vue'; import { reactive, ref, watch } from 'vue'
import {reactive, ref, watch} from 'vue' import { generateUUID } from '@/styles'
import {generateUUID} from "@/styles";
import {defineEmits} from "vue/dist/vue";
import { ElMessage, ElMessageBox } from 'element-plus' import { ElMessage, ElMessageBox } from 'element-plus'
const parameterPopup = ref() const parameterPopup = ref()
const dictStore = useDictStore()
const btnDelete = ref(false)
// ProTable 实例 // ProTable 实例
const proTable = ref<ProTableInstance>() const proTable = ref<ProTableInstance>()
const tableData = ref<any[]>([]) const tableData = ref<any[]>([])
const props = defineProps({ const props = defineProps({
parameterStr: { parameterStr: {
type: String, type: String,
required: true, required: true
}, },
isDisable: { isDisable: {
type: Boolean, type: Boolean,
default: false, default: false
}, }
}); })
const emit = defineEmits(['change-parameter']) const emit = defineEmits(['change-parameter'])
let originalParameterArr=reactive<TestSource.ParameterType[]>([]) let originalParameterArr = reactive<TestSource.ParameterType[]>([])
watch(() => props.parameterStr, (newData) => { watch(
if (newData) { () => props.parameterStr,
getTableList() newData => {
} if (newData) {
}) getTableList()
}
}
)
const defaultExpandRowKeys =computed(() => { const defaultExpandRowKeys = computed(() => {
return getDefaultKeyArray(tableData.value) return getDefaultKeyArray(tableData.value)
}) })
const getDefaultKeyArray = (data: any[]) => { const getDefaultKeyArray = (data: any[]) => {
if (!data || data.length === 0) { if (!data || data.length === 0) {
return [] return []
} }
const firstElement = data[0] const firstElement = data[0]
let result: any[] = [] let result: any[] = []
recursion(firstElement,result) recursion(firstElement, result)
return result return result
} }
const recursion = (node: any, result: any[]) => { const recursion = (node: any, result: any[]) => {
if (node.children && node.children.length !== 0) { if (node.children && node.children.length !== 0) {
result.push(node.id) result.push(node.id)
recursion(node.children[0], result) recursion(node.children[0], result)
} }
} }
const getTableList = () => { const getTableList = () => {
if (props.parameterStr) { if (props.parameterStr) {
originalParameterArr = JSON.parse(props.parameterStr) originalParameterArr = JSON.parse(props.parameterStr)
tableData.value = getTreeData(originalParameterArr) tableData.value = getTreeData(originalParameterArr)
} }
}; }
const getTreeData = (data: TestSource.ParameterType[]): TestSource.ParameterType[] => { const getTreeData = (data: TestSource.ParameterType[]): TestSource.ParameterType[] => {
const result: TestSource.ParameterType[] = []// 最终返回的树形结构数据 const result: TestSource.ParameterType[] = [] // 最终返回的树形结构数据
//不能修改原数组,所以需要深拷贝 //不能修改原数组,所以需要深拷贝
const copyData = JSON.parse(JSON.stringify(data)) const copyData = JSON.parse(JSON.stringify(data))
const map = new Map<string, TestSource.ParameterType>(); const map = new Map<string, TestSource.ParameterType>()
copyData.forEach(item => { copyData.forEach(item => {
map.set(item.id, item) map.set(item.id, item)
}); })
for (const item of copyData) { for (const item of copyData) {
let parent = map.get(item.pId); let parent = map.get(item.pId)
if (parent) { if (parent) {
if (!parent.children) { if (!parent.children) {
parent.children = []; parent.children = []
} }
parent.children.push(item); parent.children.push(item)
parent.children.sort((a, b) => { parent.children.sort((a, b) => {
if (a.sort && b.sort) { if (a.sort && b.sort) {
return a.sort - b.sort return a.sort - b.sort
} else {
return 0
}
})
} else { } else {
return 0 result.push(item)
result.sort((a, b) => {
if (a.sort && b.sort) {
return a.sort - b.sort
} else {
return 0
}
})
} }
})
} else {
result.push(item)
result.sort((a, b) => {
if (a.sort && b.sort) {
return a.sort - b.sort
} else {
return 0
}
})
} }
} return result
return result
} }
const columns = reactive<ColumnProps<any>[]>([ const columns = reactive<ColumnProps<any>[]>([
{type: 'selection', fixed: 'left', width: 70, {
selectable(row, index) { type: 'selection',
if (props.isDisable) { fixed: 'left',
return false; width: 70,
} selectable(row, index) {
return true; if (props.isDisable) {
return false
}
return true
}
}, },
}, { type: 'index', fixed: 'left', width: 70, label: '序号' },
{type: 'index', fixed: 'left', width: 70, label: '序号'}, {
{ prop: 'type',
prop: 'type', label: '参数类型',
label: '参数类型', minWidth: 180,
minWidth: 180, align: 'left',
align: 'left', headerAlign: 'center'
headerAlign:'center' },
{
}, prop: 'desc',
{ label: '参数描述',
prop: 'desc', minWidth: 220
label: '参数描述', },
minWidth: 220, {
}, prop: 'value',
{ label: '值',
prop: 'value', minWidth: 150
label: '值', },
minWidth: 150, { prop: 'operation', label: '操作', fixed: 'right', width: 250 }
},
{prop: 'operation', label: '操作', fixed: 'right', width: 250},
]) ])
// 打开 drawer(新增、编辑) // 打开 drawer(新增、编辑)
const openDialog = (titleType: string, row: Partial<TestSource.ParameterType> = {}) => { const openDialog = (titleType: string, row: Partial<TestSource.ParameterType> = {}) => {
parameterPopup.value?.open(titleType, row) parameterPopup.value?.open(titleType, row)
} }
// 批量删除源参数 // 批量删除源参数
const batchDelete = async (ids: string[]) => { const batchDelete = async (ids: string[]) => {
ElMessageBox.confirm(`是否批量删除检测源?`, "温馨提示", { ElMessageBox.confirm(`是否批量删除检测源?`, '温馨提示', {
confirmButtonText: "确定", confirmButtonText: '确定',
cancelButtonText: "取消", cancelButtonText: '取消',
draggable: true draggable: true
}).then(async () => { }).then(async () => {
let parentIds = originalParameterArr.map(item => item.pId); let parentIds = originalParameterArr.map(item => item.pId)
if (parentIds.some(item => ids.includes(item))) { if (parentIds.some(item => ids.includes(item))) {
ElMessage.error('不能删除父节点'); ElMessage.error('不能删除父节点')
return; return
} }
// 直接过滤掉需要删除的项 // 直接过滤掉需要删除的项
originalParameterArr = originalParameterArr.filter(item => !ids.includes(item.id)); originalParameterArr = originalParameterArr.filter(item => !ids.includes(item.id))
emit('change-parameter', originalParameterArr); emit('change-parameter', originalParameterArr)
tableData.value = getTreeData(originalParameterArr); tableData.value = getTreeData(originalParameterArr)
ElMessage({ ElMessage({
type: "success", type: 'success',
message: `批量删除检测源成功!` message: `批量删除检测源成功!`
}); })
}); })
} }
// 删除源参数 // 删除源参数
const handleDelete = (id: string) => { const handleDelete = (id: string) => {
ElMessageBox.confirm(`是否删除检测源?`, "温馨提示", { ElMessageBox.confirm(`是否删除检测源?`, '温馨提示', {
confirmButtonText: "确定", confirmButtonText: '确定',
cancelButtonText: "取消", cancelButtonText: '取消',
draggable: true draggable: true
}).then(async () => { }).then(async () => {
let parentIds = originalParameterArr.map(item => item.pId); let parentIds = originalParameterArr.map(item => item.pId)
if (parentIds.includes(id)) { if (parentIds.includes(id)) {
ElMessage.error('不能删除父节点'); ElMessage.error('不能删除父节点')
return; return
} }
originalParameterArr = originalParameterArr.filter(item => item.id !== id); originalParameterArr = originalParameterArr.filter(item => item.id !== id)
emit('change-parameter', originalParameterArr); emit('change-parameter', originalParameterArr)
tableData.value = getTreeData(originalParameterArr); tableData.value = getTreeData(originalParameterArr)
ElMessage({ ElMessage({
type: "success", type: 'success',
message: `删除检测源成功!` message: `删除检测源成功!`
}); })
}); })
} }
// 复制源参数 // 复制源参数
const copyRow = (row) => { const copyRow = row => {
delete row.children delete row.children
let parentIds = originalParameterArr.map(item => item.pId) let parentIds = originalParameterArr.map(item => item.pId)
if (parentIds.includes(row.id)) { if (parentIds.includes(row.id)) {
let newParameterId = generateUUID().replaceAll("-","") let newParameterId = generateUUID().replaceAll('-', '')
let children = originalParameterArr.filter(item => item.pId == row.id).map(item => ({ let children = originalParameterArr
...item, .filter(item => item.pId == row.id)
id: generateUUID().replaceAll("-",""), .map(item => ({
pId: newParameterId ...item,
})) id: generateUUID().replaceAll('-', ''),
originalParameterArr.push({...row, id: newParameterId}) pId: newParameterId
originalParameterArr.push(...children) }))
} else { originalParameterArr.push({ ...row, id: newParameterId })
originalParameterArr.push({...row, id: generateUUID().replaceAll("-",""), pId: row.pId}) originalParameterArr.push(...children)
} } else {
emit('change-parameter', originalParameterArr) originalParameterArr.push({ ...row, id: generateUUID().replaceAll('-', ''), pId: row.pId })
tableData.value = getTreeData(originalParameterArr) }
emit('change-parameter', originalParameterArr)
tableData.value = getTreeData(originalParameterArr)
} }
const getParameter = (data: TestSource.ParameterType) => { const getParameter = (data: TestSource.ParameterType) => {
// if (originalParameterArr.some(item => item.type == data.type)) { // if (originalParameterArr.some(item => item.type == data.type)) {
// ElMessage.error({message: '参数类型已存在!'}) // ElMessage.error({message: '参数类型已存在!'})
// return; // return;
// } // }
let index = originalParameterArr.findIndex(item => item.id === data.id) let index = originalParameterArr.findIndex(item => item.id === data.id)
if (index === -1) {
if (index === -1) { data.id = generateUUID().replaceAll('-', '')
data.id = generateUUID().replaceAll("-","") // 新增
// 新增 originalParameterArr.push(data)
originalParameterArr.push(data) ElMessage.success({ message: '新增成功!' })
ElMessage.success({message: '新增成功!'}) } else {
} else { // 编辑
// 编辑 originalParameterArr[index] = data
originalParameterArr[index] = data ElMessage.success({ message: '编辑成功!' })
ElMessage.success({message: '编辑成功!'}) }
} emit('change-parameter', originalParameterArr)
emit('change-parameter', originalParameterArr) tableData.value = getTreeData(originalParameterArr)
tableData.value = getTreeData(originalParameterArr)
} }
//清空数据 //清空数据
const clearData = () => { const clearData = () => {
originalParameterArr = [] originalParameterArr = []
tableData.value = [] tableData.value = []
} }
defineExpose({ defineExpose({
clearData clearData
}) })
</script> </script>
<style scoped> <style scoped></style>
</style>

View File

@@ -1,49 +1,59 @@
<template> <template>
<el-dialog :title="dialogTitle" v-model='dialogVisible' @close="close" v-bind="dialogBig" align-center> <el-dialog :title="dialogTitle" v-model="dialogVisible" @close="close" v-bind="dialogBig" align-center>
<div > <div>
<el-form :model="formContent" ref='dialogFormRef' :rules='rules' :disabled="tableIsDisable" label-width="auto" class="form-three"> <el-form
<el-form-item label="设备类型" prop="devType" > :model="formContent"
<el-select v-model='formContent.devType' placeholder="请选择源型号"> ref="dialogFormRef"
<el-option :rules="rules"
v-for="item in dictStore.getDictData(dictTypeCode)" :disabled="tableIsDisable"
:key="item.id" label-width="auto"
:label="item.name" class="form-three"
:value="item.id" >
/> <el-form-item label="设备类型" prop="devType">
</el-select> <el-select v-model="formContent.devType" placeholder="请选择源型号">
</el-form-item> <el-option
<el-form-item label="检测源类型" prop="type" > v-for="item in dictStore.getDictData(dictTypeCode)"
<el-select v-model='formContent.type' placeholder="请选择检测源类型"> :key="item.id"
<el-option :label="item.name"
v-for="item in dictStore.getDictData('Pq_Source_Type')" :value="item.id"
:key="item.id" />
:label="item.name" </el-select>
:value="item.id" </el-form-item>
/> <el-form-item label="检测源类型" prop="type">
</el-select> <el-select v-model="formContent.type" placeholder="请选择检测源类型">
</el-form-item> <el-option
</el-form> v-for="item in dictStore.getDictData('Pq_Source_Type')"
</div> :key="item.id"
:label="item.name"
<ParameterTable :parameterStr="formContent.parameter" @change-parameter="changeParameter" ref="parameterTable" :is-disable="tableIsDisable"/> :value="item.id"
<template #footer> />
<div> </el-select>
<el-button :disabled="tableIsDisable" @click='close()'> </el-button> </el-form-item>
<el-button :disabled="tableIsDisable" type="primary" @click='save()'>保存</el-button> </el-form>
</div> </div>
</template>
</el-dialog>
<ParameterTable
:parameterStr="formContent.parameter"
@change-parameter="changeParameter"
ref="parameterTable"
:is-disable="tableIsDisable"
/>
<template #footer>
<div>
<el-button :disabled="tableIsDisable" @click="close()"> </el-button>
<el-button :disabled="tableIsDisable" type="primary" @click="save()">保存</el-button>
</div>
</template>
</el-dialog>
</template> </template>
<script lang="ts" setup name="ErrorSystemDialog"> <script lang="ts" setup name="ErrorSystemDialog">
import {ElMessage, type FormItemRule} from 'element-plus' import { ElMessage, type FormItemRule } from 'element-plus'
import {computed, defineProps, Ref, ref} from 'vue'; import { computed, Ref, ref } from 'vue'
import {dialogBig} from '@/utils/elementBind' import { dialogBig } from '@/utils/elementBind'
import {addTestSource, getTestSourceById, updateTestSource} from '@/api/device/testSource/index' import { addTestSource, getTestSourceById, updateTestSource } from '@/api/device/testSource/index'
import {useDictStore} from '@/stores/modules/dict' import { useDictStore } from '@/stores/modules/dict'
import {type TestSource} from '@/api/device/interface/testSource'; import { type TestSource } from '@/api/device/interface/testSource'
// 定义弹出组件元信息 // 定义弹出组件元信息
const dialogFormRef = ref() const dialogFormRef = ref()
const dictStore = useDictStore() const dictStore = useDictStore()
@@ -53,122 +63,116 @@ const parameterTable = ref()
const tableIsDisable = ref(true) const tableIsDisable = ref(true)
function useMetaInfo() { function useMetaInfo() {
const dialogVisible = ref(false) const dialogVisible = ref(false)
const titleType = ref('add') const titleType = ref('add')
const formContent = ref<TestSource.ResTestSource>({ const formContent = ref<TestSource.ResTestSource>({
id: '', id: '',
pattern: modeId.value, pattern: modeId.value,
parameter: '', parameter: '',
type: '', type: '',
devType: '', devType: '',
state: 1, state: 1
}) })
return {dialogVisible, titleType, formContent} return { dialogVisible, titleType, formContent }
} }
const {dialogVisible, titleType, formContent} = useMetaInfo() const { dialogVisible, titleType, formContent } = useMetaInfo()
// 清空formContent // 清空formContent
const resetFormContent = () => { const resetFormContent = () => {
formContent.value = { formContent.value = {
id: '', id: '',
pattern: modeId.value, pattern: modeId.value,
parameter: '', parameter: '',
type: '', type: '',
devType: '', devType: '',
state: 1, state: 1
} }
} }
let dialogTitle = computed(() => { let dialogTitle = computed(() => {
switch (titleType.value) { switch (titleType.value) {
case 'add': case 'add':
tableIsDisable.value = false tableIsDisable.value = false
return '新增检测源'; return '新增检测源'
case 'edit': case 'edit':
tableIsDisable.value = false tableIsDisable.value = false
return '编辑检测源'; return '编辑检测源'
case 'view': case 'view':
tableIsDisable.value = true tableIsDisable.value = true
return '查看检测源'; return '查看检测源'
default: default:
return ''; // 默认情况,可选 return '' // 默认情况,可选
} }
}); })
let dictTypeCode = computed(() => { let dictTypeCode = computed(() => {
return 'S_Dev_Type_' + dictStore.getDictData('Pattern').find(item => item.id === modeId.value)?.code return 'S_Dev_Type_' + dictStore.getDictData('Pattern').find(item => item.id === modeId.value)?.code
}) })
// 定义规则 // 定义规则
const rules: Ref<Record<string, Array<FormItemRule>>> = ref({ const rules: Ref<Record<string, Array<FormItemRule>>> = ref({
name: [{required: true, message: '检测源名称必填!', trigger: 'blur'}], name: [{ required: true, message: '检测源名称必填!', trigger: 'blur' }],
devType: [{required: true, message: '请选择一项设备类型', trigger: 'change'},], devType: [{ required: true, message: '请选择一项设备类型', trigger: 'change' }],
type: [{required: true, message: '请选择一项检测源类型', trigger: 'change '},] type: [{ required: true, message: '请选择一项检测源类型', trigger: 'change ' }]
}); })
// 关闭弹窗 // 关闭弹窗
const close = () => { const close = () => {
dialogVisible.value = false dialogVisible.value = false
// 清空dialogForm中的值 // 清空dialogForm中的值
resetFormContent() resetFormContent()
// 重置表单 // 重置表单
dialogFormRef.value?.resetFields() dialogFormRef.value?.resetFields()
parameterTable.value?.clearData() parameterTable.value?.clearData()
} }
// 保存数据 // 保存数据
const save = () => { const save = () => {
try { try {
dialogFormRef.value?.validate(async (valid: boolean) => { dialogFormRef.value?.validate(async (valid: boolean) => {
if (valid) {
if (valid) { if (formContent.value.id) {
if (formContent.value.id) { await updateTestSource(formContent.value)
await updateTestSource(formContent.value); ElMessage.success({ message: `${dialogTitle.value}成功!` })
ElMessage.success({message: `${dialogTitle.value}成功!`}) } else {
} else { await addTestSource(formContent.value)
await addTestSource(formContent.value); ElMessage.success({ message: `${dialogTitle.value}成功!` })
ElMessage.success({message: `${dialogTitle.value}成功!`}) }
} close()
close() // 刷新表格
// 刷新表格 await props.refreshTable!()
await props.refreshTable!() }
} })
}) } catch (err) {
} catch (err) { console.error('验证过程中出现错误', err)
console.error('验证过程中出现错误', err) }
}
} }
// 打开弹窗,可能是新增,也可能是编辑 // 打开弹窗,可能是新增,也可能是编辑
const open = async (sign: string, data: TestSource.ResTestSource, currentMode: string) => { const open = async (sign: string, data: TestSource.ResTestSource, currentMode: string) => {
titleType.value = sign titleType.value = sign
dialogVisible.value = true dialogVisible.value = true
mode.value = currentMode mode.value = currentMode
modeId.value = dictStore.getDictData('Pattern').find(item => item.name === currentMode)?.id; modeId.value = dictStore.getDictData('Pattern').find(item => item.name === currentMode)?.id
if (data.id) { if (data.id) {
const result = await getTestSourceById(data); const result = await getTestSourceById(data)
if (result && result.data) { if (result && result.data) {
formContent.value = result.data as TestSource.ResTestSource; formContent.value = result.data as TestSource.ResTestSource
}
} else {
resetFormContent()
} }
} else { // 重置表单
resetFormContent() dialogFormRef.value?.resetFields()
}
// 重置表单
dialogFormRef.value?.resetFields()
} }
const changeParameter = (parameterArr: any) => { const changeParameter = (parameterArr: any) => {
formContent.value.parameter = JSON.stringify(parameterArr) formContent.value.parameter = JSON.stringify(parameterArr)
} }
// 对外映射 // 对外映射
defineExpose({open}) defineExpose({ open })
const props = defineProps<{ const props = defineProps<{
refreshTable: (() => Promise<void>) | undefined; refreshTable: (() => Promise<void>) | undefined
}>() }>()
</script> </script>
<style> <style></style>
</style>

View File

@@ -0,0 +1,527 @@
<template>
<div class="table_info">
<ProTable
ref="proTable"
:columns="columns"
:request-api="getTableList"
:init-param="initParam"
:data-callback="dataCallback"
@drag-sort="sortTable"
:height="tableHeight"
:stripe="true"
>
<!-- 表格 header 按钮 -->
<template #tableHeader="scope">
<el-form :model="form" label-width="80px" :inline="true">
<el-form-item label="检测状态" v-if="form.activeTabs != 5">
<el-select v-model="form.checkStatus">
<el-option
v-for="(item, index) in checkStatusList"
:label="item.label"
:value="item.value"
:key="index"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="报告状态" v-if="form.activeTabs != 5">
<el-select v-model="form.checkReportStatus">
<el-option
v-for="(item, index) in checkReportStatusList"
:label="item.label"
:value="item.value"
:key="index"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="检测结果" v-if="form.activeTabs != 5">
<el-select v-model="form.checkResult">
<el-option
v-for="(item, index) in checkResultList"
:label="item.label"
:value="item.value"
:key="index"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="绑定状态" v-if="form.activeTabs == 5">
<el-select v-model="form.deviceBindStatus">
<el-option
v-for="(item, index) in deviceBindStatusList"
:label="item.label"
:value="item.value"
:key="index"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="设备类型" v-if="form.activeTabs == 5">
<el-select v-model="form.deviceType">
<el-option
v-for="(item, index) in deviceTypeList"
:label="item.label"
:value="item.value"
:key="index"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="制造厂商" v-if="form.activeTabs == 5">
<el-select v-model="form.manufacturer">
<el-option
v-for="(item, index) in manufacturerList"
:label="item.label"
:value="item.value"
:key="index"
></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" :icon="Search" @click="handleSearch">查询</el-button>
<el-button type="primary" @click="handleTest" v-if="form.activeTabs === 0">
启动自动检测
</el-button>
<el-button type="primary" @click="handleTest" v-if="form.activeTabs === 1">
启动手动检测
</el-button>
<el-button type="primary" v-if="form.activeTabs === 2">报告生成</el-button>
<el-button type="primary" v-if="form.activeTabs === 5">设备导入</el-button>
</el-form-item>
</el-form>
</template>
<!-- 表格操作 -->
<!-- <template #operation="scope">
<el-button
dictType="primary"
link
:icon="View"
@click="openDrawer('查看', scope.row)"
>查看</el-button
>
<el-button
dictType="primary"
link
:icon="EditPen"
@click="openDrawer('编辑', scope.row)"
>导出</el-button
>
<el-button
dictType="primary"
link
:icon="Delete"
@click="deleteAccount(scope.row)"
>删除</el-button
>
</template> -->
</ProTable>
</div>
</template>
<script setup lang="tsx" name="useProTable">
import { onMounted, reactive, ref } from 'vue'
import { useRouter } from 'vue-router'
import { User } from '@/api/interface'
import { useHandleData } from '@/hooks/useHandleData'
import { ElMessage } from 'element-plus'
import ProTable from '@/components/ProTable/index.vue'
import { Search } from '@element-plus/icons-vue'
import { getPlanList } from '@/api/plan/planList'
const router = useRouter()
const value1 = ref('')
const value2 = ref('')
const tableHeight = ref(0)
console.log(window.innerHeight, '+++++++++')
tableHeight.value = window.innerHeight - 630
//下拉框数据
//检测状态数据
const checkStatusList = [
{
label: '未检',
value: 0
},
{
label: '检测中',
value: 1
},
{
label: '检测完成',
value: 2
},
{
label: '归档',
value: 3
}
]
//检测报告状态数据
const checkReportStatusList = [
{
label: '未生成报告',
value: 0
},
{
label: '已生成报告',
value: 1
}
]
//检测结果数组
const checkResultList = [
{
label: '/',
value: null
},
{
label: '不合格',
value: 0
},
{
label: '合格',
value: 1
}
]
//绑定状态数组
const deviceBindStatusList = [
{
label: '未绑定',
value: 0
},
{
label: '已绑定',
value: 1
}
]
//设备类型数组
const deviceTypeList = [
{
label: 'PQS882A',
value: 0
},
{
label: 'PQS882B4',
value: 1
},
{
label: 'PQS882B5',
value: 2
},
{
label: 'PQS882B6',
value: 3
},
{
label: 'PQS882B7',
value: 4
},
{
label: 'PQS882B8',
value: 5
}
]
//制造厂商数组
const manufacturerList = [
{
label: '南京灿能电力',
value: 0
},
{
label: '南瑞继保',
value: 1
},
{
label: '中电',
value: 2
}
]
//查询条件
const form: any = ref({
activeTabs: 0, //功能选择
checkStatus: 0, //检测状态
checkReportStatus: 0, //检测报告状态
checkResult: 0, //检测结果
deviceBindStatus: 0, //绑定状态
deviceType: 0, //设备类型
manufacturer: 0 //制造厂商
})
const searchForm = ref({
intervalType: 0,
time: ['2024-08-20', '2024-08-27'],
searchBeginTime: '',
searchEndTime: '',
checkStatus: 0,
checkReportStatus: 0,
checkResult: 0
})
// ProTable 实例
const proTable = ref<ProTableInstance>()
// 如果表格需要初始化请求参数,直接定义传给 ProTable (之后每次请求都会自动带上该参数,此参数更改之后也会一直带上,改变此参数会自动刷新表格数据)
const initParam = reactive({ type: 1, pageNum: 1, pageSize: 10 })
// dataCallback 是对于返回的表格数据做处理,如果你后台返回的数据不是 list && total 这些字段,可以在这里进行处理成这些字段
// 或者直接去 hooks/useTable.ts 文件中把字段改为你后端对应的就行
const tableList = ref([])
const dataCallback = (data: any) => {
return {
list: data || data.data || data.list,
total: data.length || data.total //total
}
}
// 如果你想在请求之前对当前请求参数做一些操作可以自定义如下函数params 为当前所有的请求参数(包括分页),最后返回请求列表接口
// 默认不做操作就直接在 ProTable 组件上绑定 :requestApi="getUserList"
const getTableList = (params: any) => {
let newParams = JSON.parse(JSON.stringify(params))
newParams.createTime && (newParams.startTime = newParams.createTime[0])
newParams.createTime && (newParams.endTime = newParams.createTime[1])
delete newParams.createTime
return getPlanList(newParams)
}
// 表格配置项
const columns = reactive<ColumnProps<User.ResUserList>[]>([
{ type: 'selection', fixed: 'left', width: 70 },
{
prop: 'checkMode',
label: '设备序列号',
width: 140,
render: scope => {
return scope.row.checkMode == 0
? '设备1'
: scope.row.checkMode == 1
? '设备2'
: scope.row.checkMode == 2
? '设备3'
: scope.row.checkMode
}
},
{
prop: 'checkMode',
label: '设备类型',
width: 140,
render: scope => {
return scope.row.checkMode == 0
? 'PQS991'
: scope.row.checkMode == 1
? 'PQS882'
: scope.row.checkMode == 2
? 'PQS6666'
: scope.row.checkMode
}
},
{
prop: 'checkFrom',
label: '制造厂商',
width: 140,
render: scope => {
return scope.row.checkFrom == 0
? '南京灿能'
: scope.row.checkFrom == 1
? '南瑞继保'
: scope.row.checkFrom == 2
? '/'
: scope.row.checkFrom
}
},
{
prop: 'numberFromName',
label: 'MAC/IP',
render: scope => {
return scope.row.numberFromName == 0
? '192.168.0.1'
: scope.row.numberFromName == 1
? '192.168.0.2'
: scope.row.numberFromName == 2
? '192.168.0.3'
: scope.row.numberFromName
}
}
// {
// prop: "checkExe",
// label: "检测脚本",
// render: (scope) => {
// return scope.row.checkExe == 0
// ? "国网入网检测脚本(单影响量-模拟式)"
// : scope.row.checkExe == 1
// ? "国网入网检测脚本"
// : scope.row.checkExe == 2
// ? "/"
// : scope.row.checkExe;
// },
// },
// {
// prop: "wctx",
// label: "误差体系",
// render: (scope) => {
// return scope.row.wctx == 0
// ? "Q/GDW 1650.2- 2016"
// : scope.row.wctx == 1
// ? "Q/GDW 10650.2 - 2021"
// : scope.row.wctx == 2
// ? "/"
// : scope.row.wctx;
// },
// },
// {
// prop: "checkStatus",
// label: "检测状态",
// width: 120,
// render: (scope) => {
// return scope.row.checkStatus == 1
// ? "未检"
// : scope.row.checkStatus == 2
// ? "检测中"
// : scope.row.checkStatus == 3
// ? "检测完成"
// : scope.row.checkStatus;
// },
// },
// {
// prop: "checkReport",
// label: "检测报告",
// width: 120,
// render: (scope) => {
// return scope.row.checkReport == 1
// ? "未生成"
// : scope.row.checkReport == 2
// ? "部分生成"
// : scope.row.checkReport == 3
// ? "全部生成"
// : scope.row.checkReport;
// },
// },
// {
// prop: "checkResult",
// label: "检测结果",
// width: 120,
// render: (scope) => {
// return scope.row.checkReport == 1
// ? "/"
// : scope.row.checkReport == 2
// ? "符合"
// : scope.row.checkReport == 3
// ? "不符合"
// : scope.row.checkReport;
// },
// },
// {
// prop: "parentNode",
// label: "父节点",
// width: 90,
// render: (scope) => {
// return scope.row.checkReport == 0
// ? "/"
// : scope.row.checkReport == 1
// ? "检测计划1"
// : scope.row.checkReport == 2
// ? "检测计划2"
// : scope.row.checkReport == 3
// ? "检测计划3"
// : scope.row.checkReport;
// },
// },
// { prop: "operation", label: "操作", fixed: "right", width: 250 },
])
// 跳转详情页
const toDetail = () => {
router.push(`/proTable/useProTable/detail/${Math.random().toFixed(3)}?params=detail-page`)
}
//重置查询条件
const resetSearchForm = () => {
searchForm.value = {
intervalType: 0,
time: ['2024-08-20', '2024-08-27'],
searchBeginTime: '',
searchEndTime: '',
checkStatus: 0,
checkReportStatus: 0,
checkResult: 0
}
}
//查询
const handleSearch = () => {
proTable.value?.getTableList()
}
//重置
const handleRefresh = () => {
proTable.value?.getTableList()
}
// 表格拖拽排序
const sortTable = ({ newIndex, oldIndex }: { newIndex?: number; oldIndex?: number }) => {
console.log(newIndex, oldIndex)
console.log(proTable.value?.tableData)
ElMessage.success('修改列表排序成功')
}
// 删除用户信息
const deleteAccount = async (params: User.ResUserList) => {
await useHandleData(deleteUser, { id: [params.id] }, `删除【${params.username}`)
proTable.value?.getTableList()
}
// 批量删除用户信息
const batchDelete = async (id: string[]) => {
await useHandleData(deleteUser, { id }, '删除所选用户信息')
proTable.value?.clearSelection()
proTable.value?.getTableList()
}
// 重置用户密码
const resetPass = async (params: User.ResUserList) => {
await useHandleData(resetUserPassWord, { id: params.id }, `重置【${params.username}】用户密码`)
proTable.value?.getTableList()
}
// 切换用户状态
const changeStatus = async (row: User.ResUserList) => {
await useHandleData(
changeUserStatus,
{ id: row.id, status: row.status == 1 ? 0 : 1 },
`切换【${row.username}】用户状态`
)
proTable.value?.getTableList()
}
//顶部功能切换时修改activeTabs
const changeActiveTabs = (val: number) => {
form.value.activeTabs = val
}
//启动自动检测/手动检测
const handleTest = () => {
//自动检测
if (form.value.activeTabs === 0) {
ElMessage.success('自动检测')
router.push({
path: '/plan/autoTest'
})
} else {
ElMessage.warning('手动检测')
}
}
onMounted(() => {
console.log(proTable.value?.tableData)
})
defineExpose({ changeActiveTabs })
</script>
<style lang="scss" scoped>
/* 当屏幕宽度小于或等于1300像素时 */
@media screen and (max-width: 1300px) {
.el-select {
width: 130px !important;
}
}
@media screen and (min-width: 1300px) {
.el-select {
width: 150px !important;
}
}
.el-form {
width: 100%;
display: flex;
flex-wrap: wrap;
.el-form-item {
display: flex;
align-items: center;
justify-content: space-between;
.el-button {
margin: 0 !important;
margin-right: 10px !important;
}
}
}
</style>

View File

@@ -1,568 +0,0 @@
<template>
<div class="table_info">
<ProTable
ref="proTable"
:columns="columns"
:request-api="getTableList"
:init-param="initParam"
:data-callback="dataCallback"
@drag-sort="sortTable"
:height="tableHeight"
:stripe="true"
>
<!-- 表格 header 按钮 -->
<template #tableHeader="scope">
<el-form :model="form" label-width="80px" :inline="true">
<el-form-item label="检测状态" v-if="form.activeTabs != 5">
<el-select v-model="form.checkStatus">
<el-option
v-for="(item, index) in checkStatusList"
:label="item.label"
:value="item.value"
:key="index"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="报告状态" v-if="form.activeTabs != 5">
<el-select v-model="form.checkReportStatus">
<el-option
v-for="(item, index) in checkReportStatusList"
:label="item.label"
:value="item.value"
:key="index"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="检测结果" v-if="form.activeTabs != 5">
<el-select v-model="form.checkResult">
<el-option
v-for="(item, index) in checkResultList"
:label="item.label"
:value="item.value"
:key="index"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="绑定状态" v-if="form.activeTabs == 5">
<el-select v-model="form.deviceBindStatus">
<el-option
v-for="(item, index) in deviceBindStatusList"
:label="item.label"
:value="item.value"
:key="index"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="设备类型" v-if="form.activeTabs == 5">
<el-select v-model="form.deviceType">
<el-option
v-for="(item, index) in deviceTypeList"
:label="item.label"
:value="item.value"
:key="index"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="制造厂商" v-if="form.activeTabs == 5">
<el-select v-model="form.manufacturer">
<el-option
v-for="(item, index) in manufacturerList"
:label="item.label"
:value="item.value"
:key="index"
></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" :icon="Search" @click="handleSearch"
>查询</el-button
>
<el-button
type="primary"
@click="handleTest"
v-if="form.activeTabs === 0"
>启动自动检测</el-button
>
<el-button
type="primary"
@click="handleTest"
v-if="form.activeTabs === 1"
>启动手动检测</el-button
>
<el-button type="primary" v-if="form.activeTabs === 2"
>报告生成</el-button
>
<el-button type="primary" v-if="form.activeTabs === 5"
>设备导入</el-button
>
</el-form-item>
</el-form>
</template>
<!-- 表格操作 -->
<!-- <template #operation="scope">
<el-button
dictType="primary"
link
:icon="View"
@click="openDrawer('查看', scope.row)"
>查看</el-button
>
<el-button
dictType="primary"
link
:icon="EditPen"
@click="openDrawer('编辑', scope.row)"
>导出</el-button
>
<el-button
dictType="primary"
link
:icon="Delete"
@click="deleteAccount(scope.row)"
>删除</el-button
>
</template> -->
</ProTable>
</div>
</template>
<script setup lang="tsx" name="useProTable">
import { ref, reactive, onMounted } from "vue";
import { useRouter } from "vue-router";
import { User } from "@/api/interface";
import { useHandleData } from "@/hooks/useHandleData";
import { useDownload } from "@/hooks/useDownload";
import { ElMessage, ElMessageBox } from "element-plus";
import ProTable from "@/components/ProTable/index.vue";
import ImportExcel from "@/components/ImportExcel/index.vue";
import {
CirclePlus,
Delete,
EditPen,
Download,
Upload,
View,
Refresh,
Search,
} from "@element-plus/icons-vue";
import { getPlanList } from "@/api/plan/planList";
const router = useRouter();
const value1 = ref("");
const value2 = ref("");
const tableHeight = ref(0);
console.log(window.innerHeight, "+++++++++");
tableHeight.value = window.innerHeight - 630;
//下拉框数据
//检测状态数据
const checkStatusList = [
{
label: "未检",
value: 0,
},
{
label: "检测中",
value: 1,
},
{
label: "检测完成",
value: 2,
},
{
label: "归档",
value: 3,
},
];
//检测报告状态数据
const checkReportStatusList = [
{
label: "未生成报告",
value: 0,
},
{
label: "已生成报告",
value: 1,
},
];
//检测结果数组
const checkResultList = [
{
label: "/",
value: null,
},
{
label: "不合格",
value: 0,
},
{
label: "合格",
value: 1,
},
];
//绑定状态数组
const deviceBindStatusList = [
{
label: "未绑定",
value: 0,
},
{
label: "已绑定",
value: 1,
},
];
//设备类型数组
const deviceTypeList = [
{
label: "PQS882A",
value: 0,
},
{
label: "PQS882B4",
value: 1,
},
{
label: "PQS882B5",
value: 2,
},
{
label: "PQS882B6",
value: 3,
},
{
label: "PQS882B7",
value: 4,
},
{
label: "PQS882B8",
value: 5,
},
];
//制造厂商数组
const manufacturerList = [
{
label: "南京灿能电力",
value: 0,
},
{
label: "南瑞继保",
value: 1,
},
{
label: "中电",
value: 2,
},
];
//查询条件
const form: any = ref({
activeTabs: 0, //功能选择
checkStatus: 0, //检测状态
checkReportStatus: 0, //检测报告状态
checkResult: 0, //检测结果
deviceBindStatus: 0, //绑定状态
deviceType: 0, //设备类型
manufacturer: 0, //制造厂商
});
const searchForm = ref({
intervalType: 0,
time: ["2024-08-20", "2024-08-27"],
searchBeginTime: "",
searchEndTime: "",
checkStatus: 0,
checkReportStatus: 0,
checkResult: 0,
});
// ProTable 实例
const proTable = ref<ProTableInstance>();
// 如果表格需要初始化请求参数,直接定义传给 ProTable (之后每次请求都会自动带上该参数,此参数更改之后也会一直带上,改变此参数会自动刷新表格数据)
const initParam = reactive({ type: 1, pageNum: 1, pageSize: 10 });
// dataCallback 是对于返回的表格数据做处理,如果你后台返回的数据不是 list && total 这些字段,可以在这里进行处理成这些字段
// 或者直接去 hooks/useTable.ts 文件中把字段改为你后端对应的就行
const tableList = ref([]);
const dataCallback = (data: any) => {
return {
list: data || data.data || data.list,
total: data.length || data.total, //total
};
};
// 如果你想在请求之前对当前请求参数做一些操作可以自定义如下函数params 为当前所有的请求参数(包括分页),最后返回请求列表接口
// 默认不做操作就直接在 ProTable 组件上绑定 :requestApi="getUserList"
const getTableList = (params: any) => {
let newParams = JSON.parse(JSON.stringify(params));
newParams.createTime && (newParams.startTime = newParams.createTime[0]);
newParams.createTime && (newParams.endTime = newParams.createTime[1]);
delete newParams.createTime;
return getPlanList(newParams);
};
// 表格配置项
const columns = reactive<ColumnProps<User.ResUserList>[]>([
{ type: "selection", fixed: "left", width: 70 },
{
prop: "checkMode",
label: "设备序列号",
width: 140,
render: (scope) => {
return scope.row.checkMode == 0
? "设备1"
: scope.row.checkMode == 1
? "设备2"
: scope.row.checkMode == 2
? "设备3"
: scope.row.checkMode;
},
},
{
prop: "checkMode",
label: "设备类型",
width: 140,
render: (scope) => {
return scope.row.checkMode == 0
? "PQS991"
: scope.row.checkMode == 1
? "PQS882"
: scope.row.checkMode == 2
? "PQS6666"
: scope.row.checkMode;
},
},
{
prop: "checkFrom",
label: "制造厂商",
width: 140,
render: (scope) => {
return scope.row.checkFrom == 0
? "南京灿能"
: scope.row.checkFrom == 1
? "南瑞继保"
: scope.row.checkFrom == 2
? "/"
: scope.row.checkFrom;
},
},
{
prop: "numberFromName",
label: "MAC/IP",
render: (scope) => {
return scope.row.numberFromName == 0
? "192.168.0.1"
: scope.row.numberFromName == 1
? "192.168.0.2"
: scope.row.numberFromName == 2
? "192.168.0.3"
: scope.row.numberFromName;
},
},
// {
// prop: "checkExe",
// label: "检测脚本",
// render: (scope) => {
// return scope.row.checkExe == 0
// ? "国网入网检测脚本(单影响量-模拟式)"
// : scope.row.checkExe == 1
// ? "国网入网检测脚本"
// : scope.row.checkExe == 2
// ? "/"
// : scope.row.checkExe;
// },
// },
// {
// prop: "wctx",
// label: "误差体系",
// render: (scope) => {
// return scope.row.wctx == 0
// ? "Q/GDW 1650.2- 2016"
// : scope.row.wctx == 1
// ? "Q/GDW 10650.2 - 2021"
// : scope.row.wctx == 2
// ? "/"
// : scope.row.wctx;
// },
// },
// {
// prop: "checkStatus",
// label: "检测状态",
// width: 120,
// render: (scope) => {
// return scope.row.checkStatus == 1
// ? "未检"
// : scope.row.checkStatus == 2
// ? "检测中"
// : scope.row.checkStatus == 3
// ? "检测完成"
// : scope.row.checkStatus;
// },
// },
// {
// prop: "checkReport",
// label: "检测报告",
// width: 120,
// render: (scope) => {
// return scope.row.checkReport == 1
// ? "未生成"
// : scope.row.checkReport == 2
// ? "部分生成"
// : scope.row.checkReport == 3
// ? "全部生成"
// : scope.row.checkReport;
// },
// },
// {
// prop: "checkResult",
// label: "检测结果",
// width: 120,
// render: (scope) => {
// return scope.row.checkReport == 1
// ? "/"
// : scope.row.checkReport == 2
// ? "符合"
// : scope.row.checkReport == 3
// ? "不符合"
// : scope.row.checkReport;
// },
// },
// {
// prop: "parentNode",
// label: "父节点",
// width: 90,
// render: (scope) => {
// return scope.row.checkReport == 0
// ? "/"
// : scope.row.checkReport == 1
// ? "检测计划1"
// : scope.row.checkReport == 2
// ? "检测计划2"
// : scope.row.checkReport == 3
// ? "检测计划3"
// : scope.row.checkReport;
// },
// },
// { prop: "operation", label: "操作", fixed: "right", width: 250 },
]);
// 跳转详情页
const toDetail = () => {
router.push(
`/proTable/useProTable/detail/${Math.random().toFixed(3)}?params=detail-page`
);
};
//重置查询条件
const resetSearchForm = () => {
searchForm.value = {
intervalType: 0,
time: ["2024-08-20", "2024-08-27"],
searchBeginTime: "",
searchEndTime: "",
checkStatus: 0,
checkReportStatus: 0,
checkResult: 0,
};
};
//查询
const handleSearch = () => {
proTable.value?.getTableList();
};
//重置
const handleRefresh = () => {
proTable.value?.getTableList();
};
// 表格拖拽排序
const sortTable = ({
newIndex,
oldIndex,
}: {
newIndex?: number;
oldIndex?: number;
}) => {
console.log(newIndex, oldIndex);
console.log(proTable.value?.tableData);
ElMessage.success("修改列表排序成功");
};
// 删除用户信息
const deleteAccount = async (params: User.ResUserList) => {
await useHandleData(
deleteUser,
{ id: [params.id] },
`删除【${params.username}`
);
proTable.value?.getTableList();
};
// 批量删除用户信息
const batchDelete = async (id: string[]) => {
await useHandleData(deleteUser, { id }, "删除所选用户信息");
proTable.value?.clearSelection();
proTable.value?.getTableList();
};
// 重置用户密码
const resetPass = async (params: User.ResUserList) => {
await useHandleData(
resetUserPassWord,
{ id: params.id },
`重置【${params.username}】用户密码`
);
proTable.value?.getTableList();
};
// 切换用户状态
const changeStatus = async (row: User.ResUserList) => {
await useHandleData(
changeUserStatus,
{ id: row.id, status: row.status == 1 ? 0 : 1 },
`切换【${row.username}】用户状态`
);
proTable.value?.getTableList();
};
//顶部功能切换时修改activeTabs
const changeActiveTabs = (val: number) => {
form.value.activeTabs = val;
};
//启动自动检测/手动检测
const handleTest = () => {
//自动检测
if (form.value.activeTabs === 0) {
ElMessage.success("自动检测");
router.push({
path:"/plan/autoTest"
})
}else{
ElMessage.warning("手动检测");
}
};
onMounted(() => {
console.log(proTable.value?.tableData);
});
defineExpose({ changeActiveTabs });
</script>
<style lang="scss" scoped>
/* 当屏幕宽度小于或等于1300像素时 */
@media screen and (max-width: 1300px) {
.el-select {
width: 130px !important;
}
}
@media screen and (min-width: 1300px) {
.el-select {
width: 150px !important;
}
}
// ::v-deep .el-select {
// width: 150px !important;
// }
.el-form {
width: 100%;
display: flex;
flex-wrap: wrap;
.el-form-item {
display: flex;
align-items: center;
justify-content: space-between;
.el-button {
margin: 0 !important;
margin-right: 10px !important;
}
}
}
</style>

File diff suppressed because it is too large Load Diff

View File

@@ -416,7 +416,7 @@ const renderTabs = () => {
}) })
} }
// 子计划 tabs // 子计划 tabs
if (planFormContent.value?.children?.length > 0) { if (planFormContent.value && planFormContent.value.children && planFormContent.value.children?.length > 0) {
planFormContent.value.children.forEach((child, index) => { planFormContent.value.children.forEach((child, index) => {
tabs.push({ tabs.push({
title: child.name, title: child.name,
@@ -445,7 +445,8 @@ const unbindDevice = (row: any) => {
await subPlanBindDev({ planId: row.planId, devIds: [row.id], bindFlag: 0 }) //解绑 0 绑定 1 await subPlanBindDev({ planId: row.planId, devIds: [row.id], bindFlag: 0 }) //解绑 0 绑定 1
// 👇 更新数据(例如清空 state 字段) // 👇 更新数据(例如清空 state 字段)
row.state = '/' row.state = '/'
proTable.value?.getTableList() await proTable.value?.getTableList()
await props.refreshTable!()
// 可选:刷新表格或提交接口 // 可选:刷新表格或提交接口
ElMessage.success('解绑成功') ElMessage.success('解绑成功')
}) })
@@ -500,6 +501,7 @@ const distribute = (childPlan: Plan.ResPlan, scope: any) => {
.then(async () => { .then(async () => {
await subPlanBindDev({ planId: childPlan.id, devIds: scope.selectedListIds, bindFlag: 1 }) //解绑 0 绑定 1 await subPlanBindDev({ planId: childPlan.id, devIds: scope.selectedListIds, bindFlag: 1 }) //解绑 0 绑定 1
proTable.value?.getTableList() proTable.value?.getTableList()
await props.refreshTable!()
ElMessage.success('分配成功') ElMessage.success('分配成功')
}) })
.catch(() => { .catch(() => {

View File

@@ -367,6 +367,7 @@ const initTree = (data: Device[]) => {
filter.value.groupBy filter.value.groupBy
) )
defaultCheckedKeys.value = data.filter(item => item.checked).map(item => item.id) defaultCheckedKeys.value = data.filter(item => item.checked).map(item => item.id)
modelValue.value = defaultCheckedKeys.value
// 统计数据 // 统计数据
statistics.value.checked = defaultCheckedKeys.value.length statistics.value.checked = defaultCheckedKeys.value.length
statistics.value.total = data.length statistics.value.total = data.length

View File

@@ -383,7 +383,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import { type CascaderOption, ElMessage, type FormItemRule } from 'element-plus' import { type CascaderOption, ElMessage, type FormItemRule } from 'element-plus'
import { computed, defineProps, reactive, ref } from 'vue' import { computed, reactive, ref } from 'vue'
import { dialogBig } from '@/utils/elementBind' import { dialogBig } from '@/utils/elementBind'
import { type Plan } from '@/api/plan/interface' import { type Plan } from '@/api/plan/interface'
import { import {
@@ -460,8 +460,10 @@ const generateData = () => {
i.manufacturer = manufacturer.name i.manufacturer = manufacturer.name
} }
} }
i.checked = boundPqDevIds.includes(i.id) i.checked = boundPqDevIds.length > 0 ? boundPqDevIds.includes(i.id) : false
i.disabled = i.checkState != 0 if (i.checkState && i.checkState != 0) {
i.disabled = true
}
if (allDisabled.value) { if (allDisabled.value) {
i.disabled = true i.disabled = true
} }
@@ -668,12 +670,12 @@ const save = () => {
if (planType.value == 1) { if (planType.value == 1) {
formContent.fatherPlanId = formContent.id formContent.fatherPlanId = formContent.id
formContent.id = '' formContent.id = ''
formContent.memberIds = [formContent.memberIds?.toString()] formContent.memberIds = formContent.memberIds ? [formContent.memberIds?.toString()] : []
await addPlan(formContent) await addPlan(formContent)
emit('update:tab') emit('update:tab')
// 编辑子计划 // 编辑子计划
} else if (planType.value == 2) { } else if (planType.value == 2) {
formContent.memberIds = [formContent.memberIds?.toString()] formContent.memberIds = formContent.memberIds ? [formContent.memberIds?.toString()] : []
await updatePlan(formContent) await updatePlan(formContent)
emit('update:tab') emit('update:tab')
console.log('更新子计划', formContent) console.log('更新子计划', formContent)
@@ -947,6 +949,13 @@ const open = async (sign: string, data: Plan.ReqPlan, currentMode: string, plan:
...user, ...user,
disabled: childrenMembers.includes(user.id) || formContent.leader === user.id disabled: childrenMembers.includes(user.id) || formContent.leader === user.id
})) }))
const subPlanIds = data.children.map((item: any) => item.id)
const subBoundDev_Result = await getBoundPqDevList({ planIdList: subPlanIds })
const subBoundDevData = Array.isArray(subBoundDev_Result.data) ? subBoundDev_Result.data : []
const subBoundDevIds = subBoundDevData.map((item: any) => item.id)
boundPqDevList.value.forEach((item: any) => {
item.disabled = subBoundDevIds.includes(item.id)
})
} }
} else if (planType.value === 1) { } else if (planType.value === 1) {
unboundPqDevList.value = boundData.filter((i: any) => !i.boundPlanName) as Device.ResPqDev[] unboundPqDevList.value = boundData.filter((i: any) => !i.boundPlanName) as Device.ResPqDev[]

View File

@@ -103,7 +103,7 @@
type="primary" type="primary"
v-auth.plan="'analysis'" v-auth.plan="'analysis'"
link link
:icon="List" icon="DataLine"
v-if="scope.row.testState == '2'" v-if="scope.row.testState == '2'"
@click="statisticalAnalysis(scope.row)" @click="statisticalAnalysis(scope.row)"
> >
@@ -149,7 +149,7 @@
<script setup lang="tsx" name="useProTable"> <script setup lang="tsx" name="useProTable">
import ProTable from '@/components/ProTable/index.vue' import ProTable from '@/components/ProTable/index.vue'
import type { ColumnProps, ProTableInstance } from '@/components/ProTable/interface' import type { ColumnProps, ProTableInstance } from '@/components/ProTable/interface'
import { CirclePlus, Delete, Download, List, Upload } from '@element-plus/icons-vue' import { CirclePlus, Delete, Download, Upload } from '@element-plus/icons-vue'
import { import {
deletePlan, deletePlan,
downloadTemplate, downloadTemplate,
@@ -365,7 +365,7 @@ const columns = reactive<ColumnProps<Plan.ReqPlan>[]>([
<el-progress <el-progress
text-inside={true} text-inside={true}
stroke-width={20} stroke-width={20}
percentage={(scope.row.progress ?? 0) * 100} percentage={Number(((scope.row.progress ?? 0) * 100).toFixed(2))}
status="success" status="success"
/> />
) )

View File

@@ -1,90 +1,77 @@
<template> <template>
<div class="table-box planList"> <div class="table-box planList">
<ProTable <ProTable
ref="proTable" ref="proTable"
:columns="columns" :columns="columns"
:request-api="getTableList" :request-api="getTableList"
:init-param="initParam" :init-param="initParam"
:data-callback="dataCallback" :data-callback="dataCallback"
@drag-sort="sortTable" @drag-sort="sortTable"
> >
<!-- 表格 header 按钮 --> <!-- 表格 header 按钮 -->
<template #tableHeader> <template #tableHeader>
<el-form :model="searchForm"> <el-form :model="searchForm">
<el-form-item label="检测时间"> <el-form-item label="检测时间">
<el-select <el-select v-model="searchForm.intervalType" style="width: 80px !important">
v-model="searchForm.intervalType" <el-option :value="0" label="按周">按周</el-option>
style="width: 80px !important" <el-option :value="1" label="按月">按月</el-option>
> <el-option :value="2" label="按日">按日</el-option>
<el-option :value="0" label="按周">按周</el-option> </el-select>
<el-option :value="1" label="按月">按月</el-option> </el-form-item>
<el-option :value="2" label="按日">按日</el-option> <el-form-item label="">
</el-select> <el-date-picker
</el-form-item> style="width: 220px"
<el-form-item label=""> v-model="searchForm.time"
<el-date-picker type="daterange"
style="width: 220px" unlink-panels
v-model="searchForm.time" range-separator="-"
type="daterange" start-placeholder="开始日期"
unlink-panels end-placeholder="结束日期"
range-separator="-" :shortcuts="shortcuts"
start-placeholder="开始日期" />
end-placeholder="结束日期" </el-form-item>
:shortcuts="shortcuts" <el-form-item label="检测状态">
/> <el-select v-model="searchForm.checkStatus">
</el-form-item> <el-option :value="0" label="全部"></el-option>
<el-form-item label="检测状态"> <el-option :value="1" label="检"></el-option>
<el-select v-model="searchForm.checkStatus"> <el-option :value="2" label="检测中"></el-option>
<el-option :value="0" label="全部"></el-option> <el-option :value="3" label="检测完成"></el-option>
<el-option :value="1" label="未检"></el-option> </el-select>
<el-option :value="2" label="检测中"></el-option> </el-form-item>
<el-option :value="3" label="检测完成"></el-option> <el-form-item label="检测报告状态">
</el-select> <el-select v-model="searchForm.checkReportStatus">
</el-form-item> <el-option :value="0" label="全部"></el-option>
<el-form-item label="检测报告状态"> <el-option :value="1" label="未生成"></el-option>
<el-select v-model="searchForm.checkReportStatus"> <el-option :value="2" label="部分生成"></el-option>
<el-option :value="0" label="全部"></el-option> <el-option :value="3" label="全部生成"></el-option>
<el-option :value="1" label="未生成"></el-option> </el-select>
<el-option :value="2" label="部分生成"></el-option> </el-form-item>
<el-option :value="3" label="全部生成"></el-option> <el-form-item label="检测结果">
</el-select> <el-select v-model="searchForm.checkResult">
</el-form-item> <el-option :value="0" label="全部"></el-option>
<el-form-item label="检测结果"> <el-option :value="1" label="/"></el-option>
<el-select v-model="searchForm.checkResult"> <el-option :value="2" label="符合"></el-option>
<el-option :value="0" label="全部"></el-option> <el-option :value="3" label="不符合"></el-option>
<el-option :value="1" label="/"></el-option> </el-select>
<el-option :value="2" label="符合"></el-option> </el-form-item>
<el-option :value="3" label="不符合"></el-option> <el-form-item>
</el-select> <el-button type="primary" :icon="Search" @click="handleSearch">查询</el-button>
</el-form-item> <el-button :icon="Refresh" @click="handleRefresh">重置</el-button>
<el-form-item> </el-form-item>
<el-button type="primary" :icon="Search" @click="handleSearch" <el-form-item>
>查询</el-button <el-button type="primary" :icon="Upload" @click="handleRefresh">导入</el-button>
> </el-form-item>
<el-button :icon="Refresh" @click="handleRefresh">重置</el-button> <el-form-item>
</el-form-item> <el-button type="primary" :icon="Check" @click="handleRefresh">合并</el-button>
<el-form-item> </el-form-item>
<el-button type="primary" :icon="Upload" @click="handleRefresh" <el-form-item>
>导入</el-button <el-button type="primary" :icon="Plus" @click="handleRefresh">新增</el-button>
> </el-form-item>
</el-form-item> <el-form-item>
<el-form-item> <el-button type="danger" :icon="Delete" @click="handleRefresh">删除</el-button>
<el-button type="primary" :icon="Check" @click="handleRefresh" </el-form-item>
>合并</el-button </el-form>
> <!-- <el-button
</el-form-item>
<el-form-item>
<el-button type="primary" :icon="Plus" @click="handleRefresh"
>新增</el-button
>
</el-form-item>
<el-form-item>
<el-button type="danger" :icon="Delete" @click="handleRefresh"
>删除</el-button
>
</el-form-item>
</el-form>
<!-- <el-button
v-auth="'add'" v-auth="'add'"
dictType="primary" dictType="primary"
:icon="CirclePlus" :icon="CirclePlus"
@@ -119,363 +106,316 @@
> >
批量删除用户 批量删除用户
</el-button> --> </el-button> -->
</template> </template>
<!-- Expand --> <!-- Expand -->
<!-- <template #expand="scope"> <!-- <template #expand="scope">
{{ scope.row }} {{ scope.row }}
</template> --> </template> -->
<!-- 表格操作 --> <!-- 表格操作 -->
<template #operation="scope"> <template #operation="scope">
<el-button <el-button type="primary" link :icon="View" @click="handleDetails('查看', scope.row)">查看</el-button>
type="primary" <el-button type="primary" link :icon="EditPen" @click="openDrawer('编辑', scope.row)">导出</el-button>
link <el-button type="primary" link :icon="Delete" @click="deleteAccount(scope.row)">删除</el-button>
:icon="View" </template>
@click="handleDetails('查看', scope.row)" </ProTable>
>查看</el-button </div>
> <plan-details ref="detailsRef"></plan-details>
<el-button
type="primary"
link
:icon="EditPen"
@click="openDrawer('编辑', scope.row)"
>导出</el-button
>
<el-button
type="primary"
link
:icon="Delete"
@click="deleteAccount(scope.row)"
>删除</el-button
>
</template>
</ProTable>
</div>
<plan-details ref="detailsRef"></plan-details>
</template> </template>
<script setup lang="tsx" name="useProTable"> <script setup lang="tsx" name="useProTable">
import { ref, reactive, onMounted } from "vue"; import { onMounted, reactive, ref } from 'vue'
import { useRouter } from "vue-router"; import { useRouter } from 'vue-router'
import { User } from "@/api/interface"; import { User } from '@/api/interface'
import { useHandleData } from "@/hooks/useHandleData"; import { useHandleData } from '@/hooks/useHandleData'
import { useDownload } from "@/hooks/useDownload"; import { ElMessage } from 'element-plus'
import { ElMessage, ElMessageBox } from "element-plus"; import ProTable from '@/components/ProTable/index.vue'
import ProTable from "@/components/ProTable/index.vue"; import planDetails from './components/details.vue'
import ImportExcel from "@/components/ImportExcel/index.vue"; import { Check, Delete, EditPen, Plus, Refresh, Search, Upload, View } from '@element-plus/icons-vue'
import planDetails from "./components/details.vue"; import { getPlanList } from '@/api/plan/planList'
import {
CirclePlus,
Delete,
EditPen,
Download,
Upload,
View,
Check,
Plus,
Refresh,
Search,
} from "@element-plus/icons-vue";
import { getPlanList } from "@/api/plan/planList";
const router = useRouter(); const router = useRouter()
const value1 = ref(""); const value1 = ref('')
const value2 = ref(""); const value2 = ref('')
const shortcuts = [ const shortcuts = [
{ {
text: "最近一周", text: '最近一周',
value: () => { value: () => {
const end = new Date(); const end = new Date()
const start = new Date(); const start = new Date()
start.setTime(start.getTime() - 3600 * 1000 * 24 * 7); start.setTime(start.getTime() - 3600 * 1000 * 24 * 7)
return [start, end]; return [start, end]
}
}, },
}, {
{ text: '最近一个月',
text: "最近一个月", value: () => {
value: () => { const end = new Date()
const end = new Date(); const start = new Date()
const start = new Date(); start.setTime(start.getTime() - 3600 * 1000 * 24 * 30)
start.setTime(start.getTime() - 3600 * 1000 * 24 * 30); return [start, end]
return [start, end]; }
}, },
}, {
{ text: '最近三个月',
text: "最近三个月", value: () => {
value: () => { const end = new Date()
const end = new Date(); const start = new Date()
const start = new Date(); start.setTime(start.getTime() - 3600 * 1000 * 24 * 90)
start.setTime(start.getTime() - 3600 * 1000 * 24 * 90); return [start, end]
return [start, end]; }
}, }
}, ]
];
// 跳转详情页 // 跳转详情页
const toDetail = () => { const toDetail = () => {
router.push( router.push(`/proTable/useProTable/detail/${Math.random().toFixed(3)}?params=detail-page`)
`/proTable/useProTable/detail/${Math.random().toFixed(3)}?params=detail-page` }
);
};
const searchForm = ref({ const searchForm = ref({
intervalType: 0, intervalType: 0,
time: ["2024-08-20", "2024-08-27"], time: ['2024-08-20', '2024-08-27'],
searchBeginTime: "", searchBeginTime: '',
searchEndTime: "", searchEndTime: '',
checkStatus: 0, checkStatus: 0,
checkReportStatus: 0, checkReportStatus: 0,
checkResult: 0, checkResult: 0
}); })
// ProTable 实例 // ProTable 实例
const proTable = ref<ProTableInstance>(); const proTable = ref<ProTableInstance>()
// 如果表格需要初始化请求参数,直接定义传给 ProTable (之后每次请求都会自动带上该参数,此参数更改之后也会一直带上,改变此参数会自动刷新表格数据) // 如果表格需要初始化请求参数,直接定义传给 ProTable (之后每次请求都会自动带上该参数,此参数更改之后也会一直带上,改变此参数会自动刷新表格数据)
const initParam = reactive({ type: 1, pageNum: 1, pageSize: 10 }); const initParam = reactive({ type: 1, pageNum: 1, pageSize: 10 })
// dataCallback 是对于返回的表格数据做处理,如果你后台返回的数据不是 list && total 这些字段,可以在这里进行处理成这些字段 // dataCallback 是对于返回的表格数据做处理,如果你后台返回的数据不是 list && total 这些字段,可以在这里进行处理成这些字段
// 或者直接去 hooks/useTable.ts 文件中把字段改为你后端对应的就行 // 或者直接去 hooks/useTable.ts 文件中把字段改为你后端对应的就行
const tableList = ref([]); const tableList = ref([])
const dataCallback = (data: any) => { const dataCallback = (data: any) => {
return { return {
list: data || data.data || data.list, list: data || data.data || data.list,
total: data.length || data.total, total: data.length || data.total
}; }
}; }
// 如果你想在请求之前对当前请求参数做一些操作可以自定义如下函数params 为当前所有的请求参数(包括分页),最后返回请求列表接口 // 如果你想在请求之前对当前请求参数做一些操作可以自定义如下函数params 为当前所有的请求参数(包括分页),最后返回请求列表接口
// 默认不做操作就直接在 ProTable 组件上绑定 :requestApi="getUserList" // 默认不做操作就直接在 ProTable 组件上绑定 :requestApi="getUserList"
const getTableList = (params: any) => { const getTableList = (params: any) => {
let newParams = JSON.parse(JSON.stringify(params)); let newParams = JSON.parse(JSON.stringify(params))
newParams.createTime && (newParams.startTime = newParams.createTime[0]); newParams.createTime && (newParams.startTime = newParams.createTime[0])
newParams.createTime && (newParams.endTime = newParams.createTime[1]); newParams.createTime && (newParams.endTime = newParams.createTime[1])
delete newParams.createTime; delete newParams.createTime
return getPlanList(newParams); return getPlanList(newParams)
}; }
//查看详情 //查看详情
const detailsRef: any = ref(); const detailsRef: any = ref()
const handleDetails = () => { const handleDetails = () => {
console.log(detailsRef.value, "+++++++++++++++"); console.log(detailsRef.value, '+++++++++++++++')
detailsRef.value.open("查看计划"); detailsRef.value.open('查看计划')
}; }
// 表格配置项 // 表格配置项
const columns = reactive<ColumnProps<User.ResUserList>[]>([ const columns = reactive<ColumnProps<User.ResUserList>[]>([
{ type: "selection", fixed: "left", width: 70 }, { type: 'selection', fixed: 'left', width: 70 },
{ type: "sort", label: "Sort", width: 80 }, { type: 'sort', label: 'Sort', width: 80 },
{ type: "expand", label: "Expand", width: 85 }, { type: 'expand', label: 'Expand', width: 85 },
{ {
prop: "planName", prop: 'planName',
label: "计划名称", label: '计划名称',
width: 120, width: 120
},
{
prop: "checkMode",
label: "检测模式",
width: 120,
render: (scope) => {
return scope.row.checkMode == 0
? "模拟式"
: scope.row.checkMode == 1
? "比对式"
: scope.row.checkMode == 2
? "数字式"
: scope.row.checkMode;
}, },
}, {
{ prop: 'checkMode',
prop: "checkFrom", label: '检测模式',
label: "检测源", width: 120,
width: 120, render: scope => {
render: (scope) => { return scope.row.checkMode == 0
return scope.row.checkFrom == 0 ? '模拟式'
? "标准源-福禄克-6100A" : scope.row.checkMode == 1
: scope.row.checkFrom == 1 ? '比对式'
? "标准源-昂立-PF2" : scope.row.checkMode == 2
: scope.row.checkFrom == 2 ? '数字式'
? "高精度设备-PQS882-1" : scope.row.checkMode
: scope.row.checkFrom; }
}, },
}, {
{ prop: 'checkFrom',
prop: "numberFromName", label: '检测源',
label: "源名称", width: 120,
render: (scope) => { render: scope => {
return scope.row.numberFromName == 0 return scope.row.checkFrom == 0
? "分钟统计数据最大值" ? '标准源-福禄克-6100A'
: scope.row.numberFromName == 1 : scope.row.checkFrom == 1
? "分钟统计数据最小值" ? '标准源-昂立-PF2'
: scope.row.numberFromName == 2 : scope.row.checkFrom == 2
? "分钟统计数据CP95值" ? '高精度设备-PQS882-1'
: scope.row.numberFromName; : scope.row.checkFrom
}
}, },
}, {
{ prop: 'numberFromName',
prop: "checkExe", label: '源名称',
label: "检测脚本", render: scope => {
width: 120, return scope.row.numberFromName == 0
render: (scope) => { ? '分钟统计数据最大值'
return scope.row.checkExe == 0 : scope.row.numberFromName == 1
? "国网入网检测脚本(单影响量-模拟式)" ? '分钟统计数据最小值'
: scope.row.checkExe == 1 : scope.row.numberFromName == 2
? "国网入网检测脚本" ? '分钟统计数据CP95值'
: scope.row.checkExe == 2 : scope.row.numberFromName
? "/" }
: scope.row.checkExe;
}, },
}, {
{ prop: 'checkExe',
prop: "wctx", label: '检测脚本',
label: "误差体系", width: 120,
width: 120, render: scope => {
render: (scope) => { return scope.row.checkExe == 0
return scope.row.wctx == 0 ? '国网入网检测脚本(单影响量-模拟式)'
? "Q/GDW 1650.2- 2016" : scope.row.checkExe == 1
: scope.row.wctx == 1 ? '国网入网检测脚本'
? "Q/GDW 10650.2 - 2021" : scope.row.checkExe == 2
: scope.row.wctx == 2 ? '/'
? "/" : scope.row.checkExe
: scope.row.wctx; }
}, },
}, {
{ prop: 'wctx',
type: "tag", label: '误差体系',
prop: "checkStatus", width: 120,
label: "检测状态", render: scope => {
width: 120, return scope.row.wctx == 0
render: (scope) => { ? 'Q/GDW 1650.2- 2016'
return scope.row.checkStatus == 1 : scope.row.wctx == 1
? "未检" ? 'Q/GDW 10650.2 - 2021'
: scope.row.checkStatus == 2 : scope.row.wctx == 2
? "检测中" ? '/'
: scope.row.checkStatus == 3 : scope.row.wctx
? "检测完成" }
: scope.row.checkStatus;
}, },
}, {
{ type: 'tag',
prop: "checkReport", prop: 'checkStatus',
label: "检测报告", label: '检测状态',
width: 120, width: 120,
render: (scope) => { render: scope => {
return scope.row.checkReport == 1 return scope.row.checkStatus == 1
? "未生成" ? '未检'
: scope.row.checkReport == 2 : scope.row.checkStatus == 2
? "部分生成" ? '检测中'
: scope.row.checkReport == 3 : scope.row.checkStatus == 3
? "全部生成" ? '检测完成'
: scope.row.checkReport; : scope.row.checkStatus
}
}, },
}, {
{ prop: 'checkReport',
prop: "checkResult", label: '检测报告',
label: "检测结果", width: 120,
width: 120, render: scope => {
render: (scope) => { return scope.row.checkReport == 1
return scope.row.checkReport == 1 ? '未生成'
? "/" : scope.row.checkReport == 2
: scope.row.checkReport == 2 ? '部分生成'
? "符合" : scope.row.checkReport == 3
: scope.row.checkReport == 3 ? '全部生成'
? "不符合" : scope.row.checkReport
: scope.row.checkReport; }
}, },
}, {
{ prop: "operation", label: "操作", fixed: "right", width: 250 }, prop: 'checkResult',
]); label: '检测结果',
width: 120,
render: scope => {
return scope.row.checkReport == 1
? '/'
: scope.row.checkReport == 2
? '符合'
: scope.row.checkReport == 3
? '不符合'
: scope.row.checkReport
}
},
{ prop: 'operation', label: '操作', fixed: 'right', width: 250 }
])
//重置查询条件 //重置查询条件
const resetSearchForm = () => { const resetSearchForm = () => {
searchForm.value = { searchForm.value = {
intervalType: 0, intervalType: 0,
time: ["2024-08-20", "2024-08-27"], time: ['2024-08-20', '2024-08-27'],
searchBeginTime: "", searchBeginTime: '',
searchEndTime: "", searchEndTime: '',
checkStatus: 0, checkStatus: 0,
checkReportStatus: 0, checkReportStatus: 0,
checkResult: 0, checkResult: 0
}; }
}; }
//查询 //查询
const handleSearch = () => { const handleSearch = () => {
proTable.value?.getTableList(); proTable.value?.getTableList()
}; }
//重置 //重置
const handleRefresh = () => { const handleRefresh = () => {
proTable.value?.getTableList(); proTable.value?.getTableList()
}; }
// 表格拖拽排序 // 表格拖拽排序
const sortTable = ({ const sortTable = ({ newIndex, oldIndex }: { newIndex?: number; oldIndex?: number }) => {
newIndex, // console.log(newIndex, oldIndex);
oldIndex, //console.log(proTable.value?.tableData);
}: { ElMessage.success('修改列表排序成功')
newIndex?: number; }
oldIndex?: number;
}) => {
// console.log(newIndex, oldIndex);
//console.log(proTable.value?.tableData);
ElMessage.success("修改列表排序成功");
};
// 删除用户信息 // 删除用户信息
const deleteAccount = async (params: User.ResUserList) => { const deleteAccount = async (params: User.ResUserList) => {
await useHandleData( await useHandleData(deleteUser, { id: [params.id] }, `删除【${params.username}`)
deleteUser, proTable.value?.getTableList()
{ id: [params.id] }, }
`删除【${params.username}`
);
proTable.value?.getTableList();
};
// 批量删除用户信息 // 批量删除用户信息
const batchDelete = async (id: string[]) => { const batchDelete = async (id: string[]) => {
await useHandleData(deleteUser, { id }, "删除所选用户信息"); await useHandleData(deleteUser, { id }, '删除所选用户信息')
proTable.value?.clearSelection(); proTable.value?.clearSelection()
proTable.value?.getTableList(); proTable.value?.getTableList()
}; }
// 重置用户密码 // 重置用户密码
const resetPass = async (params: User.ResUserList) => { const resetPass = async (params: User.ResUserList) => {
await useHandleData( await useHandleData(resetUserPassWord, { id: params.id }, `重置【${params.username}】用户密码`)
resetUserPassWord, proTable.value?.getTableList()
{ id: params.id }, }
`重置【${params.username}】用户密码`
);
proTable.value?.getTableList();
};
// 切换用户状态 // 切换用户状态
const changeStatus = async (row: User.ResUserList) => { const changeStatus = async (row: User.ResUserList) => {
await useHandleData( await useHandleData(
changeUserStatus, changeUserStatus,
{ id: row.id, status: row.status == 1 ? 0 : 1 }, { id: row.id, status: row.status == 1 ? 0 : 1 },
`切换【${row.username}】用户状态` `切换【${row.username}】用户状态`
); )
proTable.value?.getTableList(); proTable.value?.getTableList()
}; }
onMounted(() => { onMounted(() => {
console.log(proTable.value?.tableData); console.log(proTable.value?.tableData)
}); })
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.planList { .planList {
width: 100%; width: 100%;
// height: calc(100vh - 165px); // height: calc(100vh - 165px);
height: 100%; height: 100%;
} }
::v-deep .el-select { :deep(.el-select) {
width: 150px !important; width: 150px !important;
} }
.el-form { .el-form {
width: 100%; width: 100%;
display: flex;
flex-wrap: wrap;
.el-form-item {
display: flex; display: flex;
align-items: center; flex-wrap: wrap;
justify-content: space-between; .el-form-item {
.el-button { display: flex;
margin: 0 !important; align-items: center;
margin-right: 10px !important; justify-content: space-between;
.el-button {
margin: 0 !important;
margin-right: 10px !important;
}
} }
}
} }
</style> </style>