新疆大罗素
1.设备保养、设备维修、设备巡检新增时可以多选设备
2.设备台账添加区域维护字段
3.添加环境页面实时展示设备数据
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import request from "@/utils/request"; |
| | | |
| | | export function getDeviceAreaTree(params) { |
| | | return request({ |
| | | url: "/device/area/tree", |
| | | method: "get", |
| | | params, |
| | | }); |
| | | } |
| | | |
| | | export function getDeviceAreaTreeWithDevices(params) { |
| | | return request({ |
| | | url: "/device/area/treeWithDevices", |
| | | method: "get", |
| | | }); |
| | | } |
| | | |
| | | export function getDeviceAreaPage(params) { |
| | | return request({ |
| | | url: "/device/area/page", |
| | | method: "get", |
| | | params, |
| | | }); |
| | | } |
| | | |
| | | export function getDeviceAreaDetail(id) { |
| | | return request({ |
| | | url: `/device/area/${id}`, |
| | | method: "get", |
| | | }); |
| | | } |
| | | |
| | | export function addDeviceArea(data) { |
| | | return request({ |
| | | url: "/device/area", |
| | | method: "post", |
| | | data, |
| | | }); |
| | | } |
| | | |
| | | export function updateDeviceArea(data) { |
| | | return request({ |
| | | url: "/device/area", |
| | | method: "put", |
| | | data, |
| | | }); |
| | | } |
| | | |
| | | export function deleteDeviceArea(ids) { |
| | | return request({ |
| | | url: "/device/area", |
| | | method: "delete", |
| | | data: ids, |
| | | }); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import request from "@/utils/request"; |
| | | |
| | | export const getEnvironmentalRealData = () => { |
| | | return request({ |
| | | url: "/iot/getRealData", |
| | | method: "get", |
| | | }); |
| | | }; |
| | |
| | | <template>
|
| | | <div :class="classObj" class="app-wrapper" :style="{ '--current-color': theme }">
|
| | | <div v-if="device === 'mobile' && sidebar.opened" class="drawer-bg" @click="handleClickOutside"/>
|
| | | <sidebar v-if="!sidebar.hide" class="sidebar-container" />
|
| | | <div :class="{ hasTagsView: needTagsView, sidebarHide: sidebar.hide }" class="main-container">
|
| | | <div :class="classObj"
|
| | | class="app-wrapper"
|
| | | :style="{ '--current-color': theme }">
|
| | | <div v-if="device === 'mobile' && sidebar.opened"
|
| | | class="drawer-bg"
|
| | | @click="handleClickOutside" />
|
| | | <sidebar v-if="!sidebar.hide"
|
| | | class="sidebar-container" />
|
| | | <div :class="{ hasTagsView: needTagsView, sidebarHide: sidebar.hide }"
|
| | | class="main-container">
|
| | | <div :class="{ 'fixed-header': fixedHeader }">
|
| | | <navbar @setLayout="setLayout" />
|
| | | <tags-view v-if="needTagsView" />
|
| | |
| | | </template>
|
| | |
|
| | | <script setup>
|
| | | import { useWindowSize } from '@vueuse/core'
|
| | | import Sidebar from './components/Sidebar/index.vue'
|
| | | import { AppMain, Navbar, Settings, TagsView } from './components'
|
| | | import defaultSettings from '@/settings'
|
| | | import { useWindowSize } from "@vueuse/core";
|
| | | import Sidebar from "./components/Sidebar/index.vue";
|
| | | import { AppMain, Navbar, Settings, TagsView } from "./components";
|
| | | import defaultSettings from "@/settings";
|
| | |
|
| | | import useAppStore from '@/store/modules/app'
|
| | | import useSettingsStore from '@/store/modules/settings'
|
| | | import useAppStore from "@/store/modules/app";
|
| | | import useSettingsStore from "@/store/modules/settings";
|
| | |
|
| | | const settingsStore = useSettingsStore()
|
| | | const theme = computed(() => settingsStore.theme)
|
| | | const sideTheme = computed(() => settingsStore.sideTheme)
|
| | | const sidebar = computed(() => useAppStore().sidebar)
|
| | | const device = computed(() => useAppStore().device)
|
| | | const needTagsView = computed(() => settingsStore.tagsView)
|
| | | const fixedHeader = computed(() => settingsStore.fixedHeader)
|
| | | const settingsStore = useSettingsStore();
|
| | | const theme = computed(() => settingsStore.theme);
|
| | | const sideTheme = computed(() => settingsStore.sideTheme);
|
| | | const sidebar = computed(() => useAppStore().sidebar);
|
| | | const device = computed(() => useAppStore().device);
|
| | | const needTagsView = computed(() => settingsStore.tagsView);
|
| | | const fixedHeader = computed(() => settingsStore.fixedHeader);
|
| | |
|
| | | const classObj = computed(() => ({
|
| | | hideSidebar: !sidebar.value.opened,
|
| | | openSidebar: sidebar.value.opened,
|
| | | withoutAnimation: sidebar.value.withoutAnimation,
|
| | | mobile: device.value === 'mobile'
|
| | | }))
|
| | | const classObj = computed(() => ({
|
| | | hideSidebar: !sidebar.value.opened,
|
| | | openSidebar: sidebar.value.opened,
|
| | | withoutAnimation: sidebar.value.withoutAnimation,
|
| | | mobile: device.value === "mobile",
|
| | | }));
|
| | |
|
| | | const { width, height } = useWindowSize()
|
| | | const WIDTH = 992 // refer to Bootstrap's responsive design
|
| | | const { width, height } = useWindowSize();
|
| | | const WIDTH = 992; // refer to Bootstrap's responsive design
|
| | |
|
| | | watch(() => device.value, () => {
|
| | | if (device.value === 'mobile' && sidebar.value.opened) {
|
| | | useAppStore().closeSideBar({ withoutAnimation: false })
|
| | | watch(
|
| | | () => device.value,
|
| | | () => {
|
| | | if (device.value === "mobile" && sidebar.value.opened) {
|
| | | useAppStore().closeSideBar({ withoutAnimation: false });
|
| | | }
|
| | | }
|
| | | );
|
| | |
|
| | | watchEffect(() => {
|
| | | if (width.value - 1 < WIDTH) {
|
| | | useAppStore().toggleDevice("mobile");
|
| | | useAppStore().closeSideBar({ withoutAnimation: true });
|
| | | } else {
|
| | | useAppStore().toggleDevice("desktop");
|
| | | }
|
| | | });
|
| | |
|
| | | function handleClickOutside() {
|
| | | useAppStore().closeSideBar({ withoutAnimation: false });
|
| | | }
|
| | | })
|
| | |
|
| | | watchEffect(() => {
|
| | | if (width.value - 1 < WIDTH) {
|
| | | useAppStore().toggleDevice('mobile')
|
| | | useAppStore().closeSideBar({ withoutAnimation: true })
|
| | | } else {
|
| | | useAppStore().toggleDevice('desktop')
|
| | | const settingRef = ref(null);
|
| | | function setLayout() {
|
| | | settingRef.value.openSetting();
|
| | | }
|
| | | })
|
| | |
|
| | | function handleClickOutside() {
|
| | | useAppStore().closeSideBar({ withoutAnimation: false })
|
| | | }
|
| | |
|
| | | const settingRef = ref(null)
|
| | | function setLayout() {
|
| | | settingRef.value.openSetting()
|
| | | }
|
| | | </script>
|
| | |
|
| | | <style lang="scss" scoped>
|
| | | @import "@/assets/styles/mixin.scss";
|
| | | @import "@/assets/styles/variables.module.scss";
|
| | |
|
| | | .app-wrapper {
|
| | | @include clearfix;
|
| | | position: relative;
|
| | | height: 100%;
|
| | | width: 100%;
|
| | | background:
|
| | | radial-gradient(circle at top, rgba(223, 232, 226, 0.95), transparent 32%),
|
| | | linear-gradient(180deg, #f7faf8 0%, var(--app-bg) 100%);
|
| | | .app-wrapper {
|
| | | @include clearfix;
|
| | | position: relative;
|
| | | height: 100%;
|
| | | width: 100%;
|
| | | background: radial-gradient(
|
| | | circle at top,
|
| | | rgba(223, 232, 226, 0.95),
|
| | | transparent 32%
|
| | | ),
|
| | | linear-gradient(180deg, #f7faf8 0%, var(--app-bg) 100%);
|
| | |
|
| | | &.mobile.openSidebar {
|
| | | position: fixed;
|
| | | top: 0;
|
| | | &.mobile.openSidebar {
|
| | | position: fixed;
|
| | | top: 0;
|
| | | }
|
| | | }
|
| | | }
|
| | |
|
| | | .drawer-bg {
|
| | | background: #000;
|
| | | opacity: 0.3;
|
| | | width: 100%;
|
| | | top: 0;
|
| | | height: 100%;
|
| | | position: absolute;
|
| | | z-index: 999;
|
| | | }
|
| | | .drawer-bg {
|
| | | background: #000;
|
| | | opacity: 0.3;
|
| | | width: 100%;
|
| | | top: 0;
|
| | | height: 100%;
|
| | | position: absolute;
|
| | | z-index: 999;
|
| | | }
|
| | |
|
| | | .fixed-header {
|
| | | position: fixed;
|
| | | top: 12px;
|
| | | right: 16px;
|
| | | z-index: 9;
|
| | | width: calc(100% - #{$base-sidebar-width} - 32px);
|
| | | transition: width 0.28s, right 0.28s;
|
| | | padding-bottom: 8px;
|
| | | }
|
| | | .fixed-header {
|
| | | position: fixed;
|
| | | top: 0px;
|
| | | padding-top: 12px;
|
| | | right: 16px;
|
| | | z-index: 9;
|
| | | width: calc(100% - #{$base-sidebar-width} - 32px);
|
| | | transition: width 0.28s, right 0.28s;
|
| | | padding-bottom: 8px;
|
| | | background-color: #f3f6f4;
|
| | | }
|
| | | .hideSidebar .fixed-header {
|
| | | width: calc(100% - 100px);
|
| | | }
|
| | |
|
| | | .hideSidebar .fixed-header { |
| | | width: calc(100% - 100px); |
| | | } |
| | | .sidebarHide .fixed-header {
|
| | | width: calc(100% - 32px);
|
| | | }
|
| | |
|
| | | .sidebarHide .fixed-header {
|
| | | width: calc(100% - 32px);
|
| | | }
|
| | |
|
| | | .mobile .fixed-header {
|
| | | width: 100%;
|
| | | }
|
| | | .mobile .fixed-header {
|
| | | width: 100%;
|
| | | }
|
| | | </style>
|
| | |
| | | <template> |
| | | <div> |
| | | <el-dialog :title="operationType === 'add' ? 'æ°å¢å·¡æ£ä»»å¡' : 'ç¼è¾å·¡æ£ä»»å¡'" |
| | | v-model="dialogVisitable" width="800px" @close="cancel"> |
| | | <el-dialog |
| | | v-model="dialogVisitable" |
| | | :title="operationType === 'add' ? 'æ°å¢å·¡æ£ä»»å¡' : 'ç¼è¾å·¡æ£ä»»å¡'" |
| | | width="800px" |
| | | @close="cancel" |
| | | > |
| | | <el-form ref="formRef" :model="form" :rules="rules" label-width="120px"> |
| | | <el-row> |
| | | <el-col :span="12"> |
| | | <el-form-item label="设å¤åç§°" prop="taskId"> |
| | | <el-select v-model="form.taskId" @change="setDeviceModel"> |
| | | <el-form-item label="æå±åºå" prop="areaId"> |
| | | <el-tree-select |
| | | v-model="form.areaId" |
| | | :data="areaOptions" |
| | | :props="areaTreeProps" |
| | | node-key="id" |
| | | value-key="id" |
| | | check-strictly |
| | | clearable |
| | | filterable |
| | | placeholder="è¯·éæ©æå±åºå" |
| | | style="width: 100%" |
| | | @change="handleAreaChange" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="设å¤åç§°" prop="deviceLedgerIds"> |
| | | <el-select |
| | | v-model="form.deviceLedgerIds" |
| | | multiple |
| | | collapse-tags |
| | | collapse-tags-tooltip |
| | | clearable |
| | | filterable |
| | | placeholder="è¯·éæ©è®¾å¤" |
| | | style="width: 100%" |
| | | @change="setDeviceModels" |
| | | > |
| | | <el-option |
| | | v-for="(item, index) in deviceOptions" |
| | | :key="index" |
| | | v-for="item in deviceOptions" |
| | | :key="item.id" |
| | | :label="item.deviceName" |
| | | :value="item.id" |
| | | ></el-option> |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row> |
| | | <el-col :span="12"> |
| | | <el-form-item label="å·¡æ£äºº" prop="inspector"> |
| | | <el-select v-model="form.inspector" placeholder="è¯·éæ©" multiple clearable> |
| | | <el-option |
| | | v-for="item in userList" |
| | | :key="item.userId" |
| | | :label="item.nickName" |
| | | :value="item.userId" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="å·¡æ£äºº" prop="inspector"> |
| | | <el-select v-model="form.inspector" placeholder="è¯·éæ©" multiple clearable> |
| | | <el-option v-for="item in userList" :label="item.nickName" :value="item.userId" :key="item.userId"/> |
| | | </el-select> |
| | | <el-form-item label="è§æ ¼åå·"> |
| | | <el-input |
| | | v-model="form.deviceModel" |
| | | placeholder="èªå¨å¸¦åºè§æ ¼åå·" |
| | | disabled |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | |
| | | <el-col :span="12"> |
| | | <el-form-item label="ä»»å¡é¢ç" prop="frequencyType"> |
| | | <el-select v-model="form.frequencyType" placeholder="è¯·éæ©" clearable> |
| | | <el-option label="æ¯æ¥" value="DAILY"/> |
| | | <el-option label="æ¯å¨" value="WEEKLY"/> |
| | | <el-option label="æ¯æ" value="MONTHLY"/> |
| | | <!-- <el-option label="å£åº¦" value="QUARTERLY"/> --> |
| | | <el-option label="æ¯æ¥" value="DAILY" /> |
| | | <el-option label="æ¯å¨" value="WEEKLY" /> |
| | | <el-option label="æ¯æ" value="MONTHLY" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12" v-if="form.frequencyType === 'DAILY' && form.frequencyType"> |
| | | <el-col :span="12" v-if="form.frequencyType === 'DAILY'"> |
| | | <el-form-item label="æ¥æ" prop="frequencyDetail"> |
| | | <el-time-picker v-model="form.frequencyDetail" placeholder="éæ©æ¶é´" format="HH:mm" |
| | | value-format="HH:mm" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12" v-if="form.frequencyType === 'WEEKLY' && form.frequencyType"> |
| | | <el-form-item label="æ¥æ" prop="frequencyDetail"> |
| | | <el-select v-model="form.week" placeholder="è¯·éæ©" clearable style="width: 50%"> |
| | | <el-option label="å¨ä¸" value="MON"/> |
| | | <el-option label="å¨äº" value="TUE"/> |
| | | <el-option label="å¨ä¸" value="WED"/> |
| | | <el-option label="å¨å" value="THU"/> |
| | | <el-option label="å¨äº" value="FRI"/> |
| | | <el-option label="å¨å
" value="SAT"/> |
| | | <el-option label="卿¥" value="SUN"/> |
| | | </el-select> |
| | | <el-time-picker v-model="form.time" placeholder="éæ©æ¶é´" format="HH:mm" |
| | | value-format="HH:mm" style="width: 50%"/> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12" v-if="form.frequencyType === 'MONTHLY' && form.frequencyType"> |
| | | <el-form-item label="æ¥æ" prop="frequencyDetail"> |
| | | <el-date-picker |
| | | v-model="form.frequencyDetail" |
| | | type="datetime" |
| | | clearable |
| | | placeholder="éæ©å¼å§æ¥æ" |
| | | format="DD,HH:mm" |
| | | value-format="DD,HH:mm" |
| | | <el-time-picker |
| | | v-model="form.frequencyDetail" |
| | | placeholder="éæ©æ¶é´" |
| | | format="HH:mm" |
| | | value-format="HH:mm" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12" v-if="form.frequencyType === 'QUARTERLY' && form.frequencyType"> |
| | | <el-col :span="12" v-if="form.frequencyType === 'WEEKLY'"> |
| | | <el-form-item label="æ¥æ" prop="frequencyDetail"> |
| | | <el-select v-model="form.week" placeholder="è¯·éæ©" clearable style="width: 50%"> |
| | | <el-option label="å¨ä¸" value="MON" /> |
| | | <el-option label="å¨äº" value="TUE" /> |
| | | <el-option label="å¨ä¸" value="WED" /> |
| | | <el-option label="å¨å" value="THU" /> |
| | | <el-option label="å¨äº" value="FRI" /> |
| | | <el-option label="å¨å
" value="SAT" /> |
| | | <el-option label="卿¥" value="SUN" /> |
| | | </el-select> |
| | | <el-time-picker |
| | | v-model="form.time" |
| | | placeholder="éæ©æ¶é´" |
| | | format="HH:mm" |
| | | value-format="HH:mm" |
| | | style="width: 50%" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12" v-if="form.frequencyType === 'MONTHLY'"> |
| | | <el-form-item label="æ¥æ" prop="frequencyDetail"> |
| | | <el-date-picker |
| | | v-model="form.frequencyDetail" |
| | | type="datetime" |
| | | clearable |
| | | placeholder="éæ©å¼å§æ¥æ" |
| | | format="MM,DD,HH:mm" |
| | | value-format="MM,DD,HH:mm" |
| | | v-model="form.frequencyDetail" |
| | | type="datetime" |
| | | clearable |
| | | placeholder="éæ©å¼å§æ¥æ" |
| | | format="DD,HH:mm" |
| | | value-format="DD,HH:mm" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | |
| | | </template> |
| | | |
| | | <script setup> |
| | | import {reactive, ref, getCurrentInstance, toRefs} from "vue"; |
| | | import useUserStore from '@/store/modules/user' |
| | | import {addOrEditTimingTask} from "@/api/inspectionManagement/index.js"; |
| | | import {userListNoPageByTenantId} from "@/api/system/user.js"; |
| | | import { getDeviceLedger } from "@/api/equipmentManagement/ledger"; |
| | | import { getCurrentInstance, reactive, ref, toRefs } from "vue"; |
| | | import useUserStore from "@/store/modules/user"; |
| | | import { addOrEditTimingTask } from "@/api/inspectionManagement/index.js"; |
| | | import { userListNoPageByTenantId } from "@/api/system/user.js"; |
| | | import { |
| | | getDeviceAreaTree, |
| | | getDeviceAreaTreeWithDevices, |
| | | } from "@/api/equipmentManagement/deviceArea"; |
| | | |
| | | const { proxy } = getCurrentInstance() |
| | | const emit = defineEmits() |
| | | const userStore = useUserStore() |
| | | const { proxy } = getCurrentInstance(); |
| | | const emit = defineEmits(["closeDia"]); |
| | | const userStore = useUserStore(); |
| | | const dialogVisitable = ref(false); |
| | | const operationType = ref('add'); |
| | | const operationType = ref("add"); |
| | | const areaOptions = ref([]); |
| | | const deviceOptions = ref([]); |
| | | const data = reactive({ |
| | | form: { |
| | | taskId: undefined, |
| | | taskName: undefined, |
| | | inspector: '', |
| | | inspectorIds: '', |
| | | remarks: '', |
| | | frequencyType: '', |
| | | frequencyDetail: '', |
| | | week: '', |
| | | time: '' |
| | | }, |
| | | rules: { |
| | | taskId: [{ required: true, message: "è¯·éæ©è®¾å¤", trigger: "change" },], |
| | | inspector: [{ required: true, message: "请è¾å
¥å·¡æ£äºº", trigger: "blur" },], |
| | | dateStr: [{ required: true, message: "è¯·éæ©ç»è®°æ¶é´", trigger: "change" }], |
| | | frequencyType: [{ required: true, message: "è¯·éæ©ä»»å¡é¢ç", trigger: "change" }], |
| | | frequencyDetail: [ |
| | | { |
| | | required: true, |
| | | message: "è¯·éæ©æ¥æ", |
| | | trigger: "change", |
| | | validator: (rule, value, callback) => { |
| | | if (!form.value.frequencyType) { |
| | | callback() |
| | | return |
| | | } |
| | | if (form.value.frequencyType === 'WEEKLY') { |
| | | if (!form.value.week || !form.value.time) { |
| | | callback(new Error("è¯·éæ©æ¥æåæ¶é´")) |
| | | } else { |
| | | callback() |
| | | } |
| | | } else { |
| | | if (!value) { |
| | | callback(new Error("è¯·éæ©æ¥æ")) |
| | | } else { |
| | | callback() |
| | | } |
| | | } |
| | | } |
| | | } |
| | | ], |
| | | week: [ |
| | | { |
| | | required: true, |
| | | message: "è¯·éæ©ææ", |
| | | trigger: "change", |
| | | validator: (rule, value, callback) => { |
| | | if (form.value.frequencyType === 'WEEKLY' && !value) { |
| | | callback(new Error("è¯·éæ©ææ")) |
| | | } else { |
| | | callback() |
| | | } |
| | | } |
| | | } |
| | | ], |
| | | time: [ |
| | | { |
| | | required: true, |
| | | message: "è¯·éæ©æ¶é´", |
| | | trigger: "change", |
| | | validator: (rule, value, callback) => { |
| | | if (form.value.frequencyType === 'WEEKLY' && !value) { |
| | | callback(new Error("è¯·éæ©æ¶é´")) |
| | | } else { |
| | | callback() |
| | | } |
| | | } |
| | | } |
| | | ] |
| | | } |
| | | }) |
| | | const { form, rules } = toRefs(data) |
| | | const userList = ref([]) |
| | | |
| | | const loadDeviceName = async () => { |
| | | const { data } = await getDeviceLedger(); |
| | | deviceOptions.value = data; |
| | | const userList = ref([]); |
| | | const areaTreeProps = { |
| | | label: "areaName", |
| | | children: "children", |
| | | }; |
| | | |
| | | const setDeviceModel = (id) => { |
| | | const option = deviceOptions.value.find((item) => item.id === id); |
| | | if (option) { |
| | | form.value.taskName = option.deviceName; |
| | | } |
| | | } |
| | | const data = reactive({ |
| | | form: { |
| | | areaId: undefined, |
| | | taskId: undefined, |
| | | taskIds: [], |
| | | taskIdsStr: undefined, |
| | | deviceLedgerIds: [], |
| | | deviceLedgerIdsStr: undefined, |
| | | taskName: undefined, |
| | | deviceModel: undefined, |
| | | inspector: [], |
| | | inspectorIds: "", |
| | | remarks: "", |
| | | frequencyType: "", |
| | | frequencyDetail: "", |
| | | week: "", |
| | | time: "", |
| | | }, |
| | | rules: { |
| | | areaId: [{ required: true, message: "è¯·éæ©æå±åºå", trigger: "change" }], |
| | | deviceLedgerIds: [{ required: true, message: "è¯·éæ©è®¾å¤", trigger: "change" }], |
| | | inspector: [{ required: true, message: "è¯·éæ©å·¡æ£äºº", trigger: "change" }], |
| | | frequencyType: [{ required: true, message: "è¯·éæ©ä»»å¡é¢ç", trigger: "change" }], |
| | | frequencyDetail: [ |
| | | { |
| | | required: true, |
| | | trigger: "change", |
| | | validator: (rule, value, callback) => { |
| | | if (!form.value.frequencyType) { |
| | | callback(); |
| | | return; |
| | | } |
| | | if (form.value.frequencyType === "WEEKLY") { |
| | | if (!form.value.week || !form.value.time) { |
| | | callback(new Error("è¯·éæ©æ¥æåæ¶é´")); |
| | | } else { |
| | | callback(); |
| | | } |
| | | return; |
| | | } |
| | | if (!value) { |
| | | callback(new Error("è¯·éæ©æ¥æ")); |
| | | return; |
| | | } |
| | | callback(); |
| | | }, |
| | | }, |
| | | ], |
| | | }, |
| | | }); |
| | | |
| | | // æå¼å¼¹æ¡ |
| | | const { form, rules } = toRefs(data); |
| | | |
| | | const loadAreaTree = async () => { |
| | | const { data } = await getDeviceAreaTree(); |
| | | areaOptions.value = Array.isArray(data) ? data : []; |
| | | }; |
| | | |
| | | const normalizeIdList = (value) => { |
| | | if (Array.isArray(value)) { |
| | | return value |
| | | .map((item) => Number(item)) |
| | | .filter((item) => Number.isFinite(item)); |
| | | } |
| | | if (typeof value === "string") { |
| | | return value |
| | | .split(",") |
| | | .map((item) => Number(item.trim())) |
| | | .filter((item) => Number.isFinite(item)); |
| | | } |
| | | if (value !== undefined && value !== null && value !== "") { |
| | | const numericValue = Number(value); |
| | | return Number.isFinite(numericValue) ? [numericValue] : []; |
| | | } |
| | | return []; |
| | | }; |
| | | |
| | | const getNodeDevices = (node) => { |
| | | const candidates = [ |
| | | node?.deviceList, |
| | | node?.devices, |
| | | node?.deviceLedgerList, |
| | | node?.deviceLedgers, |
| | | node?.ledgerList, |
| | | node?.ledgers, |
| | | ]; |
| | | return candidates.find((item) => Array.isArray(item)) || []; |
| | | }; |
| | | |
| | | const normalizeDevice = (item) => ({ |
| | | ...item, |
| | | id: item.id ?? item.deviceLedgerId, |
| | | deviceName: item.deviceName ?? item.name, |
| | | deviceModel: item.deviceModel ?? item.model, |
| | | }); |
| | | |
| | | const collectDevices = (node) => { |
| | | const currentDevices = getNodeDevices(node).map(normalizeDevice); |
| | | const childDevices = (node?.children || []).flatMap((child) => |
| | | collectDevices(child) |
| | | ); |
| | | const deviceMap = new Map(); |
| | | [...currentDevices, ...childDevices].forEach((item) => { |
| | | if (item?.id !== undefined && item?.id !== null) { |
| | | deviceMap.set(Number(item.id), item); |
| | | } |
| | | }); |
| | | return Array.from(deviceMap.values()); |
| | | }; |
| | | |
| | | const findAreaNode = (nodes, areaId) => { |
| | | for (const node of nodes || []) { |
| | | if (Number(node.id) === Number(areaId)) { |
| | | return node; |
| | | } |
| | | const target = findAreaNode(node.children, areaId); |
| | | if (target) { |
| | | return target; |
| | | } |
| | | } |
| | | return null; |
| | | }; |
| | | |
| | | const loadDevicesByArea = async (areaId) => { |
| | | if (!areaId) { |
| | | deviceOptions.value = []; |
| | | return; |
| | | } |
| | | const { data } = await getDeviceAreaTreeWithDevices(); |
| | | const treeData = Array.isArray(data) ? data : []; |
| | | const currentNode = findAreaNode(treeData, areaId); |
| | | deviceOptions.value = currentNode ? collectDevices(currentNode) : []; |
| | | }; |
| | | |
| | | const syncDeviceFields = (deviceIds) => { |
| | | const selectedIds = normalizeIdList(deviceIds); |
| | | const selectedDevices = selectedIds |
| | | .map((deviceId) => |
| | | deviceOptions.value.find((item) => Number(item.id) === Number(deviceId)) |
| | | ) |
| | | .filter(Boolean); |
| | | |
| | | form.value.deviceLedgerIds = selectedIds; |
| | | form.value.deviceLedgerIdsStr = selectedIds.join(","); |
| | | form.value.taskIds = [...selectedIds]; |
| | | form.value.taskIdsStr = selectedIds.join(","); |
| | | form.value.taskId = selectedIds[0]; |
| | | form.value.taskName = selectedDevices |
| | | .map((item) => item.deviceName) |
| | | .filter(Boolean) |
| | | .join(","); |
| | | form.value.deviceModel = selectedDevices |
| | | .map((item) => item.deviceModel || "-") |
| | | .join(","); |
| | | }; |
| | | |
| | | const setDeviceModels = (deviceIds) => { |
| | | syncDeviceFields(deviceIds); |
| | | }; |
| | | |
| | | const handleAreaChange = async (areaId) => { |
| | | form.value.taskId = undefined; |
| | | form.value.taskIds = []; |
| | | form.value.taskIdsStr = undefined; |
| | | form.value.deviceLedgerIds = []; |
| | | form.value.deviceLedgerIdsStr = undefined; |
| | | form.value.taskName = undefined; |
| | | form.value.deviceModel = undefined; |
| | | await loadDevicesByArea(areaId); |
| | | }; |
| | | |
| | | const resetForm = () => { |
| | | if (proxy.$refs.formRef) { |
| | | proxy.$refs.formRef.resetFields(); |
| | | } |
| | | form.value = { |
| | | areaId: undefined, |
| | | taskId: undefined, |
| | | taskIds: [], |
| | | taskIdsStr: undefined, |
| | | deviceLedgerIds: [], |
| | | deviceLedgerIdsStr: undefined, |
| | | taskName: undefined, |
| | | deviceModel: undefined, |
| | | inspector: [], |
| | | inspectorIds: "", |
| | | remarks: "", |
| | | frequencyType: "", |
| | | frequencyDetail: "", |
| | | week: "", |
| | | time: "", |
| | | }; |
| | | }; |
| | | |
| | | const openDialog = async (type, row) => { |
| | | dialogVisitable.value = true |
| | | operationType.value = type |
| | | |
| | | // é置表å |
| | | dialogVisitable.value = true; |
| | | operationType.value = type; |
| | | resetForm(); |
| | | |
| | | // å è½½ç¨æ·å表 |
| | | |
| | | userListNoPageByTenantId().then((res) => { |
| | | userList.value = res.data; |
| | | }); |
| | | |
| | | // å 载设å¤å表 |
| | | await loadDeviceName(); |
| | | |
| | | if (type === 'edit' && row) { |
| | | form.value = {...row} |
| | | form.value.inspector = form.value.inspectorIds.split(',').map(Number) |
| | | |
| | | // 妿æè®¾å¤IDï¼èªå¨è®¾ç½®è®¾å¤ä¿¡æ¯ |
| | | if (form.value.taskId) { |
| | | setDeviceModel(form.value.taskId); |
| | | |
| | | await loadAreaTree(); |
| | | |
| | | if (type === "edit" && row) { |
| | | form.value = { |
| | | ...form.value, |
| | | ...row, |
| | | inspector: row.inspectorIds |
| | | ? String(row.inspectorIds) |
| | | .split(",") |
| | | .map((item) => Number(item)) |
| | | .filter((item) => Number.isFinite(item)) |
| | | : [], |
| | | }; |
| | | |
| | | form.value.deviceLedgerIds = normalizeIdList( |
| | | row.deviceLedgerIds ?? |
| | | row.deviceLedgerIdsStr ?? |
| | | row.taskIds ?? |
| | | row.taskIdsStr ?? |
| | | row.taskId |
| | | ); |
| | | form.value.deviceLedgerIdsStr = form.value.deviceLedgerIds.join(","); |
| | | form.value.taskIds = [...form.value.deviceLedgerIds]; |
| | | form.value.taskIdsStr = form.value.deviceLedgerIds.join(","); |
| | | form.value.taskId = form.value.deviceLedgerIds[0]; |
| | | |
| | | if (form.value.areaId) { |
| | | await loadDevicesByArea(form.value.areaId); |
| | | syncDeviceFields(form.value.deviceLedgerIds); |
| | | } |
| | | } |
| | | } |
| | | }; |
| | | |
| | | // å
³éå¯¹è¯æ¡ |
| | | const cancel = () => { |
| | | resetForm() |
| | | dialogVisitable.value = false |
| | | emit('closeDia') |
| | | } |
| | | resetForm(); |
| | | dialogVisitable.value = false; |
| | | emit("closeDia"); |
| | | }; |
| | | |
| | | // é置表å彿° |
| | | const resetForm = () => { |
| | | if (proxy.$refs.formRef) { |
| | | proxy.$refs.formRef.resetFields() |
| | | } |
| | | // éç½®è¡¨åæ°æ®ç¡®ä¿è®¾å¤ä¿¡æ¯æ£ç¡®éç½® |
| | | form.value = { |
| | | taskId: undefined, |
| | | taskName: undefined, |
| | | inspector: '', |
| | | inspectorIds: '', |
| | | remarks: '', |
| | | frequencyType: '', |
| | | frequencyDetail: '', |
| | | week: '', |
| | | time: '' |
| | | } |
| | | } |
| | | |
| | | // æäº¤è¡¨å |
| | | const submitForm = () => { |
| | | proxy.$refs["formRef"].validate(async valid => { |
| | | if (valid) { |
| | | try { |
| | | form.value.inspectorIds = form.value.inspector.join(',') |
| | | delete form.value.inspector |
| | | |
| | | if (form.value.frequencyType === 'WEEKLY') { |
| | | let frequencyDetail = '' |
| | | frequencyDetail = form.value.week + ',' + form.value.time |
| | | form.value.frequencyDetail = frequencyDetail |
| | | } |
| | | |
| | | let res = await userStore.getInfo() |
| | | form.value.registrantId = res.user.userId |
| | | |
| | | await addOrEditTimingTask(form.value) |
| | | cancel() |
| | | proxy.$modal.msgSuccess('æäº¤æå') |
| | | } catch (error) { |
| | | proxy.$modal.msgError('æäº¤å¤±è´¥ï¼è¯·éè¯') |
| | | } |
| | | proxy.$refs.formRef.validate(async (valid) => { |
| | | if (!valid) { |
| | | return; |
| | | } |
| | | }) |
| | | } |
| | | defineExpose({ openDialog }) |
| | | try { |
| | | syncDeviceFields(form.value.deviceLedgerIds); |
| | | const payload = { ...form.value }; |
| | | |
| | | payload.inspectorIds = Array.isArray(form.value.inspector) |
| | | ? form.value.inspector.join(",") |
| | | : ""; |
| | | delete payload.inspector; |
| | | |
| | | if (payload.frequencyType === "WEEKLY") { |
| | | payload.frequencyDetail = `${payload.week},${payload.time}`; |
| | | } |
| | | |
| | | const userInfo = await userStore.getInfo(); |
| | | payload.registrantId = userInfo.user.userId; |
| | | payload.taskId = form.value.deviceLedgerIds[0]; |
| | | payload.taskIds = [...form.value.deviceLedgerIds]; |
| | | payload.taskIdsStr = form.value.deviceLedgerIds.join(","); |
| | | payload.deviceLedgerIds = [...form.value.deviceLedgerIds]; |
| | | payload.deviceLedgerIdsStr = form.value.deviceLedgerIds.join(","); |
| | | payload.taskName = form.value.taskName; |
| | | payload.deviceModel = form.value.deviceModel || "-"; |
| | | |
| | | await addOrEditTimingTask(payload); |
| | | cancel(); |
| | | proxy.$modal.msgSuccess("æäº¤æå"); |
| | | } catch (error) { |
| | | proxy.$modal.msgError("æäº¤å¤±è´¥ï¼è¯·éè¯"); |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | defineExpose({ openDialog }); |
| | | </script> |
| | | |
| | | <style scoped> |
| | | |
| | | </style> |
| | | <style scoped></style> |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <el-form :inline="true" |
| | | :model="queryParams" |
| | | class="search-form"> |
| | | <el-form :inline="true" :model="queryParams" class="search-form"> |
| | | <el-form-item label="å·¡æ£ä»»å¡åç§°"> |
| | | <el-input v-model="queryParams.taskName" |
| | | placeholder="请è¾å
¥å·¡æ£ä»»å¡åç§°" |
| | | clearable |
| | | style="width: 200px " /> |
| | | <el-input |
| | | v-model="queryParams.taskName" |
| | | placeholder="请è¾å
¥å·¡æ£ä»»å¡åç§°" |
| | | clearable |
| | | style="width: 200px" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="æå±åºå"> |
| | | <el-tree-select |
| | | v-model="queryParams.areaId" |
| | | :data="areaOptions" |
| | | :props="areaTreeProps" |
| | | node-key="id" |
| | | value-key="id" |
| | | check-strictly |
| | | clearable |
| | | filterable |
| | | placeholder="è¯·éæ©æå±åºå" |
| | | style="width: 220px" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" |
| | | @click="handleQuery">æ¥è¯¢</el-button> |
| | | <el-button type="primary" @click="handleQuery">æ¥è¯¢</el-button> |
| | | <el-button @click="resetQuery">éç½®</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | <el-card> |
| | | <div style="display: flex;flex-direction: row;justify-content: space-between;margin-bottom: 10px;"> |
| | | <el-radio-group v-model="activeRadio" |
| | | @change="radioChange"> |
| | | <el-radio-button v-for="tab in radios" |
| | | :key="tab.name" |
| | | :label="tab.label" |
| | | :value="tab.name" /> |
| | | <div class="toolbar"> |
| | | <el-radio-group v-model="activeRadio" @change="radioChange"> |
| | | <el-radio-button |
| | | v-for="tab in radios" |
| | | :key="tab.name" |
| | | :label="tab.label" |
| | | :value="tab.name" |
| | | /> |
| | | </el-radio-group> |
| | | <!-- æä½æé®åº --> |
| | | <el-space v-if="activeRadio !== 'task'"> |
| | | <el-button type="primary" |
| | | :icon="Plus" |
| | | @click="handleAdd(undefined)">æ°å»º</el-button> |
| | | <el-button type="danger" |
| | | :icon="Delete" |
| | | @click="handleDelete">å é¤</el-button> |
| | | <el-button type="primary" :icon="Plus" @click="handleAdd(undefined)">æ°å»º</el-button> |
| | | <el-button type="danger" :icon="Delete" @click="handleDelete">å é¤</el-button> |
| | | <el-button @click="handleOut">导åº</el-button> |
| | | </el-space> |
| | | <el-space v-else> |
| | | <el-button @click="handleOut">导åº</el-button> |
| | | </el-space> |
| | | </div> |
| | | <div> |
| | | <PIMTable :table-loading="tableLoading" |
| | | :table-data="tableData" |
| | | :column="tableColumns" |
| | | @selection-change="handleSelectionChange" |
| | | @pagination="handlePagination" |
| | | :is-selection="true" |
| | | :border="true" |
| | | :page="{ |
| | | current: pageNum, |
| | | size: pageSize, |
| | | total: total, |
| | | layout: 'total, sizes, prev, pager, next, jumper' |
| | | }" |
| | | :table-style="{ width: '100%', height: 'calc(100vh - 23em)' }"> |
| | | <template #inspector="{ row }"> |
| | | <div class="person-tags"> |
| | | <!-- è°è¯ä¿¡æ¯ï¼ä¸çº¿æ¶å é¤ --> |
| | | <!-- {{ console.log('inspector data:', row.inspector) }} --> |
| | | <template v-if="row.inspector && row.inspector.length > 0"> |
| | | <el-tag v-for="(person, index) in row.inspector" |
| | | :key="index" |
| | | size="small" |
| | | type="primary" |
| | | class="person-tag"> |
| | | {{ person }} |
| | | </el-tag> |
| | | </template> |
| | | <span v-else |
| | | class="no-data">--</span> |
| | | </div> |
| | | </template> |
| | | </PIMTable> |
| | | </div> |
| | | <PIMTable |
| | | :table-loading="tableLoading" |
| | | :table-data="tableData" |
| | | :column="tableColumns" |
| | | :is-selection="true" |
| | | :border="true" |
| | | :page="{ |
| | | current: pageNum, |
| | | size: pageSize, |
| | | total, |
| | | layout: 'total, sizes, prev, pager, next, jumper', |
| | | }" |
| | | :table-style="{ width: '100%', height: 'calc(100vh - 23em)' }" |
| | | @selection-change="handleSelectionChange" |
| | | @pagination="handlePagination" |
| | | > |
| | | <template #inspector="{ row }"> |
| | | <div class="person-tags"> |
| | | <template v-if="row.inspector && row.inspector.length > 0"> |
| | | <el-tag |
| | | v-for="(person, index) in row.inspector" |
| | | :key="index" |
| | | size="small" |
| | | type="primary" |
| | | class="person-tag" |
| | | > |
| | | {{ person }} |
| | | </el-tag> |
| | | </template> |
| | | <span v-else class="no-data">--</span> |
| | | </div> |
| | | </template> |
| | | </PIMTable> |
| | | </el-card> |
| | | <form-dia ref="formDia" |
| | | @closeDia="handleQuery"></form-dia> |
| | | <view-files ref="viewFiles"></view-files> |
| | | <form-dia ref="formDia" @closeDia="handleQuery" /> |
| | | <view-files ref="viewFiles" /> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { Delete, Plus } from "@element-plus/icons-vue"; |
| | | import { onMounted, ref, reactive, getCurrentInstance, nextTick } from "vue"; |
| | | import { ElMessageBox } from "element-plus"; |
| | | import { Delete, Plus } from "@element-plus/icons-vue"; |
| | | import { ElMessageBox } from "element-plus"; |
| | | import { getCurrentInstance, nextTick, onMounted, reactive, ref } from "vue"; |
| | | import PIMTable from "@/components/PIMTable/PIMTable.vue"; |
| | | import FormDia from "@/views/equipmentManagement/inspectionManagement/components/formDia.vue"; |
| | | import ViewFiles from "@/views/equipmentManagement/inspectionManagement/components/viewFiles.vue"; |
| | | import { |
| | | delTimingTask, |
| | | inspectionTaskList, |
| | | timingTaskList, |
| | | } from "@/api/inspectionManagement/index.js"; |
| | | import { getDeviceAreaTree } from "@/api/equipmentManagement/deviceArea"; |
| | | |
| | | // ç»ä»¶å¼å
¥ |
| | | import PIMTable from "@/components/PIMTable/PIMTable.vue"; |
| | | import FormDia from "@/views/equipmentManagement/inspectionManagement/components/formDia.vue"; |
| | | import ViewFiles from "@/views/equipmentManagement/inspectionManagement/components/viewFiles.vue"; |
| | | const { proxy } = getCurrentInstance(); |
| | | const formDia = ref(); |
| | | const viewFiles = ref(); |
| | | |
| | | // æ¥å£å¼å
¥ |
| | | import { |
| | | delTimingTask, |
| | | inspectionTaskList, |
| | | timingTaskList, |
| | | } from "@/api/inspectionManagement/index.js"; |
| | | const queryParams = reactive({ |
| | | taskName: "", |
| | | areaId: undefined, |
| | | }); |
| | | |
| | | // å
¨å±åé |
| | | const { proxy } = getCurrentInstance(); |
| | | const formDia = ref(); |
| | | const viewFiles = ref(); |
| | | const areaOptions = ref([]); |
| | | const areaTreeProps = { |
| | | label: "areaName", |
| | | children: "children", |
| | | }; |
| | | |
| | | // æ¥è¯¢åæ° |
| | | const queryParams = reactive({ |
| | | taskName: "", |
| | | }); |
| | | const activeRadio = ref("taskManage"); |
| | | const radios = reactive([ |
| | | { name: "taskManage", label: "宿¶ä»»å¡ç®¡ç" }, |
| | | { name: "task", label: "宿¶ä»»å¡è®°å½" }, |
| | | ]); |
| | | |
| | | // åéæ¡é
ç½® |
| | | const activeRadio = ref("taskManage"); |
| | | const radios = reactive([ |
| | | { name: "taskManage", label: "宿¶ä»»å¡ç®¡ç" }, |
| | | { name: "task", label: "宿¶ä»»å¡è®°å½" }, |
| | | ]); |
| | | const selectedRows = ref([]); |
| | | const tableData = ref([]); |
| | | const tableColumns = ref([]); |
| | | const tableLoading = ref(false); |
| | | const total = ref(0); |
| | | const pageNum = ref(1); |
| | | const pageSize = ref(10); |
| | | |
| | | // è¡¨æ ¼æ°æ® |
| | | const selectedRows = ref([]); |
| | | const tableData = ref([]); |
| | | const operationsArr = ref([]); |
| | | const tableColumns = ref([]); |
| | | const tableLoading = ref(false); |
| | | const total = ref(0); |
| | | const pageNum = ref(1); |
| | | const pageSize = ref(10); |
| | | |
| | | // åé
ç½® |
| | | const columns = ref([ |
| | | { prop: "taskName", label: "å·¡æ£ä»»å¡åç§°", minWidth: 160 }, |
| | | { prop: "remarks", label: "夿³¨", minWidth: 150 }, |
| | | { prop: "inspector", label: "æ§è¡å·¡æ£äºº", minWidth: 150, slot: "inspector" }, |
| | | { |
| | | prop: "frequencyType", |
| | | label: "颿¬¡", |
| | | minWidth: 150, |
| | | // formatter: (_, __, val) => ({ |
| | | // DAILY: "æ¯æ¥", |
| | | // WEEKLY: "æ¯å¨", |
| | | // MONTHLY: "æ¯æ", |
| | | // QUARTERLY: "å£åº¦" |
| | | // }[val] || "") |
| | | formatData: params => { |
| | | return params === "DAILY" |
| | | ? "æ¯æ¥" |
| | | : params === "WEEKLY" |
| | | ? "æ¯å¨" |
| | | : params === "MONTHLY" |
| | | ? "æ¯æ" |
| | | : params === "QUARTERLY" |
| | | ? "å£åº¦" |
| | | : ""; |
| | | }, |
| | | }, |
| | | { |
| | | prop: "frequencyDetail", |
| | | label: "å¼å§æ¥æä¸æ¶é´", |
| | | minWidth: 150, |
| | | formatter: (row, column, cellValue) => { |
| | | // å
夿æ¯å¦æ¯å符串 |
| | | if (typeof cellValue !== "string") return ""; |
| | | let val = cellValue; |
| | | const replacements = { |
| | | MON: "å¨ä¸", |
| | | TUE: "å¨äº", |
| | | WED: "å¨ä¸", |
| | | THU: "å¨å", |
| | | FRI: "å¨äº", |
| | | SAT: "å¨å
", |
| | | SUN: "卿¥", |
| | | }; |
| | | // ä½¿ç¨æ£å䏿¬¡æ§æ¿æ¢ææå¹é
项 |
| | | return val.replace( |
| | | /MON|TUE|WED|THU|FRI|SAT|SUN/g, |
| | | match => replacements[match] |
| | | ); |
| | | }, |
| | | }, |
| | | { prop: "registrant", label: "ç»è®°äºº", minWidth: 100 }, |
| | | { prop: "createTime", label: "ç»è®°æ¥æ", minWidth: 100 }, |
| | | ]); |
| | | |
| | | // æä½åé
ç½® |
| | | const getOperationColumn = operations => { |
| | | if (!operations || operations.length === 0) return null; |
| | | |
| | | const operationConfig = { |
| | | label: "æä½", |
| | | width: 130, |
| | | fixed: "right", |
| | | dataType: "action", |
| | | operation: operations |
| | | .map(op => { |
| | | switch (op) { |
| | | case "edit": |
| | | return { |
| | | name: "ç¼è¾", |
| | | clickFun: handleAdd, |
| | | color: "#409EFF", |
| | | }; |
| | | case "viewFile": |
| | | return { |
| | | name: "æ¥çéä»¶", |
| | | clickFun: viewFile, |
| | | color: "#67C23A", |
| | | }; |
| | | default: |
| | | return null; |
| | | } |
| | | }) |
| | | .filter(Boolean), |
| | | }; |
| | | |
| | | return operationConfig; |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | radioChange("taskManage"); |
| | | }); |
| | | |
| | | // åéåå |
| | | const radioChange = value => { |
| | | if (value === "taskManage") { |
| | | const operationColumn = getOperationColumn(["edit"]); |
| | | tableColumns.value = [ |
| | | ...columns.value, |
| | | ...(operationColumn ? [operationColumn] : []), |
| | | ]; |
| | | operationsArr.value = ["edit"]; |
| | | } else if (value === "task") { |
| | | const operationColumn = getOperationColumn(["viewFile"]); |
| | | tableColumns.value = [ |
| | | ...columns.value, |
| | | ...(operationColumn ? [operationColumn] : []), |
| | | ]; |
| | | operationsArr.value = ["viewFile"]; |
| | | } |
| | | pageNum.value = 1; |
| | | pageSize.value = 10; |
| | | getList(); |
| | | }; |
| | | |
| | | // æ¥è¯¢æä½ |
| | | const handleQuery = () => { |
| | | pageNum.value = 1; |
| | | pageSize.value = 10; |
| | | getList(); |
| | | }; |
| | | // å页å¤ç |
| | | const handlePagination = val => { |
| | | pageNum.value = val.page; |
| | | pageSize.value = val.limit; |
| | | getList(); |
| | | }; |
| | | // è·ååè¡¨æ°æ® |
| | | const getList = () => { |
| | | tableLoading.value = true; |
| | | |
| | | const params = { |
| | | ...queryParams, |
| | | size: pageSize.value, |
| | | current: pageNum.value, |
| | | }; |
| | | |
| | | let apiCall; |
| | | if (activeRadio.value === "task") { |
| | | apiCall = inspectionTaskList(params); |
| | | } else { |
| | | apiCall = timingTaskList(params); |
| | | } |
| | | |
| | | apiCall |
| | | .then(res => { |
| | | const rawData = res.data.records || []; |
| | | // å¤ç inspector åæ®µï¼å°å符串转æ¢ä¸ºæ°ç»ï¼éç¨äºæææ
åµï¼ |
| | | tableData.value = rawData.map(item => { |
| | | const processedItem = { ...item }; |
| | | |
| | | // å¤ç inspector åæ®µ |
| | | if (processedItem.inspector) { |
| | | if (typeof processedItem.inspector === "string") { |
| | | // å符串æéå·åå² |
| | | processedItem.inspector = processedItem.inspector |
| | | .split(",") |
| | | .map(s => s.trim()) |
| | | .filter(s => s); |
| | | } else if (!Array.isArray(processedItem.inspector)) { |
| | | // éæ°ç»è½¬ä¸ºæ°ç» |
| | | processedItem.inspector = [processedItem.inspector]; |
| | | } |
| | | } else { |
| | | // 空å¼è®¾ä¸ºç©ºæ°ç» |
| | | processedItem.inspector = []; |
| | | } |
| | | |
| | | return processedItem; |
| | | }); |
| | | total.value = res.data.total || 0; |
| | | }) |
| | | .finally(() => { |
| | | tableLoading.value = false; |
| | | }); |
| | | }; |
| | | |
| | | // éç½®æ¥è¯¢ |
| | | const resetQuery = () => { |
| | | for (const key in queryParams) { |
| | | if (!["pageNum", "pageSize"].includes(key)) { |
| | | queryParams[key] = ""; |
| | | const columns = ref([ |
| | | { |
| | | label: "æå¨åºå", |
| | | prop: "areaName", |
| | | }, |
| | | { prop: "taskName", label: "å·¡æ£ä»»å¡åç§°", minWidth: 160 }, |
| | | { prop: "remarks", label: "夿³¨", minWidth: 150 }, |
| | | { prop: "inspector", label: "æ§è¡å·¡æ£äºº", minWidth: 150, slot: "inspector" }, |
| | | { |
| | | prop: "frequencyType", |
| | | label: "颿¬¡", |
| | | minWidth: 150, |
| | | formatData: (value) => |
| | | ({ |
| | | DAILY: "æ¯æ¥", |
| | | WEEKLY: "æ¯å¨", |
| | | MONTHLY: "æ¯æ", |
| | | QUARTERLY: "å£åº¦", |
| | | }[value] || ""), |
| | | }, |
| | | { |
| | | prop: "frequencyDetail", |
| | | label: "å¼å§æ¥æä¸æ¶é´", |
| | | minWidth: 150, |
| | | formatter: (row, column, cellValue) => { |
| | | if (typeof cellValue !== "string") { |
| | | return ""; |
| | | } |
| | | } |
| | | handleQuery(); |
| | | }; |
| | | const replacements = { |
| | | MON: "å¨ä¸", |
| | | TUE: "å¨äº", |
| | | WED: "å¨ä¸", |
| | | THU: "å¨å", |
| | | FRI: "å¨äº", |
| | | SAT: "å¨å
", |
| | | SUN: "卿¥", |
| | | }; |
| | | return cellValue.replace(/MON|TUE|WED|THU|FRI|SAT|SUN/g, (match) => replacements[match]); |
| | | }, |
| | | }, |
| | | { prop: "registrant", label: "ç»è®°äºº", minWidth: 100 }, |
| | | { prop: "createTime", label: "ç»è®°æ¥æ", minWidth: 100 }, |
| | | ]); |
| | | |
| | | // æ°å¢ / ç¼è¾ |
| | | const handleAdd = row => { |
| | | const type = row ? "edit" : "add"; |
| | | nextTick(() => { |
| | | formDia.value?.openDialog(type, row); |
| | | }); |
| | | }; |
| | | |
| | | // æ¥çéä»¶ |
| | | const viewFile = row => { |
| | | nextTick(() => { |
| | | viewFiles.value?.openDialog(row); |
| | | }); |
| | | }; |
| | | |
| | | // å é¤æä½ |
| | | const handleDelete = () => { |
| | | if (!selectedRows.value.length) { |
| | | proxy.$modal.msgWarning("è¯·éæ©è¦å é¤çæ°æ®"); |
| | | return; |
| | | } |
| | | |
| | | const deleteIds = selectedRows.value.map(item => item.id); |
| | | |
| | | proxy.$modal |
| | | .confirm("æ¯å¦ç¡®è®¤å 餿鿰æ®é¡¹ï¼") |
| | | .then(() => { |
| | | return delTimingTask(deleteIds); |
| | | }) |
| | | .then(() => { |
| | | proxy.$modal.msgSuccess("å 餿å"); |
| | | handleQuery(); |
| | | }) |
| | | .catch(() => {}); |
| | | }; |
| | | |
| | | // å¤éåæ´ |
| | | const handleSelectionChange = selection => { |
| | | selectedRows.value = selection; |
| | | }; |
| | | |
| | | // å¯¼åº |
| | | const handleOut = () => { |
| | | ElMessageBox.confirm("éä¸çå
容å°è¢«å¯¼åºï¼æ¯å¦ç¡®è®¤å¯¼åºï¼", "导åº", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }) |
| | | .then(() => { |
| | | // æ ¹æ®å½åéä¸çæ ç¾é¡µè°ç¨ä¸åçå¯¼åºæ¥å£ |
| | | if (activeRadio.value === "taskManage") { |
| | | // 宿¶ä»»å¡ç®¡ç |
| | | proxy.download("/timingTask/export", {}, "宿¶ä»»å¡ç®¡ç.xlsx"); |
| | | } else if (activeRadio.value === "task") { |
| | | // 宿¶ä»»å¡è®°å½ |
| | | proxy.download("/inspectionTask/export", {}, "宿¶ä»»å¡è®°å½.xlsx"); |
| | | const getOperationColumn = (operations) => { |
| | | if (!operations || operations.length === 0) { |
| | | return null; |
| | | } |
| | | return { |
| | | label: "æä½", |
| | | width: 130, |
| | | fixed: "right", |
| | | dataType: "action", |
| | | operation: operations |
| | | .map((op) => { |
| | | switch (op) { |
| | | case "edit": |
| | | return { |
| | | name: "ç¼è¾", |
| | | clickFun: handleAdd, |
| | | color: "#409EFF", |
| | | }; |
| | | case "viewFile": |
| | | return { |
| | | name: "æ¥çéä»¶", |
| | | clickFun: viewFile, |
| | | color: "#67C23A", |
| | | }; |
| | | default: |
| | | return null; |
| | | } |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msg("已忶"); |
| | | }); |
| | | .filter(Boolean), |
| | | }; |
| | | }; |
| | | |
| | | const loadAreaTree = async () => { |
| | | const { data } = await getDeviceAreaTree(); |
| | | areaOptions.value = Array.isArray(data) ? data : []; |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | loadAreaTree(); |
| | | radioChange("taskManage"); |
| | | }); |
| | | |
| | | const radioChange = (value) => { |
| | | if (value === "taskManage") { |
| | | const operationColumn = getOperationColumn(["edit"]); |
| | | tableColumns.value = [...columns.value, ...(operationColumn ? [operationColumn] : [])]; |
| | | } else { |
| | | const operationColumn = getOperationColumn(["viewFile"]); |
| | | tableColumns.value = [...columns.value, ...(operationColumn ? [operationColumn] : [])]; |
| | | } |
| | | pageNum.value = 1; |
| | | pageSize.value = 10; |
| | | getList(); |
| | | }; |
| | | |
| | | const handleQuery = () => { |
| | | pageNum.value = 1; |
| | | pageSize.value = 10; |
| | | getList(); |
| | | }; |
| | | |
| | | const handlePagination = (val) => { |
| | | pageNum.value = val.page; |
| | | pageSize.value = val.limit; |
| | | getList(); |
| | | }; |
| | | |
| | | const getList = () => { |
| | | tableLoading.value = true; |
| | | const params = { |
| | | ...queryParams, |
| | | size: pageSize.value, |
| | | current: pageNum.value, |
| | | }; |
| | | const apiCall = |
| | | activeRadio.value === "task" ? inspectionTaskList(params) : timingTaskList(params); |
| | | |
| | | apiCall |
| | | .then((res) => { |
| | | const rawData = res?.data?.records || []; |
| | | tableData.value = rawData.map((item) => { |
| | | const processedItem = { ...item }; |
| | | if (processedItem.inspector) { |
| | | if (typeof processedItem.inspector === "string") { |
| | | processedItem.inspector = processedItem.inspector |
| | | .split(",") |
| | | .map((text) => text.trim()) |
| | | .filter(Boolean); |
| | | } else if (!Array.isArray(processedItem.inspector)) { |
| | | processedItem.inspector = [processedItem.inspector]; |
| | | } |
| | | } else { |
| | | processedItem.inspector = []; |
| | | } |
| | | return processedItem; |
| | | }); |
| | | total.value = res?.data?.total || 0; |
| | | }) |
| | | .finally(() => { |
| | | tableLoading.value = false; |
| | | }); |
| | | }; |
| | | |
| | | const resetQuery = () => { |
| | | queryParams.taskName = ""; |
| | | queryParams.areaId = undefined; |
| | | handleQuery(); |
| | | }; |
| | | |
| | | const handleAdd = (row) => { |
| | | const type = row ? "edit" : "add"; |
| | | nextTick(() => { |
| | | formDia.value?.openDialog(type, row); |
| | | }); |
| | | }; |
| | | |
| | | const viewFile = (row) => { |
| | | nextTick(() => { |
| | | viewFiles.value?.openDialog(row); |
| | | }); |
| | | }; |
| | | |
| | | const handleDelete = () => { |
| | | if (!selectedRows.value.length) { |
| | | proxy.$modal.msgWarning("è¯·éæ©è¦å é¤çæ°æ®"); |
| | | return; |
| | | } |
| | | const deleteIds = selectedRows.value.map((item) => item.id); |
| | | proxy.$modal |
| | | .confirm("æ¯å¦ç¡®è®¤å 餿鿰æ®é¡¹ï¼") |
| | | .then(() => delTimingTask(deleteIds)) |
| | | .then(() => { |
| | | proxy.$modal.msgSuccess("å 餿å"); |
| | | handleQuery(); |
| | | }) |
| | | .catch(() => {}); |
| | | }; |
| | | |
| | | const handleSelectionChange = (selection) => { |
| | | selectedRows.value = selection; |
| | | }; |
| | | |
| | | const handleOut = () => { |
| | | ElMessageBox.confirm("éä¸çå
容å°è¢«å¯¼åºï¼æ¯å¦ç¡®è®¤å¯¼åºï¼", "导åº", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }) |
| | | .then(() => { |
| | | if (activeRadio.value === "taskManage") { |
| | | proxy.download("/timingTask/export", {}, "宿¶ä»»å¡ç®¡ç.xlsx"); |
| | | } else { |
| | | proxy.download("/inspectionTask/export", {}, "宿¶ä»»å¡è®°å½.xlsx"); |
| | | } |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msg("已忶"); |
| | | }); |
| | | }; |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .person-tags { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | gap: 4px; |
| | | } |
| | | .toolbar { |
| | | display: flex; |
| | | flex-direction: row; |
| | | justify-content: space-between; |
| | | margin-bottom: 10px; |
| | | } |
| | | |
| | | .person-tag { |
| | | margin-right: 4px; |
| | | margin-bottom: 2px; |
| | | } |
| | | .person-tags { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | gap: 4px; |
| | | } |
| | | |
| | | .no-data { |
| | | color: #909399; |
| | | font-size: 14px; |
| | | } |
| | | </style> |
| | | .person-tag { |
| | | margin-right: 4px; |
| | | margin-bottom: 2px; |
| | | } |
| | | |
| | | .no-data { |
| | | color: #909399; |
| | | font-size: 14px; |
| | | } |
| | | </style> |
| | |
| | | <el-form :model="form" label-width="120px" :rules="formRules" ref="formRef"> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="æå±åºå" prop="areaId"> |
| | | <el-tree-select |
| | | v-model="form.areaId" |
| | | :data="areaOptions" |
| | | :props="areaTreeProps" |
| | | node-key="id" |
| | | value-key="id" |
| | | check-strictly |
| | | clearable |
| | | filterable |
| | | placeholder="è¯·éæ©æå±åºå" |
| | | style="width: 100%" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="设å¤åç§°" prop="deviceName"> |
| | | <el-input v-model="form.deviceName" placeholder="请è¾å
¥è®¾å¤åç§°" /> |
| | | </el-form-item> |
| | |
| | | <el-form-item label="æ°é" prop="number"> |
| | | <el-input-number :min="1" style="width: 100%" |
| | | v-model="form.number" |
| | | disabled |
| | | placeholder="请è¾å
¥æ°é" |
| | | @change="mathNum" |
| | | /> |
| | |
| | | import useFormData from "@/hooks/useFormData"; |
| | | // import useUserStore from "@/store/modules/user"; |
| | | import { getLedgerById } from "@/api/equipmentManagement/ledger"; |
| | | import { getDeviceAreaTree } from "@/api/equipmentManagement/deviceArea"; |
| | | import dayjs from "dayjs"; |
| | | import { |
| | | calculateTaxIncludeTotalPrice, |
| | | calculateTaxExclusiveTotalPrice, |
| | | } from "@/utils/summarizeTable"; |
| | | import { ElMessage } from "element-plus"; |
| | | import {ref} from "vue"; |
| | | import { ref, onMounted } from "vue"; |
| | | |
| | | defineOptions({ |
| | | name: "设å¤å°è´¦è¡¨å", |
| | | }); |
| | | const formRef = ref(null); |
| | | const operationType = ref(''); |
| | | const areaOptions = ref([]); |
| | | const areaTreeProps = { |
| | | label: "areaName", |
| | | children: "children", |
| | | }; |
| | | // 设å¤ç±»ååºå®é项 |
| | | const deviceTypeOptions = ref([ |
| | | 'ç产设å¤', |
| | |
| | | 'å
¶ä»è®¾å¤' |
| | | ]); |
| | | const formRules = { |
| | | areaId: [{ required: true, trigger: "change", message: "è¯·éæ©æå±åºå" }], |
| | | deviceName: [{ required: true, trigger: "blur", message: "请è¾å
¥" }], |
| | | deviceModel: [{ required: true, trigger: "blur", message: "请è¾å
¥" }], |
| | | type: [{ required: true, trigger: "change", message: "è¯·éæ©æè¾å
¥è®¾å¤ç±»å" }], |
| | |
| | | } |
| | | |
| | | const { form, resetForm } = useFormData({ |
| | | areaId: undefined, // åºåID |
| | | deviceName: undefined, // 设å¤åç§° |
| | | deviceModel: undefined, // è§æ ¼åå· |
| | | deviceBrand: undefined, // 设å¤åç |
| | |
| | | } |
| | | const { code, data } = await getLedgerById(id); |
| | | if (code == 200) { |
| | | form.areaId = data.areaId; |
| | | form.deviceName = data.deviceName; |
| | | form.deviceModel = data.deviceModel; |
| | | form.deviceBrand = data.deviceBrand; |
| | |
| | | form.planRuntimeTime = undefined; |
| | | } |
| | | } |
| | | }; |
| | | |
| | | const setAreaId = (areaId) => { |
| | | form.areaId = areaId; |
| | | }; |
| | | |
| | | const loadAreaOptions = async () => { |
| | | const res = await getDeviceAreaTree(); |
| | | areaOptions.value = Array.isArray(res?.data) ? res.data : Array.isArray(res) ? res : []; |
| | | }; |
| | | |
| | | const handleDeviceTypeChange = (value) => { |
| | |
| | | clearValidate(); |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | loadAreaOptions(); |
| | | }); |
| | | |
| | | defineExpose({ |
| | | form, |
| | | loadForm, |
| | | setAreaId, |
| | | resetForm, |
| | | clearValidate, |
| | | resetFormAndValidate, |
| | |
| | | formRef.value.loadForm(id); |
| | | }; |
| | | |
| | | const openCreateModal = async (areaId) => { |
| | | openModal(); |
| | | await nextTick(); |
| | | formRef.value.setAreaId(areaId); |
| | | }; |
| | | |
| | | defineExpose({ |
| | | openModal, |
| | | loadForm, |
| | | openCreateModal, |
| | | }); |
| | | </script> |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <el-form :model="filters" :inline="true"> |
| | | <el-form-item label="设å¤åç§°"> |
| | | <div class="app-container ledger-view"> |
| | | <div class="left-panel"> |
| | | <div class="tree-toolbar"> |
| | | <el-input |
| | | v-model="filters.deviceName" |
| | | style="width: 200px" |
| | | placeholder="请è¾å
¥è®¾å¤åç§°" |
| | | v-model="treeKeyword" |
| | | style="width: calc(100% - 102px)" |
| | | placeholder="请è¾å
¥åºååç§°" |
| | | clearable |
| | | @change="getTableData" |
| | | prefix-icon="Search" |
| | | @input="filterTree" |
| | | @clear="filterTree" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="è§æ ¼åå·"> |
| | | <el-input |
| | | <el-button type="primary" @click="openAreaDialog('addRoot')">æ°å¢åºå</el-button> |
| | | </div> |
| | | <div class="tree-actions"> |
| | | <el-button link type="primary" @click="resetTreeSelection">å
¨é¨åºå</el-button> |
| | | </div> |
| | | <el-tree |
| | | ref="treeRef" |
| | | v-loading="treeLoading" |
| | | :data="treeData" |
| | | :props="treeProps" |
| | | node-key="id" |
| | | highlight-current |
| | | default-expand-all |
| | | :expand-on-click-node="false" |
| | | :filter-node-method="filterTreeNode" |
| | | class="ledger-tree" |
| | | @node-click="handleTreeNodeClick" |
| | | > |
| | | <template #default="{ node, data }"> |
| | | <div class="tree-node"> |
| | | <span class="tree-node-content"> |
| | | <el-icon class="tree-node-icon"> |
| | | <component |
| | | :is=" |
| | | data.children && data.children.length > 0 |
| | | ? node.expanded |
| | | ? 'FolderOpened' |
| | | : 'Folder' |
| | | : 'Tickets' |
| | | " |
| | | /> |
| | | </el-icon> |
| | | <span class="tree-node-label">{{ data.areaName }}</span> |
| | | </span> |
| | | <div class="tree-node-actions"> |
| | | <el-button link type="primary" @click.stop="openAreaDialog('edit', data)">ç¼è¾</el-button> |
| | | <el-button link type="primary" @click.stop="openAreaDialog('addChild', data)">æ°å¢</el-button> |
| | | <el-button |
| | | v-if="!hasChildren(data)" |
| | | link |
| | | type="danger" |
| | | @click.stop="handleDeleteArea(data)" |
| | | > |
| | | å é¤ |
| | | </el-button> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | </el-tree> |
| | | </div> |
| | | |
| | | <div class="right-panel"> |
| | | <el-form :model="filters" :inline="true"> |
| | | <el-form-item label="设å¤åç§°"> |
| | | <el-input |
| | | v-model="filters.deviceName" |
| | | style="width: 200px" |
| | | placeholder="请è¾å
¥è®¾å¤åç§°" |
| | | clearable |
| | | @change="getTableData" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="è§æ ¼åå·"> |
| | | <el-input |
| | | v-model="filters.deviceModel" |
| | | style="width: 200px" |
| | | placeholder="请è¾å
¥è§æ ¼åå·" |
| | | clearable |
| | | @change="getTableData" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="ä¾åºå"> |
| | | <el-input |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="ä¾åºå"> |
| | | <el-input |
| | | v-model="filters.supplierName" |
| | | style="width: 200px" |
| | | placeholder="请è¾å
¥ä¾åºå" |
| | | clearable |
| | | @change="getTableData" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="å½å
¥æ¥æ:"> |
| | | <el-date-picker v-model="filters.entryDate" value-format="YYYY-MM-DD" format="YYYY-MM-DD" type="daterange" |
| | | placeholder="è¯·éæ©" clearable @change="changeDaterange" /> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" @click="getTableData">æç´¢</el-button> |
| | | <el-button @click="resetFilters">éç½®</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | <div class="table_list"> |
| | | <div class="actions"> |
| | | <div></div> |
| | | <div> |
| | | <el-button type="primary" @click="add" icon="Plus"> æ°å¢ </el-button> |
| | | <el-button type="info" @click="handleImport" icon="Upload">导å
¥</el-button> |
| | | <el-button @click="handleOut" icon="download">导åº</el-button> |
| | | <el-button |
| | | type="danger" |
| | | icon="Delete" |
| | | :disabled="multipleList.length <= 0" |
| | | @click="deleteRow(multipleList.map((item) => item.id))" |
| | | > |
| | | æ¹éå é¤ |
| | | </el-button> |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="å½å
¥æ¥æ"> |
| | | <el-date-picker |
| | | v-model="filters.entryDate" |
| | | value-format="YYYY-MM-DD" |
| | | format="YYYY-MM-DD" |
| | | type="daterange" |
| | | placeholder="è¯·éæ©" |
| | | clearable |
| | | @change="changeDaterange" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" @click="getTableData">æç´¢</el-button> |
| | | <el-button @click="handleResetFilters">éç½®</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | |
| | | <div class="table_list"> |
| | | <div class="actions"> |
| | | <div class="actions-tip"> |
| | | <span v-if="selectedAreaName">å½ååºåï¼{{ selectedAreaName }}</span> |
| | | </div> |
| | | <div> |
| | | <el-button type="primary" icon="Plus" @click="add">æ°å¢</el-button> |
| | | <el-button type="info" icon="Upload" @click="handleImport">导å
¥</el-button> |
| | | <el-button icon="download" @click="handleOut">导åº</el-button> |
| | | <el-button |
| | | type="danger" |
| | | icon="Delete" |
| | | :disabled="multipleList.length <= 0" |
| | | @click="deleteRow(multipleList.map((item) => item.id))" |
| | | > |
| | | æ¹éå é¤ |
| | | </el-button> |
| | | </div> |
| | | </div> |
| | | <PIMTable |
| | | rowKey="id" |
| | | isSelection |
| | | :column="columns" |
| | | :tableData="dataList" |
| | | :page="{ |
| | | current: pagination.currentPage, |
| | | size: pagination.pageSize, |
| | | total: pagination.total, |
| | | }" |
| | | @selection-change="handleSelectionChange" |
| | | @pagination="changePage" |
| | | /> |
| | | </div> |
| | | <PIMTable |
| | | rowKey="id" |
| | | isSelection |
| | | :column="columns" |
| | | :tableData="dataList" |
| | | :page="{ |
| | | current: pagination.currentPage, |
| | | size: pagination.pageSize, |
| | | total: pagination.total, |
| | | }" |
| | | @selection-change="handleSelectionChange" |
| | | @pagination="changePage" |
| | | > |
| | | </PIMTable> |
| | | </div> |
| | | <Modal ref="modalRef" @success="getTableData"></Modal> |
| | | |
| | | <Modal ref="modalRef" @success="getTableData" /> |
| | | |
| | | <el-dialog |
| | | v-model="areaDialogVisible" |
| | | :title="areaDialogTitle" |
| | | width="480px" |
| | | @close="closeAreaDialog" |
| | | > |
| | | <el-form ref="areaFormRef" :model="areaForm" :rules="areaRules" label-width="88px"> |
| | | <el-form-item label="åºååç§°" prop="areaName"> |
| | | <el-input v-model="areaForm.areaName" placeholder="请è¾å
¥åºååç§°" /> |
| | | </el-form-item> |
| | | <el-form-item label="æåº" prop="sort"> |
| | | <el-input-number v-model="areaForm.sort" :min="0" :step="1" style="width: 100%" /> |
| | | </el-form-item> |
| | | <el-form-item label="夿³¨" prop="remark"> |
| | | <el-input |
| | | v-model="areaForm.remark" |
| | | type="textarea" |
| | | :rows="4" |
| | | maxlength="200" |
| | | show-word-limit |
| | | placeholder="请è¾å
¥å¤æ³¨" |
| | | /> |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button type="primary" @click="submitAreaForm">ç¡®å®</el-button> |
| | | <el-button @click="closeAreaDialog">åæ¶</el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | |
| | | <el-dialog v-model="qrDialogVisible" title="äºç»´ç " width="300px" draggable> |
| | | <div style="text-align:center;"> |
| | | <img :src="qrCodeUrl" alt="äºç»´ç " style="width:200px;height:200px;" /> |
| | | <div style="margin:10px 0;"> |
| | | <div class="qr-dialog"> |
| | | <img :src="qrCodeUrl" alt="äºç»´ç " class="qr-image" /> |
| | | <div class="qr-footer"> |
| | | <el-button type="primary" @click="downloadQRCode">ä¸è½½äºç»´ç å¾ç</el-button> |
| | | </div> |
| | | </div> |
| | | </el-dialog> |
| | | |
| | | <!-- 导å
¥å¯¹è¯æ¡ --> |
| | | |
| | | <el-dialog :title="upload.title" v-model="upload.open" width="400px" append-to-body> |
| | | <el-upload |
| | | ref="uploadRef" |
| | |
| | | <div class="el-upload__text">å°æä»¶æå°æ¤å¤ï¼æ<em>ç¹å»ä¸ä¼ </em></div> |
| | | <template #tip> |
| | | <div class="el-upload__tip text-center"> |
| | | <span>ä»
å
许导å
¥xlsãxlsxæ ¼å¼æä»¶ã</span> |
| | | <el-link type="primary" :underline="false" style="font-size: 12px; vertical-align: baseline; margin-left: 5px;" @click="importTemplate">ä¸è½½æ¨¡æ¿</el-link> |
| | | <span>ä»
å
许导å
¥ xlsãxlsx æ ¼å¼æä»¶ã</span> |
| | | <el-link |
| | | type="primary" |
| | | :underline="false" |
| | | style="font-size: 12px; vertical-align: baseline; margin-left: 5px" |
| | | @click="importTemplate" |
| | | > |
| | | ä¸è½½æ¨¡æ¿ |
| | | </el-link> |
| | | </div> |
| | | </template> |
| | | </el-upload> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button type="primary" @click="submitFileForm">ç¡® å®</el-button> |
| | | <el-button @click="upload.open = false">å æ¶</el-button> |
| | | <el-button type="primary" @click="submitFileForm">ç¡®å®</el-button> |
| | | <el-button @click="upload.open = false">åæ¶</el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | |
| | | |
| | | <script setup> |
| | | import { usePaginationApi } from "@/hooks/usePaginationApi"; |
| | | // import { Search } from "@element-plus/icons-vue"; |
| | | import { getLedgerPage, delLedger } from "@/api/equipmentManagement/ledger"; |
| | | import { |
| | | getDeviceAreaTree, |
| | | getDeviceAreaDetail, |
| | | addDeviceArea, |
| | | updateDeviceArea, |
| | | deleteDeviceArea, |
| | | } from "@/api/equipmentManagement/deviceArea"; |
| | | import { onMounted, getCurrentInstance, ref, reactive } from "vue"; |
| | | import Modal from "./Modal.vue"; |
| | | import { ElMessageBox, ElMessage } from "element-plus"; |
| | |
| | | name: "设å¤å°è´¦", |
| | | }); |
| | | |
| | | // è¡¨æ ¼å¤éæ¡éä¸é¡¹ |
| | | const multipleList = ref([]); |
| | | const { proxy } = getCurrentInstance(); |
| | | const modalRef = ref(); |
| | | const treeRef = ref(); |
| | | const areaFormRef = ref(); |
| | | const treeKeyword = ref(""); |
| | | const treeLoading = ref(false); |
| | | const treeData = ref([]); |
| | | const selectedAreaName = ref(""); |
| | | const areaDialogVisible = ref(false); |
| | | const areaDialogTitle = ref("æ°å¢åºå"); |
| | | const areaDialogMode = ref("addRoot"); |
| | | const qrDialogVisible = ref(false); |
| | | const qrCodeUrl = ref(""); |
| | | const qrRowData = ref(null); |
| | | const uploadRef = ref(null); |
| | | |
| | | // 导å
¥ç¸å
³ |
| | | const uploadRef = ref(null) |
| | | const treeProps = { |
| | | children: "children", |
| | | label: "areaName", |
| | | }; |
| | | |
| | | const upload = reactive({ |
| | | // æ¯å¦æ¾ç¤ºå¼¹åºå± |
| | | open: false, |
| | | // å¼¹åºå±æ é¢ |
| | | title: "", |
| | | // æ¯å¦ç¦ç¨ä¸ä¼ |
| | | isUploading: false, |
| | | // 设置ä¸ä¼ ç请æ±å¤´é¨ |
| | | headers: { Authorization: "Bearer " + getToken() }, |
| | | // ä¸ä¼ çå°å |
| | | url: import.meta.env.VITE_APP_BASE_API + "/device/ledger/import" |
| | | }) |
| | | url: import.meta.env.VITE_APP_BASE_API + "/device/ledger/import", |
| | | }); |
| | | |
| | | const areaForm = reactive({ |
| | | id: undefined, |
| | | areaName: "", |
| | | parentId: undefined, |
| | | sort: 0, |
| | | remark: "", |
| | | }); |
| | | |
| | | const areaRules = { |
| | | areaName: [{ required: true, message: "请è¾å
¥åºååç§°", trigger: "blur" }], |
| | | }; |
| | | |
| | | const { |
| | | filters, |
| | |
| | | dataList, |
| | | pagination, |
| | | getTableData, |
| | | resetFilters, |
| | | onCurrentChange, |
| | | } = usePaginationApi( |
| | | getLedgerPage, |
| | |
| | | deviceName: undefined, |
| | | deviceModel: undefined, |
| | | supplierName: undefined, |
| | | entryDate: undefined, |
| | | entryDateStart: undefined, |
| | | entryDateEnd: undefined, |
| | | areaId: undefined, |
| | | areaName: undefined, |
| | | }, |
| | | [ |
| | | { |
| | | label: "æå¨åºå", |
| | | prop: "areaName", |
| | | }, |
| | | { |
| | | label: "设å¤åç§°", |
| | | prop: "deviceName", |
| | |
| | | label: "å½å
¥æ¥æ", |
| | | prop: "createTime", |
| | | formatData: (v) => { |
| | | if (!v) return ''; |
| | | // 妿å
嫿¶åç§ï¼åªåæ¥æé¨å |
| | | if (v.includes(' ')) { |
| | | return v.split(' ')[0]; |
| | | } |
| | | return v; |
| | | if (!v) return ""; |
| | | return v.includes(" ") ? v.split(" ")[0] : v; |
| | | }, |
| | | }, |
| | | { |
| | | dataType: "action", |
| | | label: "æä½", |
| | | align: "center", |
| | | fixed: 'right', |
| | | width: 150, |
| | | operation: [ |
| | | { |
| | | name: "ç¼è¾", |
| | | clickFun: (row) => { |
| | | edit(row.id) |
| | | }, |
| | | }, |
| | | { |
| | | name: "çæäºç»´ç ", |
| | | clickFun: (row) => { |
| | | showQRCode(row) |
| | | }, |
| | | }, |
| | | ], |
| | | }, |
| | | { |
| | | dataType: "action", |
| | | label: "æä½", |
| | | align: "center", |
| | | fixed: "right", |
| | | width: 150, |
| | | operation: [ |
| | | { |
| | | name: "ç¼è¾", |
| | | clickFun: (row) => { |
| | | edit(row.id); |
| | | }, |
| | | }, |
| | | { |
| | | name: "çæäºç»´ç ", |
| | | clickFun: (row) => { |
| | | showQRCode(row); |
| | | }, |
| | | }, |
| | | ], |
| | | }, |
| | | ] |
| | | ); |
| | | |
| | | // å¤éååä»ä¹ |
| | | const loadTreeData = async () => { |
| | | treeLoading.value = true; |
| | | try { |
| | | const res = await getDeviceAreaTree(); |
| | | treeData.value = Array.isArray(res?.data) ? res.data : Array.isArray(res) ? res : []; |
| | | } finally { |
| | | treeLoading.value = false; |
| | | } |
| | | }; |
| | | |
| | | const resetAreaForm = () => { |
| | | areaForm.id = undefined; |
| | | areaForm.areaName = ""; |
| | | areaForm.parentId = undefined; |
| | | areaForm.sort = 0; |
| | | areaForm.remark = ""; |
| | | }; |
| | | |
| | | const filterTree = () => { |
| | | treeRef.value?.filter(treeKeyword.value); |
| | | }; |
| | | |
| | | const filterTreeNode = (value, data) => { |
| | | if (!value) { |
| | | return true; |
| | | } |
| | | return String(data.areaName || "").includes(value); |
| | | }; |
| | | |
| | | const handleTreeNodeClick = (data) => { |
| | | filters.areaId = data.id; |
| | | filters.areaName = data.areaName; |
| | | selectedAreaName.value = data.areaName || ""; |
| | | getTableData(); |
| | | }; |
| | | |
| | | const openAreaDialog = async (mode, row) => { |
| | | areaDialogMode.value = mode; |
| | | areaDialogTitle.value = |
| | | mode === "edit" ? "ç¼è¾åºå" : mode === "addChild" ? "æ°å¢ååºå" : "æ°å¢åºå"; |
| | | resetAreaForm(); |
| | | areaDialogVisible.value = true; |
| | | if (mode === "addChild") { |
| | | areaForm.parentId = row.id; |
| | | areaForm.sort = 0; |
| | | return; |
| | | } |
| | | if (mode === "edit" && row?.id) { |
| | | const res = await getDeviceAreaDetail(row.id); |
| | | const detail = res?.data || {}; |
| | | areaForm.id = detail.id; |
| | | areaForm.areaName = detail.areaName || ""; |
| | | areaForm.parentId = detail.parentId; |
| | | areaForm.sort = detail.sort ?? 0; |
| | | areaForm.remark = detail.remark || ""; |
| | | } |
| | | }; |
| | | |
| | | const closeAreaDialog = () => { |
| | | areaDialogVisible.value = false; |
| | | areaFormRef.value?.resetFields(); |
| | | resetAreaForm(); |
| | | }; |
| | | |
| | | const submitAreaForm = () => { |
| | | areaFormRef.value?.validate(async (valid) => { |
| | | if (!valid) { |
| | | return; |
| | | } |
| | | const submitData = { |
| | | id: areaForm.id, |
| | | areaName: areaForm.areaName, |
| | | parentId: areaForm.parentId, |
| | | sort: areaForm.sort, |
| | | remark: areaForm.remark, |
| | | }; |
| | | const request = areaDialogMode.value === "edit" ? updateDeviceArea : addDeviceArea; |
| | | const { code } = await request(submitData); |
| | | if (code === 200) { |
| | | ElMessage.success(areaDialogMode.value === "edit" ? "ä¿®æ¹æå" : "æ°å¢æå"); |
| | | closeAreaDialog(); |
| | | await loadTreeData(); |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | const handleDeleteArea = (row) => { |
| | | if (hasChildren(row)) { |
| | | ElMessage.warning("å½ååºååå¨ä¸çº§åºåï¼ä¸è½å é¤"); |
| | | return; |
| | | } |
| | | ElMessageBox.confirm("æ¤æä½å°å é¤è¯¥è®¾å¤åºåï¼æ¯å¦ç»§ç»ï¼", "æç¤º", { |
| | | confirmButtonText: "ç¡®å®", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }).then(async () => { |
| | | const { code } = await deleteDeviceArea([row.id]); |
| | | if (code === 200) { |
| | | ElMessage.success("å 餿å"); |
| | | if (filters.areaId === row.id) { |
| | | resetTreeSelection(); |
| | | } |
| | | await loadTreeData(); |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | const hasChildren = (row) => Array.isArray(row?.children) && row.children.length > 0; |
| | | |
| | | const resetTreeSelection = () => { |
| | | treeRef.value?.setCurrentKey(null); |
| | | selectedAreaName.value = ""; |
| | | filters.areaId = undefined; |
| | | filters.areaName = undefined; |
| | | getTableData(); |
| | | }; |
| | | |
| | | const handleSelectionChange = (selectionList) => { |
| | | multipleList.value = selectionList; |
| | | }; |
| | |
| | | const add = () => { |
| | | modalRef.value.openModal(); |
| | | }; |
| | | |
| | | const edit = (id) => { |
| | | modalRef.value.loadForm(id); |
| | | }; |
| | | |
| | | const changePage = ({ page, limit }) => { |
| | | pagination.currentPage = page; |
| | | pagination.pageSize = limit; |
| | | pagination.pageSize = limit; |
| | | onCurrentChange(page); |
| | | }; |
| | | |
| | | const deleteRow = (id) => { |
| | | ElMessageBox.confirm("æ¤æä½å°æ°¸ä¹
å é¤è¯¥æä»¶, æ¯å¦ç»§ç»?", "æç¤º", { |
| | | ElMessageBox.confirm("æ¤æä½å°æ°¸ä¹
å é¤è¯¥æ°æ®ï¼æ¯å¦ç»§ç»ï¼", "æç¤º", { |
| | | confirmButtonText: "ç¡®å®", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | |
| | | getTableData(); |
| | | }; |
| | | |
| | | const handleResetFilters = () => { |
| | | filters.deviceName = undefined; |
| | | filters.deviceModel = undefined; |
| | | filters.supplierName = undefined; |
| | | filters.entryDate = undefined; |
| | | filters.entryDateStart = undefined; |
| | | filters.entryDateEnd = undefined; |
| | | getTableData(); |
| | | }; |
| | | |
| | | const handleOut = () => { |
| | | ElMessageBox.confirm("éä¸çå
容å°è¢«å¯¼åºï¼æ¯å¦ç¡®è®¤å¯¼åºï¼", "导åº", { |
| | | ElMessageBox.confirm("å½åæ¥è¯¢ç»æå°è¢«å¯¼åºï¼æ¯å¦ç¡®è®¤å¯¼åºï¼", "导åº", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }) |
| | | .then(() => { |
| | | proxy.download(`/device/ledger/export`, {}, "设å¤å°è´¦æ¡£æ¡.xlsx"); |
| | | proxy.download("/device/ledger/export", {}, "设å¤å°è´¦æ¡£æ¡.xlsx"); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msg("已忶"); |
| | |
| | | }; |
| | | |
| | | const showQRCode = async (row) => { |
| | | // ç´æ¥ä½¿ç¨URLï¼ä¸è¦ç¨JSON.stringifyå
è£
|
| | | const qrContent = proxy.javaApi + '/device-info?deviceId=' + row.id; |
| | | const qrContent = proxy.javaApi + "/device-info?deviceId=" + row.id; |
| | | qrCodeUrl.value = await QRCode.toDataURL(qrContent); |
| | | qrRowData.value = row; |
| | | qrDialogVisible.value = true; |
| | |
| | | a.click(); |
| | | }; |
| | | |
| | | // 导å
¥æé®æä½ |
| | | const handleImport = () => { |
| | | upload.title = "设å¤å°è´¦å¯¼å
¥" |
| | | upload.open = true |
| | | } |
| | | upload.title = "设å¤å°è´¦å¯¼å
¥"; |
| | | upload.open = true; |
| | | }; |
| | | |
| | | // ä¸è½½æ¨¡æ¿æä½ |
| | | const importTemplate = () => { |
| | | proxy.download("/device/ledger/downloadTemplate", {}, `设å¤å°è´¦å¯¼å
¥æ¨¡æ¿_${new Date().getTime()}.xlsx`) |
| | | } |
| | | proxy.download("/device/ledger/downloadTemplate", {}, `设å¤å°è´¦å¯¼å
¥æ¨¡æ¿_${new Date().getTime()}.xlsx`); |
| | | }; |
| | | |
| | | // æä»¶ä¸ä¼ ä¸å¤ç |
| | | const handleFileUploadProgress = (event, file, fileList) => { |
| | | upload.isUploading = true |
| | | } |
| | | const handleFileUploadProgress = () => { |
| | | upload.isUploading = true; |
| | | }; |
| | | |
| | | // æä»¶ä¸ä¼ æåå¤ç |
| | | const handleFileSuccess = (response, file, fileList) => { |
| | | upload.open = false |
| | | upload.isUploading = false |
| | | proxy.$refs["uploadRef"].handleRemove(file) |
| | | proxy.$alert("<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>" + response.msg + "</div>", "导å
¥ç»æ", { dangerouslyUseHTMLString: true }) |
| | | getTableData() |
| | | } |
| | | const handleFileSuccess = (response, file) => { |
| | | upload.open = false; |
| | | upload.isUploading = false; |
| | | uploadRef.value?.handleRemove(file); |
| | | proxy.$alert( |
| | | "<div style='overflow:auto;overflow-x:hidden;max-height:70vh;padding:10px 20px 0;'>" + |
| | | response.msg + |
| | | "</div>", |
| | | "导å
¥ç»æ", |
| | | { dangerouslyUseHTMLString: true } |
| | | ); |
| | | getTableData(); |
| | | }; |
| | | |
| | | // æäº¤ä¸ä¼ æä»¶ |
| | | const submitFileForm = () => { |
| | | proxy.$refs["uploadRef"].submit() |
| | | } |
| | | uploadRef.value?.submit(); |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | onMounted(async () => { |
| | | await loadTreeData(); |
| | | getTableData(); |
| | | }); |
| | | </script> |
| | | |
| | | <style lang="scss" scoped> |
| | | .table_list { |
| | | margin-top: unset; |
| | | .ledger-view { |
| | | display: flex; |
| | | gap: 20px; |
| | | } |
| | | |
| | | .left-panel { |
| | | width: 320px; |
| | | min-width: 320px; |
| | | padding: 16px; |
| | | background: #fff; |
| | | border-radius: 4px; |
| | | } |
| | | |
| | | .right-panel { |
| | | flex: 1; |
| | | min-width: 0; |
| | | padding: 16px; |
| | | background: #fff; |
| | | border-radius: 4px; |
| | | } |
| | | |
| | | .tree-toolbar { |
| | | display: flex; |
| | | gap: 10px; |
| | | align-items: center; |
| | | margin-bottom: 8px; |
| | | } |
| | | |
| | | .tree-actions { |
| | | display: flex; |
| | | justify-content: flex-end; |
| | | margin-bottom: 8px; |
| | | } |
| | | |
| | | .ledger-tree { |
| | | height: calc(100vh - 230px); |
| | | overflow-y: auto; |
| | | } |
| | | |
| | | .tree-node { |
| | | flex: 1; |
| | | min-width: 0; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | gap: 8px; |
| | | } |
| | | |
| | | .tree-node-content { |
| | | display: flex; |
| | | align-items: center; |
| | | min-width: 0; |
| | | } |
| | | |
| | | .tree-node-icon { |
| | | color: #e6a23c; |
| | | margin-right: 8px; |
| | | font-size: 18px; |
| | | } |
| | | |
| | | .tree-node-label { |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | white-space: nowrap; |
| | | } |
| | | |
| | | .tree-node-actions { |
| | | flex-shrink: 0; |
| | | } |
| | | |
| | | .table_list { |
| | | margin-top: 0; |
| | | } |
| | | |
| | | .actions { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | margin-bottom: 10px; |
| | | gap: 12px; |
| | | } |
| | | |
| | | .actions-tip { |
| | | color: #606266; |
| | | font-size: 14px; |
| | | } |
| | | |
| | | .qr-dialog { |
| | | text-align: center; |
| | | } |
| | | |
| | | .qr-image { |
| | | width: 200px; |
| | | height: 200px; |
| | | } |
| | | |
| | | .qr-footer { |
| | | margin: 10px 0; |
| | | } |
| | | </style> |
| | |
| | | <el-form :model="form" label-width="100px"> |
| | | <el-row> |
| | | <el-col :span="12"> |
| | | <el-form-item label="æå±åºå"> |
| | | <el-tree-select |
| | | v-model="form.areaId" |
| | | :data="areaOptions" |
| | | :props="areaTreeProps" |
| | | node-key="id" |
| | | value-key="id" |
| | | check-strictly |
| | | clearable |
| | | filterable |
| | | placeholder="è¯·éæ©æå±åºå" |
| | | style="width: 100%" |
| | | @change="handleAreaChange" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="设å¤åç§°"> |
| | | <el-select v-model="form.deviceLedgerId" @change="setDeviceModel" filterable> |
| | | <el-select |
| | | v-model="form.deviceLedgerIds" |
| | | filterable |
| | | clearable |
| | | multiple |
| | | collapse-tags |
| | | collapse-tags-tooltip |
| | | placeholder="请å
éæ©åºåï¼åéæ©è®¾å¤" |
| | | style="width: 100%" |
| | | @change="setDeviceModels" |
| | | > |
| | | <el-option |
| | | v-for="(item, index) in deviceOptions" |
| | | :key="index" |
| | | v-for="item in deviceOptions" |
| | | :key="item.id" |
| | | :label="item.deviceName" |
| | | :value="item.id" |
| | | ></el-option> |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | |
| | | <el-form-item label="è§æ ¼åå·"> |
| | | <el-input |
| | | v-model="form.deviceModel" |
| | | placeholder="请è¾å
¥è§æ ¼åå·" |
| | | placeholder="èªå¨å¸¦åºè§æ ¼åå·" |
| | | disabled |
| | | /> |
| | | </el-form-item> |
| | |
| | | <el-col :span="12"> |
| | | <el-form-item label="æ¥ä¿®ç¶æ"> |
| | | <el-select v-model="form.status"> |
| | | <el-option label="å¾
ç»´ä¿®" :value="0"></el-option> |
| | | <el-option label="å®ç»" :value="1"></el-option> |
| | | <el-option label="失败" :value="2"></el-option> |
| | | <el-option label="å¾
ç»´ä¿®" :value="0" /> |
| | | <el-option label="å®ç»" :value="1" /> |
| | | <el-option label="失败" :value="2" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { nextTick, ref, unref } from "vue"; |
| | | import dayjs from "dayjs"; |
| | | import { ElMessage } from "element-plus"; |
| | | import FormDialog from "@/components/Dialog/FormDialog.vue"; |
| | | import useFormData from "@/hooks/useFormData"; |
| | | import useUserStore from "@/store/modules/user"; |
| | | import { |
| | | addRepair, |
| | | editRepair, |
| | | getRepairById, |
| | | } from "@/api/equipmentManagement/repair"; |
| | | import { ElMessage } from "element-plus"; |
| | | import dayjs from "dayjs"; |
| | | import useFormData from "@/hooks/useFormData"; |
| | | import { getDeviceLedger } from "@/api/equipmentManagement/ledger"; |
| | | import useUserStore from "@/store/modules/user"; |
| | | import { |
| | | getDeviceAreaTree, |
| | | getDeviceAreaTreeWithDevices, |
| | | } from "@/api/equipmentManagement/deviceArea"; |
| | | |
| | | defineOptions({ |
| | | name: "è®¾å¤æ¥ä¿®å¼¹çª", |
| | |
| | | const id = ref(); |
| | | const visible = ref(false); |
| | | const loading = ref(false); |
| | | |
| | | const userStore = useUserStore(); |
| | | const areaOptions = ref([]); |
| | | const deviceOptions = ref([]); |
| | | |
| | | const loadDeviceName = async () => { |
| | | const { data } = await getDeviceLedger(); |
| | | deviceOptions.value = data; |
| | | const areaTreeProps = { |
| | | label: "areaName", |
| | | children: "children", |
| | | }; |
| | | |
| | | const { form, resetForm } = useFormData({ |
| | | deviceLedgerId: undefined, // 设å¤Id |
| | | deviceName: undefined, // 设å¤åç§° |
| | | deviceModel: undefined, // è§æ ¼åå· |
| | | repairTime: dayjs().format("YYYY-MM-DD"), // æ¥ä¿®æ¥æï¼é»è®¤å½å¤© |
| | | repairName: userStore.nickName, // æ¥ä¿®äºº |
| | | remark: undefined, // æ
éç°è±¡ |
| | | status: 0, // æ¥ä¿®ç¶æ |
| | | areaId: undefined, |
| | | deviceLedgerId: undefined, |
| | | deviceLedgerIds: [], |
| | | deviceLedgerIdsStr: undefined, |
| | | deviceName: undefined, |
| | | deviceModel: undefined, |
| | | repairTime: dayjs().format("YYYY-MM-DD"), |
| | | repairName: userStore.nickName, |
| | | remark: undefined, |
| | | status: 0, |
| | | }); |
| | | |
| | | const setDeviceModel = (deviceId) => { |
| | | const option = deviceOptions.value.find((item) => item.id === deviceId); |
| | | form.deviceModel = option.deviceModel; |
| | | const loadAreaTree = async () => { |
| | | const { data } = await getDeviceAreaTree(); |
| | | areaOptions.value = Array.isArray(data) ? data : []; |
| | | }; |
| | | |
| | | const normalizeIdList = (value) => { |
| | | if (Array.isArray(value)) { |
| | | return value |
| | | .map((item) => Number(item)) |
| | | .filter((item) => Number.isFinite(item)); |
| | | } |
| | | if (typeof value === "string") { |
| | | return value |
| | | .split(",") |
| | | .map((item) => Number(item.trim())) |
| | | .filter((item) => Number.isFinite(item)); |
| | | } |
| | | if (value !== undefined && value !== null && value !== "") { |
| | | const numericValue = Number(value); |
| | | return Number.isFinite(numericValue) ? [numericValue] : []; |
| | | } |
| | | return []; |
| | | }; |
| | | |
| | | const getNodeDevices = (node) => { |
| | | const candidates = [ |
| | | node?.deviceList, |
| | | node?.devices, |
| | | node?.deviceLedgerList, |
| | | node?.deviceLedgers, |
| | | node?.ledgerList, |
| | | node?.ledgers, |
| | | ]; |
| | | return candidates.find((item) => Array.isArray(item)) || []; |
| | | }; |
| | | |
| | | const normalizeDevice = (item) => ({ |
| | | ...item, |
| | | id: item.id ?? item.deviceLedgerId, |
| | | deviceName: item.deviceName ?? item.name, |
| | | deviceModel: item.deviceModel ?? item.model, |
| | | }); |
| | | |
| | | const collectDevices = (node) => { |
| | | const currentDevices = getNodeDevices(node).map(normalizeDevice); |
| | | const childDevices = (node?.children || []).flatMap((child) => |
| | | collectDevices(child) |
| | | ); |
| | | const deviceMap = new Map(); |
| | | [...currentDevices, ...childDevices].forEach((item) => { |
| | | if (item?.id !== undefined && item?.id !== null) { |
| | | deviceMap.set(Number(item.id), item); |
| | | } |
| | | }); |
| | | return Array.from(deviceMap.values()); |
| | | }; |
| | | |
| | | const findAreaNode = (nodes, areaId) => { |
| | | for (const node of nodes || []) { |
| | | if (Number(node.id) === Number(areaId)) { |
| | | return node; |
| | | } |
| | | const target = findAreaNode(node.children, areaId); |
| | | if (target) { |
| | | return target; |
| | | } |
| | | } |
| | | return null; |
| | | }; |
| | | |
| | | const loadDevicesByArea = async (areaId) => { |
| | | if (!areaId) { |
| | | deviceOptions.value = []; |
| | | return; |
| | | } |
| | | const { data } = await getDeviceAreaTreeWithDevices(); |
| | | const treeData = Array.isArray(data) ? data : []; |
| | | const currentNode = findAreaNode(treeData, areaId); |
| | | deviceOptions.value = currentNode ? collectDevices(currentNode) : []; |
| | | }; |
| | | |
| | | const syncDeviceFields = (deviceIds) => { |
| | | const selectedIds = normalizeIdList(deviceIds); |
| | | const selectedDevices = selectedIds |
| | | .map((deviceId) => |
| | | deviceOptions.value.find((item) => Number(item.id) === Number(deviceId)) |
| | | ) |
| | | .filter(Boolean); |
| | | |
| | | form.deviceLedgerIds = selectedIds; |
| | | form.deviceLedgerId = selectedIds[0]; |
| | | form.deviceLedgerIdsStr = selectedIds.join(","); |
| | | form.deviceName = selectedDevices |
| | | .map((item) => item.deviceName) |
| | | .filter(Boolean) |
| | | .join(","); |
| | | form.deviceModel = selectedDevices |
| | | .map((item) => item.deviceModel || "-") |
| | | .join(","); |
| | | }; |
| | | |
| | | const setDeviceModels = (deviceIds) => { |
| | | syncDeviceFields(deviceIds); |
| | | }; |
| | | |
| | | const setForm = (data) => { |
| | | form.deviceLedgerId = data.deviceLedgerId; |
| | | form.areaId = data.areaId; |
| | | form.deviceLedgerIds = normalizeIdList( |
| | | data.deviceLedgerIds ?? data.deviceLedgerIdsStr ?? data.deviceLedgerId |
| | | ); |
| | | form.deviceLedgerId = form.deviceLedgerIds[0]; |
| | | form.deviceLedgerIdsStr = |
| | | data.deviceLedgerIdsStr ?? form.deviceLedgerIds.join(","); |
| | | form.deviceName = data.deviceName; |
| | | form.deviceModel = data.deviceModel; |
| | | form.repairTime = data.repairTime; |
| | |
| | | form.status = data.status; |
| | | }; |
| | | |
| | | const handleAreaChange = async (areaId) => { |
| | | form.deviceLedgerId = undefined; |
| | | form.deviceLedgerIds = []; |
| | | form.deviceLedgerIdsStr = undefined; |
| | | form.deviceName = undefined; |
| | | form.deviceModel = undefined; |
| | | await loadDevicesByArea(areaId); |
| | | }; |
| | | |
| | | const sendForm = async () => { |
| | | loading.value = true; |
| | | try { |
| | | syncDeviceFields(form.deviceLedgerIds); |
| | | const payload = { |
| | | ...form, |
| | | deviceLedgerId: form.deviceLedgerIds[0], |
| | | deviceLedgerIds: [...form.deviceLedgerIds], |
| | | deviceLedgerIdsStr: form.deviceLedgerIds.join(","), |
| | | deviceModel: form.deviceModel || "-", |
| | | }; |
| | | const { code } = id.value |
| | | ? await editRepair({ id: unref(id), ...form }) |
| | | : await addRepair(form); |
| | | if (code == 200) { |
| | | ? await editRepair({ id: unref(id), ...payload }) |
| | | : await addRepair(payload); |
| | | if (code === 200) { |
| | | ElMessage.success(`${id.value ? "ç¼è¾" : "æ°å¢"}æ¥ä¿®æå`); |
| | | visible.value = false; |
| | | emits("ok"); |
| | |
| | | id.value = undefined; |
| | | visible.value = true; |
| | | await nextTick(); |
| | | await loadDeviceName(); |
| | | await loadAreaTree(); |
| | | deviceOptions.value = []; |
| | | }; |
| | | |
| | | const openEdit = async (editId) => { |
| | |
| | | id.value = editId; |
| | | visible.value = true; |
| | | await nextTick(); |
| | | await loadDeviceName(); |
| | | await loadAreaTree(); |
| | | setForm(data); |
| | | await loadDevicesByArea(form.areaId); |
| | | syncDeviceFields(form.deviceLedgerIds); |
| | | }; |
| | | |
| | | defineExpose({ |
| | |
| | | style="width: 240px" |
| | | placeholder="请è¾å
¥è®¾å¤åç§°" |
| | | clearable |
| | | :prefix-icon="Search" |
| | | @change="getTableData" |
| | | /> |
| | | </el-form-item> |
| | |
| | | style="width: 240px" |
| | | placeholder="è¯·éæ©è§æ ¼åå·" |
| | | clearable |
| | | :prefix-icon="Search" |
| | | @change="getTableData" |
| | | /> |
| | | </el-form-item> |
| | |
| | | style="width: 240px" |
| | | placeholder="请è¾å
¥æ
éç°è±¡" |
| | | clearable |
| | | :prefix-icon="Search" |
| | | @change="getTableData" |
| | | /> |
| | | </el-form-item> |
| | |
| | | style="width: 240px" |
| | | placeholder="请è¾å
¥ç»´ä¿®äºº" |
| | | clearable |
| | | :prefix-icon="Search" |
| | | @change="getTableData" |
| | | /> |
| | | </el-form-item> |
| | |
| | | maintenanceTimeStr: undefined, |
| | | }, |
| | | [ |
| | | { |
| | | label: "æå¨åºå", |
| | | prop: "areaName", |
| | | }, |
| | | { |
| | | label: "设å¤åç§°", |
| | | align: "center", |
| | |
| | | @close="handleClose" |
| | | > |
| | | <el-form :model="form" label-width="100px"> |
| | | <el-form-item label="æå±åºå"> |
| | | <el-tree-select |
| | | v-model="form.areaId" |
| | | :data="areaOptions" |
| | | :props="areaTreeProps" |
| | | node-key="id" |
| | | value-key="id" |
| | | check-strictly |
| | | clearable |
| | | filterable |
| | | placeholder="è¯·éæ©æå±åºå" |
| | | style="width: 100%" |
| | | @change="handleAreaChange" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="设å¤åç§°"> |
| | | <el-select |
| | | v-model="form.deviceLedgerId" |
| | | @change="setDeviceModel" |
| | | placeholder="è¯·éæ©è®¾å¤" |
| | | v-model="form.deviceLedgerIds" |
| | | filterable |
| | | default-first-option |
| | | :reserve-keyword="false" |
| | | clearable |
| | | multiple |
| | | collapse-tags |
| | | collapse-tags-tooltip |
| | | placeholder="è¯·éæ©è®¾å¤" |
| | | style="width: 100%" |
| | | @change="setDeviceModels" |
| | | > |
| | | <el-option |
| | | v-for="(item, index) in deviceOptions" |
| | | :key="index" |
| | | v-for="item in deviceOptions" |
| | | :key="item.id" |
| | | :label="item.deviceName" |
| | | :value="item.id" |
| | | ></el-option> |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="è§æ ¼åå·"> |
| | | <el-input |
| | | v-model="form.deviceModel" |
| | | placeholder="请è¾å
¥è§æ ¼åå·" |
| | | placeholder="èªå¨å¸¦åºè§æ ¼åå·" |
| | | disabled |
| | | /> |
| | | </el-form-item> |
| | |
| | | </el-form-item> |
| | | <el-form-item v-if="id" label="ä¿ä¿®ç¶æ"> |
| | | <el-select v-model="form.status"> |
| | | <el-option label="å¾
ä¿ä¿®" :value="0"></el-option> |
| | | <el-option label="å®ç»" :value="1"></el-option> |
| | | <el-option label="失败" :value="2"></el-option> |
| | | <el-option label="å¾
ä¿ä¿®" :value="0" /> |
| | | <el-option label="å®ç»" :value="1" /> |
| | | <el-option label="失败" :value="2" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item label="计åä¿å
»æ¥æ"> |
| | | <el-date-picker |
| | | style="width: 100%" |
| | | v-model="form.maintenancePlanTime" |
| | | style="width: 100%" |
| | | format="YYYY-MM-DD" |
| | | value-format="YYYY-MM-DD HH:mm:ss" |
| | | type="date" |
| | | placeholder="è¯·éæ©è®¡åä¿å
»æ¥ææ¥æ" |
| | | placeholder="è¯·éæ©è®¡åä¿å
»æ¥æ" |
| | | clearable |
| | | /> |
| | | </el-form-item> |
| | |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { nextTick, onMounted, ref, unref } from "vue"; |
| | | import dayjs from "dayjs"; |
| | | import { ElMessage } from "element-plus"; |
| | | import FormDialog from "@/components/Dialog/FormDialog.vue"; |
| | | import useFormData from "@/hooks/useFormData"; |
| | | import { userListNoPage } from "@/api/system/user.js"; |
| | | import { |
| | | addUpkeep, |
| | | editUpkeep, |
| | | getUpkeepById, |
| | | } from "@/api/equipmentManagement/upkeep"; |
| | | import { ElMessage } from "element-plus"; |
| | | import useFormData from "@/hooks/useFormData"; |
| | | import { getDeviceLedger } from "@/api/equipmentManagement/ledger"; |
| | | import { onMounted } from "vue"; |
| | | import dayjs from "dayjs"; |
| | | import { userListNoPage } from "@/api/system/user.js"; |
| | | import { |
| | | getDeviceAreaTree, |
| | | getDeviceAreaTreeWithDevices, |
| | | } from "@/api/equipmentManagement/deviceArea"; |
| | | |
| | | defineOptions({ |
| | | name: "设å¤ä¿å
»æ°å¢è®¡å", |
| | |
| | | const id = ref(); |
| | | const visible = ref(false); |
| | | const loading = ref(false); |
| | | |
| | | const areaOptions = ref([]); |
| | | const deviceOptions = ref([]); |
| | | const loadDeviceName = async () => { |
| | | const { data } = await getDeviceLedger(); |
| | | deviceOptions.value = data; |
| | | const userList = ref([]); |
| | | const areaTreeProps = { |
| | | label: "areaName", |
| | | children: "children", |
| | | }; |
| | | |
| | | const { form, resetForm } = useFormData({ |
| | | deviceLedgerId: undefined, // 设å¤Id |
| | | deviceName: undefined, // 设å¤åç§° |
| | | deviceModel: undefined, // è§æ ¼åå· |
| | | maintenancePlanTime: undefined, // 计åä¿å
»æ¥æ |
| | | createUser: undefined, // å½å
¥äºº |
| | | status: 0, //ä¿ä¿®ç¶æ |
| | | areaId: undefined, |
| | | deviceLedgerId: undefined, |
| | | deviceLedgerIds: [], |
| | | deviceLedgerIdsStr: undefined, |
| | | deviceName: undefined, |
| | | deviceModel: undefined, |
| | | maintenancePlanTime: undefined, |
| | | createUser: undefined, |
| | | status: 0, |
| | | }); |
| | | |
| | | const setDeviceModel = (deviceId) => { |
| | | const option = deviceOptions.value.find((item) => item.id === deviceId); |
| | | form.deviceModel = option.deviceModel; |
| | | const loadAreaTree = async () => { |
| | | const { data } = await getDeviceAreaTree(); |
| | | areaOptions.value = Array.isArray(data) ? data : []; |
| | | }; |
| | | |
| | | /** |
| | | * @desc 设置表åå
容 |
| | | * @param data 设å¤ä¿¡æ¯ |
| | | */ |
| | | const normalizeIdList = (value) => { |
| | | if (Array.isArray(value)) { |
| | | return value |
| | | .map((item) => Number(item)) |
| | | .filter((item) => Number.isFinite(item)); |
| | | } |
| | | if (typeof value === "string") { |
| | | return value |
| | | .split(",") |
| | | .map((item) => Number(item.trim())) |
| | | .filter((item) => Number.isFinite(item)); |
| | | } |
| | | if (value !== undefined && value !== null && value !== "") { |
| | | const numericValue = Number(value); |
| | | return Number.isFinite(numericValue) ? [numericValue] : []; |
| | | } |
| | | return []; |
| | | }; |
| | | |
| | | const getNodeDevices = (node) => { |
| | | const candidates = [ |
| | | node?.deviceList, |
| | | node?.devices, |
| | | node?.deviceLedgerList, |
| | | node?.deviceLedgers, |
| | | node?.ledgerList, |
| | | node?.ledgers, |
| | | ]; |
| | | return candidates.find((item) => Array.isArray(item)) || []; |
| | | }; |
| | | |
| | | const normalizeDevice = (item) => ({ |
| | | ...item, |
| | | id: item.id ?? item.deviceLedgerId, |
| | | deviceName: item.deviceName ?? item.name, |
| | | deviceModel: item.deviceModel ?? item.model, |
| | | }); |
| | | |
| | | const collectDevices = (node) => { |
| | | const currentDevices = getNodeDevices(node).map(normalizeDevice); |
| | | const childDevices = (node?.children || []).flatMap((child) => |
| | | collectDevices(child) |
| | | ); |
| | | const deviceMap = new Map(); |
| | | [...currentDevices, ...childDevices].forEach((item) => { |
| | | if (item?.id !== undefined && item?.id !== null) { |
| | | deviceMap.set(Number(item.id), item); |
| | | } |
| | | }); |
| | | return Array.from(deviceMap.values()); |
| | | }; |
| | | |
| | | const findAreaNode = (nodes, areaId) => { |
| | | for (const node of nodes || []) { |
| | | if (Number(node.id) === Number(areaId)) { |
| | | return node; |
| | | } |
| | | const target = findAreaNode(node.children, areaId); |
| | | if (target) { |
| | | return target; |
| | | } |
| | | } |
| | | return null; |
| | | }; |
| | | |
| | | const loadDevicesByArea = async (areaId) => { |
| | | if (!areaId) { |
| | | deviceOptions.value = []; |
| | | return; |
| | | } |
| | | const { data } = await getDeviceAreaTreeWithDevices(); |
| | | const treeData = Array.isArray(data) ? data : []; |
| | | const currentNode = findAreaNode(treeData, areaId); |
| | | deviceOptions.value = currentNode ? collectDevices(currentNode) : []; |
| | | }; |
| | | |
| | | const syncDeviceFields = (deviceIds) => { |
| | | const selectedIds = normalizeIdList(deviceIds); |
| | | const selectedDevices = selectedIds |
| | | .map((deviceId) => |
| | | deviceOptions.value.find((item) => Number(item.id) === Number(deviceId)) |
| | | ) |
| | | .filter(Boolean); |
| | | |
| | | form.deviceLedgerIds = selectedIds; |
| | | form.deviceLedgerId = selectedIds[0]; |
| | | form.deviceLedgerIdsStr = selectedIds.join(","); |
| | | form.deviceName = selectedDevices |
| | | .map((item) => item.deviceName) |
| | | .filter(Boolean) |
| | | .join(","); |
| | | form.deviceModel = selectedDevices |
| | | .map((item) => item.deviceModel || "-") |
| | | .join(","); |
| | | }; |
| | | |
| | | const setDeviceModels = (deviceIds) => { |
| | | syncDeviceFields(deviceIds); |
| | | }; |
| | | |
| | | const handleAreaChange = async (areaId) => { |
| | | form.deviceLedgerId = undefined; |
| | | form.deviceLedgerIds = []; |
| | | form.deviceLedgerIdsStr = undefined; |
| | | form.deviceName = undefined; |
| | | form.deviceModel = undefined; |
| | | await loadDevicesByArea(areaId); |
| | | }; |
| | | |
| | | const setForm = (data) => { |
| | | form.deviceLedgerId = data.deviceLedgerId; |
| | | form.areaId = data.areaId; |
| | | form.deviceLedgerIds = normalizeIdList( |
| | | data.deviceLedgerIds ?? data.deviceLedgerIdsStr ?? data.deviceLedgerId |
| | | ); |
| | | form.deviceLedgerId = form.deviceLedgerIds[0]; |
| | | form.deviceLedgerIdsStr = |
| | | data.deviceLedgerIdsStr ?? form.deviceLedgerIds.join(","); |
| | | form.deviceName = data.deviceName; |
| | | form.deviceModel = data.deviceModel; |
| | | form.createUser = Number(data.createUser); |
| | | form.status = data.status; |
| | | form.maintenancePlanTime = dayjs(data.maintenancePlanTime).format( |
| | | "YYYY-MM-DD HH:mm:ss" |
| | | ); |
| | | form.maintenancePlanTime = data.maintenancePlanTime |
| | | ? dayjs(data.maintenancePlanTime).format("YYYY-MM-DD HH:mm:ss") |
| | | : undefined; |
| | | }; |
| | | |
| | | // ç¨æ·å表 |
| | | const userList = ref([]); |
| | | |
| | | onMounted(() => { |
| | | loadDeviceName(); |
| | | loadAreaTree(); |
| | | userListNoPage().then((res) => { |
| | | userList.value = res.data; |
| | | }); |
| | |
| | | id.value = editId; |
| | | visible.value = true; |
| | | await nextTick(); |
| | | await loadAreaTree(); |
| | | setForm(data); |
| | | await loadDevicesByArea(form.areaId); |
| | | syncDeviceFields(form.deviceLedgerIds); |
| | | }; |
| | | |
| | | const sendForm = async () => { |
| | | loading.value = true; |
| | | try { |
| | | syncDeviceFields(form.deviceLedgerIds); |
| | | const payload = { |
| | | ...form, |
| | | deviceLedgerId: form.deviceLedgerIds[0], |
| | | deviceLedgerIds: [...form.deviceLedgerIds], |
| | | deviceLedgerIdsStr: form.deviceLedgerIds.join(","), |
| | | deviceModel: form.deviceModel || "-", |
| | | }; |
| | | const { code } = id.value |
| | | ? await editUpkeep({ id: unref(id), ...form }) |
| | | : await addUpkeep(form); |
| | | if (code == 200) { |
| | | ? await editUpkeep({ id: unref(id), ...payload }) |
| | | : await addUpkeep(payload); |
| | | if (code === 200) { |
| | | ElMessage.success(`${id.value ? "ç¼è¾" : "æ°å¢"}计åæå`); |
| | | visible.value = false; |
| | | emits("ok"); |
| | |
| | | visible.value = false; |
| | | }; |
| | | |
| | | const openModal = () => { |
| | | const openModal = async () => { |
| | | id.value = undefined; |
| | | visible.value = true; |
| | | await nextTick(); |
| | | await loadAreaTree(); |
| | | deviceOptions.value = []; |
| | | }; |
| | | |
| | | defineExpose({ |
| | |
| | | <template> |
| | | <FormDialog |
| | | v-model="dialogVisitable" |
| | | :title="operationType === 'add' ? 'æ°å¢ä¿å
»ä»»å¡' : 'ç¼è¾ä¿å
»ä»»å¡'" |
| | | width="800px" |
| | | :operation-type="operationType" |
| | | @confirm="submitForm" |
| | | @cancel="cancel" |
| | | @close="cancel" |
| | | > |
| | | <el-form ref="formRef" :model="form" :rules="rules" label-width="120px"> |
| | | <el-row> |
| | | <el-col :span="12"> |
| | | <el-form-item label="设å¤åç§°" prop="taskId"> |
| | | <el-select v-model="form.taskId" @change="setDeviceModel" filterable> |
| | | <el-option |
| | | v-for="(item, index) in deviceOptions" |
| | | :key="index" |
| | | :label="item.deviceName" |
| | | :value="item.id" |
| | | ></el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="è§æ ¼åå·"> |
| | | <el-input |
| | | v-model="form.deviceModel" |
| | | placeholder="请è¾å
¥è§æ ¼åå·" |
| | | disabled |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row> |
| | | <el-col :span="12"> |
| | | <el-form-item label="å½å
¥äºº" prop="inspector"> |
| | | <el-select |
| | | v-model="form.inspector" |
| | | filterable |
| | | default-first-option |
| | | :reserve-keyword="false" |
| | | placeholder="è¯·éæ©" |
| | | clearable |
| | | > |
| | | <el-option |
| | | v-for="item in userList" |
| | | :label="item.nickName" |
| | | :value="item.userId" |
| | | :key="item.userId" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="ç»è®°æ¶é´" prop="registrationDate"> |
| | | <el-date-picker |
| | | v-model="form.registrationDate" |
| | | type="date" |
| | | placeholder="éæ©ç»è®°æ¥æ" |
| | | format="YYYY-MM-DD" |
| | | value-format="YYYY-MM-DD" |
| | | style="width: 100%" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row> |
| | | <el-col :span="12"> |
| | | <el-form-item label="ä»»å¡é¢ç" prop="frequencyType"> |
| | | <el-select v-model="form.frequencyType" placeholder="è¯·éæ©" clearable> |
| | | <el-option label="æ¯æ¥" value="DAILY"/> |
| | | <el-option label="æ¯å¨" value="WEEKLY"/> |
| | | <el-option label="æ¯æ" value="MONTHLY"/> |
| | | <el-option label="å£åº¦" value="QUARTERLY"/> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12" v-if="form.frequencyType === 'DAILY' && form.frequencyType"> |
| | | <el-form-item label="æ¥æ" prop="frequencyDetail"> |
| | | <el-time-picker v-model="form.frequencyDetail" placeholder="éæ©æ¶é´" format="HH:mm" |
| | | value-format="HH:mm" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12" v-if="form.frequencyType === 'WEEKLY' && form.frequencyType"> |
| | | <el-form-item label="æ¥æ" prop="frequencyDetail"> |
| | | <el-select v-model="form.week" placeholder="è¯·éæ©" clearable style="width: 50%"> |
| | | <el-option label="å¨ä¸" value="MON"/> |
| | | <el-option label="å¨äº" value="TUE"/> |
| | | <el-option label="å¨ä¸" value="WED"/> |
| | | <el-option label="å¨å" value="THU"/> |
| | | <el-option label="å¨äº" value="FRI"/> |
| | | <el-option label="å¨å
" value="SAT"/> |
| | | <el-option label="卿¥" value="SUN"/> |
| | | </el-select> |
| | | <el-time-picker v-model="form.time" placeholder="éæ©æ¶é´" format="HH:mm" |
| | | value-format="HH:mm" style="width: 50%"/> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12" v-if="form.frequencyType === 'MONTHLY' && form.frequencyType"> |
| | | <el-form-item label="æ¥æ" prop="frequencyDetail"> |
| | | <el-date-picker |
| | | v-model="form.frequencyDetail" |
| | | type="datetime" |
| | | clearable |
| | | placeholder="éæ©å¼å§æ¥æ" |
| | | format="DD,HH:mm" |
| | | value-format="DD,HH:mm" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12" v-if="form.frequencyType === 'QUARTERLY' && form.frequencyType"> |
| | | <el-form-item label="æ¥æ" prop="frequencyDetail"> |
| | | <el-date-picker |
| | | v-model="form.frequencyDetail" |
| | | type="datetime" |
| | | clearable |
| | | placeholder="éæ©å¼å§æ¥æ" |
| | | format="MM,DD,HH:mm" |
| | | value-format="MM,DD,HH:mm" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row> |
| | | <el-col :span="12"> |
| | | <el-form-item label="夿³¨" prop="remarks"> |
| | | <el-input v-model="form.remarks" placeholder="请è¾å
¥å¤æ³¨" type="textarea" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | </el-form> |
| | | </FormDialog> |
| | | <FormDialog |
| | | v-model="dialogVisitable" |
| | | :title="operationType === 'add' ? 'æ°å¢ä¿å
»ä»»å¡' : 'ç¼è¾ä¿å
»ä»»å¡'" |
| | | width="800px" |
| | | :operation-type="operationType" |
| | | @confirm="submitForm" |
| | | @cancel="cancel" |
| | | @close="cancel" |
| | | > |
| | | <el-form ref="formRef" :model="form" :rules="rules" label-width="120px"> |
| | | <el-row> |
| | | <el-col :span="12"> |
| | | <el-form-item label="æå±åºå" prop="areaId"> |
| | | <el-tree-select |
| | | v-model="form.areaId" |
| | | :data="areaOptions" |
| | | :props="areaTreeProps" |
| | | node-key="id" |
| | | value-key="id" |
| | | check-strictly |
| | | clearable |
| | | filterable |
| | | placeholder="è¯·éæ©æå±åºå" |
| | | style="width: 100%" |
| | | @change="handleAreaChange" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="设å¤åç§°" prop="deviceLedgerIds"> |
| | | <el-select |
| | | v-model="form.deviceLedgerIds" |
| | | filterable |
| | | clearable |
| | | multiple |
| | | collapse-tags |
| | | collapse-tags-tooltip |
| | | placeholder="è¯·éæ©è®¾å¤" |
| | | style="width: 100%" |
| | | @change="setDeviceModels" |
| | | > |
| | | <el-option |
| | | v-for="item in deviceOptions" |
| | | :key="item.id" |
| | | :label="item.deviceName" |
| | | :value="item.id" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="è§æ ¼åå·"> |
| | | <el-input |
| | | v-model="form.deviceModel" |
| | | placeholder="èªå¨å¸¦åºè§æ ¼åå·" |
| | | disabled |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row> |
| | | <el-col :span="12"> |
| | | <el-form-item label="å½å
¥äºº" prop="inspector"> |
| | | <el-select |
| | | v-model="form.inspector" |
| | | filterable |
| | | default-first-option |
| | | :reserve-keyword="false" |
| | | placeholder="è¯·éæ©" |
| | | clearable |
| | | > |
| | | <el-option |
| | | v-for="item in userList" |
| | | :key="item.userId" |
| | | :label="item.nickName" |
| | | :value="item.userId" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="ç»è®°æ¶é´" prop="registrationDate"> |
| | | <el-date-picker |
| | | v-model="form.registrationDate" |
| | | type="date" |
| | | placeholder="éæ©ç»è®°æ¥æ" |
| | | format="YYYY-MM-DD" |
| | | value-format="YYYY-MM-DD" |
| | | style="width: 100%" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row> |
| | | <el-col :span="12"> |
| | | <el-form-item label="ä»»å¡é¢ç" prop="frequencyType"> |
| | | <el-select v-model="form.frequencyType" placeholder="è¯·éæ©" clearable> |
| | | <el-option label="æ¯æ¥" value="DAILY" /> |
| | | <el-option label="æ¯å¨" value="WEEKLY" /> |
| | | <el-option label="æ¯æ" value="MONTHLY" /> |
| | | <el-option label="å£åº¦" value="QUARTERLY" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12" v-if="form.frequencyType === 'DAILY'"> |
| | | <el-form-item label="æ¥æ" prop="frequencyDetail"> |
| | | <el-time-picker |
| | | v-model="form.frequencyDetail" |
| | | placeholder="éæ©æ¶é´" |
| | | format="HH:mm" |
| | | value-format="HH:mm" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12" v-if="form.frequencyType === 'WEEKLY'"> |
| | | <el-form-item label="æ¥æ" prop="frequencyDetail"> |
| | | <el-select v-model="form.week" placeholder="è¯·éæ©" clearable style="width: 50%"> |
| | | <el-option label="å¨ä¸" value="MON" /> |
| | | <el-option label="å¨äº" value="TUE" /> |
| | | <el-option label="å¨ä¸" value="WED" /> |
| | | <el-option label="å¨å" value="THU" /> |
| | | <el-option label="å¨äº" value="FRI" /> |
| | | <el-option label="å¨å
" value="SAT" /> |
| | | <el-option label="卿¥" value="SUN" /> |
| | | </el-select> |
| | | <el-time-picker |
| | | v-model="form.time" |
| | | placeholder="éæ©æ¶é´" |
| | | format="HH:mm" |
| | | value-format="HH:mm" |
| | | style="width: 50%" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12" v-if="form.frequencyType === 'MONTHLY'"> |
| | | <el-form-item label="æ¥æ" prop="frequencyDetail"> |
| | | <el-date-picker |
| | | v-model="form.frequencyDetail" |
| | | type="datetime" |
| | | clearable |
| | | placeholder="éæ©å¼å§æ¥æ" |
| | | format="DD,HH:mm" |
| | | value-format="DD,HH:mm" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12" v-if="form.frequencyType === 'QUARTERLY'"> |
| | | <el-form-item label="æ¥æ" prop="frequencyDetail"> |
| | | <el-date-picker |
| | | v-model="form.frequencyDetail" |
| | | type="datetime" |
| | | clearable |
| | | placeholder="éæ©å¼å§æ¥æ" |
| | | format="MM,DD,HH:mm" |
| | | value-format="MM,DD,HH:mm" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row> |
| | | <el-col :span="12"> |
| | | <el-form-item label="夿³¨" prop="remarks"> |
| | | <el-input v-model="form.remarks" placeholder="请è¾å
¥å¤æ³¨" type="textarea" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | </el-form> |
| | | </FormDialog> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { getCurrentInstance, reactive, ref, toRefs } from "vue"; |
| | | import FormDialog from "@/components/Dialog/FormDialog.vue"; |
| | | import { reactive, ref, getCurrentInstance, toRefs } from "vue"; |
| | | import {userListNoPageByTenantId} from "@/api/system/user.js"; |
| | | import { getDeviceLedger } from "@/api/equipmentManagement/ledger"; |
| | | import { deviceMaintenanceTaskAdd, deviceMaintenanceTaskEdit } from "@/api/equipmentManagement/upkeep"; |
| | | import { userListNoPageByTenantId } from "@/api/system/user.js"; |
| | | import { |
| | | getDeviceAreaTree, |
| | | getDeviceAreaTreeWithDevices, |
| | | } from "@/api/equipmentManagement/deviceArea"; |
| | | import { |
| | | deviceMaintenanceTaskAdd, |
| | | deviceMaintenanceTaskEdit, |
| | | } from "@/api/equipmentManagement/upkeep"; |
| | | import { getCurrentDate } from "@/utils/index.js"; |
| | | import useUserStore from "@/store/modules/user.js"; |
| | | |
| | | const { proxy } = getCurrentInstance() |
| | | const emit = defineEmits() |
| | | const { proxy } = getCurrentInstance(); |
| | | const emit = defineEmits(["closeDia"]); |
| | | const dialogVisitable = ref(false); |
| | | const operationType = ref('add'); |
| | | const operationType = ref("add"); |
| | | const areaOptions = ref([]); |
| | | const deviceOptions = ref([]); |
| | | const userList = ref([]); |
| | | const areaTreeProps = { |
| | | label: "areaName", |
| | | children: "children", |
| | | }; |
| | | const userStore = useUserStore(); |
| | | const data = reactive({ |
| | | form: { |
| | | taskId: undefined, |
| | | taskName: undefined, |
| | | // å½å
¥äººï¼åéä¸ä¸ªç¨æ· id |
| | | inspector: undefined, |
| | | remarks: '', |
| | | frequencyType: '', |
| | | frequencyDetail: '', |
| | | week: '', |
| | | time: '', |
| | | deviceModel: undefined, // è§æ ¼åå· |
| | | registrationDate: '' |
| | | }, |
| | | rules: { |
| | | taskId: [{ required: true, message: "è¯·éæ©è®¾å¤", trigger: "change" },], |
| | | inspector: [{ required: true, message: "è¯·éæ©å½å
¥äºº", trigger: "blur" },], |
| | | registrationDate: [{ required: true, message: "è¯·éæ©ç»è®°æ¶é´", trigger: "change" }] |
| | | } |
| | | }) |
| | | const { form, rules } = toRefs(data) |
| | | const userList = ref([]) |
| | | |
| | | const loadDeviceName = async () => { |
| | | const { data } = await getDeviceLedger(); |
| | | deviceOptions.value = data; |
| | | const data = reactive({ |
| | | form: { |
| | | areaId: undefined, |
| | | taskId: undefined, |
| | | taskIds: [], |
| | | taskIdsStr: undefined, |
| | | deviceLedgerIds: [], |
| | | deviceLedgerIdsStr: undefined, |
| | | taskName: undefined, |
| | | inspector: undefined, |
| | | remarks: "", |
| | | frequencyType: "", |
| | | frequencyDetail: "", |
| | | week: "", |
| | | time: "", |
| | | deviceModel: undefined, |
| | | registrationDate: "", |
| | | }, |
| | | rules: { |
| | | areaId: [{ required: true, message: "è¯·éæ©æå±åºå", trigger: "change" }], |
| | | deviceLedgerIds: [{ required: true, message: "è¯·éæ©è®¾å¤", trigger: "change" }], |
| | | inspector: [{ required: true, message: "è¯·éæ©å½å
¥äºº", trigger: "change" }], |
| | | registrationDate: [{ required: true, message: "è¯·éæ©ç»è®°æ¶é´", trigger: "change" }], |
| | | }, |
| | | }); |
| | | |
| | | const { form, rules } = toRefs(data); |
| | | |
| | | const loadAreaTree = async () => { |
| | | const { data } = await getDeviceAreaTree(); |
| | | areaOptions.value = Array.isArray(data) ? data : []; |
| | | }; |
| | | |
| | | // éæ©è®¾å¤æ¶ï¼å填设å¤åç§°(taskName)åè§æ ¼åå·(deviceModel) |
| | | const setDeviceModel = (id) => { |
| | | const option = deviceOptions.value.find((item) => item.id === id); |
| | | if (option) { |
| | | form.value.taskId = option.id; |
| | | form.value.taskName = option.deviceName; |
| | | form.value.deviceModel = option.deviceModel; |
| | | } |
| | | } |
| | | const normalizeIdList = (value) => { |
| | | if (Array.isArray(value)) { |
| | | return value |
| | | .map((item) => Number(item)) |
| | | .filter((item) => Number.isFinite(item)); |
| | | } |
| | | if (typeof value === "string") { |
| | | return value |
| | | .split(",") |
| | | .map((item) => Number(item.trim())) |
| | | .filter((item) => Number.isFinite(item)); |
| | | } |
| | | if (value !== undefined && value !== null && value !== "") { |
| | | const numericValue = Number(value); |
| | | return Number.isFinite(numericValue) ? [numericValue] : []; |
| | | } |
| | | return []; |
| | | }; |
| | | |
| | | // æå¼å¼¹æ¡ |
| | | const openDialog = async (type, row) => { |
| | | dialogVisitable.value = true |
| | | operationType.value = type |
| | | |
| | | // é置表å |
| | | resetForm(); |
| | | |
| | | // å è½½ç¨æ·å表 |
| | | userListNoPageByTenantId().then((res) => { |
| | | userList.value = res.data; |
| | | }); |
| | | |
| | | // å 载设å¤å表 |
| | | await loadDeviceName(); |
| | | |
| | | if (type === 'edit' && row) { |
| | | form.value = { ...row } |
| | | // ç¼è¾æ¶ç¨æ¥å£è¿åç registrantId åæ¾å½å
¥äºº |
| | | if (row.registrantId) { |
| | | form.value.inspector = row.registrantId |
| | | } |
| | | const getNodeDevices = (node) => { |
| | | const candidates = [ |
| | | node?.deviceList, |
| | | node?.devices, |
| | | node?.deviceLedgerList, |
| | | node?.deviceLedgers, |
| | | node?.ledgerList, |
| | | node?.ledgers, |
| | | ]; |
| | | return candidates.find((item) => Array.isArray(item)) || []; |
| | | }; |
| | | |
| | | // 妿æè®¾å¤IDï¼èªå¨è®¾ç½®è®¾å¤ä¿¡æ¯ |
| | | if (form.value.taskId) { |
| | | setDeviceModel(form.value.taskId); |
| | | } |
| | | } else if (type === 'add') { |
| | | // æ°å¢æ¶è®¾ç½®ç»è®°æ¥æä¸ºå½å¤© |
| | | form.value.registrationDate = getCurrentDate(); |
| | | // æ°å¢æ¶è®¾ç½®å½å
¥äººä¸ºå½åç»å½è´¦æ· |
| | | form.value.inspector = userStore.id; |
| | | } |
| | | } |
| | | const normalizeDevice = (item) => ({ |
| | | ...item, |
| | | id: item.id ?? item.deviceLedgerId, |
| | | deviceName: item.deviceName ?? item.name, |
| | | deviceModel: item.deviceModel ?? item.model, |
| | | }); |
| | | |
| | | // å
³éå¯¹è¯æ¡ |
| | | const cancel = () => { |
| | | resetForm() |
| | | dialogVisitable.value = false |
| | | emit('closeDia') |
| | | } |
| | | const collectDevices = (node) => { |
| | | const currentDevices = getNodeDevices(node).map(normalizeDevice); |
| | | const childDevices = (node?.children || []).flatMap((child) => |
| | | collectDevices(child) |
| | | ); |
| | | const deviceMap = new Map(); |
| | | [...currentDevices, ...childDevices].forEach((item) => { |
| | | if (item?.id !== undefined && item?.id !== null) { |
| | | deviceMap.set(Number(item.id), item); |
| | | } |
| | | }); |
| | | return Array.from(deviceMap.values()); |
| | | }; |
| | | |
| | | // é置表å彿° |
| | | const findAreaNode = (nodes, areaId) => { |
| | | for (const node of nodes || []) { |
| | | if (Number(node.id) === Number(areaId)) { |
| | | return node; |
| | | } |
| | | const target = findAreaNode(node.children, areaId); |
| | | if (target) { |
| | | return target; |
| | | } |
| | | } |
| | | return null; |
| | | }; |
| | | |
| | | const loadDevicesByArea = async (areaId) => { |
| | | if (!areaId) { |
| | | deviceOptions.value = []; |
| | | return; |
| | | } |
| | | const { data } = await getDeviceAreaTreeWithDevices(); |
| | | const treeData = Array.isArray(data) ? data : []; |
| | | const currentNode = findAreaNode(treeData, areaId); |
| | | deviceOptions.value = currentNode ? collectDevices(currentNode) : []; |
| | | }; |
| | | |
| | | const syncDeviceFields = (deviceIds) => { |
| | | const selectedIds = normalizeIdList(deviceIds); |
| | | const selectedDevices = selectedIds |
| | | .map((deviceId) => |
| | | deviceOptions.value.find((item) => Number(item.id) === Number(deviceId)) |
| | | ) |
| | | .filter(Boolean); |
| | | |
| | | form.value.deviceLedgerIds = selectedIds; |
| | | form.value.deviceLedgerIdsStr = selectedIds.join(","); |
| | | form.value.taskIds = [...selectedIds]; |
| | | form.value.taskIdsStr = selectedIds.join(","); |
| | | form.value.taskId = selectedIds[0]; |
| | | form.value.taskName = selectedDevices |
| | | .map((item) => item.deviceName) |
| | | .filter(Boolean) |
| | | .join(","); |
| | | form.value.deviceModel = selectedDevices |
| | | .map((item) => item.deviceModel || "-") |
| | | .join(","); |
| | | }; |
| | | |
| | | const setDeviceModels = (deviceIds) => { |
| | | syncDeviceFields(deviceIds); |
| | | }; |
| | | |
| | | const handleAreaChange = async (areaId) => { |
| | | form.value.taskId = undefined; |
| | | form.value.taskIds = []; |
| | | form.value.taskIdsStr = undefined; |
| | | form.value.deviceLedgerIds = []; |
| | | form.value.deviceLedgerIdsStr = undefined; |
| | | form.value.taskName = undefined; |
| | | form.value.deviceModel = undefined; |
| | | await loadDevicesByArea(areaId); |
| | | }; |
| | | |
| | | const resetForm = () => { |
| | | if (proxy.$refs.formRef) { |
| | | proxy.$refs.formRef.resetFields() |
| | | } |
| | | // éç½®è¡¨åæ°æ®ç¡®ä¿è®¾å¤ä¿¡æ¯æ£ç¡®éç½® |
| | | form.value = { |
| | | taskId: undefined, |
| | | taskName: undefined, |
| | | inspector: undefined, |
| | | inspector: undefined, |
| | | remarks: '', |
| | | frequencyType: '', |
| | | frequencyDetail: '', |
| | | week: '', |
| | | time: '', |
| | | deviceModel: undefined, |
| | | registrationDate: '' |
| | | } |
| | | } |
| | | if (proxy.$refs.formRef) { |
| | | proxy.$refs.formRef.resetFields(); |
| | | } |
| | | form.value = { |
| | | areaId: undefined, |
| | | taskId: undefined, |
| | | taskIds: [], |
| | | taskIdsStr: undefined, |
| | | deviceLedgerIds: [], |
| | | deviceLedgerIdsStr: undefined, |
| | | taskName: undefined, |
| | | inspector: undefined, |
| | | remarks: "", |
| | | frequencyType: "", |
| | | frequencyDetail: "", |
| | | week: "", |
| | | time: "", |
| | | deviceModel: undefined, |
| | | registrationDate: "", |
| | | }; |
| | | }; |
| | | |
| | | // æäº¤è¡¨å |
| | | const openDialog = async (type, row) => { |
| | | dialogVisitable.value = true; |
| | | operationType.value = type; |
| | | resetForm(); |
| | | |
| | | userListNoPageByTenantId().then((res) => { |
| | | userList.value = res.data; |
| | | }); |
| | | |
| | | await loadAreaTree(); |
| | | |
| | | if (type === "edit" && row) { |
| | | form.value = { |
| | | ...form.value, |
| | | ...row, |
| | | inspector: row.registrantId || row.inspector, |
| | | }; |
| | | form.value.deviceLedgerIds = normalizeIdList( |
| | | row.deviceLedgerIds ?? |
| | | row.deviceLedgerIdsStr ?? |
| | | row.taskIds ?? |
| | | row.taskIdsStr ?? |
| | | row.taskId |
| | | ); |
| | | form.value.deviceLedgerIdsStr = form.value.deviceLedgerIds.join(","); |
| | | form.value.taskIds = [...form.value.deviceLedgerIds]; |
| | | form.value.taskIdsStr = form.value.deviceLedgerIds.join(","); |
| | | form.value.taskId = form.value.deviceLedgerIds[0]; |
| | | |
| | | if (form.value.areaId) { |
| | | await loadDevicesByArea(form.value.areaId); |
| | | syncDeviceFields(form.value.deviceLedgerIds); |
| | | } |
| | | } else { |
| | | form.value.registrationDate = getCurrentDate(); |
| | | form.value.inspector = userStore.id; |
| | | deviceOptions.value = []; |
| | | } |
| | | }; |
| | | |
| | | const cancel = () => { |
| | | resetForm(); |
| | | dialogVisitable.value = false; |
| | | emit("closeDia"); |
| | | }; |
| | | |
| | | const submitForm = () => { |
| | | proxy.$refs["formRef"].validate(async valid => { |
| | | if (valid) { |
| | | try { |
| | | const payload = { ...form.value } |
| | | // ä¸åååç«¯ä¼ ä¿å
»äººå段ï¼ä»
ä½¿ç¨æ¥å£è¦æ±ç registrant / registrantId |
| | | // æ ¹æ®éæ©ç"å½å
¥äºº"设置 registrant / registrantId |
| | | if (payload.inspector) { |
| | | const selectedUser = userList.value.find( |
| | | (u) => String(u.userId) === String(payload.inspector) |
| | | ) |
| | | if (selectedUser) { |
| | | payload.registrantId = selectedUser.userId |
| | | payload.registrant = selectedUser.nickName |
| | | } |
| | | } |
| | | delete payload.inspector |
| | | delete payload.inspectorIds |
| | | |
| | | if (payload.frequencyType === 'WEEKLY') { |
| | | let frequencyDetail = '' |
| | | frequencyDetail = payload.week + ',' + payload.time |
| | | payload.frequencyDetail = frequencyDetail |
| | | } |
| | | |
| | | // å½å
¥æ¥æï¼ç´æ¥ä½¿ç¨è¡¨åéç registrationDate åæ®µ |
| | | // ä¸äºé»è®¤ç¶æå段 |
| | | if (payload.status === undefined || payload.status === null || payload.status === '') { |
| | | payload.status = '0' // é»è®¤ç¶æï¼å¯æå®é
æä¸¾è°æ´ |
| | | } |
| | | payload.active = true |
| | | payload.deleted = 0 |
| | | |
| | | if (operationType.value === 'edit') { |
| | | await deviceMaintenanceTaskEdit(payload) |
| | | } else { |
| | | await deviceMaintenanceTaskAdd(payload) |
| | | } |
| | | cancel() |
| | | proxy.$modal.msgSuccess('æäº¤æå') |
| | | } catch (error) { |
| | | proxy.$modal.msgError('æäº¤å¤±è´¥ï¼è¯·éè¯') |
| | | } |
| | | } |
| | | }) |
| | | } |
| | | defineExpose({ openDialog }) |
| | | proxy.$refs.formRef.validate(async (valid) => { |
| | | if (!valid) { |
| | | return; |
| | | } |
| | | try { |
| | | syncDeviceFields(form.value.deviceLedgerIds); |
| | | const payload = { ...form.value }; |
| | | |
| | | if (payload.inspector) { |
| | | const selectedUser = userList.value.find( |
| | | (item) => String(item.userId) === String(payload.inspector) |
| | | ); |
| | | if (selectedUser) { |
| | | payload.registrantId = selectedUser.userId; |
| | | payload.registrant = selectedUser.nickName; |
| | | } |
| | | } |
| | | |
| | | delete payload.inspector; |
| | | delete payload.inspectorIds; |
| | | |
| | | if (payload.frequencyType === "WEEKLY") { |
| | | payload.frequencyDetail = `${payload.week},${payload.time}`; |
| | | } |
| | | |
| | | if ( |
| | | payload.status === undefined || |
| | | payload.status === null || |
| | | payload.status === "" |
| | | ) { |
| | | payload.status = "0"; |
| | | } |
| | | |
| | | payload.deviceLedgerIds = [...form.value.deviceLedgerIds]; |
| | | payload.deviceLedgerIdsStr = form.value.deviceLedgerIds.join(","); |
| | | payload.taskIds = [...form.value.deviceLedgerIds]; |
| | | payload.taskIdsStr = form.value.deviceLedgerIds.join(","); |
| | | payload.taskId = form.value.deviceLedgerIds[0]; |
| | | payload.taskName = form.value.taskName; |
| | | payload.deviceModel = form.value.deviceModel || "-"; |
| | | payload.active = true; |
| | | payload.deleted = 0; |
| | | |
| | | if (operationType.value === "edit") { |
| | | await deviceMaintenanceTaskEdit(payload); |
| | | } else { |
| | | await deviceMaintenanceTaskAdd(payload); |
| | | } |
| | | |
| | | cancel(); |
| | | proxy.$modal.msgSuccess("æäº¤æå"); |
| | | } catch (error) { |
| | | proxy.$modal.msgError("æäº¤å¤±è´¥ï¼è¯·éè¯"); |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | defineExpose({ openDialog }); |
| | | </script> |
| | | |
| | | <style scoped> |
| | | |
| | | </style> |
| | | <style scoped></style> |
| | |
| | | |
| | | // 宿¶ä»»å¡ç®¡çè¡¨æ ¼åé
ç½® |
| | | const scheduledColumns = ref([ |
| | | { |
| | | label: "æå¨åºå", |
| | | prop: "areaName", |
| | | }, |
| | | { prop: "taskName", label: "设å¤åç§°"}, |
| | | { |
| | | label: "è§æ ¼åå·", |
| | |
| | | // ä»»å¡è®°å½è¡¨æ ¼åé
ç½®ï¼å设å¤ä¿å
»è¡¨æ ¼åï¼ |
| | | const columns = ref([ |
| | | { |
| | | label: "æå¨åºå", |
| | | prop: "areaName", |
| | | }, |
| | | { |
| | | label: "设å¤åç§°", |
| | | align: "center", |
| | | prop: "deviceName", |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="environment-monitoring-page"> |
| | | <section class="chart-panel"> |
| | | <h3 class="panel-title">ç¯å¢å®æ¶æ±ç¶å¾</h3> |
| | | <Echarts |
| | | :series="barSeries" |
| | | :x-axis="xAxis" |
| | | :y-axis="yAxis" |
| | | :tooltip="tooltip" |
| | | :grid="grid" |
| | | :legend="legend" |
| | | :options="chartTheme" |
| | | :chart-style="chartStyle" |
| | | /> |
| | | </section> |
| | | |
| | | <section class="table-panel"> |
| | | <h3 class="panel-title">设å¤ç¯å¢æ°æ®å表</h3> |
| | | <div class="sensor-table"> |
| | | <div class="sensor-table__head"> |
| | | <span>设å¤</span> |
| | | <span>温度</span> |
| | | <span>湿度</span> |
| | | <span>äºæ°§å碳</span> |
| | | <span>å
ç
§</span> |
| | | </div> |
| | | <div v-for="item in deviceRows" :key="item.name" class="sensor-table__row"> |
| | | <span>{{ item.name }}</span> |
| | | <span>{{ item.temperature }}</span> |
| | | <span>{{ item.humidity }}</span> |
| | | <span>{{ item.co2 }}</span> |
| | | <span>{{ item.light }}</span> |
| | | </div> |
| | | <div v-if="!deviceRows.length" class="sensor-table__empty"> |
| | | ææ ç¯å¢æ°æ® |
| | | </div> |
| | | </div> |
| | | </section> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { computed, onBeforeUnmount, onMounted, ref } from "vue"; |
| | | import Echarts from "@/components/Echarts/echarts.vue"; |
| | | import { getEnvironmentalRealData } from "@/api/inventoryManagement/environmentalMonitoring"; |
| | | |
| | | const POLL_INTERVAL = 30000; |
| | | |
| | | const latestDevices = ref([]); |
| | | let pollTimer = null; |
| | | |
| | | const metricConfig = [ |
| | | { key: "temperature", label: "温度", color: "#ff7a59" }, |
| | | { key: "humidity", label: "湿度", color: "#1ea7fd" }, |
| | | { key: "co2", label: "äºæ°§å碳", color: "#12c48b" }, |
| | | { key: "light", label: "å
ç
§", color: "#8b5cf6" }, |
| | | ]; |
| | | |
| | | const chartTheme = { |
| | | backgroundColor: "transparent", |
| | | textStyle: { color: "#6c7c96" }, |
| | | }; |
| | | |
| | | const chartStyle = { |
| | | width: "100%", |
| | | height: "360px", |
| | | }; |
| | | |
| | | const grid = { |
| | | left: "4%", |
| | | right: "4%", |
| | | top: "16%", |
| | | bottom: "10%", |
| | | containLabel: true, |
| | | }; |
| | | |
| | | const tooltip = { |
| | | trigger: "axis", |
| | | axisPointer: { type: "shadow" }, |
| | | backgroundColor: "rgba(12, 20, 34, 0.88)", |
| | | borderColor: "rgba(126, 164, 255, 0.18)", |
| | | textStyle: { color: "#e8edf7" }, |
| | | }; |
| | | |
| | | const legend = { |
| | | top: 0, |
| | | right: 0, |
| | | textStyle: { color: "#6c7c96" }, |
| | | }; |
| | | |
| | | const extractNumericValue = (rawValue) => { |
| | | const matched = String(rawValue ?? "").match(/-?\d+(\.\d+)?/); |
| | | return matched ? Number(matched[0]) : 0; |
| | | }; |
| | | |
| | | const normalizeMetricObject = (source, index) => { |
| | | const normalized = { |
| | | name: source.deviceName || source.name || source.deviceNo || `设å¤${index + 1}`, |
| | | temperature: 0, |
| | | humidity: 0, |
| | | co2: 0, |
| | | light: 0, |
| | | }; |
| | | |
| | | Object.entries(source || {}).forEach(([key, value]) => { |
| | | const rawText = String(value ?? ""); |
| | | |
| | | if (rawText.includes("â")) { |
| | | normalized.temperature = extractNumericValue(rawText); |
| | | return; |
| | | } |
| | | if (rawText.includes("%RH")) { |
| | | normalized.humidity = extractNumericValue(rawText); |
| | | return; |
| | | } |
| | | if (rawText.includes("ppm")) { |
| | | normalized.co2 = extractNumericValue(rawText); |
| | | return; |
| | | } |
| | | if (rawText.includes("Lux")) { |
| | | normalized.light = extractNumericValue(rawText); |
| | | return; |
| | | } |
| | | |
| | | if (key === "temperature") { |
| | | normalized.temperature = extractNumericValue(rawText); |
| | | } else if (key === "humidity") { |
| | | normalized.humidity = extractNumericValue(rawText); |
| | | } else if (key === "co2") { |
| | | normalized.co2 = extractNumericValue(rawText); |
| | | } else if (key === "light") { |
| | | normalized.light = extractNumericValue(rawText); |
| | | } |
| | | }); |
| | | |
| | | return normalized; |
| | | }; |
| | | |
| | | const xAxis = computed(() => [ |
| | | { |
| | | type: "category", |
| | | data: latestDevices.value.map((item) => item.name), |
| | | axisLine: { lineStyle: { color: "rgba(79, 110, 148, 0.55)" } }, |
| | | axisLabel: { color: "#6c7c96" }, |
| | | axisTick: { show: false }, |
| | | }, |
| | | ]); |
| | | |
| | | const yAxis = [ |
| | | { |
| | | type: "value", |
| | | axisLine: { show: false }, |
| | | axisTick: { show: false }, |
| | | splitLine: { lineStyle: { color: "rgba(110, 131, 160, 0.12)" } }, |
| | | axisLabel: { color: "#6c7c96" }, |
| | | }, |
| | | ]; |
| | | |
| | | const barSeries = computed(() => |
| | | metricConfig.map((item) => ({ |
| | | name: item.label, |
| | | type: "bar", |
| | | barMaxWidth: 28, |
| | | itemStyle: { |
| | | color: item.color, |
| | | borderRadius: [8, 8, 0, 0], |
| | | }, |
| | | data: latestDevices.value.map((device) => Number(device[item.key] || 0)), |
| | | })) |
| | | ); |
| | | |
| | | const deviceRows = computed(() => |
| | | latestDevices.value.map((item) => ({ |
| | | name: item.name, |
| | | temperature: `${Number(item.temperature || 0).toFixed(2)}â`, |
| | | humidity: `${Number(item.humidity || 0).toFixed(2)}%RH`, |
| | | co2: `${Number(item.co2 || 0).toFixed(2)}ppm`, |
| | | light: `${Number(item.light || 0).toFixed(2)}Lux`, |
| | | })) |
| | | ); |
| | | |
| | | const fetchRealData = async () => { |
| | | try { |
| | | const res = await getEnvironmentalRealData(); |
| | | const dataList = Array.isArray(res?.data) ? res.data : []; |
| | | latestDevices.value = dataList.map((item, index) => normalizeMetricObject(item, index)); |
| | | } catch (error) { |
| | | latestDevices.value = []; |
| | | } |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | fetchRealData(); |
| | | pollTimer = window.setInterval(fetchRealData, POLL_INTERVAL); |
| | | }); |
| | | |
| | | onBeforeUnmount(() => { |
| | | if (pollTimer) { |
| | | window.clearInterval(pollTimer); |
| | | pollTimer = null; |
| | | } |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .environment-monitoring-page { |
| | | min-height: 100%; |
| | | padding: 20px; |
| | | } |
| | | |
| | | .chart-panel, |
| | | .table-panel { |
| | | padding: 20px; |
| | | border-radius: 16px; |
| | | background: #fff; |
| | | } |
| | | |
| | | .table-panel { |
| | | margin-top: 20px; |
| | | } |
| | | |
| | | .panel-title { |
| | | margin: 0 0 16px; |
| | | color: #1d344f; |
| | | font-size: 18px; |
| | | font-weight: 600; |
| | | } |
| | | |
| | | .sensor-table { |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 10px; |
| | | } |
| | | |
| | | .sensor-table__head, |
| | | .sensor-table__row { |
| | | display: grid; |
| | | grid-template-columns: 1.1fr 1fr 1fr 1fr 1fr; |
| | | gap: 12px; |
| | | align-items: center; |
| | | } |
| | | |
| | | .sensor-table__head { |
| | | padding: 0 6px 10px; |
| | | color: #8393a8; |
| | | font-size: 13px; |
| | | } |
| | | |
| | | .sensor-table__row { |
| | | padding: 14px 16px; |
| | | border-radius: 12px; |
| | | background: #f6f9fc; |
| | | color: #1d344f; |
| | | } |
| | | |
| | | .sensor-table__empty { |
| | | padding: 32px 0; |
| | | color: #8393a8; |
| | | text-align: center; |
| | | } |
| | | |
| | | @media (max-width: 768px) { |
| | | .environment-monitoring-page { |
| | | padding: 12px; |
| | | } |
| | | |
| | | .chart-panel, |
| | | .table-panel { |
| | | padding: 16px; |
| | | } |
| | | |
| | | .sensor-table__head, |
| | | .sensor-table__row { |
| | | grid-template-columns: repeat(2, minmax(0, 1fr)); |
| | | } |
| | | } |
| | | </style> |