Prechádzať zdrojové kódy

feat: 新增生产记录报工功能

添加生产记录、注汽检查、固废记录、质检记录及锅炉运行记录等页面及相关API接口
yusheng 3 mesiacov pred
rodič
commit
7da03d0361

+ 141 - 0
api/recordRules/index.js

@@ -0,0 +1,141 @@
+import {
+  get,
+  put,
+  putJ,
+  postJ,
+  deleteApi
+} from "@/utils/request";
+import Vue from "vue";
+
+// /main/recordrules/getById/{id} 查看详情
+export async function recordrulesGetById(id) {
+  const res = await get(Vue.prototype.apiUrl + `/main/recordrules/getById/${id}`);
+  if (res.code == 0) {
+    return res.data;
+  }
+  return Promise.reject(new Error(res.message));
+}
+
+// 规则记录分页查询
+export async function recordrulesPage(body) {
+  const res = await postJ(Vue.prototype.apiUrl + `/main/recordrules/page`, body);
+  if (res.code == 0) {
+    return res.data;
+  }
+  return Promise.reject(new Error(res.message));
+}
+
+// 规则记录分页查询 过程控制 /main/recordrules/notProduceTaskConfigRecordRulesPage
+export async function recordrulesNotProduceTaskConfigRecordRulesPage(body) {
+  const res = await postJ(
+    Vue.prototype.apiUrl + `/main/recordrules/processInspectionRecordRulesPage`,
+    body
+  );
+  if (res.code == 0) {
+    return res.data;
+  }
+  return Promise.reject(new Error(res.message));
+}
+
+// 记录计划配置 计划
+export async function recordrulesplanPage(params) {
+  const res = await get(Vue.prototype.apiUrl + `/pcs/recordRulesPlan/page`, params);
+  if (res.code == 0) {
+    return res.data;
+  }
+  return Promise.reject(new Error(res.message));
+}
+
+export async function recordrulesplanDelete(ids) {
+  const res = await deleteApi(Vue.prototype.apiUrl + `/pcs/recordRulesPlan/delete`, ids);
+  if (res.code == 0) {
+    return res.data;
+  }
+  return Promise.reject(new Error(res.message));
+}
+
+// /mes/recordrulesplan/saveOrUpdate
+export async function save(body) {
+  const res = await postJ(Vue.prototype.apiUrl + `/pcs/recordRulesPlan/save`, body);
+  if (res.code == 0) {
+    return res.data;
+  }
+  return Promise.reject(new Error(res.message));
+}
+
+export async function update(body) {
+  const res = await putJ(Vue.prototype.apiUrl + `/pcs/recordRulesPlan/update`, body);
+  if (res.code == 0) {
+    return res.data;
+  }
+  return Promise.reject(new Error(res.message));
+}
+
+// 获取记录规则计划详情 /mes/recordrulesplan/getById/{id}
+export async function getRecordRulesPlanDetail(id) {
+  const res = await get(Vue.prototype.apiUrl + `/pcs/recordRulesPlan/getById/${id}`);
+  if (res.code == 0) {
+    return res.data;
+  }
+  return Promise.reject(new Error(res.message));
+}
+
+// /mes/recordrulesplan/revoke post 撤回
+export async function recordrulesplanRevoke(id) {
+  const res = await put(Vue.prototype.apiUrl + `/pcs/recordRulesPlan/revoke`, id);
+  if (res.code == 0) {
+    return res.data;
+  }
+  return Promise.reject(new Error(res.message));
+}
+
+// /mes/producetaskrulerecord/queryRecordWorkOrderPage
+export async function producetaskrulerecordQueryRecordWorkOrderPage(params) {
+  const res = await get(Vue.prototype.apiUrl + `/pcs/recordrulesorder/page`, params);
+  if (res.code == 0) {
+    return res.data;
+  }
+  return Promise.reject(new Error(res.message));
+}
+
+// /mes/recordrulesplan/manualDispatchOrder 手动派单
+export async function recordrulesplanManualDispatchOrder(body) {
+  const res = await put(Vue.prototype.apiUrl + `/pcs/recordRulesPlan/dispatchOrder`, body);
+  if (res.code == 0) {
+    return res.data;
+  }
+  return Promise.reject(new Error(res.message));
+}
+
+// /mes/recordrulesplan/reManualDispatchOrder
+export async function recordrulesplanReManualDispatchOrder(body) {
+  const res = await put(Vue.prototype.apiUrl + `/pcs/recordrulesorder/reassign`, body);
+  if (res.code == 0) {
+    return res.data;
+  }
+  return Promise.reject(new Error(res.message));
+}
+
+// /mes/producetaskrulerecord/saveOrUpdateAndSubmit 报工
+export async function producetaskrulerecordSaveOrUpdateAndSubmit(body) {
+  const res = await putJ(Vue.prototype.apiUrl + `/pcs/recordrulesorder/reportingWork`, body);
+  if (res.code == 0) {
+    return res.data;
+  }
+  return Promise.reject(new Error(res.message));
+}
+
+export async function getById(id) {
+  const res = await get(Vue.prototype.apiUrl + `/pcs/recordrulesorder/getById/${id}`);
+  if (res.code == 0) {
+    return res.data;
+  }
+  return Promise.reject(new Error(res.message));
+}
+
+export async function checkReportingWork(id) {
+  const res = await get(
+    Vue.prototype.apiUrl + `/pcs/recordrulesorder/checkReportingWork/${id}`
+  );
+  return res.code;
+}

+ 2 - 0
enum/dict.js

