| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737 |
- <template>
- <u-popup
- :show="visible"
- mode="bottom"
- :round="10"
- :closeOnClickOverlay="false"
- @close="handleClose"
- class="patrol-popup"
- >
- <view class="popup-content">
- <!-- 头部 -->
- <view class="popup-header">
- <text class="popup-title">{{ dialogTitle }}</text>
- <view class="close-btn" @click="handleClose">×</view>
- </view>
- <!-- ===== 工单列表 ===== -->
- <template v-if="mode === 'order'">
- <scroll-view
- class="popup-body"
- scroll-y
- @scrolltolower="loadMoreOrders"
- >
- <view
- v-for="(item, index) in orderList"
- :key="item.id || item.code"
- class="card-wrapper"
- >
- <myCard
- :item="item"
- :index="index + 1"
- :columns="currentOrderColumns"
- :title="item.code || item.planCode"
- :status="getOrderStatusLabel(item.orderStatus)"
- :showRadio="true"
- :radioValue="selectedOrderId"
- @radioChange="onOrderSelect"
- :showDetail="false"
- />
- </view>
- <view style="height: 20rpx"></view>
- <view v-if="loadingOrder" class="load-more">加载中...</view>
- <view v-if="orderIsEnd && orderList.length > 0" class="load-more"
- >没有更多了</view
- >
- <u-empty
- class="no-data"
- v-if="!loadingOrder && orderList.length === 0"
- text="暂无工单"
- />
- </scroll-view>
- </template>
- <!-- ===== 设备列表 ===== -->
- <template v-if="mode === 'device'">
- <scroll-view class="popup-body" scroll-y>
- <view class="device-tip">请选择该工单对应的设备</view>
- <view
- v-for="(item, index) in deviceList"
- :key="index"
- class="card-wrapper"
- >
- <myCard
- :item="item"
- :index="index + 1"
- :columns="deviceColumns"
- :showDetail="false"
- :title="(item.substance && item.substance.name) || '设备'"
- :showRadio="true"
- :radioValue="selectedDeviceId"
- @radioChange="onDeviceSelect"
- />
- </view>
- <view style="height: 20rpx"></view>
- <u-empty
- class="no-data"
- v-if="deviceList.length === 0"
- text="暂无设备"
- />
- </scroll-view>
- </template>
- <!-- 底部按钮 -->
- <view class="popup-footer">
- <view class="footer-left">
- <text class="selected-info" v-if="mode === 'order' && selectedOrder">
- 已选:{{ selectedOrder.planName || selectedOrder.code }}
- </text>
- <text
- class="selected-info"
- v-else-if="mode === 'device' && selectedDevice"
- >
- 已选:{{
- (selectedDevice.substance && selectedDevice.substance.name) ||
- "设备"
- }}
- </text>
- <text class="selected-info" v-else>请选择一条记录</text>
- </view>
- <view class="footer-right">
- <u-button type="default" size="small" @click="handleClose"
- >取消</u-button
- >
- <u-button
- type="primary"
- size="small"
- :disabled="!canConfirm"
- @click="handleConfirm"
- >确定</u-button
- >
- </view>
- </view>
- </view>
- <u-toast ref="uToast" />
- </u-popup>
- </template>
- <script>
- import myCard from "@/components/myCard.vue";
- import {
- getWorkOrderPage,
- getWordOrderDetail,
- getWorkOrderDetail,
- getWorkOrderList,
- getAssetInfo,
- } from "@/api/hazardManagement/patrol.js";
- export default {
- components: {
- myCard,
- },
- data() {
- return {
- visible: false,
- loading: false,
- // 模式:order-工单列表,device-设备列表
- mode: "order",
- // 工单类型:1-巡点检,2-保养,3-维修,5-量具送检
- type: 1,
- // 工单列表
- orderList: [],
- orderPage: 1,
- orderSize: 10,
- orderIsEnd: false,
- loadingOrder: false,
- // 选中的工单
- selectedOrder: null,
- selectedOrderId: null,
- // 设备列表
- deviceList: [],
- // 选中的设备
- selectedDevice: null,
- selectedDeviceId: null,
- // 缓存工单详情(用于设备选择后返回)
- cachedOrderDetail: null,
- };
- },
- computed: {
- dialogTitle() {
- if (this.mode === "device") {
- return "选择设备";
- }
- const map = {
- 1: "选择巡点检工单",
- 2: "选择设备保养工单",
- 3: "选择设备维修工单",
- 5: "选择量具送检工单",
- };
- return map[this.type] || "选择工单";
- },
- canConfirm() {
- if (this.mode === "order") {
- return !!this.selectedOrder;
- }
- return !!this.selectedDevice;
- },
- // 工单卡片列配置(根据 type 动态变化)
- currentOrderColumns() {
- const baseCols = [
- [
- {
- prop: "planCode",
- label: "计划单号",
- className: "perce100",
- },
- ],
- ];
- if (this.type === 1) {
- return [
- [
- {
- prop: "code",
- label: "工单单号",
- className: "perce100",
- },
- ],
- [
- {
- prop: "planCode",
- label: "计划单号",
- className: "perce100",
- },
- ],
- [
- {
- prop: "planName",
- label: "巡点检名称",
- className: "perce100",
- },
- ],
- [
- {
- prop: "ruleName",
- label: "规则名称",
- className: "perce100",
- },
- ],
- [
- {
- prop: "createTime",
- label: "生成时间",
- className: "perce100",
- },
- ],
- ];
- }
- if (this.type === 2) {
- return [
- [
- {
- prop: "code",
- label: "工单单号",
- className: "perce100",
- },
- ],
- [
- {
- prop: "planCode",
- label: "计划单号",
- className: "perce100",
- },
- ],
- [
- {
- prop: "planName",
- label: "保养名称",
- className: "perce100",
- },
- ],
- [
- {
- prop: "ruleName",
- label: "规则名称",
- className: "perce100",
- },
- ],
- [
- {
- prop: "createTime",
- label: "生成时间",
- className: "perce100",
- },
- ],
- ];
- }
- if (this.type === 3) {
- return [
- [
- {
- prop: "code",
- label: "工单编号",
- className: "perce100",
- },
- ],
- [
- {
- prop: "planCode",
- label: "计划单号",
- className: "perce100",
- },
- ],
- [
- {
- prop: "planName",
- label: "维修名称",
- className: "perce100",
- },
- ],
- [
- {
- prop: "substanceDetailVO",
- label: "设备名称",
- className: "perce100",
- formatter: (row) => {
- return (
- (row.substanceDetailVO && row.substanceDetailVO.name) || "-"
- );
- },
- },
- ],
- [
- {
- prop: "executeUserName",
- label: "执行人",
- className: "perce100",
- },
- ],
- ];
- }
- if (this.type === 5) {
- return [
- [
- {
- prop: "code",
- label: "工单单号",
- className: "perce100",
- },
- ],
- [
- {
- prop: "planCode",
- label: "计划单号",
- className: "perce100",
- },
- ],
- [
- {
- prop: "planName",
- label: "送检名称",
- className: "perce100",
- },
- ],
- [
- {
- prop: "ruleName",
- label: "规则名称",
- className: "perce100",
- },
- ],
- [
- {
- prop: "createTime",
- label: "生成时间",
- className: "perce100",
- },
- ],
- ];
- }
- return baseCols;
- },
- // 设备卡片列配置
- deviceColumns() {
- return [
- [
- {
- prop: "substance",
- label: "设备编号",
- className: "perce100",
- formatter: (row) => {
- return (row.substance && row.substance.codeNumber) || "-";
- },
- },
- ],
- [
- {
- prop: "substance",
- label: "设备名称",
- className: "perce100",
- formatter: (row) => {
- return (row.substance && row.substance.name) || "-";
- },
- },
- ],
- [
- {
- prop: "substance",
- label: "设备位置",
- className: "perce100",
- formatter: (row) => {
- return (row.substance && row.substance.positionNames) || "-";
- },
- },
- ],
- ];
- },
- },
- methods: {
- // ============ 外部调用 ============
- open(type = 1) {
- this.type = type;
- this.visible = true;
- this.mode = "order";
- this.resetState();
- this.loadOrders();
- },
- resetState() {
- this.orderList = [];
- this.orderPage = 1;
- this.orderIsEnd = false;
- this.loadingOrder = false;
- this.selectedOrder = null;
- this.selectedOrderId = null;
- this.deviceList = [];
- this.selectedDevice = null;
- this.selectedDeviceId = null;
- this.cachedOrderDetail = null;
- },
- // ============ 工单列表加载 ============
- async loadOrders() {
- if (this.loadingOrder || this.orderIsEnd) return;
- this.loadingOrder = true;
- try {
- const params = {
- pageNum: this.orderPage,
- size: this.orderSize,
- };
- let res;
- if (this.type === 3) {
- // 维修工单
- res = await getWorkOrderList({
- ...params,
- status: 4,
- type: this.type,
- });
- } else {
- // 其他工单
- res = await getWorkOrderPage({
- ...params,
- orderStatus: 3,
- type: this.type,
- });
- }
- const list = res.list || [];
- if (this.orderPage === 1) {
- this.orderList = list;
- } else {
- this.orderList = this.orderList.concat(list);
- }
- this.orderIsEnd =
- list.length < this.orderSize || this.orderList.length >= res.count;
- this.orderPage += 1;
- } catch (e) {
- console.error("加载工单失败", e);
- this.$refs.uToast.show({
- type: "error",
- message: "加载工单失败",
- });
- } finally {
- this.loadingOrder = false;
- }
- },
- loadMoreOrders() {
- if (!this.orderIsEnd && !this.loadingOrder) {
- this.loadOrders();
- }
- },
- // ============ 工单选择 ============
- onOrderSelect(item) {
- this.selectedOrder = item;
- this.selectedOrderId = item.id || item.code;
- },
- // ============ 设备选择 ============
- onDeviceSelect(item) {
- this.selectedDevice = item;
- this.selectedDeviceId =
- item.id || (item.substance && item.substance.id) || Date.now();
- },
- // ============ 确认选择 ============
- async handleConfirm() {
- if (this.mode === "order") {
- await this.handleOrderConfirm();
- } else {
- await this.handleDeviceConfirm();
- }
- },
- async handleOrderConfirm() {
- if (!this.selectedOrder) {
- this.$refs.uToast.show({
- type: "warning",
- message: "请选择一条工单",
- });
- return;
- }
- this.loading = true;
- try {
- let detail = null;
- let deviceList = [];
- if (this.type === 3) {
- // 维修工单:直接获取设备信息
- detail = await getWorkOrderDetail(this.selectedOrder.code);
- const deviceData = await getAssetInfo(
- detail.repairRequestResponse &&
- detail.repairRequestResponse.deviceId,
- );
- if (deviceData) {
- // 维修工单直接返回设备
- this.emitResult({
- substance: {
- id: deviceData.id,
- name: deviceData.name,
- codeNumber: deviceData.codeNumber,
- positionNames:
- (deviceData.deviceLocationName || "") +
- "-" +
- (deviceData.deviceDetailAddress || ""),
- },
- });
- this.loading = false;
- return;
- }
- this.$refs.uToast.show({
- type: "warning",
- message: "未找到设备信息",
- });
- this.loading = false;
- return;
- }
- // 巡点检、保养、量具送检
- detail = await getWordOrderDetail(this.selectedOrder.id);
- deviceList = (detail && detail.deviceList) || [];
- this.cachedOrderDetail = detail;
- if (deviceList.length === 0) {
- this.$refs.uToast.show({
- type: "warning",
- message: "该工单暂无设备信息",
- });
- this.loading = false;
- return;
- }
- if (deviceList.length === 1) {
- // 只有一个设备,直接返回
- this.emitResult(deviceList[0]);
- this.loading = false;
- return;
- }
- // 多个设备,切换到设备选择模式
- this.deviceList = deviceList;
- this.selectedDevice = null;
- this.selectedDeviceId = null;
- this.mode = "device";
- this.loading = false;
- } catch (e) {
- console.error("获取工单详情失败", e);
- this.$refs.uToast.show({
- type: "error",
- message: e.message || "获取详情失败",
- });
- this.loading = false;
- }
- },
- handleDeviceConfirm() {
- if (!this.selectedDevice) {
- this.$refs.uToast.show({
- type: "warning",
- message: "请选择一个设备",
- });
- return;
- }
- this.emitResult(this.selectedDevice);
- },
- // ============ 返回结果 ============
- emitResult(device) {
- const data = {
- sourceCode: this.selectedOrder.code || this.selectedOrder.id,
- sourceId: this.selectedOrder.id || this.selectedOrder.code,
- sourceName: this.selectedOrder.planName || this.selectedOrder.code,
- deviceList: device,
- };
- this.$emit("confirm", data);
- this.handleClose();
- },
- // ============ 状态标签 ============
- getOrderStatusLabel(status) {
- const map = {
- 0: "待接收",
- 1: "已接收",
- 2: "执行中",
- 3: "已完成",
- };
- return map[status] || status;
- },
- // ============ 关闭弹窗 ============
- handleClose() {
- this.visible = false;
- this.mode = "order";
- this.resetState();
- },
- },
- };
- </script>
- <style lang="scss" scoped>
- .patrol-popup {
- /deep/ .u-popup__content {
- border-radius: 32rpx 32rpx 0 0;
- overflow: hidden;
- }
- .popup-content {
- height: 75vh;
- display: flex;
- flex-direction: column;
- background: #f5f7fb;
- }
- // ===== 头部 =====
- .popup-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- padding: 30rpx 32rpx;
- background: #fff;
- border-bottom: 2rpx solid #eef2f6;
- flex-shrink: 0;
- .popup-title {
- font-size: 36rpx;
- font-weight: bold;
- color: #1f2b3c;
- }
- .close-btn {
- width: 60rpx;
- height: 60rpx;
- display: flex;
- align-items: center;
- justify-content: center;
- font-size: 52rpx;
- color: #8e9aae;
- line-height: 1;
- }
- }
- // ===== 列表主体 =====
- .popup-body {
- flex: 1;
- overflow-y: auto;
- padding: 16rpx 24rpx;
- background: #f5f7fb;
- .card-wrapper {
- margin-top: 20rpx;
- &:first-child {
- margin-top: 0;
- }
- }
- .device-tip {
- font-size: 28rpx;
- color: #8e9aae;
- padding: 20rpx 8rpx 8rpx;
- text-align: center;
- }
- .no-data {
- margin-top: 30vh;
- }
- .load-more {
- text-align: center;
- font-size: 26rpx;
- color: #aaa;
- padding: 30rpx 0 40rpx;
- }
- }
- // ===== 底部 =====
- .popup-footer {
- display: flex;
- justify-content: space-between;
- align-items: center;
- padding: 16rpx 24rpx;
- background: #fff;
- border-top: 2rpx solid #eef2f6;
- flex-shrink: 0;
- min-height: 90rpx;
- .footer-left {
- flex: 1;
- .selected-info {
- font-size: 28rpx;
- color: #2979ff;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- display: block;
- max-width: 340rpx;
- }
- }
- .footer-right {
- display: flex;
- gap: 16rpx;
- flex-shrink: 0;
- /deep/ .u-button {
- border-radius: 48rpx;
- padding: 0 32rpx;
- height: 64rpx;
- font-size: 26rpx;
- }
- /deep/ .u-button--primary {
- background: #2979ff;
- }
- /deep/ .u-button--primary.u-button--disabled {
- background: #ccc;
- color: #999;
- }
- }
- }
- }
- </style>
|