From ed0dd09175513033a41a3bc90d05f683c4809075 Mon Sep 17 00:00:00 2001
From: zhangwencui <1064582902@qq.com>
Date: 星期二, 28 四月 2026 14:48:20 +0800
Subject: [PATCH] 工序管理模块开发

---
 src/pages/productionDesign/processManagement/index.vue  |  261 +++++++++++++++
 src/pages.json                                          |   21 +
 src/pages/works.vue                                     |    5 
 src/pages/productionDesign/processManagement/params.vue |  413 ++++++++++++++++++++++++
 src/api/productionManagement/processManagement.js       |   80 ++++
 src/pages/productionDesign/processManagement/edit.vue   |  236 +++++++++++++
 6 files changed, 1,016 insertions(+), 0 deletions(-)

diff --git a/src/api/productionManagement/processManagement.js b/src/api/productionManagement/processManagement.js
new file mode 100644
index 0000000..15331ba
--- /dev/null
+++ b/src/api/productionManagement/processManagement.js
@@ -0,0 +1,80 @@
+import request from "@/utils/request";
+
+export function getProcessList(query) {
+  return request({
+    url: "/technologyOperation/listPage",
+    method: "get",
+    params: query,
+  });
+}
+
+export function add(data) {
+  return request({
+    url: "/technologyOperation/add",
+    method: "post",
+    data: data,
+  });
+}
+
+export function update(data) {
+  return request({
+    url: "/technologyOperation/update",
+    method: "put",
+    data: data,
+  });
+}
+
+export function del(ids) {
+  return request({
+    url: "/technologyOperation/batchDelete",
+    method: "delete",
+    data: ids,
+  });
+}
+
+export function getProcessParamList(params) {
+  return request({
+    url: "/technologyOperationParam/list",
+    method: "get",
+    params,
+  });
+}
+
+export function addProcessParam(data) {
+  return request({
+    url: "/technologyOperationParam/",
+    method: "post",
+    data: data,
+  });
+}
+
+export function editProcessParam(data) {
+  return request({
+    url: "/technologyOperationParam/",
+    method: "post",
+    data: data,
+  });
+}
+
+export function deleteProcessParam(id) {
+  return request({
+    url: `/technologyOperationParam/batchDelete/${id}`,
+    method: "delete",
+  });
+}
+
+export function getDeviceLedger(query) {
+  return request({
+    url: "/device/ledger/getDeviceLedger",
+    method: "get",
+    params: query,
+  });
+}
+
+export function getBaseParamList(query) {
+  return request({
+    url: "/technologyParam/list",
+    method: "get",
+    params: query,
+  });
+}
diff --git a/src/pages.json b/src/pages.json
index 1a946d7..d6ade75 100644
--- a/src/pages.json
+++ b/src/pages.json
@@ -381,6 +381,27 @@
       }
     },
     {
+      "path": "pages/productionDesign/processManagement/index",
+      "style": {
+        "navigationBarTitleText": "宸ュ簭绠$悊",
+        "navigationStyle": "custom"
+      }
+    },
+    {
+      "path": "pages/productionDesign/processManagement/edit",
+      "style": {
+        "navigationBarTitleText": "宸ュ簭璇︽儏",
+        "navigationStyle": "custom"
+      }
+    },
+    {
+      "path": "pages/productionDesign/processManagement/params",
+      "style": {
+        "navigationBarTitleText": "宸ュ簭鍙傛暟閰嶇疆",
+        "navigationStyle": "custom"
+      }
+    },
+    {
       "path": "pages/cooperativeOffice/collaborativeApproval/index1",
       "style": {
         "navigationBarTitleText": "鍏嚭绠$悊",
diff --git a/src/pages/productionDesign/processManagement/edit.vue b/src/pages/productionDesign/processManagement/edit.vue
new file mode 100644
index 0000000..425be43
--- /dev/null
+++ b/src/pages/productionDesign/processManagement/edit.vue
@@ -0,0 +1,236 @@
+<template>
+  <view class="process-edit">
+    <PageHeader :title="pageTitle"
+                @back="goBack" />
+    <up-form ref="formRef"
+             :model="form"
+             :rules="rules"
+             :errorType="['none']"
+             label-width="110">
+      <up-form-item label="宸ュ簭缂栫爜"
+                    prop="no">
+        <up-input v-model="form.no"
+                  placeholder="璇疯緭鍏ュ伐搴忕紪鐮�"
+                  clearable />
+      </up-form-item>
+      <up-form-item label="宸ュ簭鍚嶇О"
+                    prop="name"
+                    required>
+        <up-input v-model="form.name"
+                  placeholder="璇疯緭鍏ュ伐搴忓悕绉�"
+                  clearable />
+      </up-form-item>
+      <up-form-item label="宸ヨ祫瀹氶"
+                    prop="salaryQuota">
+        <up-input v-model="form.salaryQuota"
+                  type="number"
+                  placeholder="璇疯緭鍏ュ伐璧勫畾棰�"
+                  clearable />
+      </up-form-item>
+      <up-form-item label="璁¤垂绫诲瀷"
+                    prop="type">
+        <up-input v-model="typeText"
+                  placeholder="璇烽�夋嫨璁¤垂绫诲瀷"
+                  readonly
+                  @click="showTypeSheet = true" />
+        <template #right>
+          <up-icon name="arrow-right"
+                   @click="showTypeSheet = true"></up-icon>
+        </template>
+      </up-form-item>
+      <up-form-item label="鏄惁璐ㄦ"
+                    prop="isQuality">
+        <view style="display: flex; justify-content: flex-end; width: 100%;">
+          <up-switch v-model="form.isQuality" />
+        </view>
+      </up-form-item>
+      <up-form-item label="鏄惁鐢熶骇"
+                    prop="isProduction">
+        <view style="display: flex; justify-content: flex-end; width: 100%;">
+          <up-switch v-model="form.isProduction" />
+        </view>
+      </up-form-item>
+      <up-form-item label="鍏宠仈璁惧"
+                    prop="deviceLedgerId">
+        <up-input v-model="deviceText"
+                  placeholder="璇烽�夋嫨鍏宠仈璁惧"
+                  readonly
+                  @click="showDeviceSheet = true" />
+        <template #right>
+          <up-icon name="arrow-right"
+                   @click="showDeviceSheet = true"></up-icon>
+        </template>
+      </up-form-item>
+      <up-form-item label="宸ュ簭鎻忚堪"
+                    prop="remark">
+        <up-textarea v-model="form.remark"
+                     placeholder="璇疯緭鍏ュ伐搴忔弿杩�"
+                     autoHeight />
+      </up-form-item>
+    </up-form>
+    <FooterButtons :loading="loading"
+                   :confirmText="processId ? '淇濆瓨' : '鏂板'"
+                   @cancel="goBack"
+                   @confirm="handleSubmit" />
+    <!-- 璁¤垂绫诲瀷閫夋嫨 -->
+    <up-action-sheet :show="showTypeSheet"
+                     title="閫夋嫨璁¤垂绫诲瀷"
+                     :actions="typeActions"
+                     @select="onSelectType"
+                     @close="showTypeSheet = false" />
+    <!-- 璁惧閫夋嫨 -->
+    <up-action-sheet :show="showDeviceSheet"
+                     title="閫夋嫨鍏宠仈璁惧"
+                     :actions="deviceActions"
+                     @select="onSelectDevice"
+                     @close="showDeviceSheet = false" />
+  </view>
+</template>
+
+<script setup>
+  import { reactive, ref, computed, onMounted } from "vue";
+  import { onLoad, onReady } from "@dcloudio/uni-app";
+  import FooterButtons from "@/components/FooterButtons.vue";
+  import {
+    add,
+    update,
+    getDeviceLedger,
+  } from "@/api/productionManagement/processManagement";
+
+  const formRef = ref(null);
+  const loading = ref(false);
+  const processId = ref(null);
+  const pageTitle = computed(() => (processId.value ? "缂栬緫宸ュ簭" : "鏂板宸ュ簭"));
+
+  const form = ref({
+    no: "",
+    name: "",
+    salaryQuota: "",
+    isQuality: false,
+    isProduction: false,
+    remark: "",
+    deviceLedgerId: null,
+    type: 0,
+  });
+
+  const rules = {
+    name: [{ required: true, message: "璇疯緭鍏ュ伐搴忓悕绉�" }],
+    salaryQuota: [
+      {
+        validator: (rule, value, callback) => {
+          if (value !== "" && value !== null && (isNaN(value) || value < 0)) {
+            callback(new Error("宸ヨ祫瀹氶蹇呴』鏄潪璐熸暟瀛�"));
+          } else {
+            callback();
+          }
+        },
+      },
+    ],
+  };
+
+  const showTypeSheet = ref(false);
+  const typeActions = [
+    { name: "璁℃椂", value: 0 },
+    { name: "璁′欢", value: 1 },
+  ];
+  const typeText = computed(() => {
+    const action = typeActions.find(a => a.value === form.value.type);
+    return action ? action.name : "";
+  });
+
+  const showDeviceSheet = ref(false);
+  const deviceActions = ref([]);
+  const deviceText = ref("");
+
+  const onSelectType = e => {
+    form.value.type = e.value;
+    showTypeSheet.value = false;
+  };
+
+  const onSelectDevice = e => {
+    form.value.deviceLedgerId = e.id;
+    deviceText.value = e.name;
+    showDeviceSheet.value = false;
+  };
+
+  const loadDevices = async () => {
+    try {
+      const { data } = await getDeviceLedger();
+      deviceActions.value = (data || []).map(item => ({
+        name: item.deviceName,
+        id: item.id,
+      }));
+      if (form.value.deviceLedgerId) {
+        const device = deviceActions.value.find(
+          d => d.id === Number(form.value.deviceLedgerId)
+        );
+        if (device) deviceText.value = device.name;
+      }
+    } catch (error) {
+      console.error("鍔犺浇璁惧澶辫触", error);
+    }
+  };
+
+  const goBack = () => {
+    uni.navigateBack();
+  };
+
+  const handleSubmit = () => {
+    formRef.value
+      .validate()
+      .then(() => {
+        loading.value = true;
+        const promise = processId.value ? update(form.value) : add(form.value);
+        promise
+          .then(() => {
+            uni.showToast({ title: processId.value ? "淇濆瓨鎴愬姛" : "鏂板鎴愬姛" });
+            setTimeout(() => {
+              goBack();
+            }, 1500);
+          })
+          .catch(err => {
+            uni.showToast({ title: err.msg || "鎻愪氦澶辫触", icon: "error" });
+          })
+          .finally(() => {
+            loading.value = false;
+          });
+      })
+      .catch(errors => {
+        if (errors && errors.length > 0) {
+          uni.showToast({
+            title: errors[0].message,
+            icon: "none",
+          });
+        }
+      });
+  };
+
+  onLoad(option => {
+    if (option.item) {
+      const item = JSON.parse(decodeURIComponent(option.item));
+      processId.value = item.id;
+      Object.assign(form.value, item);
+      // 澶勭悊绫诲瀷杞崲锛岀‘淇濇槸鏁板瓧
+      form.value.type = Number(form.value.type);
+      form.value.isQuality = !!form.value.isQuality;
+      form.value.isProduction = !!form.value.isProduction;
+    }
+  });
+
+  onReady(() => {
+    formRef.value.setRules(rules);
+  });
+
+  onMounted(() => {
+    loadDevices();
+  });
+</script>
+
+<style scoped lang="scss">
+  @import "@/static/scss/form-common.scss";
+
+  .process-edit {
+    min-height: 100vh;
+    background: #f5f5f5;
+  }
+</style>
\ No newline at end of file
diff --git a/src/pages/productionDesign/processManagement/index.vue b/src/pages/productionDesign/processManagement/index.vue
new file mode 100644
index 0000000..6ca2f76
--- /dev/null
+++ b/src/pages/productionDesign/processManagement/index.vue
@@ -0,0 +1,261 @@
+<template>
+  <view class="sales-account">
+    <PageHeader title="宸ュ簭绠$悊"
+                @back="goBack" />
+    <view class="search-section">
+      <view class="search-bar">
+        <view class="search-input">
+          <up-input class="search-text"
+                    v-model="queryParams.name"
+                    placeholder="璇疯緭鍏ュ伐搴忓悕绉�"
+                    clearable
+                    @change="handleSearch" />
+        </view>
+        <view class="filter-button"
+              @click="handleSearch">
+          <up-icon name="search"
+                   size="24"
+                   color="#999999"></up-icon>
+        </view>
+      </view>
+    </view>
+    <view v-if="list.length > 0"
+          class="ledger-list">
+      <view v-for="item in list"
+            :key="item.id"
+            class="ledger-item">
+        <view class="item-header">
+          <view class="item-left">
+            <view class="document-icon">
+              <up-icon name="list-dot"
+                       size="16"
+                       color="#ffffff"></up-icon>
+            </view>
+            <text class="item-id">{{ item.name || "-" }}</text>
+          </view>
+          <text class="item-index">{{ item.no || "-" }}</text>
+        </view>
+        <up-divider></up-divider>
+        <view class="item-details">
+          <view class="detail-row">
+            <text class="detail-label">鍏宠仈璁惧</text>
+            <text class="detail-value">{{ getDeviceName(item.deviceLedgerId) }}</text>
+          </view>
+          <view class="detail-row">
+            <text class="detail-label">宸ヨ祫瀹氶</text>
+            <text class="detail-value highlight">楼{{ item.salaryQuota || 0 }}</text>
+          </view>
+          <view class="detail-row">
+            <text class="detail-label">宸ュ簭鐘舵��</text>
+            <view class="detail-value">
+              <up-tag :text="item.isQuality ? '璐ㄦ' : '闈炶川妫�'"
+                      :type="item.isQuality ? 'warning' : 'info'"
+                      size="mini"
+                      style="margin-left: 8rpx" />
+              <up-tag :text="item.isProduction ? '鐢熶骇' : '涓嶇敓浜�'"
+                      :type="item.isProduction ? 'warning' : 'info'"
+                      size="mini"
+                      style="margin-left: 8rpx" />
+              <up-tag v-if="item.type !== null && item.type !== undefined"
+                      :text="item.type == 0 ? '璁℃椂' : '璁′欢'"
+                      :type="item.type == 1 ? 'primary' : 'success'"
+                      size="mini"
+                      style="margin-left: 8rpx" />
+            </view>
+          </view>
+          <view class="detail-row">
+            <text class="detail-label">澶囨敞</text>
+            <text class="detail-value">{{ item.remark || "-" }}</text>
+          </view>
+        </view>
+        <view class="action-buttons">
+          <up-button class="action-btn"
+                     size="small"
+                     type="primary"
+                     @click="goEdit(item)">缂栬緫</up-button>
+          <up-button class="action-btn"
+                     size="small"
+                     type="warning"
+                     @click="goParams(item)">鍙傛暟閰嶇疆</up-button>
+          <up-button class="action-btn"
+                     size="small"
+                     type="error"
+                     @click="handleDelete(item)">鍒犻櫎</up-button>
+        </view>
+      </view>
+      <up-loadmore :status="pageStatus" />
+    </view>
+    <view v-else
+          class="no-data">
+      <text>鏆傛棤宸ュ簭鏁版嵁</text>
+    </view>
+    <view class="fab-button"
+          @click="goAdd">
+      <up-icon name="plus"
+               size="28"
+               color="#ffffff"></up-icon>
+    </view>
+  </view>
+</template>
+
+<script setup>
+  import { reactive, ref } from "vue";
+  import { onReachBottom, onShow } from "@dcloudio/uni-app";
+  import {
+    getProcessList,
+    del,
+    getDeviceLedger,
+  } from "@/api/productionManagement/processManagement";
+
+  const queryParams = reactive({
+    name: "",
+  });
+  const list = ref([]);
+  const deviceOptions = ref([]);
+  const pageStatus = ref("loadmore");
+
+  const page = reactive({
+    current: 1,
+    size: 10,
+    total: 0,
+  });
+
+  const goBack = () => {
+    uni.navigateBack();
+  };
+
+  const getDeviceName = deviceId => {
+    if (!deviceId) return "鏈叧鑱�";
+    const device = deviceOptions.value.find(item => item.id === Number(deviceId));
+    return device?.deviceName || "鏈叧鑱�";
+  };
+
+  const loadDevices = async () => {
+    try {
+      const { data } = await getDeviceLedger();
+      deviceOptions.value = data || [];
+    } catch (error) {
+      console.error("鍔犺浇璁惧鍒楄〃澶辫触", error);
+    }
+  };
+
+  const handleSearch = () => {
+    page.current = 1;
+    pageStatus.value = "loadmore";
+    list.value = [];
+    getList();
+  };
+
+  const getList = () => {
+    if (pageStatus.value === "loading" || pageStatus.value === "nomore") return;
+
+    pageStatus.value = "loading";
+    getProcessList({
+      current: page.current,
+      size: page.size,
+      name: queryParams.name,
+    })
+      .then(res => {
+        const records = res?.data?.records || res?.records || [];
+        const total = res?.data?.total || res?.total || 0;
+
+        if (page.current === 1) {
+          list.value = records;
+        } else {
+          list.value = [...list.value, ...records];
+        }
+
+        page.total = total;
+        if (list.value.length >= total) {
+          pageStatus.value = "nomore";
+        } else {
+          pageStatus.value = "loadmore";
+          page.current++;
+        }
+      })
+      .catch(() => {
+        uni.showToast({ title: "鏌ヨ澶辫触", icon: "error" });
+        pageStatus.value = "loadmore";
+      });
+  };
+
+  const goAdd = () => {
+    uni.navigateTo({ url: "/pages/productionDesign/processManagement/edit" });
+  };
+
+  const goEdit = item => {
+    uni.navigateTo({
+      url: `/pages/productionDesign/processManagement/edit?item=${encodeURIComponent(
+        JSON.stringify(item)
+      )}`,
+    });
+  };
+
+  const goParams = item => {
+    uni.navigateTo({
+      url: `/pages/productionDesign/processManagement/params?id=${item.id}&name=${encodeURIComponent(item.name)}`,
+    });
+  };
+
+  const handleDelete = item => {
+    uni.showModal({
+      title: "鎻愮ず",
+      content: "纭畾瑕佸垹闄よ宸ュ簭鍚楋紵",
+      success: res => {
+        if (res.confirm) {
+          del([item.id]).then(() => {
+            uni.showToast({ title: "鍒犻櫎鎴愬姛" });
+            handleSearch();
+          });
+        }
+      },
+    });
+  };
+
+  onReachBottom(() => {
+    getList();
+  });
+
+  onShow(async () => {
+    await loadDevices();
+    handleSearch();
+  });
+</script>
+
+<style scoped lang="scss">
+  @import "@/styles/procurement-common.scss";
+
+  .no-data {
+    padding-top: 100rpx;
+    text-align: center;
+    color: #999;
+    font-size: 28rpx;
+  }
+
+  .action-buttons {
+    display: flex;
+    justify-content: flex-end;
+    gap: 20rpx;
+    padding-bottom: 30rpx;
+  }
+
+  .action-btn {
+    flex: 1;
+    margin: 0 !important;
+  }
+
+  .fab-button {
+    position: fixed;
+    right: 40rpx;
+    bottom: 60rpx;
+    width: 100rpx;
+    height: 100rpx;
+    background: #2979ff;
+    border-radius: 50%;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    box-shadow: 0 4rpx 12rpx rgba(41, 121, 255, 0.4);
+    z-index: 100;
+  }
+</style>
\ No newline at end of file
diff --git a/src/pages/productionDesign/processManagement/params.vue b/src/pages/productionDesign/processManagement/params.vue
new file mode 100644
index 0000000..0fa0bc0
--- /dev/null
+++ b/src/pages/productionDesign/processManagement/params.vue
@@ -0,0 +1,413 @@
+<template>
+  <view class="process-params">
+    <PageHeader :title="processName + ' - 鍙傛暟閰嶇疆'"
+                @back="goBack" />
+    <view class="ledger-list">
+      <view v-if="paramList.length > 0">
+        <view v-for="item in paramList"
+              :key="item.id"
+              class="ledger-item">
+          <view class="item-header">
+            <view class="item-left">
+              <view class="document-icon">
+                <up-icon name="setting-fill"
+                         size="16"
+                         color="#ffffff"></up-icon>
+              </view>
+              <text class="item-id">{{ item.paramName || "-" }}</text>
+            </view>
+          </view>
+          <up-divider></up-divider>
+          <view class="item-details">
+            <view class="detail-row">
+              <text class="detail-label">鏍囧噯鍊�</text>
+              <text class="detail-value highlight">{{ item.standardValue || "-" }}</text>
+            </view>
+            <view class="detail-row">
+              <text class="detail-label">鍗曚綅</text>
+              <text class="detail-value">{{ item.unit || "-" }}</text>
+            </view>
+            <view class="detail-row">
+              <text class="detail-label">鍙傛暟绫诲瀷</text>
+              <up-tag :text="getParamTypeText(item.paramType)"
+                      :type="getParamTypeTag(item.paramType)"
+                      size="mini" />
+            </view>
+            <view class="detail-row">
+              <text class="detail-label">鍙栧�兼牸寮�</text>
+              <text class="detail-value">{{ item.paramFormat || "-" }}</text>
+            </view>
+          </view>
+          <view class="action-buttons">
+            <up-button class="action-btn"
+                       size="small"
+                       type="primary"
+                       @click="handleEditParam(item)">缂栬緫</up-button>
+            <up-button class="action-btn"
+                       size="small"
+                       type="error"
+                       @click="handleDeleteParam(item)">鍒犻櫎</up-button>
+          </view>
+        </view>
+      </view>
+      <view v-else
+            class="no-data">
+        <up-empty text="鏆傛棤鍙傛暟閰嶇疆"
+                  icon="account"
+                  iconSize="60"></up-empty>
+      </view>
+    </view>
+    <!-- 娴姩鏂板鎸夐挳 -->
+    <view class="fab-button"
+          @click="openSelectModal">
+      <up-icon name="plus"
+               size="28"
+               color="#ffffff"></up-icon>
+    </view>
+    <!-- 閫夋嫨鍙傛暟寮圭獥 -->
+    <up-modal :show="selectModalVisible"
+              title="閫夋嫨鍙傛暟"
+              width="650rpx"
+              @confirm="handleSelectSubmit"
+              @cancel="selectModalVisible = false"
+              :closeOnClickOverlay="false"
+              showCancelButton>
+      <view class="modal-content">
+        <view class="search-box">
+          <up-input v-model="searchKeyword"
+                    placeholder="鎼滅储鍩虹鍙傛暟鍚嶇О"
+                    clearable
+                    @confirm="handleSearch"
+                    @change="handleSearch" />
+        </view>
+        <scroll-view scroll-y
+                     class="param-scroll-list"
+                     @scrolltolower="loadMoreParams">
+          <view v-for="param in availableParams"
+                :key="param.id"
+                class="param-select-item"
+                :class="{ active: selectedBaseParam?.id === param.id }"
+                @click="selectParam(param)">
+            <view class="param-main">
+              <text class="param-name">{{ param.paramName }}</text>
+              <up-tag :text="getParamTypeText(param.paramType)"
+                      :type="getParamTypeTag(param.paramType)"
+                      size="mini" />
+            </view>
+            <text class="param-code">{{ param.paramCode }}</text>
+          </view>
+          <up-loadmore :status="availablePageStatus" />
+        </scroll-view>
+        <view v-if="selectedBaseParam"
+              class="standard-input-box">
+          <text class="label">鏍囧噯鍊硷細</text>
+          <up-input v-model="selectedStandardValue"
+                    placeholder="璇疯緭鍏ヨ宸ュ簭鐨勬爣鍑嗗��" />
+        </view>
+      </view>
+    </up-modal>
+    <!-- 缂栬緫鍙傛暟鏍囧噯鍊煎脊绐� -->
+    <up-modal :show="editModalVisible"
+              title="缂栬緫鏍囧噯鍊�"
+              width="500rpx"
+              @confirm="handleEditSubmit"
+              @cancel="editModalVisible = false"
+              :closeOnClickOverlay="false"
+              showCancelButton>
+      <view class="modal-content">
+        <view class="edit-info">
+          <text class="edit-label">鍙傛暟锛歿{ currentEditParam?.paramName }}</text>
+          <up-input v-model="currentEditValue"
+                    placeholder="璇疯緭鍏ユ柊鐨勬爣鍑嗗��" />
+        </view>
+      </view>
+    </up-modal>
+  </view>
+</template>
+
+<script setup>
+  import { reactive, ref, onMounted } from "vue";
+  import { onLoad } from "@dcloudio/uni-app";
+  import {
+    getProcessParamList,
+    addProcessParam,
+    editProcessParam,
+    deleteProcessParam,
+    getBaseParamList,
+  } from "@/api/productionManagement/processManagement";
+
+  const processId = ref(null);
+  const processName = ref("");
+  const paramList = ref([]);
+  const loading = ref(false);
+
+  // 閫夋嫨鍙傛暟鐩稿叧
+  const selectModalVisible = ref(false);
+  const availableParams = ref([]);
+  const searchKeyword = ref("");
+  const selectedBaseParam = ref(null);
+  const selectedStandardValue = ref("");
+  const availablePage = reactive({ current: 1, size: 20, total: 0 });
+  const availablePageStatus = ref("loadmore");
+
+  // 缂栬緫鍙傛暟鐩稿叧
+  const editModalVisible = ref(false);
+  const currentEditParam = ref(null);
+  const currentEditValue = ref("");
+
+  const goBack = () => {
+    uni.navigateBack();
+  };
+
+  const getParamList = () => {
+    loading.value = true;
+    getProcessParamList({ technologyOperationId: processId.value })
+      .then(res => {
+        paramList.value = res?.data || [];
+      })
+      .catch(() => {
+        uni.showToast({ title: "鑾峰彇鍒楄〃澶辫触", icon: "none" });
+      })
+      .finally(() => {
+        loading.value = false;
+      });
+  };
+
+  const openSelectModal = () => {
+    searchKeyword.value = "";
+    selectedBaseParam.value = null;
+    selectedStandardValue.value = "";
+    availableParams.value = [];
+    availablePage.current = 1;
+    availablePageStatus.value = "loadmore";
+    selectModalVisible.value = true;
+    loadAvailableParams(true);
+  };
+
+  const handleSearch = () => {
+    availablePage.current = 1;
+    availableParams.value = [];
+    availablePageStatus.value = "loadmore";
+    loadAvailableParams(true);
+  };
+
+  const loadMoreParams = () => {
+    if (
+      availablePageStatus.value === "nomore" ||
+      availablePageStatus.value === "loading"
+    )
+      return;
+    loadAvailableParams(false);
+  };
+
+  const loadAvailableParams = (isReset = false) => {
+    if (availablePageStatus.value === "loading") return;
+    if (isReset) {
+      availablePage.current = 1;
+      availableParams.value = [];
+      availablePageStatus.value = "loading";
+    } else if (availablePageStatus.value === "nomore") {
+      return;
+    } else {
+      availablePageStatus.value = "loading";
+    }
+    getBaseParamList({
+      paramName: searchKeyword.value,
+      current: availablePage.current,
+      size: availablePage.size,
+    })
+      .then(res => {
+        const records = res?.data?.records || res?.records || [];
+        const total = res?.data?.total || res?.total || 0;
+
+        if (isReset || availablePage.current === 1) {
+          availableParams.value = records;
+        } else {
+          availableParams.value = [...availableParams.value, ...records];
+        }
+
+        availablePage.total = total;
+        if (availableParams.value.length >= total) {
+          availablePageStatus.value = "nomore";
+        } else {
+          availablePageStatus.value = "loadmore";
+          availablePage.current++;
+        }
+      })
+      .catch(() => {
+        availablePageStatus.value = "loadmore";
+      });
+  };
+
+  const selectParam = param => {
+    selectedBaseParam.value = param;
+    selectedStandardValue.value = param.standardValue || "";
+  };
+
+  const handleSelectSubmit = () => {
+    if (!selectedBaseParam.value) {
+      uni.showToast({ title: "璇烽�夋嫨涓�涓熀纭�鍙傛暟", icon: "none" });
+      return;
+    }
+    if (!selectedStandardValue.value) {
+      uni.showToast({ title: "璇疯緭鍏ユ爣鍑嗗��", icon: "none" });
+      return;
+    }
+    addProcessParam({
+      technologyOperationId: processId.value,
+      technologyParamId: selectedBaseParam.value.id,
+      standardValue: selectedStandardValue.value,
+    })
+      .then(() => {
+        uni.showToast({ title: "娣诲姞鎴愬姛" });
+        selectModalVisible.value = false;
+        getParamList();
+      })
+      .catch(err => {
+        uni.showToast({ title: err.msg || "娣诲姞澶辫触", icon: "error" });
+      });
+  };
+
+  const handleEditParam = item => {
+    currentEditParam.value = item;
+    currentEditValue.value = item.standardValue;
+    editModalVisible.value = true;
+  };
+
+  const handleEditSubmit = () => {
+    if (!currentEditValue.value) {
+      uni.showToast({ title: "璇疯緭鍏ユ爣鍑嗗��", icon: "none" });
+      return;
+    }
+    editProcessParam({
+      id: currentEditParam.value.id,
+      technologyOperationId: processId.value,
+      technologyParamId: currentEditParam.value.technologyParamId,
+      standardValue: currentEditValue.value,
+    })
+      .then(() => {
+        uni.showToast({ title: "淇敼鎴愬姛" });
+        editModalVisible.value = false;
+        getParamList();
+      })
+      .catch(err => {
+        uni.showToast({ title: err.msg || "淇敼澶辫触", icon: "error" });
+      });
+  };
+
+  const handleDeleteParam = item => {
+    uni.showModal({
+      title: "鎻愮ず",
+      content: "纭畾瑕佸垹闄よ鍙傛暟閰嶇疆鍚楋紵",
+      success: res => {
+        if (res.confirm) {
+          deleteProcessParam(item.id).then(() => {
+            uni.showToast({ title: "鍒犻櫎鎴愬姛" });
+            getParamList();
+          });
+        }
+      },
+    });
+  };
+
+  const getParamTypeText = type => {
+    const typeMap = { 1: "鏁板��", 2: "鏂囨湰", 3: "涓嬫媺", 4: "鏃堕棿" };
+    return typeMap[type] || "鏈煡";
+  };
+
+  const getParamTypeTag = type => {
+    const typeMap = { 1: "primary", 2: "info", 3: "warning", 4: "success" };
+    return typeMap[type] || "default";
+  };
+
+  onLoad(option => {
+    if (option.id) {
+      processId.value = option.id;
+      processName.value = decodeURIComponent(option.name || "");
+      getParamList();
+    }
+  });
+</script>
+
+<style scoped lang="scss">
+  @import "@/styles/procurement-common.scss";
+
+  .process-params {
+    min-height: 100vh;
+    background: #f5f5f5;
+  }
+
+  .modal-content {
+    padding: 20rpx 0;
+    width: 100%;
+  }
+
+  .param-scroll-list {
+    height: 500rpx;
+    margin-top: 20rpx;
+    border: 1px solid #eee;
+    border-radius: 8rpx;
+  }
+
+  .param-select-item {
+    padding: 20rpx;
+    border-bottom: 1px solid #f5f5f5;
+    width: 100%;
+    &.active {
+      background-color: #e3f2fd;
+    }
+  }
+
+  .param-main {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    margin-bottom: 8rpx;
+  }
+
+  .param-name {
+    font-size: 28rpx;
+    font-weight: bold;
+    color: #333;
+  }
+
+  .param-code {
+    font-size: 24rpx;
+    color: #999;
+  }
+
+  .standard-input-box {
+    margin-top: 30rpx;
+    display: flex;
+    align-items: center;
+    .label {
+      width: 120rpx;
+      font-size: 28rpx;
+      color: #333;
+    }
+  }
+
+  .edit-info {
+    .edit-label {
+      display: block;
+      margin-bottom: 20rpx;
+      font-size: 28rpx;
+      color: #666;
+    }
+  }
+
+  .fab-button {
+    position: fixed;
+    right: 40rpx;
+    bottom: 60rpx;
+    width: 100rpx;
+    height: 100rpx;
+    background: #2979ff;
+    border-radius: 50%;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    box-shadow: 0 4rpx 12rpx rgba(41, 121, 255, 0.4);
+    z-index: 100;
+  }
+</style>
\ No newline at end of file
diff --git a/src/pages/works.vue b/src/pages/works.vue
index 72f1d0a..ee32b41 100644
--- a/src/pages/works.vue
+++ b/src/pages/works.vue
@@ -996,6 +996,11 @@
           url: "/pages/productionDesign/basicParameters/index",
         });
         break;
+      case "宸ュ簭绠$悊":
+        uni.navigateTo({
+          url: "/pages/productionDesign/processManagement/index",
+        });
+        break;
       default:
         uni.showToast({
           title: `鐐瑰嚮浜�${item.label}`,

--
Gitblit v1.9.3