|
|
@@ -1,491 +1,429 @@
|
|
|
-<template>
|
|
|
- <z-paging
|
|
|
- class="page repair"
|
|
|
- ref="paging"
|
|
|
- v-model="dataList"
|
|
|
- @query="queryList"
|
|
|
- >
|
|
|
- <!-- z-paging默认铺满全屏,此时页面所有view都应放在z-paging标签内,否则会被盖住 -->
|
|
|
- <!-- 需要固定在页面顶部的view请通过slot="top"插入,包括自定义的导航栏 -->
|
|
|
- <template #top>
|
|
|
- <view class="page-top">
|
|
|
- <view class="page-back"></view>
|
|
|
- <view class="uni-page-head navgator justify-center align-center">
|
|
|
- <view class="nav-back" @click="navigatorBack()">
|
|
|
- <uni-icons type="left"></uni-icons>
|
|
|
- </view>
|
|
|
- <view class="nav-title">
|
|
|
- {{ $t("equipmentMaintenance.title") }}
|
|
|
- </view>
|
|
|
- </view>
|
|
|
- <view class="page-content">
|
|
|
- <view class="content-search">
|
|
|
- <uni-easyinput
|
|
|
- prefixIcon="search"
|
|
|
- confirmType="search"
|
|
|
- v-model="search"
|
|
|
- :placeholder="$t('common.searchHint')"
|
|
|
- @confirm="onSearch"
|
|
|
- >
|
|
|
- </uni-easyinput>
|
|
|
- </view>
|
|
|
- <uni-row
|
|
|
- class="content-statistics flex-row align-center justify-around"
|
|
|
- >
|
|
|
- <!-- 已完成 -->
|
|
|
- <uni-col class="statistics-item flex-col align-center">
|
|
|
- <view class="statistics-count font-BiaoTiHei">
|
|
|
- {{ statistics.total }}
|
|
|
- </view>
|
|
|
- <view class="statistics-title">
|
|
|
- {{ $t("status.finished") }}
|
|
|
- </view>
|
|
|
- </uni-col>
|
|
|
- <!-- 待填写 -->
|
|
|
- <uni-col class="statistics-item flex-col align-center">
|
|
|
- <view class="statistics-count font-BiaoTiHei">
|
|
|
- {{ statistics.todo }}
|
|
|
- </view>
|
|
|
- <view class="statistics-title">
|
|
|
- {{ $t("status.tobeFilled") }}
|
|
|
- </view>
|
|
|
- </uni-col>
|
|
|
- <!-- 平均解决时间 -->
|
|
|
- <uni-col class="statistics-item flex-col align-center">
|
|
|
- <view class="statistics-count font-BiaoTiHei">
|
|
|
- {{ statistics.average }}
|
|
|
- </view>
|
|
|
- <view class="statistics-title">
|
|
|
- {{ $t("equipmentMaintenance.averageResolutionTime") }}
|
|
|
- </view>
|
|
|
- </uni-col>
|
|
|
- </uni-row>
|
|
|
- <button class="full-btn" type="primary" @click="onCreate">
|
|
|
- <uni-icons type="plusempty"></uni-icons>
|
|
|
- {{ $t("equipmentMaintenance.createButton") }}
|
|
|
- </button>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
- </template>
|
|
|
- <view class="paging-list">
|
|
|
- <view class="item" v-for="(item, index) in dataList" :key="index">
|
|
|
- <view
|
|
|
- class="item-module flex-row align-center justify-between"
|
|
|
- :class="{ tobeFilled: item.status == 'tx' }"
|
|
|
- >
|
|
|
- <view class="module-name">
|
|
|
- {{ $t("equipmentMaintenance.repairCode") }}: {{ item.failureCode }}
|
|
|
- </view>
|
|
|
- <view
|
|
|
- class="module-status"
|
|
|
- :class="{ pending: item.status == 'tx' }"
|
|
|
- v-if="statusDict[item.status]"
|
|
|
- >
|
|
|
- <!-- 状态 -->
|
|
|
- <span>{{ statusDict[item.status] }}</span>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
- <view class="item-content">
|
|
|
- <!-- 设备编号 -->
|
|
|
- <view class="item-title flex-row">
|
|
|
- <span class="item-title-width">{{ $t("device.deviceCode") }}:</span>
|
|
|
- <span>{{ item.deviceCode }}</span>
|
|
|
- </view>
|
|
|
- <!-- 设备名称 -->
|
|
|
- <view class="item-title flex-row">
|
|
|
- <span class="item-title-width">{{ $t("device.deviceName") }}:</span>
|
|
|
- <span>{{ item.deviceName }}</span>
|
|
|
- </view>
|
|
|
- <!-- 故障名称 -->
|
|
|
- <view class="item-title flex-row">
|
|
|
- <span class="item-title-width">{{ $t("fault.faultName") }}:</span>
|
|
|
- <span>{{ item.failureName }}</span>
|
|
|
- </view>
|
|
|
- <!-- 故障时间 -->
|
|
|
- <view class="item-title flex-row">
|
|
|
- <span class="item-title-width">{{ $t("fault.faultTime") }}:</span>
|
|
|
- <span>
|
|
|
- {{ item.failureTime ? formatDate(item.failureTime) : "" }}
|
|
|
- </span>
|
|
|
- </view>
|
|
|
- <!-- 维修开始时间 -->
|
|
|
- <view class="item-title flex-row">
|
|
|
- <span class="item-title-width">
|
|
|
- {{ $t("equipmentMaintenance.maintenanceStartTime") }}:
|
|
|
- </span>
|
|
|
- <span>
|
|
|
- {{
|
|
|
- item.maintainStartTime ? formatDate(item.maintainStartTime) : ""
|
|
|
- }}
|
|
|
- </span>
|
|
|
- </view>
|
|
|
- <!-- 执行时间 -->
|
|
|
- <view class="item-title flex-row">
|
|
|
- <span class="item-title-width">
|
|
|
- {{ $t("workOrder.executionTime") }}:
|
|
|
- </span>
|
|
|
- <span>
|
|
|
- {{ item.executeDate ? formatDate(item.executeDate) : "" }}
|
|
|
- </span>
|
|
|
- </view>
|
|
|
- <!-- 审核状态 -->
|
|
|
- <view class="item-title flex-row">
|
|
|
- <span class="item-title-width">
|
|
|
- {{ $t("workOrder.auditStatus") }}:
|
|
|
- </span>
|
|
|
- <span>{{ auditStatusDict[item.auditStatus] }}</span>
|
|
|
- </view>
|
|
|
- <!-- 是否停机 -->
|
|
|
- <view class="item-title flex-row">
|
|
|
- <span class="item-title-width">
|
|
|
- {{ $t("equipmentMaintenance.isStop") }}:
|
|
|
- </span>
|
|
|
- <span :class="{ 'color-red': item.ifStop }">
|
|
|
- {{ item.ifStop ? $t("operation.yes") : $t("operation.no") }}
|
|
|
- </span>
|
|
|
- </view>
|
|
|
- <!-- 工单来源 -->
|
|
|
- <view class="item-title flex-row">
|
|
|
- <span class="item-title-width">
|
|
|
- {{ $t("workOrder.workOrderSource") }}:
|
|
|
- </span>
|
|
|
- <span>{{ item.maintainType }}</span>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
- <view
|
|
|
- class="item-btn flex-row align-center justify-end"
|
|
|
- v-if="companyInfo.data !== 'rh'"
|
|
|
- >
|
|
|
- <button
|
|
|
- type="primary"
|
|
|
- :plain="false"
|
|
|
- v-if="item.status !== 'tx'"
|
|
|
- @click="onView(item)"
|
|
|
- >
|
|
|
- {{ $t("workOrder.viewDetails") }}
|
|
|
- </button>
|
|
|
- <button type="primary" v-else @click="onEdit(item)">
|
|
|
- {{ $t("operation.fill") }}
|
|
|
- </button>
|
|
|
- </view>
|
|
|
-
|
|
|
- <view class="item-btn flex-row align-center justify-end" v-else>
|
|
|
- <button type="primary" :plain="false" @click="onView(item)">
|
|
|
- {{ $t("workOrder.viewDetails") }}
|
|
|
- </button>
|
|
|
-
|
|
|
- <button
|
|
|
- type="primary"
|
|
|
- :plain="false"
|
|
|
- v-if="
|
|
|
- item.status === 'personnel' && userInfo.id === item.maintainPerson
|
|
|
- "
|
|
|
- @click="changeMethod(item)"
|
|
|
- >
|
|
|
- 维修方式
|
|
|
- </button>
|
|
|
-
|
|
|
- <button
|
|
|
- type="primary"
|
|
|
- @click="onEdit(item)"
|
|
|
- v-if="
|
|
|
- item.status === 'tx' &&
|
|
|
- (item.auditStatus === 20 || item.auditStatus === null)
|
|
|
- "
|
|
|
- >
|
|
|
- {{ $t("operation.fill") }}
|
|
|
- </button>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
- </z-paging>
|
|
|
-
|
|
|
- <uni-popup type="dialog" ref="chooseMethodRef" @close="cancelRepairMethod">
|
|
|
- <view class="popup-content">
|
|
|
- <view class="popup-title">维修方式</view>
|
|
|
- <view class="form-item">
|
|
|
- <text class="label">*</text>
|
|
|
- <text class="label-text">维修方式</text>
|
|
|
- <picker
|
|
|
- @change="onPickerChange"
|
|
|
- :value="selectedValue"
|
|
|
- :range="methodOptions"
|
|
|
- >
|
|
|
- <view class="picker-view">
|
|
|
- {{ methodOptions[selectedValue] || "请选择维修方式" }}
|
|
|
- </view>
|
|
|
- </picker>
|
|
|
-
|
|
|
- <!-- <uni-data-select
|
|
|
- :clear="false"
|
|
|
- v-model="selectedValue"
|
|
|
- :localdata="methodOptions"
|
|
|
- @change="onPickerChange"
|
|
|
- >
|
|
|
- </uni-data-select> -->
|
|
|
- </view>
|
|
|
-
|
|
|
- <view class="form-item">
|
|
|
- <text class="label">*</text>
|
|
|
- <text class="label-text">备注说明</text>
|
|
|
- <textarea
|
|
|
- v-model="repairMethodForm.remark"
|
|
|
- placeholder="请输入备注说明"
|
|
|
- class="textarea"
|
|
|
- maxlength="200"
|
|
|
- ></textarea>
|
|
|
- </view>
|
|
|
-
|
|
|
- <view class="popup-footer">
|
|
|
- <view class="btn-cancel" @click="cancelRepairMethod">取消</view>
|
|
|
- <view class="btn-confirm" @click="submitRepairMethod">确定</view>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
- </uni-popup>
|
|
|
-</template>
|
|
|
-<script setup>
|
|
|
-import { ref, reactive, onMounted, nextTick } from "vue";
|
|
|
-import { onShow } from "@dcloudio/uni-app";
|
|
|
-import { getRepairCount, getRepairList, maintainMethod } from "@/api/repair";
|
|
|
-import { getLoginUserInfo } from "@/api/login";
|
|
|
-import { getDeptName } from "@/api/recordFilling";
|
|
|
-import dayjs from "dayjs";
|
|
|
-import { useDataDictStore } from "@/store/modules/dataDict";
|
|
|
-// 字典项
|
|
|
-const { getDataDictList } = useDataDictStore();
|
|
|
-// 状态
|
|
|
-const statusDict = reactive({});
|
|
|
-getDataDictList("pms_maintain_status").map((item) => {
|
|
|
- statusDict[item.value] = item.label;
|
|
|
-});
|
|
|
-console.log("statusDict", statusDict);
|
|
|
-// 审核状态
|
|
|
-const auditStatusDict = reactive({});
|
|
|
-getDataDictList("crm_audit_status").map((item) => {
|
|
|
- auditStatusDict[item.value] = item.label;
|
|
|
-});
|
|
|
-
|
|
|
-const methodOptions = ref([]); // 使用 ref 创建数组
|
|
|
-const methodOptionsMap = reactive({}); // 保存 value -> label 的映射
|
|
|
-
|
|
|
-getDataDictList("maintain_method").forEach((item) => {
|
|
|
- methodOptions.value.push(item.label); // 只存储 label 用于显示
|
|
|
- methodOptionsMap[item.value] = item.label;
|
|
|
-});
|
|
|
-console.log("auditStatusDict", auditStatusDict);
|
|
|
-
|
|
|
-// --- 列表 ---start---
|
|
|
-const search = ref("");
|
|
|
-const paging = ref(null);
|
|
|
-// v-model绑定的这个变量不要在分页请求结束中自己赋值,直接使用即可
|
|
|
-const dataList = ref([]);
|
|
|
-
|
|
|
-// @query所绑定的方法不要自己调用!!需要刷新列表数据时,只需要调用paging.value.reload()即可
|
|
|
-const queryList = (pageNo, pageSize) => {
|
|
|
- // 此处请求仅为演示,请替换为自己项目中的请求
|
|
|
- getRepairList({
|
|
|
- pageNo,
|
|
|
- pageSize,
|
|
|
- commonParam: search.value,
|
|
|
- })
|
|
|
- .then((res) => {
|
|
|
- // 将请求结果通过complete传给z-paging处理,同时也代表请求结束,这一行必须调用
|
|
|
- paging.value.complete(res.data.list);
|
|
|
- })
|
|
|
- .catch((res) => {
|
|
|
- // 如果请求失败写paging.value.complete(false);
|
|
|
- // 注意,每次都需要在catch中写这句话很麻烦,z-paging提供了方案可以全局统一处理
|
|
|
- // 在底层的网络请求抛出异常时,写uni.$emit('z-paging-error-emit');即可
|
|
|
- paging.value.complete(false);
|
|
|
- });
|
|
|
-};
|
|
|
-const onSearch = () => {
|
|
|
- paging.value.reload();
|
|
|
-};
|
|
|
-const formatDate = (time) => {
|
|
|
- return dayjs(time).format("YYYY-MM-DD HH:mm:ss");
|
|
|
-};
|
|
|
-// -- end --
|
|
|
-// 获取顶部统计数量
|
|
|
-const statistics = reactive({});
|
|
|
-const getCount = () => {
|
|
|
- getRepairCount().then((res) => {
|
|
|
- statistics.total = res.data.maintainStatus?.finished || 0;
|
|
|
- statistics.todo = res.data.maintainStatus?.tx || 0;
|
|
|
- statistics.average = 4.8;
|
|
|
- });
|
|
|
-};
|
|
|
-const currentRepairItem = ref(null); // 当前操作的工单项
|
|
|
-const repairMethodForm = ref({
|
|
|
- // 表单数据
|
|
|
- maintainMethod: "",
|
|
|
- remark: "",
|
|
|
-});
|
|
|
-const chooseMethodRef = ref(null); // 控制弹窗显示
|
|
|
-
|
|
|
-const selectedValue = ref(null);
|
|
|
-const changeMethod = (item) => {
|
|
|
- console.log("选择维修方式的工单项", item);
|
|
|
- // 打开弹窗前先初始化表单数据
|
|
|
- currentRepairItem.value = item;
|
|
|
- repairMethodForm.value.maintainMethod = "";
|
|
|
- repairMethodForm.value.remark = "";
|
|
|
- chooseMethodRef.value.open();
|
|
|
-};
|
|
|
-
|
|
|
-const submitRepairMethod = () => {
|
|
|
- if (!repairMethodForm.value.maintainMethod) {
|
|
|
- uni.showToast({
|
|
|
- title: "请选择维修方式",
|
|
|
- icon: "none",
|
|
|
- });
|
|
|
- return;
|
|
|
- }
|
|
|
- if (!repairMethodForm.value.remark) {
|
|
|
- uni.showToast({
|
|
|
- title: "请输入备注说明",
|
|
|
- icon: "none",
|
|
|
- });
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- // 调用接口
|
|
|
- maintainMethod({
|
|
|
- id: currentRepairItem.value.id,
|
|
|
- maintainMethod: repairMethodForm.value.maintainMethod,
|
|
|
- remark: repairMethodForm.value.remark,
|
|
|
- })
|
|
|
- .then((res) => {
|
|
|
- uni.showToast({
|
|
|
- title: "提交成功",
|
|
|
- icon: "success",
|
|
|
- });
|
|
|
- chooseMethodRef.value.close();
|
|
|
- // 可选:刷新列表或更新当前项状态
|
|
|
- onSearch(); // 刷新列表
|
|
|
- })
|
|
|
- .catch((err) => {
|
|
|
- uni.showToast({
|
|
|
- title: "提交失败",
|
|
|
- icon: "none",
|
|
|
- });
|
|
|
- });
|
|
|
-};
|
|
|
-
|
|
|
-const cancelRepairMethod = () => {
|
|
|
- chooseMethodRef.value.close();
|
|
|
- repairMethodForm.value.maintainMethod = "";
|
|
|
- repairMethodForm.value.remark = "";
|
|
|
- selectedValue.value = null;
|
|
|
-};
|
|
|
-const onPickerChange = (e) => {
|
|
|
- const selectedIndex = e.detail.value;
|
|
|
- selectedValue.value = selectedIndex;
|
|
|
-
|
|
|
- // 通过索引找到对应的 value
|
|
|
- const selectedLabel = methodOptions.value[selectedIndex];
|
|
|
- const selectedKey = Object.keys(methodOptionsMap).find(
|
|
|
- (key) => methodOptionsMap[key] === selectedLabel,
|
|
|
- );
|
|
|
-
|
|
|
- repairMethodForm.value.maintainMethod = selectedKey; // 设置表单值为 key
|
|
|
-};
|
|
|
-onShow(() => {
|
|
|
- getCount();
|
|
|
- nextTick(() => {
|
|
|
- onSearch();
|
|
|
- });
|
|
|
-});
|
|
|
-
|
|
|
-const onCreate = () => {
|
|
|
- uni.navigateTo({
|
|
|
- url: "/pages/repair/create",
|
|
|
- });
|
|
|
-};
|
|
|
-const onEdit = (item) => {
|
|
|
- uni.navigateTo({
|
|
|
- url: "/pages/repair/edit?id=" + item.id,
|
|
|
- });
|
|
|
-};
|
|
|
-const onView = (item) => {
|
|
|
- uni.navigateTo({
|
|
|
- url: "/pages/repair/detail?id=" + item.id,
|
|
|
- });
|
|
|
-};
|
|
|
-const navigatorBack = () => {
|
|
|
- uni.navigateBack();
|
|
|
-};
|
|
|
-
|
|
|
-const userInfo = ref({});
|
|
|
-const companyInfo = ref({});
|
|
|
-
|
|
|
-onMounted(async () => {
|
|
|
- userInfo.value = (await getLoginUserInfo()).data;
|
|
|
- companyInfo.value = await getDeptName(userInfo.value.dept.id);
|
|
|
-
|
|
|
- useDataDictStore().loadDataDictList();
|
|
|
-});
|
|
|
-</script>
|
|
|
-<style lang="scss" scoped>
|
|
|
-@import "@/style/work-order.scss";
|
|
|
-
|
|
|
-.popup-content {
|
|
|
- width: 500rpx;
|
|
|
- padding: 30rpx;
|
|
|
- background-color: #fff;
|
|
|
- border-radius: 16rpx;
|
|
|
-
|
|
|
- .popup-title {
|
|
|
- font-size: 36rpx;
|
|
|
- margin-bottom: 30rpx;
|
|
|
- text-align: center;
|
|
|
- }
|
|
|
-
|
|
|
- .form-item {
|
|
|
- margin-bottom: 40rpx;
|
|
|
-
|
|
|
- .label {
|
|
|
- color: red;
|
|
|
- font-size: 28rpx;
|
|
|
- margin-right: 10rpx;
|
|
|
- }
|
|
|
-
|
|
|
- .label-text {
|
|
|
- font-size: 28rpx;
|
|
|
- color: #333;
|
|
|
- }
|
|
|
-
|
|
|
- .picker-view {
|
|
|
- margin-top: 10rpx;
|
|
|
- padding: 20rpx;
|
|
|
- border: 1px solid #ccc;
|
|
|
- border-radius: 8rpx;
|
|
|
- font-size: 28rpx;
|
|
|
- }
|
|
|
-
|
|
|
- .textarea {
|
|
|
- width: 95.5%;
|
|
|
- height: 150rpx;
|
|
|
- padding: 10rpx;
|
|
|
- border: 1px solid #ccc;
|
|
|
- border-radius: 8rpx;
|
|
|
- font-size: 28rpx;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- .popup-footer {
|
|
|
- display: flex;
|
|
|
- justify-content: flex-end;
|
|
|
- gap: 30rpx;
|
|
|
-
|
|
|
- .btn-cancel {
|
|
|
- color: #333;
|
|
|
- border: none;
|
|
|
- }
|
|
|
-
|
|
|
- .btn-confirm {
|
|
|
- color: #007aff;
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-</style>
|
|
|
+<template>
|
|
|
+ <z-paging class="page repair" ref="paging" v-model="dataList" @query="queryList">
|
|
|
+ <!-- z-paging默认铺满全屏,此时页面所有view都应放在z-paging标签内,否则会被盖住 -->
|
|
|
+ <!-- 需要固定在页面顶部的view请通过slot="top"插入,包括自定义的导航栏 -->
|
|
|
+ <template #top>
|
|
|
+ <view class="page-top">
|
|
|
+ <view class="page-back"></view>
|
|
|
+ <view class="uni-page-head navgator justify-center align-center">
|
|
|
+ <view class="nav-back" @click="navigatorBack()">
|
|
|
+ <uni-icons type="left"></uni-icons>
|
|
|
+ </view>
|
|
|
+ <view class="nav-title">
|
|
|
+ {{ $t('equipmentMaintenance.title') }}
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view class="page-content">
|
|
|
+ <view class="content-search">
|
|
|
+ <uni-easyinput prefixIcon="search" confirmType="search" v-model="search" :placeholder="$t('common.searchHint')" @confirm="onSearch"></uni-easyinput>
|
|
|
+ </view>
|
|
|
+ <uni-row class="content-statistics flex-row align-center justify-around">
|
|
|
+ <!-- 已完成 -->
|
|
|
+ <uni-col class="statistics-item flex-col align-center">
|
|
|
+ <view class="statistics-count font-BiaoTiHei">
|
|
|
+ {{ statistics.total }}
|
|
|
+ </view>
|
|
|
+ <view class="statistics-title">
|
|
|
+ {{ $t('status.finished') }}
|
|
|
+ </view>
|
|
|
+ </uni-col>
|
|
|
+ <!-- 待填写 -->
|
|
|
+ <uni-col class="statistics-item flex-col align-center">
|
|
|
+ <view class="statistics-count font-BiaoTiHei">
|
|
|
+ {{ statistics.todo }}
|
|
|
+ </view>
|
|
|
+ <view class="statistics-title">
|
|
|
+ {{ $t('status.tobeFilled') }}
|
|
|
+ </view>
|
|
|
+ </uni-col>
|
|
|
+ <!-- 平均解决时间 -->
|
|
|
+ <uni-col class="statistics-item flex-col align-center">
|
|
|
+ <view class="statistics-count font-BiaoTiHei">
|
|
|
+ {{ statistics.average }}
|
|
|
+ </view>
|
|
|
+ <view class="statistics-title">
|
|
|
+ {{ $t('equipmentMaintenance.averageResolutionTime') }}
|
|
|
+ </view>
|
|
|
+ </uni-col>
|
|
|
+ </uni-row>
|
|
|
+ <button class="full-btn" type="primary" @click="onCreate">
|
|
|
+ <uni-icons type="plusempty"></uni-icons>
|
|
|
+ {{ $t('equipmentMaintenance.createButton') }}
|
|
|
+ </button>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </template>
|
|
|
+ <view class="paging-list">
|
|
|
+ <view class="item" v-for="(item, index) in dataList" :key="index">
|
|
|
+ <view class="item-module flex-row align-center justify-between" :class="{ tobeFilled: item.status == 'tx' }">
|
|
|
+ <view class="module-name">{{ $t('equipmentMaintenance.repairCode') }}: {{ item.failureCode }}</view>
|
|
|
+ <view class="module-status" :class="{ pending: item.status == 'tx' }" v-if="statusDict[item.status]">
|
|
|
+ <!-- 状态 -->
|
|
|
+ <span>{{ statusDict[item.status] }}</span>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view class="item-content">
|
|
|
+ <!-- 设备编号 -->
|
|
|
+ <view class="item-title flex-row">
|
|
|
+ <span class="item-title-width">{{ $t('device.deviceCode') }}:</span>
|
|
|
+ <span>{{ item.deviceCode }}</span>
|
|
|
+ </view>
|
|
|
+ <!-- 设备名称 -->
|
|
|
+ <view class="item-title flex-row">
|
|
|
+ <span class="item-title-width">{{ $t('device.deviceName') }}:</span>
|
|
|
+ <span>{{ item.deviceName }}</span>
|
|
|
+ </view>
|
|
|
+ <!-- 故障名称 -->
|
|
|
+ <view class="item-title flex-row">
|
|
|
+ <span class="item-title-width">{{ $t('fault.faultName') }}:</span>
|
|
|
+ <span>{{ item.failureName }}</span>
|
|
|
+ </view>
|
|
|
+ <!-- 故障时间 -->
|
|
|
+ <view class="item-title flex-row">
|
|
|
+ <span class="item-title-width">{{ $t('fault.faultTime') }}:</span>
|
|
|
+ <span>
|
|
|
+ {{ item.failureTime ? formatDate(item.failureTime) : '' }}
|
|
|
+ </span>
|
|
|
+ </view>
|
|
|
+ <!-- 维修开始时间 -->
|
|
|
+ <view class="item-title flex-row">
|
|
|
+ <span class="item-title-width">{{ $t('equipmentMaintenance.maintenanceStartTime') }}:</span>
|
|
|
+ <span>
|
|
|
+ {{ item.maintainStartTime ? formatDate(item.maintainStartTime) : '' }}
|
|
|
+ </span>
|
|
|
+ </view>
|
|
|
+ <!-- 执行时间 -->
|
|
|
+ <view class="item-title flex-row">
|
|
|
+ <span class="item-title-width">{{ $t('workOrder.executionTime') }}:</span>
|
|
|
+ <span>
|
|
|
+ {{ item.executeDate ? formatDate(item.executeDate) : '' }}
|
|
|
+ </span>
|
|
|
+ </view>
|
|
|
+ <!-- 审核状态 -->
|
|
|
+ <view class="item-title flex-row">
|
|
|
+ <span class="item-title-width">{{ $t('workOrder.auditStatus') }}:</span>
|
|
|
+ <span>{{ auditStatusDict[item.auditStatus] }}</span>
|
|
|
+ </view>
|
|
|
+ <!-- 是否停机 -->
|
|
|
+ <view class="item-title flex-row">
|
|
|
+ <span class="item-title-width">{{ $t('equipmentMaintenance.isStop') }}:</span>
|
|
|
+ <span :class="{ 'color-red': item.ifStop }">
|
|
|
+ {{ item.ifStop ? $t('operation.yes') : $t('operation.no') }}
|
|
|
+ </span>
|
|
|
+ </view>
|
|
|
+ <!-- 工单来源 -->
|
|
|
+ <view class="item-title flex-row">
|
|
|
+ <span class="item-title-width">{{ $t('workOrder.workOrderSource') }}:</span>
|
|
|
+ <span>{{ item.maintainType }}</span>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <view class="item-btn flex-row align-center justify-end" v-if="companyInfo.data !== 'rh'">
|
|
|
+ <button type="primary" :plain="false" v-if="item.status !== 'tx'" @click="onView(item)">
|
|
|
+ {{ $t('workOrder.viewDetails') }}
|
|
|
+ </button>
|
|
|
+ <button type="primary" v-else @click="onEdit(item)">
|
|
|
+ {{ $t('operation.fill') }}
|
|
|
+ </button>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view class="item-btn flex-row align-center justify-end" v-else>
|
|
|
+ <button type="primary" :plain="false" @click="onView(item)">
|
|
|
+ {{ $t('workOrder.viewDetails') }}
|
|
|
+ </button>
|
|
|
+
|
|
|
+ <button type="primary" :plain="false" v-if="item.status === 'personnel' && userInfo.id === item.maintainPerson" @click="changeMethod(item)">维修方式</button>
|
|
|
+
|
|
|
+ <button type="primary" @click="onEdit(item)" v-if="item.status === 'tx' && (item.auditStatus === 20 || item.auditStatus === null)">
|
|
|
+ {{ $t('operation.fill') }}
|
|
|
+ </button>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </z-paging>
|
|
|
+
|
|
|
+ <uni-popup type="dialog" ref="chooseMethodRef" @close="cancelRepairMethod">
|
|
|
+ <view class="popup-content">
|
|
|
+ <view class="popup-title">维修方式</view>
|
|
|
+ <view class="form-item">
|
|
|
+ <text class="label">*</text>
|
|
|
+ <text class="label-text">维修方式</text>
|
|
|
+ <picker @change="onPickerChange" :value="selectedValue" :range="methodOptions">
|
|
|
+ <view class="picker-view">
|
|
|
+ {{ methodOptions[selectedValue] || '请选择维修方式' }}
|
|
|
+ </view>
|
|
|
+ </picker>
|
|
|
+
|
|
|
+ <!-- <uni-data-select
|
|
|
+ :clear="false"
|
|
|
+ v-model="selectedValue"
|
|
|
+ :localdata="methodOptions"
|
|
|
+ @change="onPickerChange"
|
|
|
+ >
|
|
|
+ </uni-data-select> -->
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view class="form-item">
|
|
|
+ <text class="label">*</text>
|
|
|
+ <text class="label-text">备注说明</text>
|
|
|
+ <textarea v-model="repairMethodForm.remark" placeholder="请输入备注说明" class="textarea" maxlength="200"></textarea>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view class="popup-footer">
|
|
|
+ <view class="btn-cancel" @click="cancelRepairMethod">取消</view>
|
|
|
+ <view class="btn-confirm" @click="submitRepairMethod">确定</view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </uni-popup>
|
|
|
+</template>
|
|
|
+<script setup>
|
|
|
+import { ref, reactive, onMounted, nextTick } from 'vue';
|
|
|
+import { onShow } from '@dcloudio/uni-app';
|
|
|
+import { getRepairCount, getRepairList, maintainMethod } from '@/api/repair';
|
|
|
+import { getLoginUserInfo } from '@/api/login';
|
|
|
+import { getDeptName } from '@/api/recordFilling';
|
|
|
+import dayjs from 'dayjs';
|
|
|
+import { useDataDictStore } from '@/store/modules/dataDict';
|
|
|
+// 字典项
|
|
|
+const { getDataDictList } = useDataDictStore();
|
|
|
+// 状态
|
|
|
+const statusDict = reactive({});
|
|
|
+getDataDictList('pms_maintain_status').map((item) => {
|
|
|
+ statusDict[item.value] = item.label;
|
|
|
+});
|
|
|
+console.log('statusDict', statusDict);
|
|
|
+// 审核状态
|
|
|
+const auditStatusDict = reactive({});
|
|
|
+getDataDictList('crm_audit_status').map((item) => {
|
|
|
+ auditStatusDict[item.value] = item.label;
|
|
|
+});
|
|
|
+
|
|
|
+const methodOptions = ref([]); // 使用 ref 创建数组
|
|
|
+const methodOptionsMap = reactive({}); // 保存 value -> label 的映射
|
|
|
+
|
|
|
+getDataDictList('maintain_method').forEach((item) => {
|
|
|
+ methodOptions.value.push(item.label); // 只存储 label 用于显示
|
|
|
+ methodOptionsMap[item.value] = item.label;
|
|
|
+});
|
|
|
+console.log('auditStatusDict', auditStatusDict);
|
|
|
+
|
|
|
+// --- 列表 ---start---
|
|
|
+const search = ref('');
|
|
|
+const paging = ref(null);
|
|
|
+// v-model绑定的这个变量不要在分页请求结束中自己赋值,直接使用即可
|
|
|
+const dataList = ref([]);
|
|
|
+
|
|
|
+// @query所绑定的方法不要自己调用!!需要刷新列表数据时,只需要调用paging.value.reload()即可
|
|
|
+const queryList = (pageNo, pageSize) => {
|
|
|
+ // 此处请求仅为演示,请替换为自己项目中的请求
|
|
|
+ getRepairList({
|
|
|
+ pageNo,
|
|
|
+ pageSize,
|
|
|
+ commonParam: search.value
|
|
|
+ })
|
|
|
+ .then((res) => {
|
|
|
+ // 将请求结果通过complete传给z-paging处理,同时也代表请求结束,这一行必须调用
|
|
|
+ paging.value.complete(res.data.list);
|
|
|
+ })
|
|
|
+ .catch((res) => {
|
|
|
+ // 如果请求失败写paging.value.complete(false);
|
|
|
+ // 注意,每次都需要在catch中写这句话很麻烦,z-paging提供了方案可以全局统一处理
|
|
|
+ // 在底层的网络请求抛出异常时,写uni.$emit('z-paging-error-emit');即可
|
|
|
+ paging.value.complete(false);
|
|
|
+ });
|
|
|
+};
|
|
|
+const onSearch = () => {
|
|
|
+ paging.value.reload();
|
|
|
+};
|
|
|
+const formatDate = (time) => {
|
|
|
+ return dayjs(time).format('YYYY-MM-DD HH:mm:ss');
|
|
|
+};
|
|
|
+// -- end --
|
|
|
+// 获取顶部统计数量
|
|
|
+const statistics = reactive({});
|
|
|
+const getCount = () => {
|
|
|
+ getRepairCount().then((res) => {
|
|
|
+ statistics.total = res.data.maintainStatus?.finished || 0;
|
|
|
+ statistics.todo = res.data.maintainStatus?.tx || 0;
|
|
|
+ statistics.average = 4.8;
|
|
|
+ });
|
|
|
+};
|
|
|
+const currentRepairItem = ref(null); // 当前操作的工单项
|
|
|
+const repairMethodForm = ref({
|
|
|
+ // 表单数据
|
|
|
+ maintainMethod: '',
|
|
|
+ remark: ''
|
|
|
+});
|
|
|
+const chooseMethodRef = ref(null); // 控制弹窗显示
|
|
|
+
|
|
|
+const selectedValue = ref(null);
|
|
|
+const changeMethod = (item) => {
|
|
|
+ console.log('选择维修方式的工单项', item);
|
|
|
+ // 打开弹窗前先初始化表单数据
|
|
|
+ currentRepairItem.value = item;
|
|
|
+ repairMethodForm.value.maintainMethod = '';
|
|
|
+ repairMethodForm.value.remark = '';
|
|
|
+ chooseMethodRef.value.open();
|
|
|
+};
|
|
|
+
|
|
|
+const submitRepairMethod = () => {
|
|
|
+ if (!repairMethodForm.value.maintainMethod) {
|
|
|
+ uni.showToast({
|
|
|
+ title: '请选择维修方式',
|
|
|
+ icon: 'none'
|
|
|
+ });
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (!repairMethodForm.value.remark) {
|
|
|
+ uni.showToast({
|
|
|
+ title: '请输入备注说明',
|
|
|
+ icon: 'none'
|
|
|
+ });
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 调用接口
|
|
|
+ maintainMethod({
|
|
|
+ id: currentRepairItem.value.id,
|
|
|
+ maintainMethod: repairMethodForm.value.maintainMethod,
|
|
|
+ remark: repairMethodForm.value.remark
|
|
|
+ })
|
|
|
+ .then((res) => {
|
|
|
+ uni.showToast({
|
|
|
+ title: '提交成功',
|
|
|
+ icon: 'success'
|
|
|
+ });
|
|
|
+ chooseMethodRef.value.close();
|
|
|
+ // 可选:刷新列表或更新当前项状态
|
|
|
+ onSearch(); // 刷新列表
|
|
|
+ })
|
|
|
+ .catch((err) => {
|
|
|
+ uni.showToast({
|
|
|
+ title: '提交失败',
|
|
|
+ icon: 'none'
|
|
|
+ });
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+const cancelRepairMethod = () => {
|
|
|
+ chooseMethodRef.value.close();
|
|
|
+ repairMethodForm.value.maintainMethod = '';
|
|
|
+ repairMethodForm.value.remark = '';
|
|
|
+ selectedValue.value = null;
|
|
|
+};
|
|
|
+const onPickerChange = (e) => {
|
|
|
+ const selectedIndex = e.detail.value;
|
|
|
+ selectedValue.value = selectedIndex;
|
|
|
+
|
|
|
+ // 通过索引找到对应的 value
|
|
|
+ const selectedLabel = methodOptions.value[selectedIndex];
|
|
|
+ const selectedKey = Object.keys(methodOptionsMap).find((key) => methodOptionsMap[key] === selectedLabel);
|
|
|
+
|
|
|
+ repairMethodForm.value.maintainMethod = selectedKey; // 设置表单值为 key
|
|
|
+};
|
|
|
+onShow(() => {
|
|
|
+ getCount();
|
|
|
+ nextTick(() => {
|
|
|
+ onSearch();
|
|
|
+ });
|
|
|
+});
|
|
|
+
|
|
|
+const onCreate = () => {
|
|
|
+ uni.navigateTo({
|
|
|
+ url: '/pages/repair/create'
|
|
|
+ });
|
|
|
+};
|
|
|
+const onEdit = (item) => {
|
|
|
+ if (companyInfo.value.data === 'rh' && item.maintainPerson === userInfo.value.id && item.status === 'tx') {
|
|
|
+ uni.showToast({
|
|
|
+ title: '维修人员无法填写工单',
|
|
|
+ icon: 'none',
|
|
|
+ className: 'custom-toast' // 添加自定义类名
|
|
|
+ });
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ uni.navigateTo({
|
|
|
+ url: '/pages/repair/edit?id=' + item.id
|
|
|
+ });
|
|
|
+};
|
|
|
+const onView = (item) => {
|
|
|
+ uni.navigateTo({
|
|
|
+ url: '/pages/repair/detail?id=' + item.id
|
|
|
+ });
|
|
|
+};
|
|
|
+const navigatorBack = () => {
|
|
|
+ uni.navigateBack();
|
|
|
+};
|
|
|
+
|
|
|
+const userInfo = ref({});
|
|
|
+const companyInfo = ref({});
|
|
|
+
|
|
|
+onMounted(async () => {
|
|
|
+ userInfo.value = (await getLoginUserInfo()).data;
|
|
|
+ companyInfo.value = await getDeptName(userInfo.value.dept.id);
|
|
|
+
|
|
|
+ useDataDictStore().loadDataDictList();
|
|
|
+});
|
|
|
+</script>
|
|
|
+<style lang="scss" scoped>
|
|
|
+@import '@/style/work-order.scss';
|
|
|
+
|
|
|
+.popup-content {
|
|
|
+ width: 500rpx;
|
|
|
+ padding: 30rpx;
|
|
|
+ background-color: #fff;
|
|
|
+ border-radius: 16rpx;
|
|
|
+
|
|
|
+ .popup-title {
|
|
|
+ font-size: 36rpx;
|
|
|
+ margin-bottom: 30rpx;
|
|
|
+ text-align: center;
|
|
|
+ }
|
|
|
+
|
|
|
+ .form-item {
|
|
|
+ margin-bottom: 40rpx;
|
|
|
+
|
|
|
+ .label {
|
|
|
+ color: red;
|
|
|
+ font-size: 28rpx;
|
|
|
+ margin-right: 10rpx;
|
|
|
+ }
|
|
|
+
|
|
|
+ .label-text {
|
|
|
+ font-size: 28rpx;
|
|
|
+ color: #333;
|
|
|
+ }
|
|
|
+
|
|
|
+ .picker-view {
|
|
|
+ margin-top: 10rpx;
|
|
|
+ padding: 20rpx;
|
|
|
+ border: 1px solid #ccc;
|
|
|
+ border-radius: 8rpx;
|
|
|
+ font-size: 28rpx;
|
|
|
+ }
|
|
|
+
|
|
|
+ .textarea {
|
|
|
+ width: 95.5%;
|
|
|
+ height: 150rpx;
|
|
|
+ padding: 10rpx;
|
|
|
+ border: 1px solid #ccc;
|
|
|
+ border-radius: 8rpx;
|
|
|
+ font-size: 28rpx;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .popup-footer {
|
|
|
+ display: flex;
|
|
|
+ justify-content: flex-end;
|
|
|
+ gap: 30rpx;
|
|
|
+
|
|
|
+ .btn-cancel {
|
|
|
+ color: #333;
|
|
|
+ border: none;
|
|
|
+ }
|
|
|
+
|
|
|
+ .btn-confirm {
|
|
|
+ color: #007aff;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|