@@ -11,6 +11,8 @@ export default {
   质检标准类型: "quality_testing_code",
   取样类型: "quality_method_code",
   计量单位: "measuring_uint",
+  记录规则类型: 'record_sheet',
+
 };
 export const numberList = [
 

+ 1 - 1
manifest.json

@@ -10,7 +10,7 @@
             "proxy" : {
                 "/api" : {
                     // "target" : "http://192.168.1.110:18086/",
-                    "target" : "http://192.168.1.125:18086/",
+                    "target" : "http://192.168.1.251:18086/",
                     // "target" : "http://192.168.1.251:18086/",
                     // "target" : "http://192.168.1.251:18086/",
                     // "target" : "http://110.41.182.105/api/",

+ 40 - 0
pages.json

@@ -2619,6 +2619,46 @@
 				"navigationStyle": "custom",
 				"navigationBarTextStyle": "black"
 			}
+		},
+		{
+			"path": "pages/pcs/productionRecords",
+			"style": {
+				"navigationBarTitleText": "生产记录",
+				"navigationStyle": "custom",
+				"navigationBarTextStyle": "black"
+			}
+		},
+		{
+			"path": "pages/pcs/steamInjectionInspectionRecord",
+			"style": {
+				"navigationBarTitleText": "注汽检查记录",
+				"navigationStyle": "custom",
+				"navigationBarTextStyle": "black"
+			}
+		},
+		{
+			"path": "pages/pcs/solidWasteRecord",
+			"style": {
+				"navigationBarTitleText": "固废记录",
+				"navigationStyle": "custom",
+				"navigationBarTextStyle": "black"
+			}
+		},
+		{
+			"path": "pages/pcs/qualityTestRecords",
+			"style": {
+				"navigationBarTitleText": "质量检查检测记录",
+				"navigationStyle": "custom",
+				"navigationBarTextStyle": "black"
+			}
+		},
+		{
+			"path": "pages/pcs/boilerOperationRecord",
+			"style": {
+				"navigationBarTitleText": "锅炉运行记录",
+				"navigationStyle": "custom",
+				"navigationBarTextStyle": "black"
+			}
 		}
 	],
 	"tabBar": {

+ 43 - 0
pages/pcs/boilerOperationRecord.vue

@@ -0,0 +1,43 @@
+<template>
+	<view>
+		<list ref="listRef" pageName="boilerOperationRecord"></list>
+	</view>
+</template>
+
+<script>
+	import list from './list.vue'
+
+	export default {
+		components: {
+			list
+		},
+		mixins: [],
+		data() {
+			return {}
+		},
+		computed: {},
+		created() {
+			uni.$off('successInit')
+			uni.$on('successInit', (data) => {
+				this.$nextTick(() => {
+					this.$refs.listRef.successInit()
+				})
+			})
+		},
+		onUnload() {
+			uni.$off('successInit')
+		},
+		onLoad() {
+			this.$nextTick(() => {
+				this.$refs.listRef.getList()
+			})
+			uni.setNavigationBarColor({
+				frontColor: '#000000',
+			})
+		},
+		methods: {}
+	}
+</script>
+
+<style lang="scss" scoped>
+</style>

+ 371 - 0
pages/pcs/components/myCard.vue

@@ -0,0 +1,371 @@
+<template>
+  <view class="card_container">
+    <view class="card_box">
+      <!-- 标题区域 - 独立出来,宽度100% -->
+      <view class="header_box" v-if="title">
+        <view class="title_left">
+          <view class="round" v-if="index">{{ index }}</view>
+          <view class="orderId" :style="{ marginLeft: index ? '16rpx' : '' }">{{
+            title
+          }}</view>
+        </view>
+        <!-- 状态 - 固定在右上角 -->
+        <view class="status-tag" v-if="status">{{ status }}</view>
+      </view>
+
+      <view class="item_box rx-bc" v-for="(_item, i) in columns" :key="i">
+        <template v-for="val in _item">
+          <view
+            class="perce50"
+            :class="[val.className, { 'full-width': val.isFullWidth }]"
+            :style="val.style"
+            :key="val.prop"
+            v-if="!val.isNone"
+          >
+            <!-- 操作行 -->
+            <view class="item_one rx-sc" v-if="val.type == 'action'">
+              <view class="lable">{{ val.label }}</view>
+              <view class="text" style="flex-wrap: wrap">
+                <template v-for="(btn, bI) in btnList">
+                  <u-button
+                    :plain="true"
+                    :hairline="true"
+                    size="mini"
+                    :type="btn.btnType"
+                    v-if="judge(btn)"
+                    :text="btn.name"
+                    @click="action(btn)"
+                    :key="bI"
+                  ></u-button>
+                </template>
+              </view>
+            </view>
+
+            <!-- 普通信息行 -->
+            <view class="item_one rx-sc kk" v-else>
+              <view class="lable">{{ val.label }}</view>
+              <view class="text" :class="val.valueClass" v-if="val.formatter">{{
+                val.formatter(item) || ""
+              }}</view>
+              <view class="text" :class="val.valueClass" v-else-if="val.slot">
+                <slot :name="val.slot"></slot>
+              </view>
+              <view class="text" :class="val.valueClass" v-else>{{
+                item[val.prop] || ""
+              }}</view>
+            </view>
+          </view>
+        </template>
+      </view>
+
+      <!-- 查看详情 -->
+      <view class="footer-link" v-if="showDetail" @click="goDetail">
+        <text>查看详情</text>
+        <u-icon name="arrow-right" size="24" color="#999999"></u-icon>
+      </view>
+    </view>
+  </view>
+</template>
+
+<script>
+export default {
+  props: {
+    btnList: {
+      type: Array,
+      default: () => [],
+    },
+    item: {
+      type: Object,
+      default: () => ({}),
+    },
+    columns: {
+      type: Array,
+      default: () => [],
+    },
+    title: {
+      type: String,
+      default: "",
+    },
+    status: {
+      type: String,
+      default: "",
+    },
+    index: "",
+    showDetail: {
+      type: Boolean,
+      default: true,
+    },
+  },
+  computed: {
+    judge() {
+      return (item) => {
+        if (item.judge) {
+          let is = true;
+          item.judge.forEach(({ key, value, authorities, fn }) => {
+            if (authorities) {
+              is = this.$isAuthorities(authorities);
+            }
+            if (value && !value.includes(this.item[key])) {
+              is = false;
+            }
+            if (fn) {
+              is = fn(this.item);
+            }
+          });
+          return is;
+        } else {
+          return true;
+        }
+      };
+    },
+  },
+  data() {
+    return {};
+  },
+  methods: {
+    action(item) {
+      if (item.type == 1) {
+        uni.navigateTo({
+          url: item.pageUrl + "?id=" + this.item.id + (item.query || ""),
+        });
+      } else {
+        this.$emit(item.apiName);
+      }
+    },
+    goDetail() {
+      this.$emit("goDetail", this.item);
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+.card_container {
+  padding: 20rpx 24rpx;
+  background: #f5f5f5;
+}
+
+.card_box {
+  background: #ffffff;
+  border-radius: 16rpx;
+  padding: 28rpx;
+  box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.08);
+  position: relative;
+
+  .rx-bc {
+    display: flex;
+    align-items: flex-start;
+    flex-flow: row wrap;
+
+    > view {
+      margin-top: 28rpx;
+
+      &:first-child,
+      &:nth-child(2) {
+        margin-top: 0;
+      }
+    }
+  }
+
+  .rx-sc {
+    display: flex;
+    align-items: flex-start;
+  }
+
+  // 头部样式
+  .header_box {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    width: 100%;
+    position: relative;
+    background: linear-gradient(135deg, #e8f5e9 0%, #f1f8e9 100%);
+    padding: 20rpx 24rpx;
+    border-radius: 12rpx 12rpx 0 0;
+    margin: -28rpx -28rpx 28rpx -28rpx;
+    width: calc(100% + 56rpx);
+    box-sizing: border-box;
+    .round {
+      width: 44rpx;
+      height: 44rpx;
+      line-height: 44rpx;
+      border-radius: 50%;
+      background: $theme-color;
+      color: #fff;
+      text-align: center;
+      font-size: 24rpx;
+      font-weight: 600;
+      flex-shrink: 0;
+    }
+
+    .orderId {
+      color: #333333;
+      font-size: 32rpx;
+      font-weight: 600;
+      white-space: nowrap;
+      overflow: hidden;
+      text-overflow: ellipsis;
+    }
+
+    .title_left {
+      display: flex;
+      align-items: center;
+      flex: 1;
+      padding-right: 140rpx;
+      overflow: hidden;
+    }
+
+    // 状态标签
+    .status-tag {
+      background: #e3f2fd;
+      color: #2196f3;
+      font-size: 24rpx;
+      padding: 8rpx 20rpx;
+      border-radius: 24rpx;
+      font-weight: 500;
+      position: absolute;
+      top: 50%;
+      transform: translateY(-50%);
+      right: 24rpx;
+      z-index: 1;
+    }
+  }
+
+  .item_box {
+    .text {
+      display: flex;
+      flex: 1;
+
+      uni-button:after {
+        border: none;
+      }
+
+      uni-button {
+        width: 100rpx;
+        margin-left: 10rpx;
+        margin-right: 0;
+        color: #fff !important;
+        border: none;
+        background: #157a2c;
+        margin-top: 3px;
+      }
+    }
+
+    .kk .text {
+      overflow: hidden;
+      text-overflow: ellipsis;
+      white-space: nowrap;
+      display: block;
+    }
+
+    .item_one {
+      width: 100%;
+      font-size: 28rpx;
+      line-height: 44rpx;
+      display: flex;
+      align-items: flex-start;
+
+      .lable {
+        color: #666666;
+        flex-shrink: 0;
+        margin-right: 12rpx;
+        font-size: 28rpx;
+      }
+
+      .text {
+        color: #000;
+        font-size: 28rpx;
+        flex: 1;
+        white-space: nowrap;
+        overflow: hidden;
+        text-overflow: ellipsis;
+        min-width: 0;
+
+        // 高亮值样式
+        &.highlight {
+          color: #4caf50;
+        }
+      }
+    }
+
+    .gylx {
+      color: $theme-color;
+    }
+
+    .perce50 {
+      width: 50%;
+      box-sizing: border-box;
+      padding-right: 20rpx;
+
+      &:nth-child(2n) {
+        padding-right: 0;
+        padding-left: 20rpx;
+      }
+    }
+    .perce100 {
+      width: 100%;
+    }
+
+    .full-width {
+      width: 100% !important;
+      padding-left: 0 !important;
+      padding-right: 0 !important;
+    }
+  }
+
+  // 底部查看详情
+  .footer-link {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    margin-top: 28rpx;
+    padding-top: 24rpx;
+    border-top: 1rpx solid #f0f0f0;
+    color: #666666;
+    font-size: 28rpx;
+    cursor: pointer;
+
+    &:active {
+      opacity: 0.7;
+    }
+  }
+}
+
+/deep/.u-input {
+  padding: 0 !important;
+  height: 44rpx !important;
+  font-size: 26rpx !important;
+}
+
+/deep/.u-input__content__field-wrapper__field {
+  font-size: 26rpx !important;
+}
+
+/deep/.uni-date-editor--x .uni-date__icon-clear {
+  border: none !important;
+}
+
+/deep/.uni-date__x-input,
+/deep/.uni-date-x {
+  padding: 0 !important;
+  height: 44rpx !important;
+  font-size: 26rpx !important;
+}
+
+/deep/.input-value {
+  font-size: 26rpx !important;
+  height: 44rpx !important;
+
+  uni-text {
+    font-size: 26rpx !important;
+  }
+}
+
+/deep/.u-textarea {
+  padding: 2px !important;
+}
+
+/deep/.u-textarea__field {
+  font-size: 26rpx !important;
+}
+</style>

+ 1088 - 0
pages/pcs/components/workOrderReport.vue

@@ -0,0 +1,1088 @@
+<template>
+  <u-popup
+    :show="visible"
+    :round="0"
+    :closeOnClickOverlay="false"
+    :zIndex="99999"
+    @close="closePopup"
+    class="u-popup-my"
+  >
+    <view class="popup-content">
+      <view class="popup-header">
+        <text class="popup-title">{{ title }}</text>
+        <view class="close-btn" @click="closePopup">×</view>
+      </view>
+
+      <scroll-view class="popup-body" scroll-y>
+        <view class="page">
+          <view class="card-a">
+            <!-- 头部 -->
+            <view class="a-header">
+              <text class="a-main-title">{{ form.ruleName }}</text>
+              <view class="a-sub">
+                <text
+                  >📋
+                  {{
+                    getDictValue("记录规则类型", form.recordRulesClassify)
+                  }}</text
+                >
+              </view>
+            </view>
+            <!-- 基本信息网格 -->
+            <view class="info-grid">
+              <view class="info-item">
+                <text class="info-label">检查时间</text>
+                <uni-datetime-picker
+                  type="datetime"
+                  v-model="form.checkStartTime"
+                  :disabled="title == '详情'"
+                >
+                  <view class="info-value">{{
+                    form.checkStartTime || "请选择"
+                  }}</view>
+                </uni-datetime-picker>
+              </view>
+              <view class="info-item">
+                <text class="info-label">报工时间</text>
+
+                <uni-datetime-picker
+                  type="datetime"
+                  v-model="form.checkFinishTime"
+                  :disabled="title == '详情'"
+                >
+                  <view class="info-value">{{
+                    form.checkFinishTime || "请选择"
+                  }}</view>
+                </uni-datetime-picker>
+              </view>
+              <view class="info-item" v-if="!form.type">
+                <text class="info-label">部门</text>
+                <view
+                  class="info-value"
+                  :class="{ disabled: title == '详情' }"
+                  @click="title != '详情' && $refs.treePicker._show()"
+                  >{{ form.groupName || "请选择" }}</view
+                >
+              </view>
+              <view class="info-item" v-if="!form.type">
+                <text class="info-label">指定负责人</text>
+                <view
+                  class="info-value"
+                  :class="{ disabled: title == '详情' }"
+                  @click="title != '详情' && $refs.selector.open()"
+                  >{{
+                    form.executeUsers.map((item) => item.userName).toString() ||
+                    "请选择"
+                  }}</view
+                >
+              </view>
+              <view class="info-item" v-if="form.type">
+                <text class="info-label">班组</text>
+                <view class="info-value">{{ form.teamName }}</view>
+              </view>
+              <view class="info-item" v-if="form.type">
+                <text class="info-label">执行人</text>
+                <view
+                  class="info-value"
+                  :class="{ disabled: title == '详情' }"
+                  @click="title != '详情' && $refs.selector.open()"
+                  >{{
+                    form.executeUsers.map((item) => item.userName).toString() ||
+                    "请选择"
+                  }}</view
+                >
+              </view>
+              <view class="info-item" v-if="form.type">
+                <text class="info-label">场站</text>
+                <view
+                  class="info-value"
+                  :class="{ disabled: title == '详情' }"
+                  @click="title != '详情' && (showProductLineIdPicker = true)"
+                >
+                  {{ form.productLineName || "请选择" }}
+                </view>
+              </view>
+              <view
+                class="info-item"
+                v-if="pageName == 'steamInjectionInspectionRecord'"
+              >
+                <text class="info-label">甲方检查人</text>
+                <view
+                  class="info-value"
+                  :class="{ disabled: title == '详情' }"
+                  @click="title != '详情' && selectContactShow(17)"
+                  >{{ form.contactName || "请选择" }}</view
+                >
+              </view>
+              <view class="info-item" v-if="pageName == 'solidWasteRecord'">
+                <text class="info-label">处理方</text>
+                <view
+                  class="info-value"
+                  :class="{ disabled: title == '详情' }"
+                  @click="title != '详情' && selectContactShow(20)"
+                  >{{ form.supplierName || "请选择" }}</view
+                >
+              </view>
+              <view class="info-item" v-if="pageName == 'qualityTestRecords'">
+                <text class="info-label">甲方检查人</text>
+                <view
+                  class="info-value"
+                  :class="{ disabled: title == '详情' }"
+                  @click="title != '详情' && selectContactShow(17)"
+                  >{{ form.contactName || "请选择" }}</view
+                >
+              </view>
+            </view>
+            <!-- 运行参数记录区 -->
+            <view class="records-area">
+              <view class="section-header">
+                <view class="section-title">
+                  <text>📊 记录数据</text>
+                </view>
+              </view>
+              <!-- 批量操作按钮放在标题下方 -->
+              <view
+                class="batch-bar"
+                v-if="pageName != 'productionRecords' && title != '详情'"
+              >
+                <button class="btn btn-primary" @click="batchCheck">
+                  ✅ 批量检查
+                </button>
+                <button class="btn btn-secondary" @click="batchQualified">
+                  🏭 批量合格
+                </button>
+              </view>
+
+              <!-- 检查项列表 -->
+              <view
+                v-for="(item, idx) in form.detailList"
+                :key="idx"
+                class="check-item-a"
+              >
+                <view class="item-row1">
+                  <view class="item-info">
+                    <text class="item-name"
+                      >{{ idx + 1 }}. {{ item.paramValue }}
+                      {{ item.unitName ? "(" + item.unitName + ")" : "" }}</text
+                    >
+               
+                  </view>
+                </view>
+				<view class="item-row-input" v-if="item.substanceName">
+				  <text class="input-label">设备</text>
+				  <view class="item-input"> {{ item.substanceName }}</view>
+				
+				</view>
+                <!-- 描述/数量 -->
+                <view class="item-row-input">
+                  <text class="input-label">{{
+                    pageName == "qualityTestRecords" ? "描述" : "数量"
+                  }}</text>
+				
+
+                  <input
+                    class="item-input"
+                    v-model="item.num"
+                    type="text"
+                    placeholder="请输入数量"
+                    :disabled="title == '详情'"
+                  />
+                </view>
+                <view
+                  class="item-row-input"
+                  v-if="pageName == 'qualityTestRecords'"
+                >
+                  <text class="input-label">执行人</text>
+
+                  <uni-data-select
+                    :multiple="true"
+                    mode="multiple"
+                    v-model="item.executeUsersIds"
+                    :localdata="
+                      (form.executeUsers &&
+                        form.executeUsers.map((val) => {
+                          return { value: val.userId, text: val.userName };
+                        })) ||
+                      []
+                    "
+                    @change="executeUsersChange(idx)"
+                  ></uni-data-select>
+                </view>
+                <view
+                  class="item-actions"
+                  v-if="pageName != 'productionRecords'"
+                >
+                  <u-radio-group
+                    class="result-group"
+                    v-model="item.checkStatus"
+                    :disabled="title == '详情'"
+                  >
+                    <u-radio label="已检查" :name="1"></u-radio>
+                    <u-radio label="未检查" :name="0"></u-radio>
+                  </u-radio-group>
+                  <u-radio-group
+                    class="result-group"
+                    v-model="item.checkResult"
+                    :disabled="title == '详情'"
+                  >
+                    <u-radio label="合格" :name="1"></u-radio>
+                    <u-radio label="不合格" :name="0"></u-radio>
+                  </u-radio-group>
+                </view>
+              </view>
+            </view>
+          </view>
+        </view>
+      </scroll-view>
+      <view class="popup-footer">
+        <u-button type="default" @click="closePopup">关闭</u-button>
+        <u-button
+          type="primary"
+          @click="submit()"
+          v-if="title == '报工'"
+          :loading="loading"
+          >提交</u-button
+        >
+      </view>
+    </view>
+    <u-toast ref="uToast"></u-toast>
+
+    <ba-tree-picker
+      ref="treePicker"
+      key="verify"
+      :multiple="false"
+      @select-change="searchDeptNodeClick"
+      title="选择部门"
+      :localdata="classificationList"
+      valueKey="id"
+      textKey="name"
+      childrenKey="children"
+    />
+    <search-select
+      :multiple="true"
+      ref="selector"
+      v-model="form.executeUsersIds"
+      :data-list="
+        executorList.map((val) => {
+          return {
+            text: val.name,
+            value: val.id,
+          };
+        })
+      "
+      title="选择"
+      @confirm="executeIdListChange"
+    >
+    </search-select>
+    <!-- 场站 -->
+    <u-picker
+      :show="showProductLineIdPicker"
+      keyName="label"
+      :columns="[
+        productLineList.map((item) => {
+          return {
+            label: item.name,
+            value: item.id,
+          };
+        }),
+      ]"
+      @confirm="confirmProductLine"
+      @cancel="showProductLineIdPicker = false"
+    ></u-picker>
+
+    <!-- <u-picker
+      :show="showCheckUsersIds"
+      keyName="label"
+      mode="multiSelector"
+      :columns="[
+        form.executeUsers &&
+          form.executeUsers.map((item) => {
+            return {
+              label: item.userName,
+              value: item.userId,
+            };
+          }),
+      ]"
+      @confirm="confirmCheckUsersIds"
+      @cancel="showCheckUsersIds = false"
+    ></u-picker> -->
+  </u-popup>
+</template>
+
+<script>
+const formBaseData = {
+  id: null,
+  workshopArea: "",
+  workshopAreaId: null,
+  checkFinishTime: "",
+  checkStartTime: "",
+  checkValidity: null,
+  checkValidityUnit: "",
+  conclusion: null,
+  detailList: [],
+  deviceId: 0,
+  deviceName: "",
+  batchNo: "",
+  executeMethod: 0,
+  formingNum: 0,
+  itemType: 0,
+  produceRoutingId: 0,
+  produceRoutingName: "",
+  produceTaskConfigId: 0,
+  produceTaskId: 0,
+  produceTaskName: "",
+  productCode: "",
+  productModel: "",
+  productName: "",
+  recordRulesClassify: null,
+  recordTemplateStyle: null,
+  ruleId: 0,
+  ruleName: "",
+  reportWorkType: 0,
+  specification: "",
+  workOrderCode: "",
+  workOrderId: 0,
+  itemTaskName: "",
+  brandNo: "",
+  duration: null,
+  // 执行人
+  executeUsersIds: [],
+  executeUsers: [],
+  showProductLineIdPicker: false,
+  // 班组id
+  teamId: "",
+  groupId: null,
+  // 物料字段name
+  pickDetails: [],
+  // 本次产出明细
+  outputDetails: [],
+  recordRulesExecuteMethodId: null,
+  recordRulesExecuteMethodName: "",
+  // 	产出类型 1-原材料,2-在制品,3.BOM标准产出
+  outputType: 1,
+  type: 0,
+  contactName: "",
+  contactId: "",
+  supplierId: "",
+  supplierName: "",
+  productLineId: null,
+  productLineName: "",
+};
+import {
+  getById,
+  producetaskrulerecordSaveOrUpdateAndSubmit,
+} from "@/api/recordRules/index";
+import { getTeamPage } from "@/api/pda/workOrderHandover.js";
+import { getUserPage, listOrganizations } from "@/api/common.js";
+import { toTreeData } from "@/utils/utils.js";
+import { mapGetters } from "vuex";
+import searchSelect from "@/pages/salesServiceManagement/accessory/components/searchSelect.vue";
+
+export default {
+  data() {
+    return {
+      visible: false,
+      title: "",
+      loading: false,
+      butLoading: false,
+      checked: false,
+      teamUserList: [],
+      teamList: [],
+      teamAllList: [],
+      classificationList: [],
+      showProductLineIdPicker: false,
+      showCheckUsersIds: false,
+      executorList: [],
+      allTeamList: [],
+      productLineList: [],
+      currentIndex: "",
+      form: JSON.parse(JSON.stringify(formBaseData)),
+    };
+  },
+  computed: {
+    ...mapGetters(["getDictValue"]),
+  },
+  components: {
+    searchSelect,
+  },
+  props: {
+    pageName: "",
+  },
+  methods: {
+    async open(row, type) {
+      uni.$off("setSelectList");
+      uni.$on("setSelectList", (data) => {
+        console.log(data, "data");
+        if (data && data.length > 0) {
+          this.form.contactName = data[0].name;
+          this.form.contactId = data[0].id;
+          this.form.supplierName = data[0].name;
+          this.form.supplierId = data[0].id;
+        }
+      });
+
+      if (type == "edit") {
+        this.title = "报工";
+      } else {
+        this.title = "详情";
+      }
+      this.getTreeList();
+      await this.getOrderDetials(row.id);
+      this.visible = true;
+    },
+    cancel() {
+      this.form = {
+        ...JSON.parse(JSON.stringify(formBaseData)),
+      };
+
+      this.visible = false;
+    },
+    async getTreeList() {
+      const data = await listOrganizations({});
+      let treeList = toTreeData({
+        data: data || [],
+        idField: "id",
+        parentIdField: "parentId",
+      });
+      this.classificationList = treeList;
+    },
+    selectContactShow(type) {
+      uni.navigateTo({
+        url:
+          "/pages/saleManage/components/selectContact?isAll=" +
+          false +
+          "&contactType=" +
+          type,
+      });
+    },
+    confirmProductLine(e) {
+      this.form.productLineId = e.value[0].value;
+      this.form.productLineName = e.value[0].label;
+      this.showProductLineIdPicker = false;
+    },
+
+    closePopup() {
+      this.cancel();
+    },
+
+    handParent() {
+      this.$refs.parentListRef.open();
+    },
+    changeParent(data) {
+      this.form.contactName = data.name;
+      this.form.contactId = data.id;
+      this.form.supplierName = data.name;
+      this.form.supplierId = data.id;
+    },
+    // 获取工单详情
+    async getOrderDetials(id) {
+      try {
+        const data = await getById(id);
+        data.detailList = data.detailList.map((i) => {
+          i.toolNames = i.tools.map((j) => j.toolName).join(",");
+          if (i.checkUsers && i.checkUsers.length > 0) {
+            console.log("i.checkUsers", i.checkUsers);
+            i.checkUsersIds = i.checkUsers.map((j) => j.userId);
+          }
+
+          if (i.checkUsersIds?.length == 0 && data.executeUsers.length > 0) {
+            // 默认执行人作为检查人
+            i.checkUsersIds = data.executeUsers
+              .filter((i) => i.userId)
+              .map((j) => j.userId);
+            i.checkUsers = data.executeUsers
+              .filter((i) => i.userId)
+              .map((j) => {
+                return {
+                  teamId: j.teamId,
+                  teamName: j.teamName,
+                  userId: j.userId,
+                  userName: j.userName,
+                };
+              });
+          }
+          return i;
+        });
+        // this.$util.assignObject(this.form, data);
+        Object.assign(this.form, data);
+
+        this.form.executeUsersIds = this.form.executeUsers
+          .map((i) => i.userId)
+          .filter((i) => i); // 过滤掉 undefined
+
+        if (this.form.executeUsers.length > 0 && !this.form.type) {
+          this.form.groupId = this.form.executeUsers[0]?.groupId + "";
+          this.form.groupName = this.form.executeUsers[0]?.groupName;
+          if (this.form.groupId) {
+            this.searchDeptNodeClick(
+              this.form.groupId,
+              this.form.groupName,
+              "init",
+            );
+          }
+        }
+
+        if (!this.form.teamId && this.teamList.length > 0) {
+          this.form.teamId = this.teamList[0].id;
+        }
+
+        this.form.recordRulesClassify += "";
+
+        // 加载班组人员列表
+        if (this.form.teamId && this.form.type) {
+          await this.getAllTeamList();
+
+          const index = this.allTeamList.findIndex(
+            (item) => item.id == this.form.teamId,
+          );
+          this.executorList = this.allTeamList[index].userVOList;
+
+          this.productLineList = [];
+
+          this.allTeamList[index].factoryWorkstationVOList.forEach((item) => {
+            if (
+              !this.productLineList.find((p) => p.id === item.productionLineId)
+            ) {
+              this.productLineList.push({
+                name: item.productionLineName,
+                id: item.productionLineId,
+              });
+            }
+          });
+        }
+
+        this.$nextTick(() => {
+          this.loading = false;
+        });
+      } catch (error) {
+        console.log("error", error);
+        this.loading = false;
+      }
+    },
+    checkTeamList(id) {
+      const index = this.teamList.findIndex((item) => item.id == id);
+      this.teamUserList = this.teamAllList[index];
+      this.form.teamName = this.teamList[index].name;
+      console.log("this.teamUserList", this.teamUserList);
+    },
+
+    // 批量检查
+    batchCheck() {
+      this.form.detailList.forEach((i, index) => {
+        this.$set(this.form.detailList[index], "checkStatus", 1);
+      });
+    },
+    // 批量合格
+    batchQualified() {
+      this.form.detailList.forEach((i, index) => {
+        this.$set(this.form.detailList[index], "checkResult", 1);
+      });
+    },
+
+    executeUsersChange(index) {
+      const checkUsersIds = this.form.dataList[index].checkUsersIds;
+      const checkUsers = checkUsersIds.map((i) => {
+        const user = this.form.executeUsers.find((item) => item.userId === i);
+        return user;
+      });
+      this.$set(this.form.dataList[index], "checkUsers", checkUsers);
+    },
+
+    // 获取审核人列表、巡点检人员
+    async getUserList(params) {
+      try {
+        let data = {
+          pageNum: 1,
+          size: -1,
+        };
+        // 如果传了参数就是获取部门人员数据
+        if (params) {
+          data = Object.assign(data, params);
+        }
+        const res = await getUserPage(data);
+        if (params) {
+          this.executorList = res.list;
+        }
+      } catch (error) {}
+    },
+    //选择部门(搜索)
+    async searchDeptNodeClick(id, name, type) {
+      this.form.groupId = id;
+      this.form.groupName = name;
+      if (id) {
+        // 根据部门获取人员
+        const params = {
+          groupId: id,
+        };
+        await this.getUserList(params);
+      } else {
+        this.form.groupId = null;
+      }
+      if (type != "init") {
+        this.form.detailList.forEach((detail) => {
+          detail.checkUsersIds = [];
+          detail.checkUsers = [];
+        });
+        this.form.executeUsers = [];
+        this.form.executeUsersIds = [];
+      }
+    },
+    // 负责人变更 同步执行人列表
+    executeIdListChange() {
+      console.log(this.form.executeUsersIds, "this.form.executeUsersIds");
+      this.form.executeUsers = this.form.executeUsersIds
+        .map((userId) => {
+          const user = this.executorList.find((u) => u.id === userId);
+          if (!user) return null;
+          return {
+            userId: user.id,
+            userName: user.name,
+            groupId: user.groupId,
+            groupName: user.groupName,
+          };
+        })
+        .filter((i) => i);
+      // 同步详情执行人
+      this.form.detailList.forEach((detail) => {
+        detail.checkUsersIds = this.form.executeUsersIds;
+        detail.checkUsers = this.form.executeUsers;
+      });
+      console.log("this.form.executeUsers", this.form.executeUsers);
+    },
+    async getAllTeamList() {
+      const { list } = await getTeamPage({
+        pageNum: 1,
+        size: -1,
+      });
+      console.log("teamAllList 班组", list);
+      this.allTeamList = list;
+    },
+
+    // 提交
+    async submit() {
+      // 验证检查时间和报工时间必填
+      if (!this.form.checkStartTime) {
+        this.$refs.uToast.show({
+          type: "error",
+          icon: false,
+          message: `请选择检查时间`,
+        });
+        return;
+      }
+      if (!this.form.checkFinishTime) {
+        this.$refs.uToast.show({
+          type: "error",
+          icon: false,
+          message: `请选择报工时间`,
+        });
+        return;
+      }
+      // 验证报工时间必须大于等于检查时间
+      const startTime = new Date(this.form.checkStartTime).getTime();
+      const finishTime = new Date(this.form.checkFinishTime).getTime();
+      if (finishTime < startTime) {
+        this.$refs.uToast.show({
+          type: "error",
+          icon: false,
+          message: `报工时间不能早于检查时间`,
+        });
+        return;
+      }
+
+      if (this.form.executeUsersIds.length == 0) {
+        this.$refs.uToast.show({
+          type: "error",
+          icon: false,
+          message: `请选择执行人`,
+        });
+        return;
+      }
+
+      // 报工需要验证 缓存不验证 排除 recordTemplateStyle ==3 物料添加 == 4生产统计 模板
+      if (this.pageName != "productionRecords") {
+        // 验证检查项目
+        const detailRequired = this.form.detailList.some((i) => {
+          return i.checkResult == null || i.checkStatus == null;
+        });
+
+        if (detailRequired) {
+          this.$refs.uToast.show({
+            type: "error",
+            icon: false,
+            message: `请先完善、检查情况、检查结果`,
+          });
+          return;
+        }
+      }
+      const body = JSON.parse(JSON.stringify(this.form));
+
+      try {
+        await producetaskrulerecordSaveOrUpdateAndSubmit(body);
+        this.$emit("refresh");
+        this.closePopup();
+      } catch (error) {
+        console.log(error, "dsdsd");
+      }
+    },
+  },
+};
+</script>
+
+<style scoped lang="scss">
+.popup-content {
+  width: 100vw;
+  height: calc(100vh - 100px);
+  background: #fff;
+  border-radius: 0;
+  display: flex;
+  background-color: #eff2f7;
+  flex-direction: column;
+}
+
+.popup-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 30rpx;
+  border-bottom: 1rpx solid #e5e5e5;
+
+  .popup-title {
+    font-size: 36rpx;
+    font-weight: bold;
+    color: #333;
+  }
+
+  .close-btn {
+    width: 60rpx;
+    height: 60rpx;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    font-size: 60rpx;
+    color: #999;
+    line-height: 1;
+  }
+}
+
+.popup-body {
+  flex: 1;
+  overflow-y: auto;
+  padding: 28rpx;
+}
+
+.page {
+  font-family:
+    system-ui,
+    -apple-system,
+    "Segoe UI",
+    Roboto,
+    Helvetica,
+    sans-serif;
+}
+
+.design-section {
+  /* margin-bottom: 60rpx; */
+}
+
+.design-header {
+  margin-bottom: 20rpx;
+  padding-left: 8rpx;
+}
+
+.design-title {
+  font-size: 44rpx;
+  font-weight: 800;
+  color: #1f2b3c;
+  display: block;
+}
+
+.design-desc {
+  font-size: 26rpx;
+  color: #6b7280;
+  margin-top: 6rpx;
+}
+
+/* 卡片白色风格 */
+.card-a {
+  background: #ffffff;
+  border-radius: 48rpx;
+  box-shadow: 0 12rpx 40rpx rgba(0, 0, 0, 0.05);
+  overflow: hidden;
+}
+
+.a-header {
+  padding: 40rpx 32rpx 24rpx;
+  border-bottom: 2rpx solid #f0f2f5;
+}
+
+.a-main-title {
+  font-size: 36rpx;
+  font-weight: 800;
+  background: linear-gradient(135deg, #1f2b3c, #2c3e50);
+  background-clip: text;
+  -webkit-background-clip: text;
+  color: transparent;
+  letter-spacing: -0.5rpx;
+}
+
+.a-sub {
+  font-size: 24rpx;
+  color: #8e9aae;
+  margin-top: 12rpx;
+  display: flex;
+  gap: 24rpx;
+}
+
+.info-grid {
+  padding: 30rpx 32rpx;
+  display: grid;
+  grid-template-columns: 1fr 1fr;
+  gap: 28rpx 20rpx;
+  // background: #fcfdfe;
+  border-bottom: 2rpx solid #f0f2f5;
+}
+
+.info-item {
+  display: flex;
+  flex-direction: column;
+  gap: 8rpx;
+}
+
+.info-label {
+  font-size: 26rpx;
+  font-weight: 600;
+  color: #6c7a91;
+  text-transform: uppercase;
+}
+
+.records-area {
+  padding: 16rpx 28rpx 32rpx;
+}
+
+.section-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin: 16rpx 0 20rpx 8rpx;
+}
+
+.section-title {
+  font-size: 36rpx;
+  font-weight: 700;
+  color: #1f2a44;
+  display: flex;
+  align-items: center;
+  gap: 16rpx;
+}
+
+.badge {
+  background: #eff3fa;
+  padding: 6rpx 20rpx;
+  border-radius: 60rpx;
+  font-size: 24rpx;
+  font-weight: normal;
+  color: #2c5f8a;
+}
+
+.device-card-a {
+  background: #f8fbfe;
+  border-radius: 36rpx;
+  padding: 20rpx 24rpx;
+  margin-bottom: 30rpx;
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  flex-wrap: wrap;
+  border: 2rpx solid #e9edf2;
+}
+
+.device-label {
+  font-weight: 700;
+  font-size: 28rpx;
+  color: #1f2a44;
+  background: #eff3fa;
+  padding: 8rpx 24rpx;
+  border-radius: 60rpx;
+}
+
+.device-input-a {
+  flex: 1;
+  min-width: 280rpx;
+  background: #ffffff;
+  border: 2rpx solid #dce3ec;
+  border-radius: 36rpx;
+  padding: 16rpx 24rpx;
+  font-size: 28rpx;
+}
+
+.check-item-a {
+  background: #ffffff;
+  border-radius: 36rpx;
+  padding: 24rpx 24rpx;
+  margin-bottom: 24rpx;
+  box-shadow:
+    0 4rpx 16rpx rgba(0, 0, 0, 0.02),
+    0 0 0 2rpx #edf2f7;
+}
+
+.item-row1 {
+  display: flex;
+  justify-content: space-between;
+  align-items: baseline;
+  flex-wrap: wrap;
+  margin-bottom: 20rpx;
+  gap: 16rpx;
+}
+
+.item-name {
+  font-weight: 620;
+  font-size: 30rpx;
+  color: #1f2a44;
+  background: #f5f7fb;
+  padding: 6rpx 20rpx;
+  border-radius: 50rpx;
+}
+
+.item-info {
+  display: flex;
+  flex-direction: column;
+  gap: 8rpx;
+}
+
+
+.item-row-input {
+  display: flex;
+  align-items: center;
+  gap: 16rpx;
+  margin-bottom: 20rpx;
+  padding: 0 8rpx;
+}
+
+.input-label {
+  font-size: 28rpx;
+  color: #555;
+  font-weight: 500;
+  white-space: nowrap;
+}
+
+.item-input {
+  // background: #f8fafe;
+  border: 2rpx solid #e2e8f0;
+  border-radius: 36rpx;
+  padding: 12rpx 24rpx;
+  font-size: 30rpx;
+  height: 60rpx;
+  flex: 1;
+  font-family: monospace;
+}
+
+.item-actions {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  flex-wrap: wrap;
+  gap: 20rpx;
+}
+
+.check-status,
+.result-group {
+  display: flex;
+  align-items: center;
+  gap: 24rpx;
+  background: #f8fafe;
+  padding: 8rpx 24rpx;
+  border-radius: 60rpx;
+  font-size: 28rpx;
+}
+
+/deep/.result-group {
+  .u-radio__text {
+    font-size: 28rpx !important;
+  }
+
+  .u-radio__icon-wrap {
+    width: 30rpx !important;
+    height: 30rpx !important;
+  }
+}
+
+.radio-label {
+  display: flex;
+  align-items: center;
+  gap: 8rpx;
+}
+
+.batch-bar {
+  display: flex;
+  gap: 16rpx;
+  margin: 16rpx 0 20rpx 8rpx;
+}
+
+.btn {
+  flex: 1;
+  text-align: center;
+  border-radius: 80rpx;
+  font-weight: 700;
+  font-size: 30rpx;
+  border: none;
+}
+
+.btn-primary {
+  background: #1e6f5c;
+  color: white;
+  box-shadow: 0 4rpx 12rpx rgba(30, 111, 92, 0.2);
+}
+
+.btn-secondary {
+  background: #2c7da0;
+  color: white;
+}
+
+.footnote {
+  font-size: 22rpx;
+  color: #8e9aab;
+  text-align: center;
+  margin-top: 16rpx;
+  display: block;
+}
+
+/* 修复组件样式 */
+radio,
+checkbox {
+  transform: scale(0.9);
+  margin-right: 6rpx;
+}
+
+button:after {
+  border: none;
+}
+
+.info-value {
+  font-size: 28rpx;
+  font-weight: 500;
+  color: #1e2a3a;
+  // background: #f2f5f9;
+  padding: 16rpx 20rpx;
+  border-radius: 24rpx;
+  border: 2rpx solid #e9edf2;
+
+  &.disabled {
+    color: #999;
+    background: #f5f5f5;
+  }
+}
+.popup-footer {
+  display: flex;
+  padding: 20rpx 30rpx;
+  border-top: 1rpx solid #e5e5e5;
+  gap: 20rpx;
+
+  /deep/ .u-button {
+    flex: 1;
+  }
+}
+/deep/.uni-select{
+	border-radius: 36rpx;
+
+}
+</style>

+ 340 - 0
pages/pcs/list.vue

@@ -0,0 +1,340 @@
+<template>
+  <view class="mainBox">
+    <uni-nav-bar
+      fixed="true"
+      statusBar="true"
+      left-icon="back"
+      :title="getTitle"
+      @clickLeft="back"
+    >
+    </uni-nav-bar>
+
+    <view class="top-wrapper">
+      <uni-section>
+        <uni-easyinput
+          prefixIcon="search"
+          style="width: 460rpx"
+          v-model="keyWord"
+          placeholder="工单单号,计划单号,记录规则名称"
+        >
+        </uni-easyinput>
+      </uni-section>
+      <button class="search_btn" @click="doSearch">搜索</button>
+    </view>
+    <div style="height: 100rpx; width: 475rpx"></div>
+    <view class="wrapper">
+      <u-list @scrolltolower="scrolltolower" class="listContent">
+        <view
+          v-for="(item, index) in tableList"
+          :key="index"
+          style="position: relative"
+        >
+          <myCard
+            :item="item"
+            :index="index + 1"
+            :btnList="btnList"
+            :columns="columns"
+            :title="item.code"
+            :status="statusMap[item.status]"
+            @goDetail="goDetail(item, 'view')"
+            @edit="goDetail(item, 'edit')"
+          >
+          </myCard>
+        </view>
+        <view style="width: 100%; height: 40rpx"></view>
+        <view style="margin-top: 20vh" v-if="tableList.length == 0">
+          <u-empty iconSize="150" textSize="32" text="暂无数据"> </u-empty>
+        </view>
+      </u-list>
+    </view>
+
+    <u-toast ref="uToast"></u-toast>
+    <workOrderReport
+      ref="workOrderReportRef"
+      :pageName="pageName"
+      @refresh="successInit"
+    ></workOrderReport>
+  </view>
+</template>
+
+<script>
+import dictMixns from "@/mixins/dictMixins";
+import myCard from "./components/myCard.vue";
+import workOrderReport from "./components/workOrderReport.vue";
+import { producetaskrulerecordQueryRecordWorkOrderPage } from "@/api/recordRules/index";
+export default {
+  components: {
+    myCard,
+    workOrderReport,
+  },
+  mixins: [dictMixns],
+  props: {
+    pageName: {
+      default: "",
+    },
+  },
+  data() {
+    return {
+      statusMap: {
+        0: "未报工",
+        1: "执行中",
+        2: "已执行",
+      },
+      planTypeList: {
+        productionRecords: 2,
+        steamInjectionInspectionRecord: 3,
+        solidWasteRecord: 4,
+        qualityTestRecords: 5,
+        boilerOperationRecord: 6,
+      },
+      btnList: [
+        {
+          name: "报工",
+          apiName: "edit",
+          btnType: "primary",
+
+          judge: [
+            {
+              key: "status",
+              value: [1],
+            },
+          ],
+        },
+      ],
+      columns: [
+        [
+          {
+            label: "计划单号:",
+            prop: "planCode",
+            className: "perce100",
+          },
+        ],
+        [
+          {
+            label: "记录规则名称:",
+            prop: "ruleName",
+            className: "perce100",
+          },
+        ],
+        [
+          {
+            label: "场站名称:",
+            className: "perce100",
+            prop: "productLineName",
+          },
+        ],
+        [
+          {
+            className: "perce100",
+            label: "班组:",
+            prop: "teamName",
+          },
+        ],
+        [
+          {
+            label: "工单生成时间:",
+            className: "perce100",
+            prop: "createTime",
+          },
+        ],
+        [
+          {
+            label: "检查时间:",
+            className: "perce100",
+            prop: "checkStartTime",
+          },
+        ],
+        [
+          {
+            label: "报工时间:",
+            className: "perce100",
+            prop: "checkFinishTime",
+          },
+        ],
+        [
+          {
+            label: "执行人:",
+            className: "perce100",
+            prop: "executeUsers",
+            formatter: (row) => {
+              return row.executeUsers.map((i) => i.userName).join(",");
+            },
+          },
+        ],
+        [
+          {
+            label: "甲方检查人:",
+            prop: "contactName",
+            isNone: this.pageName != "steamInjectionInspectionRecord",
+          },
+          {
+            label: "处理方:",
+            prop: "supplierName",
+            isNone: this.pageName != "solidWasteRecord",
+          },
+          {
+            label: "联合站检查人:",
+            prop: "contactName",
+            isNone: this.pageName != "qualityTestRecords",
+          },
+        ],
+        [
+          {
+            label: "操作:",
+            prop: "action",
+            type: "action",
+            className: "perce100",
+          },
+        ],
+      ].filter((item) => !item.isNone),
+
+      tableList: [],
+      page: 1,
+      size: 10,
+      isEnd: false,
+      keyWord: "",
+      userInfo: {},
+    };
+  },
+  computed: {
+    getTitle() {
+      return this.pageName == "productionRecords"
+        ? "生产记录"
+        : this.pageName == "steamInjectionInspectionRecord"
+          ? "注汽检查记录"
+          : this.pageName == "solidWasteRecord"
+            ? "固废记录"
+            : this.pageName == "qualityTestRecords"
+              ? "质量检查检测记录"
+              : "锅炉运行记录";
+    },
+  },
+  created() {
+    this.requestDict("记录规则类型");
+  },
+  onLoad() {},
+
+  methods: {
+    goDetail(item, type) {
+      console.log(item, "item");
+      this.$refs.workOrderReportRef.open(item, type);
+    },
+
+    successInit() {
+      uni.showLoading({
+        title: "加载中",
+      });
+
+      let data = {
+        pageNum: 1,
+        size: this.tableList.length,
+        keyword: this.keyWord,
+        planType: this.planTypeList[this.pageName],
+        currentLoginUserId: this.userInfo.userId,
+      };
+
+      producetaskrulerecordQueryRecordWorkOrderPage(data)
+        .then((res) => {
+          this.tableList = res.list;
+        })
+        .then(() => {
+          uni.hideLoading();
+        });
+    },
+    doSearch() {
+      this.isEnd = false;
+      this.page = 1;
+      this.getList();
+    },
+    //获取列表信息
+    getList() {
+      this.userInfo = uni.getStorageSync("userInfo");
+      if (this.isEnd || !this.userInfo.userId) {
+        return;
+      }
+      uni.showLoading({
+        title: "加载中",
+      });
+
+      let data = {
+        pageNum: this.page,
+        size: this.size,
+        keyword: this.keyWord,
+        planType: this.planTypeList[this.pageName],
+        currentLoginUserId: this.userInfo.userId,
+      };
+
+      producetaskrulerecordQueryRecordWorkOrderPage(data)
+        .then((res) => {
+          if (this.page === 1) {
+            this.tableList = res.list;
+          } else {
+            this.tableList.push(...res.list);
+          }
+          this.page += 1;
+          this.isEnd = this.tableList.length >= res.count;
+        })
+        .then(() => {
+          uni.hideLoading();
+        });
+    },
+    scrolltolower() {
+      if (this.isEnd) {
+        return;
+      }
+      this.getList();
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+.mainBox {
+  background-color: #f3f8fb;
+}
+
+// .wrapper{
+
+// }
+.top-wrapper {
+  background-color: #fff;
+  display: flex;
+  width: 750rpx;
+  height: 88rpx;
+  padding: 16rpx 32rpx;
+  align-items: center;
+  // gap: 16rpx;
+  position: absolute;
+  z-index: 999;
+  // top: 44px;
+  // // #ifdef APP-PLUS
+  // top: 140rpx;
+
+  // // #endif
+  /deep/.uni-section {
+    margin-top: 0px;
+  }
+
+  /deep/.uni-section-header {
+    padding: 0px;
+  }
+
+  .search_btn {
+    width: 120rpx;
+    height: 70rpx;
+    line-height: 70rpx;
+    padding: 0 24rpx;
+    background: $theme-color;
+    font-size: 32rpx;
+    color: #fff;
+    margin: 0;
+    margin-left: 26rpx;
+  }
+
+  .menu_icon {
+    width: 44rpx;
+    height: 44rpx;
+    margin-left: 14rpx;
+  }
+}
+</style>

+ 60 - 0
pages/pcs/productionRecords.vue

@@ -0,0 +1,60 @@
+<template>
+	<view>
+
+
+		<list ref="listRef" pageName="productionRecords"></list>
+
+	</view>
+</template>
+
+<script>
+	import list from './list.vue'
+
+	export default {
+		components: {
+			list
+		},
+		mixins: [],
+		data() {
+			return {
+
+
+
+
+			}
+		},
+		computed: {
+
+		},
+		created() {
+			uni.$off('successInit')
+			uni.$on('successInit', (data) => {
+				this.$nextTick(() => {
+					this.$refs.listRef.successInit()
+				})
+			})
+		},
+		onUnload() {
+		
+			uni.$off('successInit')
+		
+		},
+		onLoad() {
+			this.$nextTick(() => {
+				this.$refs.listRef.getList()
+			})
+			uni.setNavigationBarColor({
+			   frontColor: '#000000',
+			 });
+		},
+
+
+		methods: {
+
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+
+</style>

+ 43 - 0
pages/pcs/qualityTestRecords.vue

@@ -0,0 +1,43 @@
+<template>
+	<view>
+		<list ref="listRef" pageName="qualityTestRecords"></list>
+	</view>
+</template>
+
+<script>
+	import list from './list.vue'
+
+	export default {
+		components: {
+			list
+		},
+		mixins: [],
+		data() {
+			return {}
+		},
+		computed: {},
+		created() {
+			uni.$off('successInit')
+			uni.$on('successInit', (data) => {
+				this.$nextTick(() => {
+					this.$refs.listRef.successInit()
+				})
+			})
+		},
+		onUnload() {
+			uni.$off('successInit')
+		},
+		onLoad() {
+			this.$nextTick(() => {
+				this.$refs.listRef.getList()
+			})
+			uni.setNavigationBarColor({
+				frontColor: '#000000',
+			})
+		},
+		methods: {}
+	}
+</script>
+
+<style lang="scss" scoped>
+</style>

+ 43 - 0
pages/pcs/solidWasteRecord.vue

@@ -0,0 +1,43 @@
+<template>
+	<view>
+		<list ref="listRef" pageName="solidWasteRecord"></list>
+	</view>
+</template>
+
+<script>
+	import list from './list.vue'
+
+	export default {
+		components: {
+			list
+		},
+		mixins: [],
+		data() {
+			return {}
+		},
+		computed: {},
+		created() {
+			uni.$off('successInit')
+			uni.$on('successInit', (data) => {
+				this.$nextTick(() => {
+					this.$refs.listRef.successInit()
+				})
+			})
+		},
+		onUnload() {
+			uni.$off('successInit')
+		},
+		onLoad() {
+			this.$nextTick(() => {
+				this.$refs.listRef.getList()
+			})
+			uni.setNavigationBarColor({
+				frontColor: '#000000',
+			})
+		},
+		methods: {}
+	}
+</script>
+
+<style lang="scss" scoped>
+</style>

+ 43 - 0
pages/pcs/steamInjectionInspectionRecord.vue

@@ -0,0 +1,43 @@
+<template>
+	<view>
+		<list ref="listRef" pageName="steamInjectionInspectionRecord"></list>
+	</view>
+</template>
+
+<script>
+	import list from './list.vue'
+
+	export default {
+		components: {
+			list
+		},
+		mixins: [],
+		data() {
+			return {}
+		},
+		computed: {},
+		created() {
+			uni.$off('successInit')
+			uni.$on('successInit', (data) => {
+				this.$nextTick(() => {
+					this.$refs.listRef.successInit()
+				})
+			})
+		},
+		onUnload() {
+			uni.$off('successInit')
+		},
+		onLoad() {
+			this.$nextTick(() => {
+				this.$refs.listRef.getList()
+			})
+			uni.setNavigationBarColor({
+				frontColor: '#000000',
+			})
+		},
+		methods: {}
+	}
+</script>
+
+<style lang="scss" scoped>
+</style>

+ 1 - 2
pages/qms/inspectionWork/addSample.vue

@@ -299,8 +299,7 @@
 				<view class="popup-footer">
 					<u-button type="default" @click="closePopup">关闭</u-button>
 					<u-button type="primary" @click="save()" v-if="type != 'view'" :loading="loading">保存</u-button>
-					<!-- <u-button type="success" @click="save('submit')" v-if="type != 'view' && isSamplingApproval == 1"
-						:loading="loading">提交</u-button> -->
+			
 				</view>
 			</view>
 			<u-toast ref="uToast"></u-toast>

+ 469 - 417
pages/saleManage/components/selectContact.vue

@@ -1,424 +1,476 @@
 <template>
-	<view class="mainBox">
-		<uni-nav-bar fixed="true" statusBar="true" left-icon="back" title="选择" @clickLeft="backAdd">
-			<!--右菜单-->
-			<template slot="right">
-				<u-button type="success" size="small" class="u-reset-button" @click="$refs.treePicker._show()"
-					text="选择分类"></u-button>
-			</template>
-		</uni-nav-bar>
-		<view class="searchBox">
-			<input v-model="searchVal" placeholder="请输入名称" class="searchInput" />
-			<u-button type="icon-shixiangxinzeng" size="30" @click="doSearch" data-icon="Search" class="searchBtn">
-				<view class="iconfont icon-sousuo"></view>
-				<view class="text">搜索</view>
-			</u-button>
-		</view>
-		<view class="wrapper">
-			<u-list @scrolltolower="scrolltolower" class="listContent">
-				<checkbox-group v-for="(item, index) in listData" :key="index" @change="e => selectVal(e, item, index)">
-					<label>
-						<view class="listBox">
-							<view class="listBox-sel">
-								<checkbox :value="item.code" color="#fff" :disabled="item.disabled"
-									:checked="item.checked" />
-							</view>
-							<view class="listBox-con">
-								<view class="listBox-top">
-									<view class="listBox-name">
-										{{ item.name }}
-									</view>
-
-								</view>
-								<view class="listBox-bottom">
-									<!-- <view v-for="(itm, index) in tableHeader" :key="index">{{ itm.label }}:{{ item[itm.prop] }}</view> -->
-									<view>客户代号:{{ item.serialNo||'' }}</view>
-									<view>详细地址:{{(item.addressName||'')+item.address||''}}</view>
-									<view>是否指派:{{(item.assignStatus=== 1 ? '是' : '否')||''}}</view>
-									<view>销售员:{{item.salesmanName||''}}</view>
-									<view>创建人:{{item.createUsername||''}}</view>
-								</view>
-							</view>
-						</view>
-					</label>
-				</checkbox-group>
-				<u-empty class="noDate" style="margin-top: 20vh" v-if="!listData.length"></u-empty>
-			</u-list>
-		</view>
-
-		<view class="footer">
-			<view class="bottom" v-if="this.isAll==1">
-				<checkbox v-if="!seletedAll" color="#fff" :checked="seletedAll" @tap="_seletedAll">全选</checkbox>
-				<checkbox class="select-all" color="#fff" v-else :checked="seletedAll" @tap="_seletedAll">取消全选
-				</checkbox>
-			</view>
-			<u-button type="success" size="small" class="u-reset-button" :disabled="!checkListLen" @click="jumpAdd">
-				<view class="selBtn">选择( {{ checkListLen }} )</view>
-			</u-button>
-		</view>
-		<ba-tree-picker ref="treePicker" key="verify" :multiple="false" @select-change="confirm" title="选择分类"
-			:localdata="classificationList" valueKey="id" textKey="name" />
-	</view>
+  <view class="mainBox">
+    <uni-nav-bar
+      fixed="true"
+      statusBar="true"
+      left-icon="back"
+      title="选择"
+      @clickLeft="backAdd"
+    >
+      <!--右菜单-->
+      <template slot="right">
+        <u-button
+          type="success"
+          size="small"
+          class="u-reset-button"
+          @click="$refs.treePicker._show()"
+          text="选择分类"
+        ></u-button>
+      </template>
+    </uni-nav-bar>
+    <view class="searchBox">
+      <input v-model="searchVal" placeholder="请输入名称" class="searchInput" />
+      <u-button
+        type="icon-shixiangxinzeng"
+        size="30"
+        @click="doSearch"
+        data-icon="Search"
+        class="searchBtn"
+      >
+        <view class="iconfont icon-sousuo"></view>
+        <view class="text">搜索</view>
+      </u-button>
+    </view>
+    <view class="wrapper">
+      <u-list @scrolltolower="scrolltolower" class="listContent">
+        <checkbox-group
+          v-for="(item, index) in listData"
+          :key="index"
+          @change="(e) => selectVal(e, item, index)"
+        >
+          <label>
+            <view class="listBox">
+              <view class="listBox-sel">
+                <checkbox
+                  :value="item.code"
+                  color="#fff"
+                  :disabled="item.disabled"
+                  :checked="item.checked"
+                />
+              </view>
+              <view class="listBox-con">
+                <view class="listBox-top">
+                  <view class="listBox-name">
+                    {{ item.name }}
+                  </view>
+                </view>
+                <view class="listBox-bottom">
+                  <!-- <view v-for="(itm, index) in tableHeader" :key="index">{{ itm.label }}:{{ item[itm.prop] }}</view> -->
+                  <view>代号:{{ item.serialNo || "" }}</view>
+                  <view
+                    >详细地址:{{
+                      (item.addressName || "") + item.address || ""
+                    }}</view
+                  >
+                  <view
+                    >是否指派:{{
+                      (item.assignStatus === 1 ? "是" : "否") || ""
+                    }}</view
+                  >
+                  <view>销售员:{{ item.salesmanName || "" }}</view>
+                  <view>创建人:{{ item.createUsername || "" }}</view>
+                </view>
+              </view>
+            </view>
+          </label>
+        </checkbox-group>
+        <u-empty
+          class="noDate"
+          style="margin-top: 20vh"
+          v-if="!listData.length"
+        ></u-empty>
+      </u-list>
+    </view>
+
+    <view class="footer">
+      <view class="bottom" v-if="this.isAll == 1">
+        <checkbox
+          v-if="!seletedAll"
+          color="#fff"
+          :checked="seletedAll"
+          @tap="_seletedAll"
+          >全选</checkbox
+        >
+        <checkbox
+          class="select-all"
+          color="#fff"
+          v-else
+          :checked="seletedAll"
+          @tap="_seletedAll"
+          >取消全选
+        </checkbox>
+      </view>
+      <u-button
+        type="success"
+        size="small"
+        class="u-reset-button"
+        :disabled="!checkListLen"
+        @click="jumpAdd"
+      >
+        <view class="selBtn">选择( {{ checkListLen }} )</view>
+      </u-button>
+    </view>
+    <ba-tree-picker
+      ref="treePicker"
+      key="verify"
+      :multiple="false"
+      @select-change="confirm"
+      title="选择分类"
+      :localdata="classificationList"
+      valueKey="id"
+      textKey="name"
+    />
+  </view>
 </template>
 
 <script>
-	import {
-		contactPage,
-
-	} from '@/api/saleManage/contact/index.js'
-	import {
-		getTreeByPid
-	} from "@/api/classifyManage/index.js"
-	import baTreePicker from '@/components/ba-tree-picker/ba-tree-picker.vue'
-	export default {
-		components: {
-			baTreePicker
-		},
-
-		data() {
-			return {
-				page: 1,
-				size: 20,
-				isEnd: true,
-				searchVal: '',
-				pickTabIndex: 1,
-				popupShow: false, //右侧搜索窗
-				typeIndex: 1,
-				listData: [], //列表数据
-				classificationList: [], //分类数据
-				seletedAll: false, //全选状态,
-				isAll: '',
-				isDemand: ''
-			}
-		},
-		//选择的列表长度
-		computed: {
-
-			checkListLen() {
-
-				return this.listData.filter(el => el.checked).length
-			},
-
-		},
-		onLoad({
-			isAll,
-			type
-		}) {
-			this.isAll = isAll //1多选 2单选
-			// *** 新增 需求进来的话 要增加查询条件
-			if (type == '需求') {
-				this.isDemand = '1'
-			}
-			this.getClassify()
-		},
-		onShow() {},
-		methods: {
-			scrolltolower() {
-				if (this.isEnd) {
-					return
-				}
-				// 显示加载图标
-				uni.showLoading({
-					title: '数据加载中'
-				})
-				//获取更多数据
-				this.page++
-				this.getList()
-			},
-			//列表数据
-			async getList() {
-				this.isEnd = false
-				this._getClassifyList()
-			},
-			async _getClassifyList() {
-				uni.showLoading({
-					title: '数据加载中'
-				})
-				const params = {
-					pageNum: this.page,
-					size: this.size,
-					name: this.searchVal,
-					categoryId: this.categoryLevelId
-				}
-				// 需求新增参数 *** 
-				if (this.isDemand == '1') {
-					params.type = '1'
-					params.status = '1'
-				}
-				contactPage(params).then(res => {
-					uni.hideLoading()
-					if (this.page == 1) {
-						this.listData = []
-					}
-					this.listData = this.listData.concat(res.list)
-					this.isEnd = this.listData.length >= res.count
-				})
-			},
-			confirm([id]) {
-				this.categoryLevelId = id
-				this.page = 1
-
-
-				if (this.isAll === '2') {
-					this.listData.forEach(item => item.checked = false)
-				}
-
-				this.getList()
-			},
-			async getClassify() {
-				getTreeByPid(17).then(res => {
-					this.classificationList = res.data
-					this.page = 1
-					this.getList()
-				});
-			},
-			doSearch() {
-				this.page = 1
-				this.getList()
-			},
-			//勾选
-			selectVal(e, val, index) {
-
-				this.$set(this.listData[index], 'checked', !this.listData[index].checked)
-
-				if (this.isAll != 1) {
-					this.listData.forEach((item, i) => {
-						if (item.id != val.id) {
-							this.$set(this.listData[i], 'checked', false)
-						}
-					})
-				} else {
-
-					this.seletedAll = !this.listData.some(item => !item.checked)
-				}
-
-			},
-			//全选按钮
-			_seletedAll() {
-				if (!this.seletedAll) {
-					this.seletedAll = true
-					this.listData.map(item => {
-						this.$set(item, 'checked', true)
-					})
-				} else {
-					this.seletedAll = false
-					//this.checkListLen = 0;
-					this.listData.map(item => {
-						this.$set(item, 'checked', false)
-					})
-				}
-			},
-			//跳转回添加页面
-			jumpAdd() {
-				uni.$emit(
-					'setSelectList',
-					this.listData.filter(item => item.checked)
-				)
-				console.log(
-					this.listData.filter(item => item.checked),
-					'222'
-				)
-				uni.navigateBack()
-			},
-			//返回添加页
-			backAdd() {
-				uni.navigateBack()
-			}
-		}
-	}
+import { contactPage } from "@/api/saleManage/contact/index.js";
+import { getTreeByPid } from "@/api/classifyManage/index.js";
+import baTreePicker from "@/components/ba-tree-picker/ba-tree-picker.vue";
+export default {
+  components: {
+    baTreePicker,
+  },
+
+  data() {
+    return {
+      page: 1,
+      size: 20,
+      isEnd: true,
+      searchVal: "",
+      pickTabIndex: 1,
+      popupShow: false, //右侧搜索窗
+      typeIndex: 1,
+      listData: [], //列表数据
+      classificationList: [], //分类数据
+      seletedAll: false, //全选状态,
+      isAll: "",
+      isDemand: "",
+      contactType: "",
+    };
+  },
+  //选择的列表长度
+  computed: {
+    checkListLen() {
+      return this.listData.filter((el) => el.checked).length;
+    },
+  },
+  onLoad({ isAll, type, contactType }) {
+    this.isAll = isAll; //1多选 2单选
+    this.contactType = contactType || 17; //17客户 20供应商
+
+    // *** 新增 需求进来的话 要增加查询条件
+    if (type == "需求") {
+      this.isDemand = "1";
+    }
+    this.getClassify();
+  },
+  onShow() {},
+  methods: {
+    scrolltolower() {
+      if (this.isEnd) {
+        return;
+      }
+      // 显示加载图标
+      uni.showLoading({
+        title: "数据加载中",
+      });
+      //获取更多数据
+      this.page++;
+      this.getList();
+    },
+    //列表数据
+    async getList() {
+      this.isEnd = false;
+      this._getClassifyList();
+    },
+    async _getClassifyList() {
+      uni.showLoading({
+        title: "数据加载中",
+      });
+      const params = {
+        pageNum: this.page,
+        size: this.size,
+        name: this.searchVal,
+        categoryId: this.categoryLevelId,
+        status: 1,
+        type: this.contactType == 17 ? 1 : 2,
+      };
+      // 需求新增参数 ***
+      if (this.isDemand == "1") {
+        params.type = "1";
+        params.status = "1";
+      }
+      contactPage(params).then((res) => {
+        uni.hideLoading();
+        if (this.page == 1) {
+          this.listData = [];
+        }
+        this.listData = this.listData.concat(res.list);
+        this.isEnd = this.listData.length >= res.count;
+      });
+    },
+    confirm([id]) {
+      this.categoryLevelId = id;
+      this.page = 1;
+
+      if (this.isAll === "2") {
+        this.listData.forEach((item) => (item.checked = false));
+      }
+
+      this.getList();
+    },
+    async getClassify() {
+      getTreeByPid(17).then((res) => {
+        this.classificationList = res.data;
+        this.page = 1;
+        this.getList();
+      });
+    },
+    doSearch() {
+      this.page = 1;
+      this.getList();
+    },
+    //勾选
+    selectVal(e, val, index) {
+      this.$set(this.listData[index], "checked", !this.listData[index].checked);
+
+      if (this.isAll != 1) {
+        this.listData.forEach((item, i) => {
+          if (item.id != val.id) {
+            this.$set(this.listData[i], "checked", false);
+          }
+        });
+      } else {
+        this.seletedAll = !this.listData.some((item) => !item.checked);
+      }
+    },
+    //全选按钮
+    _seletedAll() {
+      if (!this.seletedAll) {
+        this.seletedAll = true;
+        this.listData.map((item) => {
+          this.$set(item, "checked", true);
+        });
+      } else {
+        this.seletedAll = false;
+        //this.checkListLen = 0;
+        this.listData.map((item) => {
+          this.$set(item, "checked", false);
+        });
+      }
+    },
+    //跳转回添加页面
+    jumpAdd() {
+      uni.$emit(
+        "setSelectList",
+        this.listData.filter((item) => item.checked),
+      );
+      console.log(
+        this.listData.filter((item) => item.checked),
+        "222",
+      );
+      uni.navigateBack();
+    },
+    //返回添加页
+    backAdd() {
+      uni.navigateBack();
+    },
+  },
+};
 </script>
 
 <style lang="scss" scoped>
-	.mainBox {
-		height: 100vh;
-		display: flex;
-		flex-direction: column;
-
-		.wrapper {
-			flex: 1;
-			overflow: hidden;
-		}
-
-		.searchBox {
-			padding: 10rpx 0;
-			box-sizing: border-box;
-			background-color: #dedede;
-			height: 90rpx;
-			width: 100%;
-			line-height: 90rpx;
-			display: flex;
-			justify-content: space-around;
-			align-items: center;
-
-			input {
-				height: 78rpx;
-				width: 65%;
-				background: #f9f9f9 !important;
-				margin: 0 10rpx;
-				padding: 0 10rpx;
-				box-sizing: border-box;
-				border-radius: 5rpx;
-			}
-
-			.searchBtn {
-				height: 80rpx;
-				background: #f9f9f9 !important;
-				color: #676767;
-				font-size: 28rpx;
-				padding: 0 42rpx;
-				box-sizing: border-box;
-				outline: none;
-				border: none;
-				width: 260rpx;
-
-				.icon-sousuo {
-					font-size: 22px;
-				}
-
-				.text {
-					font-size: 16px;
-					margin-left: 10px;
-				}
-			}
-		}
-
-		.tab-title {
-			position: fixed;
-			top: 190rpx;
-			z-index: 99;
-			width: 100%;
-			display: flex;
-			justify-content: space-between;
-			align-items: center;
-			height: $tab-height;
-			line-height: $tab-height;
-			background-color: #ffffff;
-			border-bottom: 2rpx solid #f2f2f2;
-			box-sizing: border-box;
-
-			.tab-item {
-				width: 25%;
-				text-align: center;
-				font-size: 32rpx;
-				color: $uni-text-color-grey;
-			}
-
-			.tab-item.active {
-				color: $j-primary-border-green;
-				border-bottom: 1px solid $j-primary-border-green;
-				font-weight: bold;
-			}
-
-			.tab-item.filter {
-				flex: 1;
-				padding: 0px 30rpx;
-
-				.uni-icons {
-					display: flex;
-					padding-top: 5px;
-				}
-			}
-
-			.screenIcon {
-				display: flex;
-				width: 80px;
-				justify-content: center;
-
-				.screenText {
-					font-size: 32rpx;
-					color: $uni-text-color-grey;
-				}
-			}
-		}
-
-		.listContent {
-			height: 100% !important;
-
-			.listBox {
-				display: flex;
-				// height: 180rpx;
-				padding: 20rpx 0;
-				border-bottom: 2rpx solid #e5e5e5;
-
-				.listBox-sel {
-					height: 90rpx;
-					width: 80rpx;
-					// line-height: 90rpx;
-					text-align: center;
-
-					checkbox {
-						transform: scale(1.2);
-					}
-				}
-
-				.listBox-con {
-					width: 100%;
-					// display: flex;
-					// flex-wrap: wrap;
-					// justify-content: space-between;
-					align-items: center;
-					padding: 0 18rpx 0 0;
-
-					.listBox-top {
-						width: 100%;
-						display: flex;
-						justify-content: space-between;
-						padding-bottom: 10rpx;
-
-						.listBox-name,
-						.listBox-code {
-							display: inline-block;
-							font-size: $uni-font-size-sm;
-							font-weight: bold;
-						}
-					}
-
-					.listBox-bottom {
-						width: 100%;
-						display: flex;
-						justify-content: space-between;
-						font-size: $uni-font-size-sm;
-						flex-wrap: wrap;
-
-						>view {
-							width: 50%;
-							overflow: hidden;
-							white-space: nowrap;
-							text-overflow: ellipsis;
-						}
-					}
-				}
-			}
-
-			.noDate {
-				height: 100%;
-			}
-		}
-
-		//底部按钮
-		.footer {
-			height: 90rpx;
-			position: relative;
-			display: flex;
-			justify-content: space-between;
-			align-items: center;
-			bottom: 0;
-			width: 100%;
-			height: 100rpx;
-			border-top: 1rpx solid #eeecec;
-			background-color: #ffffff;
-			z-index: 999;
-
-			.bottom {
-				margin-left: 10rpx;
-			}
-
-			.u-reset-button {
-				position: absolute;
-				right: 10rpx;
-				top: 20rpx;
-				width: 150rpx;
-			}
-		}
-	}
-</style>
+.mainBox {
+  height: 100vh;
+  display: flex;
+  flex-direction: column;
+
+  .wrapper {
+    flex: 1;
+    overflow: hidden;
+  }
+
+  .searchBox {
+    padding: 10rpx 0;
+    box-sizing: border-box;
+    background-color: #dedede;
+    height: 90rpx;
+    width: 100%;
+    line-height: 90rpx;
+    display: flex;
+    justify-content: space-around;
+    align-items: center;
+
+    input {
+      height: 78rpx;
+      width: 65%;
+      background: #f9f9f9 !important;
+      margin: 0 10rpx;
+      padding: 0 10rpx;
+      box-sizing: border-box;
+      border-radius: 5rpx;
+    }
+
+    .searchBtn {
+      height: 80rpx;
+      background: #f9f9f9 !important;
+      color: #676767;
+      font-size: 28rpx;
+      padding: 0 42rpx;
+      box-sizing: border-box;
+      outline: none;
+      border: none;
+      width: 260rpx;
+
+      .icon-sousuo {
+        font-size: 22px;
+      }
+
+      .text {
+        font-size: 16px;
+        margin-left: 10px;
+      }
+    }
+  }
+
+  .tab-title {
+    position: fixed;
+    top: 190rpx;
+    z-index: 99;
+    width: 100%;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    height: $tab-height;
+    line-height: $tab-height;
+    background-color: #ffffff;
+    border-bottom: 2rpx solid #f2f2f2;
+    box-sizing: border-box;
+
+    .tab-item {
+      width: 25%;
+      text-align: center;
+      font-size: 32rpx;
+      color: $uni-text-color-grey;
+    }
+
+    .tab-item.active {
+      color: $j-primary-border-green;
+      border-bottom: 1px solid $j-primary-border-green;
+      font-weight: bold;
+    }
+
+    .tab-item.filter {
+      flex: 1;
+      padding: 0px 30rpx;
+
+      .uni-icons {
+        display: flex;
+        padding-top: 5px;
+      }
+    }
+
+    .screenIcon {
+      display: flex;
+      width: 80px;
+      justify-content: center;
+
+      .screenText {
+        font-size: 32rpx;
+        color: $uni-text-color-grey;
+      }
+    }
+  }
+
+  .listContent {
+    height: 100% !important;
+
+    .listBox {
+      display: flex;
+      // height: 180rpx;
+      padding: 20rpx 0;
+      border-bottom: 2rpx solid #e5e5e5;
+
+      .listBox-sel {
+        height: 90rpx;
+        width: 80rpx;
+        // line-height: 90rpx;
+        text-align: center;
+
+        checkbox {
+          transform: scale(1.2);
+        }
+      }
+
+      .listBox-con {
+        width: 100%;
+        // display: flex;
+        // flex-wrap: wrap;
+        // justify-content: space-between;
+        align-items: center;
+        padding: 0 18rpx 0 0;
+
+        .listBox-top {
+          width: 100%;
+          display: flex;
+          justify-content: space-between;
+          padding-bottom: 10rpx;
+
+          .listBox-name,
+          .listBox-code {
+            display: inline-block;
+            font-size: $uni-font-size-sm;
+            font-weight: bold;
+          }
+        }
+
+        .listBox-bottom {
+          width: 100%;
+          display: flex;
+          justify-content: space-between;
+          font-size: $uni-font-size-sm;
+          flex-wrap: wrap;
+
+          > view {
+            width: 50%;
+            overflow: hidden;
+            white-space: nowrap;
+            text-overflow: ellipsis;
+          }
+        }
+      }
+    }
+
+    .noDate {
+      height: 100%;
+    }
+  }
+
+  //底部按钮
+  .footer {
+    height: 90rpx;
+    position: relative;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    bottom: 0;
+    width: 100%;
+    height: 100rpx;
+    border-top: 1rpx solid #eeecec;
+    background-color: #ffffff;
+    z-index: 999;
+
+    .bottom {
+      margin-left: 10rpx;
+    }
+
+    .u-reset-button {
+      position: absolute;
+      right: 10rpx;
+      top: 20rpx;
+      width: 150rpx;
+    }
+  }
+}
+</style>

+ 76 - 16
pages/salesServiceManagement/accessory/components/searchSelect.vue

@@ -14,10 +14,16 @@
 			<!-- 列表数据 -->
 			<scroll-view scroll-y class="list-container">
 				<view v-for="(item, index) in filteredData" :key="item.value" class="list-item"
-					:class="{ selected: innerValue === item.value }" @click="selectItem(item)">
+					:class="{ selected: isSelected(item.value) }" @click="selectItem(item)">
 					<view class="item-text">{{ item.text }}</view>
-					<uni-icons v-if="innerValue === item.value" type="checkmarkempty" size="20"
+					<!-- 单选模式显示对勾 -->
+					<uni-icons v-if="!multiple && innerValue === item.value" type="checkmarkempty" size="20"
 						color="#2979ff"></uni-icons>
+					<!-- 多选模式显示勾选框 -->
+					<view v-else-if="multiple" class="checkbox"
+						:class="{ checked: isSelected(item.value) }">
+						<uni-icons v-if="isSelected(item.value)" type="checkmarkempty" size="16" color="#fff"></uni-icons>
+					</view>
 				</view>
 
 				<!-- 空状态提示 -->
@@ -30,7 +36,8 @@
 			<!-- 底部按钮 -->
 			<view class="footer">
 				<button class="btn cancel" @click="close">取消</button>
-				<!-- <button class="btn confirm" @click="confirm">确定</button> -->
+				<!-- 多选模式显示确定按钮 -->
+				<button v-if="multiple" class="btn confirm" @click="confirm">确定</button>
 			</view>
 		</view>
 	</uni-popup>
@@ -50,10 +57,15 @@
 				type: Array,
 				default: () => []
 			},
-			// 选中的值(v-model)
+			// 选中的值(v-model)- 单选为 String/Number,多选为 Array
 			value: {
-				type: [String, Number],
+				type: [String, Number, Array],
 				default: ''
+			},
+			// 是否为多选模式
+			multiple: {
+				type: Boolean,
+				default: false
 			}
 		},
 		data() {
@@ -81,7 +93,8 @@
 			// 打开弹窗
 			open() {
 				this.$refs.popup.open();
-				this.innerValue = this.value;
+				// 深拷贝,避免直接修改父组件的值
+				this.innerValue = this.multiple ? [...(this.value || [])] : this.value;
 			},
 			clearSearchText(){
 				this.searchText = ''
@@ -104,21 +117,51 @@
 				);
 			},
 
+			// 判断是否选中
+			isSelected(value) {
+				if (this.multiple) {
+					return this.innerValue.includes(value);
+				}
+				return this.innerValue === value;
+			},
+
 			// 选择项目
 			selectItem(item) {
-				this.innerValue = item.value;
-				// this.selectedItem = item;
-				this.$emit('input', this.innerValue);
-				this.$emit('change', item);
-				this.close();
+				if (this.multiple) {
+					// 多选模式
+					const index = this.innerValue.indexOf(item.value);
+					if (index > -1) {
+						// 已选中则取消
+						this.innerValue.splice(index, 1);
+					} else {
+						// 未选中则添加
+						this.innerValue.push(item.value);
+					}
+					// 触发change事件,但不关闭弹窗
+					this.$emit('change', this.getSelectedItems());
+				} else {
+					// 单选模式
+					this.innerValue = item.value;
+					this.$emit('input', this.innerValue);
+					this.$emit('change', item);
+					this.close();
+				}
+			},
+
+			// 获取选中的完整数据项(多选模式)
+			getSelectedItems() {
+				if (!this.multiple) {
+					return this.dataList.find(item => item.value === this.innerValue);
+				}
+				return this.dataList.filter(item => this.innerValue.includes(item.value));
 			},
 
-			// 确定选择
+			// 确定选择(多选模式)
 			confirm() {
-				console.log(this.innerValue,'123')
-				if (this.innerValue) {
+				if (this.multiple) {
 					// 更新父组件v-model绑定的值
-					this.$emit('input', this.innerValue);
+					this.$emit('input', [...this.innerValue]);
+					this.$emit('confirm', this.getSelectedItems());
 				}
 				this.close();
 			}
@@ -207,6 +250,23 @@
 		flex: 1;
 	}
 
+	/* 勾选框样式(多选模式) */
+	.checkbox {
+		width: 40rpx;
+		height: 40rpx;
+		border-radius: 50%;
+		border: 2rpx solid #ccc;
+		display: flex;
+		align-items: center;
+		justify-content: center;
+		transition: all 0.2s;
+	}
+
+	.checkbox.checked {
+		background-color: #2979ff;
+		border-color: #2979ff;
+	}
+
 	/* 空状态提示 */
 	.empty-tip {
 		display: flex;
@@ -251,4 +311,4 @@
 		background-color: #2979ff;
 		color: white;
 	}
-</style>
+</style>