From 47e1cecb6f5cd01c029ff1a2f1658326a33025f4 Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期六, 15 十一月 2025 11:51:35 +0800
Subject: [PATCH] 生产管控-左右页面逻辑修改

---
 src/pages/index.vue                                                                 |    6 
 src/pages.json                                                                      |   21 
 src/utils/request.ts                                                                |   22 
 src/pages/productionManagement/productionDispatching/components/autoDispatchDia.vue |  381 ++++++++++
 src/api/productionManagement/productionOrder.js                                     |   34 
 src/pages/productionManagement/operationScheduling/components/formDia.vue           |  282 +++++++
 src/pages/sales/salesAccount/index.vue                                              |    5 
 src/pages/productionManagement/operationScheduling/index.vue                        |  282 +++++++
 src/pages/login.vue                                                                 |    2 
 src/pages/sales/salesAccount/view.vue                                               |    4 
 src/pages/sales/salesAccount/detail.vue                                             |   19 
 src/pages/productionManagement/productionDispatching/index.vue                      |  580 +++++++++------
 src/pages/productionManagement/productionReporting/components/formDia.vue           |  160 ++++
 src/config.js                                                                       |    5 
 src/pages/productionManagement/productionReporting/index.vue                        |  202 +++++
 src/pages/productionManagement/productionCosting/index.vue                          |  107 ++
 16 files changed, 1,857 insertions(+), 255 deletions(-)

diff --git a/src/api/productionManagement/productionOrder.js b/src/api/productionManagement/productionOrder.js
index 9c1e7de..956b6e7 100644
--- a/src/api/productionManagement/productionOrder.js
+++ b/src/api/productionManagement/productionOrder.js
@@ -17,6 +17,14 @@
     data: query,
   });
 }
+// 鑷姩娲惧伐
+export function productionDispatchList(query) {
+  return request({
+    url: "/salesLedger/scheduling/productionDispatchList",
+    method: "post",
+    data: query,
+  });
+}
 // 鑾峰彇鐐掓満姝e湪宸ヤ綔閲忔暟鎹�
 export function schedulingList(query) {
   return request({
@@ -42,4 +50,30 @@
     method: "post",
     data: data,
   });
+}
+
+// 鏌ヨ鎹熻�楃巼
+export function getLossRate() {
+  return request({
+    url: "/salesLedger/scheduling/loss",
+    method: "get",
+  });
+}
+
+// 鏂板鎹熻�楃巼
+export function addLossRate(data) {
+  return request({
+    url: "/salesLedger/scheduling/addLoss",
+    method: "post",
+    data: data,
+  });
+}
+
+// 淇敼鎹熻�楃巼
+export function updateLossRate(data) {
+  return request({
+    url: "/salesLedger/scheduling/updateLoss",
+    method: "post",
+    data: data,
+  });
 }
\ No newline at end of file
diff --git a/src/config.js b/src/config.js
index ee29e3c..e451dd8 100644
--- a/src/config.js
+++ b/src/config.js
@@ -2,9 +2,8 @@
 const config = {
   //  baseUrl: 'https://vue.ruoyi.vip/prod-api',
   // baseUrl: 'http://localhost/prod-api',
-  // baseUrl: 'http://114.132.189.42:9066', // 瀹佸娑︽嘲
-  // baseUrl: 'http://114.132.189.42:9068', // 鏂扮枂娴峰窛寮�蹇�
-  baseUrl: 'http://192.168.1.147:8080', // 鏈湴娴嬭瘯
+  baseUrl: 'http://114.132.189.42:9068', // 鏂扮枂娴峰窛寮�蹇�
+  // baseUrl: 'http://192.168.1.185:9988', // 鏈湴娴嬭瘯
    //cloud鍚庡彴缃戝叧鍦板潃
   //  baseUrl: 'http://192.168.10.3:8080',
    // 搴旂敤淇℃伅
diff --git a/src/pages.json b/src/pages.json
index 4151447..8aca2bc 100644
--- a/src/pages.json
+++ b/src/pages.json
@@ -413,6 +413,27 @@
         "navigationBarTitleText": "鐢熶骇娲惧伐",
         "navigationStyle": "custom"
       }
+    },
+    {
+      "path": "pages/productionManagement/operationScheduling/index",
+      "style": {
+        "navigationBarTitleText": "宸ュ簭鎺掍骇",
+        "navigationStyle": "custom"
+      }
+    },
+    {
+      "path": "pages/productionManagement/productionReporting/index",
+      "style": {
+        "navigationBarTitleText": "鐢熶骇鎶ュ伐",
+        "navigationStyle": "custom"
+      }
+    },
+    {
+      "path": "pages/productionManagement/productionCosting/index",
+      "style": {
+        "navigationBarTitleText": "鐢熶骇鏍哥畻",
+        "navigationStyle": "custom"
+      }
     }
   ],
   "subPackages": [
diff --git a/src/pages/index.vue b/src/pages/index.vue
index 7a0673c..7922cc1 100644
--- a/src/pages/index.vue
+++ b/src/pages/index.vue
@@ -437,17 +437,17 @@
 			break;
 		case '宸ュ簭鎺掍骇':
 			uni.navigateTo({
-				url: '/pages/productionManagement/processScheduling/index'
+				url: '/pages/productionManagement/operationScheduling/index'
 			});
 			break;
 		case '鐢熶骇鎶ュ伐':
 			uni.navigateTo({
-				url: '/pages/productionManagement/productionReport/index'
+				url: '/pages/productionManagement/productionReporting/index'
 			});
 			break;
 		case '鐢熶骇鏍哥畻':
 			uni.navigateTo({
-				url: '/pages/productionManagement/productionAccounting/index'
+				url: '/pages/productionManagement/productionCosting/index'
 			});
 			break;
 		case '璁惧鍙拌处':
diff --git a/src/pages/login.vue b/src/pages/login.vue
index 860fd09..1b997d8 100644
--- a/src/pages/login.vue
+++ b/src/pages/login.vue
@@ -138,8 +138,6 @@
 		showToast("璇疯緭鍏ユ偍鐨勮处鍙�")
 	} else if (loginForm.value.password === "") {
 		showToast("璇疯緭鍏ユ偍鐨勫瘑鐮�")
-	} else if (loginForm.value.factoryId === "") {
-		showToast("璇烽�夋嫨鍏徃")
 	} else {
 		showToast("鐧诲綍涓紝璇疯�愬績绛夊緟...")
 		pwdLogin()
diff --git a/src/pages/productionManagement/operationScheduling/components/formDia.vue b/src/pages/productionManagement/operationScheduling/components/formDia.vue
new file mode 100644
index 0000000..c5b0599
--- /dev/null
+++ b/src/pages/productionManagement/operationScheduling/components/formDia.vue
@@ -0,0 +1,282 @@
+<template>
+  <view>
+    <up-popup v-model:show="dialogFormVisible" mode="bottom" round="12" @close="closeDia" :customStyle="{ height: '85vh' }">
+      <view class="dia-container">
+        <view class="dia-header">
+          <text class="title">宸ュ簭鎺掍骇</text>
+          <up-button size="mini" @click="addRow" type="primary">鏂板</up-button>
+          <text class="pending">寰呮帓浜ф暟閲忥細{{ pendingNum }}</text>
+        </view>
+
+        <scroll-view class="rows" scroll-y>
+          <view v-for="(row, index) in tableData" :key="index" class="row-card">
+            <view class="row-header">
+              <text class="row-index">#{{ index + 1 }}</text>
+              <up-button size="mini" type="error" plain @click="removeRow(index)">鍒犻櫎</up-button>
+            </view>
+
+            <up-form>
+              <up-form-item label="宸ュ簭" label-width="80">
+                <up-input v-model="row.process" placeholder="璇疯緭鍏ュ伐搴�" />
+              </up-form-item>
+              <up-form-item label="鍗曚綅" label-width="80">
+                <up-input v-model="row.unit" placeholder="璇疯緭鍏ュ崟浣�" />
+              </up-form-item>
+              <up-form-item label="鍙e懗/鍝佸悕/瑙勬牸" label-width="110">
+                <up-input v-model="row.type" placeholder="璇疯緭鍏�" />
+              </up-form-item>
+              <up-form-item label="鎺掍骇鏁伴噺" label-width="80">
+                <up-input v-model.number="row.schedulingNum" type="number" placeholder="璇疯緭鍏�" />
+              </up-form-item>
+              <up-form-item label="宸ユ椂瀹氶" label-width="80">
+                <up-input v-model.number="row.workHours" type="number" placeholder="璇疯緭鍏�" />
+              </up-form-item>
+              <up-form-item label="鎺掍骇鏃ユ湡" label-width="80" @click="openDatePicker(index)">
+                <up-input v-model="row.schedulingDate" placeholder="閫夋嫨鏃ユ湡" readonly @click="openDatePicker(index)" />
+                <template #right>
+                  <up-icon name="calendar" @click="openDatePicker(index)"></up-icon>
+                </template>
+              </up-form-item>
+              <up-form-item label="鎺掍骇浜�" label-width="80" @click="openUserPicker(index)">
+                <up-input v-model="row.schedulingUserName" placeholder="閫夋嫨浜哄憳" readonly @click="openUserPicker(index)" />
+                <template #right>
+                  <up-icon name="arrow-right" @click="openUserPicker(index)"></up-icon>
+                </template>
+              </up-form-item>
+              <up-form-item label="澶囨敞" label-width="80">
+                <up-input v-model="row.remark" placeholder="璇疯緭鍏ュ娉�" />
+              </up-form-item>
+            </up-form>
+          </view>
+        </scroll-view>
+
+        <view class="summary">
+          <text>鎺掍骇鏁伴噺鍚堣锛歿{ totalSchedulingNum }}</text>
+        </view>
+
+        <view class="dia-footer">
+          <up-button type="primary" @click="submitForm">纭</up-button>
+          <up-button @click="closeDia">鍙栨秷</up-button>
+        </view>
+      </view>
+    </up-popup>
+
+    <!-- 鏃ユ湡閫夋嫨鍣紙up 绯诲垪锛� -->
+    <up-popup :show="datePicker.show" mode="bottom" @close="datePicker.show = false">
+      <up-datetime-picker :show="true" v-model="datePicker.valueData" mode="date" @confirm="onDateConfirm" @cancel="datePicker.show = false" />
+    </up-popup>
+
+    <!-- 浜哄憳閫夋嫨鍣紙up 绯诲垪 action-sheet锛� -->
+    <up-action-sheet
+      :show="userPicker.show"
+      :actions="userActionList"
+      title="閫夋嫨浜哄憳"
+      @select="onUserSelect"
+      @close="userPicker.show = false"
+    />
+  </view>
+</template>
+
+<script setup>
+import { ref, getCurrentInstance, computed } from 'vue'
+import { userListNoPageByTenantId } from '@/api/system/user.js'
+import { processScheduling } from '@/api/productionManagement/operationScheduling.js'
+const { proxy } = getCurrentInstance()
+const emit = defineEmits(['close'])
+
+const dialogFormVisible = ref(false)
+const operationType = ref('')
+const tableData = ref([])
+const unitFromRow = ref('')
+const idFromRow = ref('')
+const specificationModelFromRow = ref('')
+const pendingNum = ref(0)
+const userList = ref([])
+const receive = ref('')
+
+// pickers
+const datePicker = ref({ show: false, valueData: Date.now(), rowIndex: -1 })
+
+const userPicker = ref({ show: false, rowIndex: -1 })
+
+// ActionSheet 鏁版嵁
+const userActionList = computed(() => {
+  return userList.value.map(u => ({ name: u.nickName, value: u.userId }))
+})
+
+const totalSchedulingNum = computed(() => {
+  return tableData.value.reduce((sum, r) => sum + (Number(r.schedulingNum || 0)), 0)
+})
+
+const userLabel = (uid) => {
+  const u = userList.value.find(u => u.userId === uid)
+  return u ? u.nickName : ''
+}
+
+// 鎵撳紑寮规
+const openDialog = (type, row) => {
+  operationType.value = type
+  dialogFormVisible.value = true
+  userListNoPageByTenantId().then((res) => {
+    userList.value = res.data
+  })
+
+  pendingNum.value = row?.pendingNum ?? 0
+  unitFromRow.value = row?.unit ?? ''
+  idFromRow.value = row?.id ?? ''
+  specificationModelFromRow.value = row?.specificationModel ?? ''
+  tableData.value = [createRow()]
+}
+
+const createRow = () => ({
+  id: idFromRow.value,
+  process: '',
+  schedulingDate: '',
+  schedulingNum: null,
+  schedulingUserId: '',
+  schedulingUserName: '',
+  workHours: null,
+  unit: unitFromRow.value,
+  remark: '',
+  type: specificationModelFromRow.value,
+})
+
+const openDatePicker = (idx) => {
+  datePicker.value.rowIndex = idx
+  datePicker.value.valueData = Date.now()
+  datePicker.value.show = true
+}
+const onDateConfirm = (e) => {
+  const val = e.value
+  const d = new Date(val)
+  const y = d.getFullYear()
+  const m = String(d.getMonth() + 1).padStart(2, '0')
+  const day = String(d.getDate()).padStart(2, '0')
+  const str = `${y}-${m}-${day}`
+  if (datePicker.value.rowIndex > -1) {
+    tableData.value[datePicker.value.rowIndex].schedulingDate = str
+  }
+  datePicker.value.show = false
+}
+
+const openUserPicker = (idx) => {
+  userPicker.value.rowIndex = idx
+  userPicker.value.show = true
+}
+const onUserSelect = (item) => {
+  if (item && userPicker.value.rowIndex > -1) {
+    const row = tableData.value[userPicker.value.rowIndex]
+    row.schedulingUserId = item.value
+    row.schedulingUserName = item.name
+  }
+  userPicker.value.show = false
+}
+
+const submitForm = () => {
+  // 1. 妫�鏌ユ瘡涓�琛屾槸鍚﹀~鍐欏畬鏁�
+  for (let i = 0; i < tableData.value.length; i++) {
+    const row = tableData.value[i]
+    if (!row.process || !row.schedulingDate || row.schedulingNum === '' || row.schedulingNum === null || !row.schedulingUserId || row.workHours === '' || row.workHours === null || !row.unit) {
+      uni.showToast({ title: `绗�${i + 1}琛屾暟鎹湭濉啓瀹屾暣`, icon: 'none' })
+      return
+    }
+  }
+  // 2. 鍚堣鎺掍骇鏁伴噺
+  const total = tableData.value.reduce((sum, row) => sum + Number(row.schedulingNum || 0), 0)
+  if (total > Number(pendingNum.value)) {
+    uni.showToast({ title: '鎺掍骇鏁伴噺鍚堣涓嶈兘瓒呰繃寰呮帓浜ф暟閲�', icon: 'none' })
+    return
+  }
+  // 3. 鎷艰鏁版嵁
+  const submitData = tableData.value.map(row => {
+    const { loss, ...rest } = row
+    return { ...rest, receive: receive.value }
+  })
+  processScheduling(submitData).then(() => {
+    uni.showToast({ title: '鎻愪氦鎴愬姛', icon: 'success' })
+    closeDia()
+  })
+}
+
+// 鍏抽棴寮规
+const closeDia = () => {
+  dialogFormVisible.value = false
+  receive.value = ''
+  tableData.value = []
+  unitFromRow.value = ''
+  idFromRow.value = ''
+  specificationModelFromRow.value = ''
+  pendingNum.value = 0
+  emit('close')
+}
+defineExpose({ openDialog })
+
+const addRow = () => {
+  tableData.value.push(createRow())
+}
+const removeRow = (index) => {
+  tableData.value.splice(index, 1)
+}
+</script>
+
+<style scoped lang="scss">
+.dia-container { 
+  padding: 12px; 
+  height: 100%; 
+  display: flex; 
+  flex-direction: column; 
+}
+.dia-header { 
+  display: flex; 
+  align-items: center; 
+  gap: 8px; 
+  margin-bottom: 10px; 
+}
+.dia-header .title { 
+  font-weight: 600; 
+  font-size: 16px; 
+  color: #333; 
+}
+.dia-header .pending { 
+  margin-left: auto; 
+  color: #666; 
+  font-size: 12px; 
+}
+.rows { 
+  display: flex; 
+  flex-direction: column; 
+  gap: 10px; 
+  overflow-y: auto; 
+  -webkit-overflow-scrolling: touch; 
+  flex: 1;
+  min-height: 0;
+}
+.row-card { 
+  background: #fff; 
+  border-radius: 10px; 
+  padding: 8px; 
+  box-shadow: 0 2px 8px rgba(0,0,0,0.05); 
+}
+.row-header { 
+  display: flex; 
+  justify-content: space-between; 
+  align-items: center; 
+  margin-bottom: 6px; 
+}
+.row-index { 
+  color: #999; 
+  font-size: 12px; 
+}
+.summary { 
+  padding: 10px 0; 
+  color: #333; 
+  font-size: 14px; 
+  text-align: right; 
+}
+.dia-footer { 
+  display: flex; 
+  gap: 10px; 
+  justify-content: flex-end; 
+  padding-top: 8px; 
+}
+</style>
\ No newline at end of file
diff --git a/src/pages/productionManagement/operationScheduling/index.vue b/src/pages/productionManagement/operationScheduling/index.vue
new file mode 100644
index 0000000..a3d86a5
--- /dev/null
+++ b/src/pages/productionManagement/operationScheduling/index.vue
@@ -0,0 +1,282 @@
+<template>
+  <view class="op-scheduling">
+    <PageHeader title="宸ュ簭鎺掍骇" />
+
+    <view class="search_form">
+      <u-form>
+        <view class="form-row">
+          <u-form-item label="瀹㈡埛鍚嶇О" label-width="80">
+            <up-input v-model="searchForm.customerName" placeholder="璇疯緭鍏�" clearable @change="handleQuery" />
+          </u-form-item>
+          <u-form-item label="椤圭洰鍚嶇О" label-width="80">
+            <up-input v-model="searchForm.projectName" placeholder="璇疯緭鍏�" clearable @change="handleQuery" />
+          </u-form-item>
+        </view>
+        <view class="form-row">
+          <u-form-item label="鐘舵��" label-width="80">
+            <up-input v-model="statusDisplay" placeholder="璇烽�夋嫨鐘舵��" readonly @click="showStatusPicker = true" />
+          </u-form-item>
+        </view>
+        <view class="form-actions">
+          <u-button type="primary" @click="handleQuery" size="small">鎼滅储</u-button>
+        </view>
+      </u-form>
+    </view>
+
+    <!-- 椤堕儴鎿嶄綔宸茬Щ闄� -->
+
+    <view class="list_container">
+      <u-loading-icon v-if="tableLoading" text="鍔犺浇涓�..."></u-loading-icon>
+      <view v-else>
+        <view v-if="!tableData || tableData.length === 0" class="empty">鏆傛棤鏁版嵁</view>
+        <view v-else class="card_list">
+          <view v-for="item in tableData" :key="item.id" class="card_item">
+            <view class="card_header">
+              <u-tag :type="statusType(item.status)" size="mini">{{ statusText(item.status) }}</u-tag>
+              <text class="card_title">{{ item.projectName }}</text>
+            </view>
+            <view class="card_body">
+              <view class="row"><text class="label">娲惧伐鏃ユ湡</text><text class="value">{{ item.schedulingDate }}</text></view>
+              <view class="row"><text class="label">娲惧伐浜�</text><text class="value">{{ item.schedulingUserName }}</text></view>
+              <view class="row"><text class="label">鍚堝悓鍙�</text><text class="value">{{ item.salesContractNo }}</text></view>
+              <view class="row"><text class="label">瀹㈡埛鍚堝悓鍙�</text><text class="value">{{ item.customerContractNo }}</text></view>
+              <view class="row"><text class="label">瀹㈡埛鍚嶇О</text><text class="value">{{ item.customerName }}</text></view>
+              <view class="row"><text class="label">浜у搧澶х被</text><text class="value">{{ item.productCategory }}</text></view>
+              <view class="row"><text class="label">瑙勬牸鍨嬪彿</text><text class="value">{{ item.specificationModel }}</text></view>
+              <view class="row"><text class="label">缁戝畾鏈哄櫒</text><text class="value">{{ item.speculativeTradingName }}</text></view>
+              <view class="row inline">
+                <view class="col"><text class="label">鍗曚綅</text><text class="value">{{ item.unit }}</text></view>
+                <view class="col"><text class="label">鎺掍骇鎬绘暟</text><text class="value">{{ item.schedulingNum }}</text></view>
+                <view class="col"><text class="label">宸叉帓浜ф暟閲�</text><text class="value">{{ item.successNum }}</text></view>
+                <view class="col"><text class="label">寰呮帓浜ф暟閲�</text><text class="value">{{ item.pendingNum }}</text></view>
+              </view>
+            </view>
+            <view class="card_actions">
+              <u-button
+                type="primary"
+                size="small"
+                @click="openForm('add', item)"
+                :disabled="item.pendingNum == 0"
+              >宸ュ簭鎺掍骇</u-button>
+              <u-button
+                type="error"
+                plain
+                size="small"
+                class="ml8"
+                @click="handleCancel(item)"
+                :disabled="item.status == 3"
+              >鍙栨秷鎺掍骇</u-button>
+            </view>
+          </view>
+        </view>
+
+        
+      </view>
+    </view>
+
+    <form-dia ref="formDia" @close="handleQuery"></form-dia>
+
+    <!-- 鐘舵�侀�夋嫨鍣紙up 绯诲垪锛� -->
+    <up-action-sheet
+      :show="showStatusPicker"
+      :actions="statusActions"
+      title="閫夋嫨鐘舵��"
+      @select="onStatusSelect"
+      @close="showStatusPicker = false"
+    />
+  </view>
+</template>
+
+<script setup>
+import { onMounted, ref, reactive, toRefs, nextTick, getCurrentInstance, computed } from 'vue'
+import PageHeader from '@/components/PageHeader.vue'
+import FormDia from './components/formDia.vue'
+import dayjs from 'dayjs'
+import { listPageProcess, productionDispatchDelete } from '@/api/productionManagement/operationScheduling.js'
+
+const data = reactive({
+  searchForm: {
+    staffName: "",
+    status: 1,
+    entryDate: null, // 褰曞叆鏃ユ湡
+    entryDateStart: undefined,
+    entryDateEnd: undefined,
+  },
+});
+const { searchForm } = toRefs(data);
+const tableData = ref([])
+const tableLoading = ref(false)
+const page = reactive({
+  current: -1,
+  size: -1,
+});
+const formDia = ref()
+const { proxy } = getCurrentInstance()
+
+// 鐘舵�侀�夋嫨鍣�
+const showStatusPicker = ref(false)
+const statusOptions = ref([
+  { label: '寰呮帓浜�', value: 1 },
+  { label: '鎺掍骇涓�', value: 2 },
+  { label: '宸叉帓浜�', value: 3 }
+])
+const statusActions = computed(() => statusOptions.value.map(o => ({ name: o.label, value: o.value })))
+const statusDisplay = ref('')
+
+// 鏃ユ湡鑼冨洿绛涢�夊凡绉婚櫎
+
+// picker handlers
+const onStatusSelect = (item) => {
+  if (item) {
+    searchForm.value.status = item.value
+    statusDisplay.value = item.name
+    handleQuery()
+  }
+  showStatusPicker.value = false
+}
+// 鏃ユ湡鑼冨洿鍥炶皟宸茬Щ闄�
+
+// status display helpers
+const statusText = (s) => {
+  if (s == 3) return '宸叉帓浜�'
+  if (s == 1) return '寰呮帓浜�'
+  return '鎺掍骇涓�'
+}
+const statusType = (s) => {
+  if (s == 3) return 'success'
+  if (s == 1) return 'primary'
+  return 'warning'
+}
+
+// 鏌ヨ鍒楄〃
+/** 鎼滅储鎸夐挳鎿嶄綔 */
+const handleQuery = () => {
+	page.current = -1;
+	page.size = -1;
+	getList();
+};
+// changeDaterange 宸茬Щ闄�
+const getList = () => {
+	tableLoading.value = true;
+	const params = { ...searchForm.value, ...page };
+	params.entryDate = undefined
+	listPageProcess(params).then(res => {
+		tableLoading.value = false;
+		tableData.value = res.data.records.map(item => ({
+			...item,
+			pendingNum: (Number(item.schedulingNum) || 0) - (Number(item.successNum) || 0)
+		}));
+	}).catch(err => {
+		tableLoading.value = false;
+	})
+};
+// 鍙栨秷澶氶�夌浉鍏抽�昏緫锛岄噰鐢ㄥ崱鐗囧唴鍗曟潯鎿嶄綔
+
+// 鎵撳紑寮规
+const openForm = (type, row) => {
+	if (!row) {
+		uni.showToast({ title: '鏈壘鍒版暟鎹�', icon: 'none' })
+		return;
+	}
+	if ((Number(row.pendingNum) || 0) === 0) {
+		uni.showToast({ title: '鏃犻渶鍐嶆帓浜�', icon: 'none' })
+		return;
+	}
+	nextTick(() => {
+		formDia.value?.openDialog(type, row)
+	})
+};
+
+// 鍗曟潯鍙栨秷鎺掍骇
+const handleCancel = (row) => {
+  if (!row) return
+  if (row.status == 3) {
+    uni.showToast({ title: '宸叉帓浜ф暟鎹笉鑳藉彇娑堟帓浜�', icon: 'none' })
+    return
+  }
+  uni.showModal({
+    title: '鍒犻櫎鎻愮ず',
+    content: '鏄惁纭鍙栨秷鎺掍骇锛�',
+    success: (res) => {
+      if (res.confirm) {
+        tableLoading.value = true
+        productionDispatchDelete([row.id])
+          .then(() => {
+            uni.showToast({ title: '鍙栨秷鎺掍骇鎴愬姛', icon: 'success' })
+            getList()
+          })
+          .finally(() => {
+            tableLoading.value = false
+          })
+      }
+    }
+  })
+}
+
+onMounted(() => {
+	getList();
+  // 鍒濆鍖栨樉绀哄瓧娈�
+  const cur = statusOptions.value.find(o => o.value === searchForm.value.status)
+  statusDisplay.value = cur ? cur.label : ''
+});
+</script>
+
+<style scoped lang="scss">
+.op-scheduling {
+  padding-bottom: 12px;
+}
+.search_form {
+  margin: 12px;
+  background: #fff;
+  border-radius: 8px;
+  padding: 10px;
+}
+.form-row {
+  display: flex;
+  gap: 12px;
+}
+.form-actions {
+  display: flex;
+  justify-content: flex-end;
+}
+.table_actions {
+  display: flex;
+  gap: 8px;
+  padding: 0 12px 10px 12px;
+  justify-content: flex-end;
+}
+.list_container {
+  padding: 0 12px;
+}
+.empty {
+  text-align: center;
+  color: #888;
+  padding: 20px 0;
+}
+.card_list {
+  display: flex;
+  flex-direction: column;
+  gap: 10px;
+}
+.card_item {
+  background: #fff;
+  border-radius: 10px;
+  padding: 10px;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.05);
+}
+.card_header {
+  display: flex;
+  align-items: center;
+  gap: 8px;
+  margin-bottom: 6px;
+}
+.card_title { font-weight: 500; color: #333; margin-left: auto; }
+.card_body .row { display: flex; justify-content: space-between; padding: 4px 0; }
+.card_body .row.inline { display: flex; gap: 10px; flex-wrap: wrap; }
+.card_body .row.inline .col { min-width: 45%; display: flex; justify-content: space-between; }
+.label { color: #666; font-size: 12px; }
+.value { color: #333; font-size: 12px; }
+.card_actions { display: flex; justify-content: flex-end; gap: 8px; padding-top: 8px; }
+.ml8 { margin-left: 8px; }
+
+</style>
diff --git a/src/pages/productionManagement/productionCosting/index.vue b/src/pages/productionManagement/productionCosting/index.vue
new file mode 100644
index 0000000..8e6db58
--- /dev/null
+++ b/src/pages/productionManagement/productionCosting/index.vue
@@ -0,0 +1,107 @@
+<template>
+  <view class="prod-costing">
+    <PageHeader title="鐢熶骇鏍哥畻" />
+
+    <view class="search_form">
+      <u-form>
+        
+        <view class="form-row">
+          <u-form-item label="鐢熶骇浜�" label-width="80">
+            <up-input v-model="searchForm.schedulingUserName" placeholder="璇疯緭鍏�" clearable @change="handleQuery" />
+          </u-form-item>
+        </view>
+        <view class="form-actions">
+          <u-button type="primary" size="small" @click="handleQuery">鎼滅储</u-button>
+          
+        </view>
+      </u-form>
+    </view>
+
+    <view class="list_container">
+      <u-loading-icon v-if="tableLoading" text="鍔犺浇涓�..." />
+      <view v-else>
+        <view v-if="!tableData || tableData.length === 0" class="empty">鏆傛棤鏁版嵁</view>
+        <view v-else class="card_list">
+          <view v-for="item in tableData" :key="item.id" class="card_item">
+            <view class="card_header">
+              <text class="card_title">{{ item.projectName }}</text>
+            </view>
+            <view class="card_body">
+              <view class="row"><text class="label">鐢熶骇鏃ユ湡</text><text class="value">{{ item.schedulingDate }}</text></view>
+              <view class="row"><text class="label">鐢熶骇浜�</text><text class="value">{{ item.schedulingUserName }}</text></view>
+              <view class="row"><text class="label">鍚堝悓鍙�</text><text class="value">{{ item.salesContractNo }}</text></view>
+              <view class="row"><text class="label">瀹㈡埛鍚堝悓鍙�</text><text class="value">{{ item.customerContractNo }}</text></view>
+              <view class="row"><text class="label">瀹㈡埛鍚嶇О</text><text class="value">{{ item.customerName }}</text></view>
+              <view class="row"><text class="label">浜у搧澶х被</text><text class="value">{{ item.productCategory }}</text></view>
+              <view class="row"><text class="label">瑙勬牸鍨嬪彿</text><text class="value">{{ item.specificationModel }}</text></view>
+              <view class="row inline">
+                <view class="col"><text class="label">鍗曚綅</text><text class="value">{{ item.unit }}</text></view>
+                <view class="col"><text class="label">宸ュ簭</text><text class="value">{{ item.process }}</text></view>
+                <view class="col"><text class="label">鐢熶骇鏁伴噺</text><text class="value">{{ item.finishedNum }}</text></view>
+                <view class="col"><text class="label">宸ユ椂瀹氶</text><text class="value">{{ item.workHours }}</text></view>
+                <view class="col"><text class="label">宸ヨ祫</text><text class="value">{{ item.wages }}</text></view>
+              </view>
+            </view>
+          </view>
+        </view>
+
+        
+      </view>
+    </view>
+
+    
+  </view>
+</template>
+
+<script setup>
+import { onMounted, ref, reactive, toRefs } from "vue";
+import PageHeader from '@/components/PageHeader.vue'
+import { productionAccountingListPage } from "@/api/productionManagement/productionCosting.js";
+
+// state
+const tableData = ref([]);
+const tableLoading = ref(false);
+const page = reactive({ current: -1, size: -1 });
+const data = reactive({
+  searchForm: {
+    schedulingUserName: "",
+  },
+});
+const { searchForm } = toRefs(data);
+
+// 鏃犳棩鏈熺瓫閫�
+
+// 鏌ヨ锛堜笉鍒嗛〉锛屽浐瀹氫紶 -1锛�
+const handleQuery = () => { page.current = -1; page.size = -1; getList(); };
+const getList = () => {
+  tableLoading.value = true;
+  const params = { ...searchForm.value, ...page };
+  productionAccountingListPage(params).then((res) => {
+    tableLoading.value = false;
+    tableData.value = res.data.records || [];
+  }).catch(() => { tableLoading.value = false; })
+};
+
+onMounted(() => { getList(); });
+</script>
+
+<style scoped lang="scss">
+.prod-costing { padding-bottom: 12px; }
+.search_form { margin: 12px; background: #fff; border-radius: 8px; padding: 10px; }
+.form-row { display: flex; gap: 12px; }
+.form-actions { display: flex; justify-content: flex-end; }
+.ml8 { margin-left: 8px; }
+.list_container { padding: 0 12px; }
+.empty { text-align: center; color: #888; padding: 20px 0; }
+.card_list { display: flex; flex-direction: column; gap: 10px; }
+.card_item { background: #fff; border-radius: 10px; padding: 10px; box-shadow: 0 2px 8px rgba(0,0,0,0.05); }
+.card_header { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; }
+.card_title { font-weight: 500; color: #333; }
+.card_body .row { display: flex; justify-content: space-between; padding: 4px 0; }
+.card_body .row.inline { display: flex; gap: 10px; flex-wrap: wrap; }
+.card_body .row.inline .col { min-width: 45%; display: flex; justify-content: space-between; }
+.label { color: #666; font-size: 12px; }
+.value { color: #333; font-size: 12px; }
+.pagination { display: flex; align-items: center; justify-content: center; gap: 10px; padding: 12px 0; }
+.page_text { color: #666; font-size: 12px; }
+</style>
diff --git a/src/pages/productionManagement/productionDispatching/components/autoDispatchDia.vue b/src/pages/productionManagement/productionDispatching/components/autoDispatchDia.vue
new file mode 100644
index 0000000..7b2dfdc
--- /dev/null
+++ b/src/pages/productionManagement/productionDispatching/components/autoDispatchDia.vue
@@ -0,0 +1,381 @@
+<template>
+  <view>
+    <up-popup
+        v-model:show="dialogFormVisible"
+        mode="center"
+        border-radius="20"
+        :closeable="true"
+        @close="closeDia"
+    >
+      <view class="popup-content">
+        <view class="popup-header">
+          <text class="popup-title">鑷姩娲惧伐</text>
+        </view>
+        
+        <view class="popup-body">
+          <view class="section-title">娲惧伐鍒楄〃</view>
+          
+          <view class="card-list">
+            <view 
+                v-for="(item, index) in dispatchList" 
+                :key="index"
+                class="dispatch-card"
+                :class="{ 'even-card': index % 2 === 1 }"
+            >
+              <view class="card-header">
+                <text class="card-index">{{ index + 1 }}</text>
+                <text class="card-project">{{ item.projectName }}</text>
+              </view>
+              
+              <view class="card-content">
+                <view class="info-row">
+                  <text class="info-label">鍚堝悓鍙凤細</text>
+                  <text class="info-value">{{ item.salesContractNo }}</text>
+                </view>
+                
+                <view class="info-row">
+                  <text class="info-label">瀹㈡埛锛�</text>
+                  <text class="info-value">{{ item.customerName }}</text>
+                </view>
+                
+                <view class="info-row">
+                  <text class="info-label">浜у搧绫诲埆锛�</text>
+                  <text class="info-value">{{ item.productCategory }}</text>
+                </view>
+                
+                <view class="info-row">
+                  <text class="info-label">瑙勬牸鍨嬪彿锛�</text>
+                  <text class="info-value">{{ item.specificationModel }}</text>
+                </view>
+                
+                <view class="info-row">
+                  <text class="info-label">缁戝畾鏈哄櫒锛�</text>
+                  <text class="info-value">{{ item.speculativeTradingName }}</text>
+                </view>
+                
+                <view class="quantity-row">
+                  <view class="quantity-item">
+                    <text class="quantity-label">鎬绘暟閲忥細</text>
+                    <text class="quantity-value">{{ item.quantity }}</text>
+                  </view>
+                  
+                  <view class="quantity-item">
+                    <text class="quantity-label">宸叉帓浜э細</text>
+                    <text class="quantity-value">{{ item.schedulingNum }}</text>
+                  </view>
+                  
+                  <view class="quantity-item">
+                    <text class="quantity-label">寰呮帓浜э細</text>
+                    <text class="quantity-value">{{ item.pendingQuantity }}</text>
+                  </view>
+                </view>
+                
+                <view class="scheduling-row">
+                  <text class="scheduling-label">鏈鎺掍骇锛�</text>
+                  <up-number-box
+                      v-model="item.schedulingNum"
+                      :min="0"
+                      :max="item.pendingQuantity"
+                      :step="1"
+                      :precision="0"
+                      size="mini"
+                      @change="(value) => changeCurrentNum(value, item)"
+                      class="scheduling-input"
+                  />
+                </view>
+              </view>
+            </view>
+          </view>
+          
+          <view v-if="dispatchList.length === 0" class="empty-state">
+            <text class="empty-text">鏆傛棤娲惧伐鏁版嵁</text>
+          </view>
+        </view>
+        
+        <view class="popup-footer">
+          <up-button type="primary" @click="submitForm" class="confirm-btn">纭娲惧伐</up-button>
+          <up-button @click="closeDia" class="cancel-btn">鍙栨秷</up-button>
+        </view>
+      </view>
+    </up-popup>
+  </view>
+</template>
+
+<script setup>
+import { ref, reactive, toRefs } from "vue";
+import { productionDispatchList } from "@/api/productionManagement/productionOrder.js";
+
+const emit = defineEmits(['close'])
+
+const dialogFormVisible = ref(false);
+const operationType = ref('')
+
+const data = reactive({
+  form: {},
+  dispatchList: [], // 娲惧伐鍒楄〃鏁版嵁
+});
+
+const { form, dispatchList } = toRefs(data);
+
+// 琛ㄦ牸琛屾牱寮�
+const tableRowClassName = ({ rowIndex }) => {
+  if (rowIndex % 2 === 1) {
+    return 'even-row'
+  }
+  return ''
+}
+
+// 淇敼鏈鎺掍骇鏁伴噺
+const changeCurrentNum = (value, row) => {
+  if (value > row.pendingQuantity) {
+    row.schedulingNum = row.pendingQuantity
+    uni.$u.toast('鎺掍骇鏁伴噺涓嶅彲澶т簬寰呮帓浜ф暟閲�')
+  }
+}
+
+// 鎵撳紑寮规
+const openDialog = (rows) => {
+  dialogFormVisible.value = true;
+  
+  console.log('鎺ユ敹鍒颁紶鍏ョ殑鏁版嵁:', rows);
+  console.log('浼犲叆鏁版嵁鏁伴噺:', rows.length);
+  
+  // 澶勭悊浼犲叆鐨勬暟鎹�
+  dispatchList.value = rows.map((row, index) => ({
+    ...row,
+    schedulingNum: 0, // 鍒濆鍖栨湰娆℃帓浜ф暟閲忎负0
+    pendingQuantity: (Number(row.quantity) || 0) - (Number(row.schedulingNum) || 0) // 璁$畻寰呮帓浜ф暟閲�
+  }))
+  
+  console.log('澶勭悊鍚庣殑娲惧伐鍒楄〃:', dispatchList.value);
+  console.log('娲惧伐鍒楄〃鏁伴噺:', dispatchList.value.length);
+}
+
+// 鎻愪氦琛ㄥ崟
+const submitForm = () => {
+  // 妫�鏌ユ槸鍚︽湁鎺掍骇鏁版嵁
+  const hasSchedulingData = dispatchList.value.some(item => item.schedulingNum > 0)
+  if (!hasSchedulingData) {
+    uni.$u.toast('璇疯嚦灏戜负涓�鏉¤褰曡缃帓浜ф暟閲�')
+    return
+  }
+  
+  // 鏋勯�犳彁浜ゆ暟鎹� - 鐩存帴浼犻�掓暟缁勶紝涓嶈繃婊�
+  const submitData = dispatchList.value
+  
+  console.log('鎻愪氦鑷姩娲惧伐鏁版嵁:', submitData)
+  
+  // 璋冪敤API锛堣繖閲岄渶瑕佹牴鎹疄闄呮帴鍙h皟鏁达級
+  productionDispatchList(submitData).then(res => {
+    uni.$u.toast(res.msg || '娲惧伐鎴愬姛');
+    closeDia();
+  }).catch(err => {
+    uni.$u.toast('娲惧伐澶辫触');
+    console.error('娲惧伐澶辫触:', err);
+  })
+}
+
+// 鍏抽棴寮规
+const closeDia = () => {
+  dialogFormVisible.value = false;
+  dispatchList.value = []
+  emit('close')
+};
+
+defineExpose({
+  openDialog,
+});
+</script>
+
+<style lang="scss" scoped>
+.popup-content {
+  width: 90vw;
+  max-width: 1200px;
+  background: #fff;
+  border-radius: 20rpx;
+  overflow: hidden;
+}
+
+.popup-header {
+  padding: 30rpx;
+  border-bottom: 1rpx solid #f0f0f0;
+  text-align: center;
+}
+
+.popup-title {
+  font-size: 36rpx;
+  font-weight: bold;
+  color: #333;
+}
+
+.popup-body {
+  padding: 30rpx;
+  height: 60vh;
+  overflow-y: auto;
+  overflow-x: hidden;
+  -webkit-overflow-scrolling: touch;
+  max-height: 60vh;
+}
+
+.section-title {
+  font-size: 32rpx;
+  font-weight: bold;
+  color: #333;
+  margin-bottom: 20rpx;
+  flex-shrink: 0;
+}
+
+.card-list {
+  display: flex;
+  flex-direction: column;
+  gap: 20rpx;
+  min-height: 0;
+  overflow-y: auto;
+  max-height: 60vh;
+}
+
+.dispatch-card {
+  background: #f8f9fa;
+  border-radius: 12rpx;
+  padding: 24rpx;
+  border: 1rpx solid #e9ecef;
+  transition: all 0.3s ease;
+  flex-shrink: 0;
+}
+
+.dispatch-card:hover {
+  box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
+  transform: translateY(-2rpx);
+}
+
+.even-card {
+  background: #ffffff;
+}
+
+.card-header {
+  display: flex;
+  align-items: center;
+  margin-bottom: 20rpx;
+  padding-bottom: 16rpx;
+  border-bottom: 1rpx solid #e9ecef;
+}
+
+.card-index {
+  background: #1890ff;
+  color: white;
+  width: 40rpx;
+  height: 40rpx;
+  border-radius: 50%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  font-size: 24rpx;
+  font-weight: bold;
+  margin-right: 16rpx;
+}
+
+.card-project {
+  font-size: 28rpx;
+  font-weight: bold;
+  color: #333;
+  flex: 1;
+}
+
+.card-content {
+  display: flex;
+  flex-direction: column;
+  gap: 12rpx;
+}
+
+.info-row {
+  display: flex;
+  align-items: center;
+}
+
+.info-label {
+  font-size: 26rpx;
+  color: #666;
+  width: 140rpx;
+  flex-shrink: 0;
+}
+
+.info-value {
+  font-size: 26rpx;
+  color: #333;
+  flex: 1;
+}
+
+.quantity-row {
+  display: flex;
+  gap: 20rpx;
+  margin: 8rpx 0;
+}
+
+.quantity-item {
+  display: flex;
+  align-items: center;
+  background: #f8f9fa;
+  padding: 8rpx 16rpx;
+  border-radius: 6rpx;
+  border: 1rpx solid #e9ecef;
+}
+
+.quantity-label {
+  font-size: 24rpx;
+  color: #666;
+  margin-right: 8rpx;
+}
+
+.quantity-value {
+  font-size: 24rpx;
+  color: #1890ff;
+  font-weight: bold;
+}
+
+.scheduling-row {
+  display: flex;
+  align-items: center;
+  margin-top: 12rpx;
+  padding-top: 12rpx;
+  border-top: 1rpx dashed #e9ecef;
+}
+
+.scheduling-label {
+  font-size: 26rpx;
+  color: #333;
+  font-weight: bold;
+  margin-right: 16rpx;
+  width: 140rpx;
+  flex-shrink: 0;
+}
+
+.scheduling-input {
+  flex: 1;
+}
+
+.empty-state {
+  text-align: center;
+  padding: 60rpx 30rpx;
+  color: #999;
+}
+
+.empty-text {
+  font-size: 28rpx;
+}
+
+.popup-footer {
+  padding: 30rpx;
+  border-top: 1rpx solid #f0f0f0;
+  display: flex;
+  justify-content: center;
+  gap: 20rpx;
+}
+
+.confirm-btn {
+  width: 200rpx;
+}
+
+.cancel-btn {
+  width: 200rpx;
+}
+</style>
\ No newline at end of file
diff --git a/src/pages/productionManagement/productionDispatching/index.vue b/src/pages/productionManagement/productionDispatching/index.vue
index 87c3da0..6168994 100644
--- a/src/pages/productionManagement/productionDispatching/index.vue
+++ b/src/pages/productionManagement/productionDispatching/index.vue
@@ -2,7 +2,7 @@
 	<view class="production-dispatching">
 		<!-- 浣跨敤閫氱敤椤甸潰澶撮儴缁勪欢 -->
 		<PageHeader title="鐢熶骇娲惧伐" @back="goBack" />
-		
+
 		<!-- 鐐掓満鐘舵�佸睍绀� -->
 		<view class="machines-section">
 			<view class="section-title">鐐掓満鐘舵��</view>
@@ -33,6 +33,28 @@
 					</view>
 				</view>
 			</view>
+			<!-- 鎹熻�楃巼璁剧疆 -->
+		<view class="loss-rate-section">
+			<view class="section-title">鎹熻�楃巼璁剧疆</view>
+			<view class="loss-rate-content">
+				<view class="loss-rate-item">
+					<up-button 
+						class="loss-rate-btn" 
+						type="primary" 
+						plain
+						size="small"
+						@click="showLossRateSheet = true"
+					>{{ lossRate ? `鎹熻�楃巼: ${lossRate}%` : '璇烽�夋嫨鎹熻�楃巼' }}</up-button>
+					<up-action-sheet 
+					:show="showLossRateSheet"
+					:actions="lossRateOptions" 
+					@select="onLossRateSelect"
+					title="閫夋嫨鎹熻�楃巼"
+					@close="showLossRateSheet = false"
+				/>
+				</view>
+			</view>
+		</view>
 			<view class="save-section">
 				<up-button type="primary" @click="saveMachineTotals" size="normal" class="save-btn">淇濆瓨鐐掓満璁剧疆</up-button>
 			</view>
@@ -71,46 +93,41 @@
 		</view>
 		
 		<!-- 鎵归噺鎿嶄綔鍖哄煙 -->
-		<view v-if="showBatchActions" class="batch-actions-section">
+		<view class="batch-actions-section" v-if="showBatchActions">
 			<view class="batch-info">
-				<text class="batch-count">宸查�夋嫨 {{ selectedItems.length }} 涓」鐩�</text>
+				<text class="batch-text">宸查�夋嫨 {{ selectedItems.length }} 涓」鐩�</text>
 			</view>
 			<view class="batch-buttons">
-				<up-button type="primary" size="small" @click="handleAutoDispatch" class="batch-btn">
-					<up-icon name="play-circle" size="16" color="#ffffff"></up-icon>
-					鑷姩娲惧崟
-				</up-button>
-				<up-button type="default" size="small" @click="clearSelection" class="batch-btn">
-					<up-icon name="close-circle" size="16" color="#6c757d"></up-icon>
-					鍙栨秷閫夋嫨
-				</up-button>
+				<up-button type="primary" size="small" @click="handleAutoDispatch" class="batch-btn">鑷姩娲惧崟</up-button>
+				<up-button type="default" size="small" @click="clearSelection" class="batch-btn">鍙栨秷閫夋嫨</up-button>
 			</view>
 		</view>
-		
+
 		<!-- 鍏ㄩ�夋搷浣滃尯鍩� -->
-		<view v-if="tableData.length > 0" class="select-all-section">
-			<view class="select-all-checkbox" @click="toggleAllSelection">
-				<up-icon 
-					:name="isAllSelected ? 'checkbox-mark' : 'circle'" 
-					:color="isAllSelected ? '#409eff' : '#c0c4cc'"
-					size="18"
-				></up-icon>
-				<text class="select-all-text">{{ isAllSelected ? '鍙栨秷鍏ㄩ��' : '鍏ㄩ��' }}</text>
+		<view class="select-all-section" v-if="tableData.length > 0">
+			<view class="select-all-content">
+				<up-checkbox 
+				v-model="isAllSelected" 
+				@change="toggleAllSelection"
+				label="鍏ㄩ��"
+				class="select-all-checkbox"
+				:disabled="tableData.length === 0 || tableData.filter(item => item.pendingQuantity > 0 && item.speculativeTradingName).length === 0"
+			/>
 			</view>
-			<text class="select-all-hint">锛堜粎閫夋嫨寰呮帓鏁伴噺澶т簬0鐨勯」鐩級</text>
 		</view>
-		
+
 		<!-- 鐢熶骇娲惧伐鍒楄〃 -->
 		<view class="ledger-list" v-if="tableData.length > 0">
 			<view v-for="(item, index) in tableData" :key="item.id || index" class="list-item">
 				<view class="ledger-item">
 					<!-- 閫夋嫨澶嶉�夋 -->
-					<view class="item-checkbox" @click="toggleItemSelection(item)">
-						<up-icon 
-							:name="selectedItems.includes(item.id) ? 'checkbox-mark' : 'circle'" 
-							:color="selectedItems.includes(item.id) ? '#409eff' : '#c0c4cc'"
-							size="18"
-						></up-icon>
+					<view class="item-checkbox">
+						<up-checkbox 
+					:model-value="selectedItems.some(selected => selected.id === item.id)"
+					@change="(checked) => toggleItemSelection(item, checked)"
+					:disabled="item.pendingQuantity <= 0 || !item.speculativeTradingName"
+					shape="circle"
+				/>
 					</view>
 					
 					<view class="item-content">
@@ -146,6 +163,10 @@
 								<text class="detail-value">{{ item.specificationModel }}</text>
 							</view>
 							<view class="detail-row">
+								<text class="detail-label">缁戝畾鏈哄櫒</text>
+								<text class="detail-value">{{ item.speculativeTradingName }}</text>
+							</view>
+							<view class="detail-row">
 								<text class="detail-label">鍗曚綅</text>
 								<text class="detail-value">{{ item.unit }}</text>
 							</view>
@@ -165,14 +186,14 @@
 							<!-- 鎿嶄綔鎸夐挳鍖哄煙 -->
 							<view class="action-buttons">
 								<up-button
-									type="primary"
-									size="small"
-									@click="handleDispatch(item)"
-									class="action-btn"
-									:disabled="item.pendingQuantity <= 0"
-								>
-									{{ item.pendingQuantity <= 0 ? '鏃犻渶娲惧伐' : '鐢熶骇娲惧伐' }}
-								</up-button>
+						type="primary"
+						size="small"
+						@click="handleDispatch(item)"
+						class="action-btn"
+						:disabled="item.pendingQuantity <= 0 || !item.speculativeTradingName"
+					>
+						{{ item.pendingQuantity <= 0 ? '鏃犻渶娲惧伐' : !item.speculativeTradingName ? '鏈粦瀹氭満鍣�' : '鐢熶骇娲惧伐' }}
+					</up-button>
 							</view>
 						</view>
 					</view>
@@ -188,16 +209,20 @@
 		
 		<!-- 娲惧伐寮圭獥 -->
 		<DispatchModal ref="dispatchModalRef" @confirm="handleDispatchConfirm" />
+		
+		<!-- 鑷姩娲惧崟寮圭獥 -->
+		<AutoDispatchDia ref="autoDispatchDia" />
 	</view>
 </template>
 
 <script setup>
-import { ref, reactive, toRefs, getCurrentInstance } from "vue";
+import { ref, reactive, toRefs, getCurrentInstance, nextTick } from "vue";
 import { onShow } from '@dcloudio/uni-app';
 import dayjs from "dayjs";
-import {schedulingListPage, schedulingList, addSpeculatTrading, updateSpeculatTrading} from "@/api/productionManagement/productionOrder.js";
+import {schedulingListPage, schedulingList, addSpeculatTrading, updateSpeculatTrading, getLossRate, addLossRate, updateLossRate} from "@/api/productionManagement/productionOrder.js";
 import PageHeader from "@/components/PageHeader.vue";
 import DispatchModal from "./components/DispatchModal.vue";
+import AutoDispatchDia from "./components/autoDispatchDia.vue";
 
 const { proxy } = getCurrentInstance();
 
@@ -207,10 +232,10 @@
 // 鍒楄〃鏁版嵁
 const tableData = ref([]);
 
-// 鎵归噺閫夋嫨鐩稿叧鏁版嵁
-const selectedItems = ref([]); // 閫変腑鐨勯」鐩甀D鏁扮粍
-const isAllSelected = ref(false); // 鏄惁鍏ㄩ��
-const showBatchActions = ref(false); // 鏄惁鏄剧ず鎵归噺鎿嶄綔鍖哄煙
+// 閫夋嫨鐩稿叧鏁版嵁
+const selectedItems = ref([]);
+const isAllSelected = ref(false);
+const showBatchActions = ref(false);
 
 // 鎼滅储琛ㄥ崟鏁版嵁
 const data = reactive({
@@ -261,8 +286,23 @@
 // 鏄惁鏈夋煡璇㈡暟鎹紙鐢ㄤ簬鍒ゆ柇鏄柊澧炶繕鏄慨鏀癸級
 const hasQueryData = ref(false);
 
+// 鎹熻�楃巼鐩稿叧鏁版嵁
+const lossRate = ref(""); // 褰撳墠閫夋嫨鐨勬崯鑰楃巼
+const showLossRateSheet = ref(false); // 鎺у埗鎹熻�楃巼閫夋嫨闈㈡澘鏄剧ず
+const lossRateOptions = ref([
+	{ name: "6%", value: "6" },
+	{ name: "7%", value: "7" },
+	{ name: "8%", value: "8" },
+	{ name: "9%", value: "9" },
+	{ name: "10%", value: "10" }
+]);
+const lossRateData = ref(null); // 鎹熻�楃巼鏌ヨ杩斿洖鐨勬暟鎹�
+
 // 娲惧伐寮圭獥寮曠敤
 const dispatchModalRef = ref();
+
+// 鑷姩娲惧崟寮圭獥寮曠敤
+const autoDispatchDia = ref();
 
 // 閫氱敤鎻愮ず鍑芥暟
 const showLoadingToast = (message) => {
@@ -328,6 +368,28 @@
 	});
 };
 
+// 鎹熻�楃巼閫夋嫨浜嬩欢
+const onLossRateSelect = (action) => {
+	lossRate.value = action.value;
+	showLossRateSheet.value = false;
+	console.log('閫夋嫨浜嗘崯鑰楃巼:', action.name, '鍊�:', action.value);
+};
+
+// 鑾峰彇鎹熻�楃巼鏁版嵁
+const getLossRateData = () => {
+	getLossRate().then((res) => {
+		if (res.data) {
+			lossRateData.value = res.data;
+			// 璁剧疆褰撳墠閫夋嫨鐨勬崯鑰楃巼
+			if (res.data.rate !== null && res.data.rate !== undefined) {
+				lossRate.value = res.data.rate.toString();
+			}
+		}
+	}).catch(err => {
+		console.error('鑾峰彇鎹熻�楃巼澶辫触:', err);
+	});
+};
+
 // 鑾峰彇鍒楄〃鏁版嵁
 const getList = () => {
 	loading.value = true;
@@ -340,14 +402,17 @@
 		closeToast();
 		
 		tableData.value = (res.data.records || []).map(item => ({
-			...item,
-			pendingQuantity: (Number(item.quantity) || 0) - (Number(item.schedulingNum) || 0)
-		}));
+				...item,
+				pendingQuantity: (Number(item.quantity) || 0) - (Number(item.schedulingNum) || 0)
+			})).filter(item => item.pendingQuantity > 0);
 		
 		page.total = res.data.total || 0;
 		
 		// 鑾峰彇鐐掓満鏁版嵁
 		getMachineProductionData();
+		
+		// 鑾峰彇鎹熻�楃巼鏁版嵁
+		getLossRateData();
 		
 	}).catch(() => {
 		loading.value = false;
@@ -364,6 +429,14 @@
 	if (item.pendingQuantity <= 0) {
 		uni.showToast({
 			title: '璇ラ」鐩棤闇�鍐嶆淳宸�',
+			icon: 'none'
+		});
+		return;
+	}
+	
+	if (!item.speculativeTradingName) {
+		uni.showToast({
+			title: '璇ラ」鐩湭缁戝畾鏈哄櫒锛屾棤娉曟淳宸�',
 			icon: 'none'
 		});
 		return;
@@ -392,6 +465,51 @@
 		workLoad: machineTotal[`m${machineId}`] || 0,
 		currentWorkLoad: machineInProduction[`m${machineId}`] || 0
 	};
+};
+
+// 淇濆瓨鎹熻�楃巼璁剧疆
+const saveLossRate = () => {
+	if (!lossRate.value) {
+		console.log('鏈�夋嫨鎹熻�楃巼锛岃烦杩囦繚瀛�');
+		return Promise.resolve();
+	}
+	
+	const lossRateDataToSave = {
+		rate: parseFloat(lossRate.value) || 0
+	};
+	
+	// 濡傛灉鏈夋煡璇㈠埌鐨勬崯鑰楃巼鏁版嵁锛岃鏄庢槸淇敼鎿嶄綔锛岄渶瑕佷紶閫抜d
+	if (lossRateData.value && lossRateData.value.id) {
+		lossRateDataToSave.id = lossRateData.value.id;
+	}
+	
+	console.log('淇濆瓨鎹熻�楃巼鏁版嵁:', lossRateDataToSave);
+	
+	// 鏍规嵁鏄惁鏈夋崯鑰楃巼鏁版嵁鍐冲畾璋冪敤鏂板鎺ュ彛杩樻槸淇敼鎺ュ彛
+	const saveLossApi = lossRateData.value && lossRateData.value.id ? updateLossRate : addLossRate;
+	const successMessage = lossRateData.value && lossRateData.value.id ? '鎹熻�楃巼淇敼鎴愬姛' : '鎹熻�楃巼鏂板鎴愬姛';
+	
+	return saveLossApi(lossRateDataToSave).then(res => {
+		console.log('鎹熻�楃巼淇濆瓨鎴愬姛:', res);
+		uni.showToast({
+			title: successMessage,
+			icon: 'success'
+		});
+		
+		// 鏇存柊鎹熻�楃巼鏁版嵁
+		if (res.data) {
+			lossRateData.value = res.data;
+		}
+		
+		return res;
+	}).catch(err => {
+		console.error('鎹熻�楃巼淇濆瓨澶辫触:', err);
+		uni.showToast({
+			title: '鎹熻�楃巼淇濆瓨澶辫触',
+			icon: 'none'
+		});
+		throw err;
+	});
 };
 
 // 淇濆瓨鐐掓満鎬婚噺璁剧疆
@@ -425,9 +543,15 @@
 	
 	console.log(`璋冪敤鎺ュ彛: ${hasQueryData.value ? '淇敼' : '鏂板'}`);
 	
-	// 璋冪敤鍚庣API淇濆瓨
-	saveApi(saveData).then(res => {
-		proxy.$message.success(successMessage);
+	// 鍏堜繚瀛樻崯鑰楃巼锛屽啀淇濆瓨鐐掓満璁剧疆
+	saveLossRate().then(() => {
+		// 璋冪敤鍚庣API淇濆瓨鐐掓満璁剧疆
+		return saveApi(saveData);
+	}).then(res => {
+		uni.showToast({
+			title: successMessage,
+			icon: 'success'
+		});
 		console.log('淇濆瓨鎴愬姛:', res);
 		
 		// 淇濆瓨鎴愬姛鍚庯紝璁剧疆hasQueryData涓簍rue锛屼笅娆′繚瀛樺皢璋冪敤淇敼鎺ュ彛
@@ -435,61 +559,69 @@
 			hasQueryData.value = true;
 		}
 	}).catch(err => {
-		proxy.$message.error('淇濆瓨澶辫触');
+		uni.showToast({
+			title: '淇濆瓨澶辫触',
+			icon: 'none'
+		});
 		console.error('淇濆瓨澶辫触:', err);
 	});
 };
 
-// 鎵归噺閫夋嫨鐩稿叧鍑芥暟
-
-// 鍒囨崲鍗曚釜椤圭洰鐨勯�夋嫨鐘舵��
-const toggleItemSelection = (item) => {
-	const itemId = item.id;
-	const index = selectedItems.value.indexOf(itemId);
+// 鍒囨崲鍗曚釜椤圭洰閫夋嫨鐘舵��
+const toggleItemSelection = (item, checked) => {
+	// 浠呭厑璁搁�夋嫨宸茬粦瀹氭満鍣ㄤ笖寰呮淳鏁伴噺>0鐨勯」鐩�
+	if (!item.speculativeTradingName || item.pendingQuantity <= 0) return;
 	
-	if (index > -1) {
-		// 濡傛灉宸查�変腑锛屽垯鍙栨秷閫夋嫨
-		selectedItems.value.splice(index, 1);
+	console.log('鍒囨崲閫夋嫨鐘舵��:', item.id, checked);
+	
+	// 浣跨敤鏇翠弗鏍肩殑姣旇緝閫昏緫锛岀‘淇滻D鍞竴鎬�
+	const index = selectedItems.value.findIndex(selected => {
+		// 娣卞害姣旇緝瀵硅薄锛岀‘淇濇槸鍚屼竴涓」鐩�
+		return JSON.stringify(selected) === JSON.stringify(item);
+	});
+	
+	if (checked) {
+		// 濡傛灉閫変腑涓斾笉鍦ㄩ�変腑鍒楄〃涓紝鍒欐坊鍔�
+		if (index === -1) {
+			selectedItems.value.push({...item}); // 鍒涘缓鏂板璞★紝閬垮厤寮曠敤闂
+			console.log('娣诲姞椤圭洰鍚庨�変腑鏁伴噺:', selectedItems.value.length);
+		}
 	} else {
-		// 濡傛灉鏈�変腑锛屽垯娣诲姞閫夋嫨
-		selectedItems.value.push(itemId);
+		// 濡傛灉鍙栨秷閫変腑涓斿湪閫変腑鍒楄〃涓紝鍒欑Щ闄�
+		if (index > -1) {
+			selectedItems.value.splice(index, 1);
+			console.log('绉婚櫎椤圭洰鍚庨�変腑鏁伴噺:', selectedItems.value.length);
+		}
 	}
 	
-	// 鏇存柊鍏ㄩ�夌姸鎬�
+	console.log('褰撳墠閫変腑椤圭洰鍒楄〃:', selectedItems.value.map(s => s.id));
 	updateAllSelectedStatus();
-	// 鏇存柊鎵归噺鎿嶄綔鍖哄煙鏄剧ず鐘舵��
 	updateBatchActionsVisibility();
 };
 
 // 鍒囨崲鍏ㄩ�夌姸鎬�
 const toggleAllSelection = () => {
 	if (isAllSelected.value) {
-		// 鍙栨秷鍏ㄩ��
 		selectedItems.value = [];
 	} else {
-		// 鍏ㄩ��
-		selectedItems.value = tableData.value
-			.filter(item => item.pendingQuantity > 0) // 鍙�夋嫨寰呮帓鏁伴噺澶т簬0鐨勯」鐩�
-			.map(item => item.id);
+		selectedItems.value = tableData.value.filter(item => item.pendingQuantity > 0 && item.speculativeTradingName).map(item => ({ ...item }));
 	}
-	
 	isAllSelected.value = !isAllSelected.value;
 	updateBatchActionsVisibility();
 };
 
 // 鏇存柊鍏ㄩ�夌姸鎬�
 const updateAllSelectedStatus = () => {
-	const selectableItems = tableData.value.filter(item => item.pendingQuantity > 0);
-	if (selectableItems.length === 0) {
+	const selectableItems = tableData.value.filter(item => item.pendingQuantity > 0 && item.speculativeTradingName);
+	if (selectableItems.length > 0 && selectedItems.value.length === selectableItems.length && 
+		selectableItems.every(item => selectedItems.value.some(selected => selected.id === item.id))) {
+		isAllSelected.value = true;
+	} else {
 		isAllSelected.value = false;
-		return;
 	}
-	
-	isAllSelected.value = selectedItems.value.length === selectableItems.length && 
-		selectableItems.every(item => selectedItems.value.includes(item.id));
 };
 
-// 鏇存柊鎵归噺鎿嶄綔鍖哄煙鏄剧ず鐘舵��
+// 鏇存柊鎵归噺鎿嶄綔鏄剧ず鐘舵��
 const updateBatchActionsVisibility = () => {
 	showBatchActions.value = selectedItems.value.length > 0;
 };
@@ -503,80 +635,36 @@
 
 // 鑾峰彇閫変腑鐨勯」鐩�
 const getSelectedItems = () => {
-	return tableData.value.filter(item => selectedItems.value.includes(item.id));
+	return selectedItems.value;
 };
 
-// 鑷姩娲惧崟鍔熻兘
+// 澶勭悊鑷姩娲惧崟
 const handleAutoDispatch = () => {
-	const selectedItemsList = getSelectedItems();
-	
-	if (selectedItemsList.length === 0) {
+	if (selectedItems.value.length === 0) {
 		uni.showToast({
-			title: '璇峰厛閫夋嫨瑕佹淳宸ョ殑椤圭洰',
+			title: '璇烽�夋嫨瑕佹淳宸ョ殑椤圭洰',
 			icon: 'none'
 		});
 		return;
 	}
 	
-	// 妫�鏌ユ槸鍚︽湁椤圭洰寰呮帓鏁伴噺涓嶈冻
-	const invalidItems = selectedItemsList.filter(item => item.pendingQuantity <= 0);
-	if (invalidItems.length > 0) {
+	// 妫�鏌ユ槸鍚︽墍鏈夐�変腑椤圭洰閮芥湁缁戝畾鏈哄櫒
+	const unboundItems = selectedItems.value.filter(item => !item.speculativeTradingName);
+	if (unboundItems.length > 0) {
 		uni.showToast({
-			title: `鏈�${invalidItems.length}涓」鐩棤闇�娲惧伐锛屽凡鑷姩杩囨护`,
-			icon: 'none'
-		});
-	}
-	
-	// 杩囨护鎺夊緟鎺掓暟閲忎笉瓒崇殑椤圭洰
-	const validItems = selectedItemsList.filter(item => item.pendingQuantity > 0);
-	
-	if (validItems.length === 0) {
-		uni.showToast({
-			title: '娌℃湁鍙淳宸ョ殑椤圭洰',
+			title: '鎵�閫夐」鐩腑鏈夋湭缁戝畾鏈哄櫒鐨勯」鐩紝鏃犳硶鑷姩娲惧崟',
 			icon: 'none'
 		});
 		return;
 	}
 	
-	uni.showModal({
-		title: '纭鑷姩娲惧崟',
-		content: `纭畾瑕佸閫変腑鐨�${validItems.length}涓」鐩繘琛岃嚜鍔ㄦ淳鍗曞悧锛焋,
-		success: (res) => {
-			if (res.confirm) {
-				executeAutoDispatch(validItems);
-			}
-		}
-	});
-};
-
-// 鎵ц鑷姩娲惧崟
-const executeAutoDispatch = (items) => {
-	showLoadingToast('鑷姩娲惧崟涓�...');
-	
-	// 妯℃嫙鑷姩娲惧崟杩囩▼
-	setTimeout(() => {
-		closeToast();
-		
-		// 杩欓噷搴旇璋冪敤瀹為檯鐨勮嚜鍔ㄦ淳鍗旳PI
-		// 鏆傛椂浣跨敤妯℃嫙鎴愬姛
-		uni.showToast({
-			title: `鎴愬姛涓�${items.length}涓」鐩畬鎴愯嚜鍔ㄦ淳鍗昤,
-			icon: 'success'
-		});
-		
-		// 娓呯┖閫夋嫨
-		clearSelection();
-		// 鍒锋柊鍒楄〃
-		getList();
-		
-		console.log('鑷姩娲惧崟椤圭洰:', items);
-	}, 1500);
+	// 纭繚浼犻�掔殑鏄畬鏁寸殑閫変腑椤圭洰鏁扮粍
+	autoDispatchDia.value?.openDialog([...selectedItems.value]);
 };
 
 // 椤甸潰鏄剧ず鏃跺姞杞芥暟鎹�
 onShow(() => {
 	getList();
-	// 娓呯┖閫夋嫨鐘舵��
 	clearSelection();
 });
 </script>
@@ -588,16 +676,63 @@
 	padding: 20rpx;
 }
 
+// 鎹熻�楃巼璁剧疆鍖哄煙
+.loss-rate-section {
+	background: #ffffff;
+	border: 1rpx solid #e4e7ed;
+	border-radius: 12rpx;
+	padding: 32rpx;
+	margin-top: 24rpx;
+	margin-bottom: 32rpx;
+	box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.08);
+}
+
+.loss-rate-section .section-title {
+	font-size: 32rpx;
+	font-weight: 600;
+	color: #303133;
+	margin-bottom: 20rpx;
+}
+
+.loss-rate-section .loss-rate-content {
+	display: flex;
+	flex-direction: column;
+	gap: 24rpx;
+}
+
+.loss-rate-section .loss-rate-content .loss-rate-item {
+	display: flex;
+	align-items: center;
+	gap: 24rpx;
+}
+
+.loss-rate-section .loss-rate-content .loss-rate-label {
+	font-size: 30rpx;
+	font-weight: 500;
+	color: #303133;
+	min-width: 140rpx;
+	white-space: nowrap;
+}
+
+.loss-rate-section .loss-rate-content .loss-rate-btn {
+	min-width: 260rpx;
+	font-size: 28rpx;
+	height: 64rpx;
+	line-height: 64rpx;
+	border-radius: 8rpx;
+	font-weight: 500;
+}
+
 // 鐐掓満鐘舵�佸尯鍩�
 .machines-section {
 	margin-bottom: 30rpx;
-	
-	.section-title {
-		font-size: 32rpx;
-		font-weight: 600;
-		color: #303133;
-		margin-bottom: 20rpx;
-	}
+}
+
+.machines-section .section-title {
+	font-size: 32rpx;
+	font-weight: 600;
+	color: #303133;
+	margin-bottom: 20rpx;
 }
 
 .machines-grid {
@@ -771,10 +906,10 @@
 	align-items: center;
 	padding: 12rpx 0;
 	border-bottom: 1rpx solid #f5f5f5;
-	
-	&:last-child {
-		border-bottom: none;
-	}
+}
+
+.detail-row:last-child {
+	border-bottom: none;
 }
 
 .detail-label {
@@ -786,16 +921,16 @@
 	font-size: 26rpx;
 	color: #303133;
 	font-weight: 500;
-	
-	&.highlight {
-		color: #ff6b35;
-		font-weight: 600;
-	}
-	
-	&.danger {
-		color: #ee0a24;
-		font-weight: 600;
-	}
+}
+
+.detail-value.highlight {
+	color: #ff6b35;
+	font-weight: 600;
+}
+
+.detail-value.danger {
+	color: #ee0a24;
+	font-weight: 600;
 }
 
 .action-buttons {
@@ -808,6 +943,69 @@
 	min-width: 180rpx;
 }
 
+// 鎵归噺鎿嶄綔鍖哄煙鏍峰紡
+.batch-actions-section {
+	background: #e8f4ff;
+	border: 1rpx solid #409eff;
+	border-radius: 12rpx;
+	padding: 20rpx 24rpx;
+	margin-bottom: 24rpx;
+	display: flex;
+	justify-content: space-between;
+	align-items: center;
+}
+
+.batch-actions-section .batch-text {
+	font-size: 28rpx;
+	font-weight: 600;
+	color: #409eff;
+}
+
+.batch-actions-section .batch-buttons {
+	display: flex;
+	gap: 16rpx;
+}
+
+.batch-actions-section .batch-btn {
+	min-width: 140rpx;
+}
+
+// 鍏ㄩ�夋搷浣滃尯鍩熸牱寮�
+.select-all-section {
+	background: #ffffff;
+	border-radius: 12rpx;
+	padding: 20rpx 24rpx;
+	margin-bottom: 16rpx;
+	border: 1rpx solid #e4e7ed;
+}
+
+.select-all-section .select-all-content {
+	display: flex;
+	align-items: center;
+}
+
+.select-all-section .select-all-checkbox {
+	font-size: 28rpx;
+	font-weight: 500;
+}
+
+// 鍒楄〃椤归�夋嫨妗嗘牱寮�
+.ledger-item {
+	display: flex;
+	align-items: flex-start;
+	padding: 0;
+}
+
+.item-checkbox {
+	padding: 24rpx 16rpx 0 24rpx;
+	display: flex;
+	align-items: center;
+}
+
+.item-content {
+	flex: 1;
+}
+
 // 绌虹姸鎬�
 .no-data {
 	padding: 100rpx 0;
@@ -818,88 +1016,6 @@
 	font-size: 28rpx;
 	color: #909399;
 	margin-top: 20rpx;
-}
-
-// 鎵归噺鎿嶄綔鍖哄煙鏍峰紡
-.batch-actions-section {
-	background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
-	border-radius: 16rpx;
-	padding: 24rpx;
-	margin-bottom: 24rpx;
-	box-shadow: 0 8rpx 24rpx rgba(102, 126, 234, 0.3);
-	color: #ffffff;
-}
-
-.batch-info {
-	display: flex;
-	justify-content: space-between;
-	align-items: center;
-	margin-bottom: 20rpx;
-}
-
-.batch-count {
-	font-size: 28rpx;
-	font-weight: 600;
-}
-
-.batch-buttons {
-	display: flex;
-	gap: 20rpx;
-	justify-content: flex-end;
-}
-
-.batch-btn {
-	min-width: 180rpx;
-}
-
-// 鍏ㄩ�夋搷浣滃尯鍩熸牱寮�
-.select-all-section {
-	display: flex;
-	justify-content: space-between;
-	align-items: center;
-	background: #f8f9fa;
-	border-radius: 12rpx;
-	padding: 20rpx 24rpx;
-	margin-bottom: 20rpx;
-	border: 1rpx solid #e9ecef;
-}
-
-.select-all-checkbox {
-	display: flex;
-	align-items: center;
-	gap: 12rpx;
-	cursor: pointer;
-}
-
-.select-all-text {
-	font-size: 26rpx;
-	color: #606266;
-	font-weight: 500;
-}
-
-.select-all-hint {
-	font-size: 22rpx;
-	color: #909399;
-}
-
-// 鍒楄〃椤归�夋嫨鏍峰紡
-.ledger-item {
-	display: flex;
-	align-items: flex-start;
-	padding: 0;
-}
-
-.item-checkbox {
-	padding: 24rpx 16rpx 0 24rpx;
-	cursor: pointer;
-	display: flex;
-	align-items: center;
-	min-height: 48rpx;
-}
-
-.item-content {
-	flex: 1;
-	padding: 0;
 }
 
 // 鐐瑰嚮缂栬緫鍖哄煙鏍峰紡
diff --git a/src/pages/productionManagement/productionReporting/components/formDia.vue b/src/pages/productionManagement/productionReporting/components/formDia.vue
new file mode 100644
index 0000000..1ef480f
--- /dev/null
+++ b/src/pages/productionManagement/productionReporting/components/formDia.vue
@@ -0,0 +1,160 @@
+<template>
+  <view>
+    <up-popup v-model:show="dialogFormVisible" mode="bottom" round="12" :customStyle="{ height: '70vh' }" @close="closeDia">
+      <view class="dia-container">
+        <view class="dia-header">
+          <text class="title">鐢熶骇鎶ュ伐</text>
+        </view>
+
+        <scroll-view class="rows" scroll-y>
+          <up-form :model="form" label-width="120" ref="formRef">
+            <up-form-item label="鎺掍骇鏁伴噺">
+              <up-input v-model="form.schedulingNum" placeholder="璇疯緭鍏�" disabled />
+            </up-form-item>
+            <up-form-item label="鏈鐢熶骇鏁伴噺" prop="finishedNum">
+              <up-input v-model="form.finishedNum" type="number" placeholder="璇疯緭鍏�" @change="changeNum" />
+            </up-form-item>
+            <up-form-item label="寰呯敓浜ф暟閲�">
+              <up-input v-model="form.pendingNum" placeholder="璇疯緭鍏�" disabled />
+            </up-form-item>
+            <up-form-item label="鐢熶骇浜�" @click="openUserPicker">
+              <up-input v-model="form.schedulingUserName" placeholder="閫夋嫨浜哄憳" readonly @click="openUserPicker" />
+              <template #right>
+                <up-icon name="arrow-right" @click="openUserPicker"></up-icon>
+              </template>
+            </up-form-item>
+            <up-form-item label="鐢熶骇鏃ユ湡" @click="openDatePicker">
+              <up-input v-model="form.schedulingDate" placeholder="璇烽�夋嫨鏃ユ湡" readonly @click="openDatePicker" />
+              <template #right>
+                <up-icon name="calendar" @click="openDatePicker"></up-icon>
+              </template>
+            </up-form-item>
+          </up-form>
+        </scroll-view>
+
+        <view class="dia-footer">
+          <up-button type="primary" @click="submitForm">纭</up-button>
+          <up-button @click="closeDia">鍙栨秷</up-button>
+        </view>
+      </view>
+    </up-popup>
+
+    <!-- 鏃ユ湡閫夋嫨鍣� -->
+    <up-popup :show="datePicker.show" mode="bottom" @close="datePicker.show = false">
+      <up-datetime-picker :show="true" v-model="datePicker.value" mode="date" @confirm="onDateConfirm" @cancel="datePicker.show = false" />
+    </up-popup>
+
+    <!-- 浜哄憳閫夋嫨鍣� -->
+    <up-action-sheet :show="userPicker.show" :actions="userActionList" title="閫夋嫨浜哄憳" @select="onUserSelect" @close="userPicker.show = false" />
+  </view>
+</template>
+
+<script setup>
+import { ref, reactive, toRefs, getCurrentInstance, computed } from "vue";
+import { userListNoPageByTenantId } from "@/api/system/user.js";
+import { productionReport, productionReportUpdate } from "@/api/productionManagement/productionReporting.js";
+const { proxy } = getCurrentInstance()
+
+const emit = defineEmits(['close'])
+
+const userList = ref([])
+const dialogFormVisible = ref(false);
+const operationType = ref('')
+const data = reactive({
+  form: {
+		successNum: "",
+		schedulingNum: "",
+		finishedNum: "",
+		schedulingUserId: "",
+		schedulingUserName: "",
+		schedulingDate: "",
+  },
+  rules: {
+		schedulingNum: [{ required: true, message: "璇疯緭鍏�", trigger: "blur" },],
+  },
+});
+const { form, rules } = toRefs(data);
+
+// pickers
+const datePicker = ref({ show: false, value: Date.now() })
+const userPicker = ref({ show: false })
+const userActionList = computed(() => userList.value.map(u => ({ name: u.nickName, value: u.userId })))
+
+// 鎵撳紑寮规
+const openDialog = (type, row) => {
+  operationType.value = type;
+  dialogFormVisible.value = true;
+	userListNoPageByTenantId().then((res) => {
+		userList.value = res.data;
+	});
+	form.value = { ...row, schedulingUserName: row.schedulingUserName || '' }
+	// 鍒濆鍖栵細鏈鐢熶骇鏁伴噺缃┖锛屽緟鐢熶骇 = 鎺掍骇鏁伴噺
+	const sched = Number(form.value.schedulingNum) || 0
+	form.value.finishedNum = ''
+	form.value.pendingNum = sched
+}
+
+const changeNum = (value) => {
+  const sched = Number(form.value.schedulingNum) || 0
+  let num = Number(value)
+  if (isNaN(num) || num < 0) num = 0
+  if (num > sched) {
+    num = sched
+    uni.showToast({ title: '鏈鐢熶骇鏁伴噺涓嶅彲澶т簬鎺掍骇鏁伴噺', icon: 'none' })
+  }
+  form.value.finishedNum = String(num)
+  form.value.pendingNum = sched - num
+}
+
+const openDatePicker = () => {
+  datePicker.value.value = Date.now()
+  datePicker.value.show = true
+}
+const onDateConfirm = (e) => {
+  const d = new Date(e.value)
+  const y = d.getFullYear(); const m = String(d.getMonth()+1).padStart(2, '0'); const day = String(d.getDate()).padStart(2, '0')
+  form.value.schedulingDate = `${y}-${m}-${day}`
+  datePicker.value.show = false
+}
+const openUserPicker = () => { userPicker.value.show = true }
+const onUserSelect = (item) => {
+  if (item) {
+    form.value.schedulingUserId = item.value
+    form.value.schedulingUserName = item.name
+  }
+  userPicker.value.show = false
+}
+
+// 鎻愪氦浜у搧琛ㄥ崟
+const submitForm = () => {
+  // 绠�鍖栨牎楠岋細浠呯‘淇濆繀濉瓧娈�
+  if (!form.value.finishedNum || !form.value.schedulingUserId || !form.value.schedulingDate) {
+    uni.showToast({ title: '璇峰畬鍠勫繀濉俊鎭�', icon: 'none' })
+    return
+  }
+  form.value.staffState = 1
+  const req = operationType.value === 'add' ? productionReport : productionReportUpdate
+  req(form.value).then(() => {
+    uni.showToast({ title: '鎻愪氦鎴愬姛', icon: 'success' })
+    closeDia()
+  })
+}
+
+// 鍏抽棴寮规
+const closeDia = () => {
+  dialogFormVisible.value = false;
+  emit('close')
+};
+
+defineExpose({
+  openDialog,
+});
+</script>
+
+<style scoped lang="scss">
+.dia-container { padding: 12px; height: 100%; display: flex; flex-direction: column; }
+.dia-header { display: flex; align-items: center; justify-content: center; margin-bottom: 10px; }
+.title { font-weight: 600; font-size: 16px; color: #333; }
+.rows { flex: 1; min-height: 0; overflow-y: auto; }
+.dia-footer { display: flex; gap: 10px; justify-content: flex-end; padding-top: 8px; }
+</style>
\ No newline at end of file
diff --git a/src/pages/productionManagement/productionReporting/index.vue b/src/pages/productionManagement/productionReporting/index.vue
new file mode 100644
index 0000000..b8b92f4
--- /dev/null
+++ b/src/pages/productionManagement/productionReporting/index.vue
@@ -0,0 +1,202 @@
+<template>
+  <view class="prod-reporting">
+    <PageHeader title="鐢熶骇鎶ュ伐" />
+
+    <view class="search_form">
+      <u-form>
+        <view class="form-row">
+          <u-form-item label="瀹㈡埛鍚嶇О" label-width="80">
+            <up-input v-model="searchForm.customerName" placeholder="璇疯緭鍏�" clearable @change="handleQuery" />
+          </u-form-item>
+          <u-form-item label="椤圭洰鍚嶇О" label-width="80">
+            <up-input v-model="searchForm.projectName" placeholder="璇疯緭鍏�" clearable @change="handleQuery" />
+          </u-form-item>
+        </view>
+        <view class="form-row">
+          <u-form-item label="鐘舵��" label-width="80">
+            <up-input v-model="statusDisplay" placeholder="璇烽�夋嫨鐘舵��" readonly @click="showStatusPicker = true" />
+          </u-form-item>
+        </view>
+        <view class="form-actions">
+          <u-button type="primary" size="small" @click="handleQuery">鎼滅储</u-button>
+        </view>
+      </u-form>
+    </view>
+
+    <view class="list_container">
+      <u-loading-icon v-if="tableLoading" text="鍔犺浇涓�..." />
+      <view v-else>
+        <view v-if="!tableData || tableData.length === 0" class="empty">鏆傛棤鏁版嵁</view>
+        <view v-else class="card_list">
+          <view v-for="item in tableData" :key="item.id" class="card_item">
+            <view class="card_header">
+              <u-tag :type="statusType(item.status)" size="mini">{{ statusText(item.status) }}</u-tag>
+              <text class="card_title">{{ item.projectName }}</text>
+            </view>
+            <view class="card_body">
+              <view class="row"><text class="label">鎺掍骇鏃ユ湡</text><text class="value">{{ item.schedulingDate }}</text></view>
+              <view class="row"><text class="label">鎺掍骇浜�</text><text class="value">{{ item.schedulingUserName }}</text></view>
+              <view class="row"><text class="label">鍚堝悓鍙�</text><text class="value">{{ item.salesContractNo }}</text></view>
+              <view class="row"><text class="label">瀹㈡埛鍚堝悓鍙�</text><text class="value">{{ item.customerContractNo }}</text></view>
+              <view class="row"><text class="label">瀹㈡埛鍚嶇О</text><text class="value">{{ item.customerName }}</text></view>
+              <view class="row"><text class="label">浜у搧澶х被</text><text class="value">{{ item.productCategory }}</text></view>
+              <view class="row"><text class="label">瑙勬牸鍨嬪彿</text><text class="value">{{ item.specificationModel }}</text></view>
+              <view class="row inline">
+                <view class="col"><text class="label">鍗曚綅</text><text class="value">{{ item.unit }}</text></view>
+                <view class="col"><text class="label">鎺掍骇鏁伴噺</text><text class="value">{{ item.schedulingNum }}</text></view>
+                <view class="col"><text class="label">鐢熶骇鏁伴噺</text><text class="value">{{ item.finishedNum }}</text></view>
+                <view class="col"><text class="label">寰呯敓浜ф暟閲�</text><text class="value">{{ item.pendingFinishNum }}</text></view>
+              </view>
+            </view>
+            <view class="card_actions">
+              <u-button type="primary" size="small" @click="openForm('add', item)" :disabled="item.pendingFinishNum == 0">鐢熶骇鎶ュ伐</u-button>
+            </view>
+          </view>
+        </view>
+
+        
+      </view>
+    </view>
+
+    <form-dia ref="formDia" @close="handleQuery"></form-dia>
+
+    <!-- 鐘舵�侀�夋嫨鍣� -->
+    <up-action-sheet :show="showStatusPicker" :actions="statusActions" title="閫夋嫨鐘舵��" @select="onStatusSelect" @close="showStatusPicker = false" />
+  </view>
+</template>
+
+<script setup>
+import { onMounted, ref, reactive, toRefs, nextTick, computed } from "vue";
+import PageHeader from '@/components/PageHeader.vue'
+import FormDia from './components/formDia.vue'
+import { workListPage } from "@/api/productionManagement/productionReporting.js";
+const data = reactive({
+  searchForm: {
+    customerName: "",
+    projectName: "",
+    status: undefined,
+  },
+});
+const { searchForm } = toRefs(data);
+const showStatusPicker = ref(false)
+const statusOptions = ref([
+  { label: '寰呯敓浜�', value: 1 },
+  { label: '鐢熶骇涓�', value: 2 },
+  { label: '宸叉姤宸�', value: 3 },
+])
+const statusActions = computed(() => statusOptions.value.map(o => ({ name: o.label, value: o.value })))
+const statusDisplay = ref('')
+const tableData = ref([]);
+const tableLoading = ref(false);
+const page = reactive({
+  current: -1,
+  size: -1,
+});
+const formDia = ref()
+
+// 鏌ヨ鍒楄〃
+/** 鎼滅储鎸夐挳鎿嶄綔 */
+const handleQuery = () => {
+  page.current = -1;
+  page.size = -1;
+  getList();
+};
+const getList = () => {
+  tableLoading.value = true;
+  const params = { ...searchForm.value, ...page };
+  workListPage(params).then(res => {
+    tableLoading.value = false;
+    tableData.value = res.data.records.map(item => ({
+      ...item,
+      pendingFinishNum: (Number(item.schedulingNum) || 0) - (Number(item.finishedNum) || 0)
+    }));
+  }).catch(err => {
+    tableLoading.value = false;
+  })
+};
+// 鐘舵�侀�夋嫨
+const onStatusSelect = (item) => {
+  searchForm.value.status = item?.value
+  statusDisplay.value = item?.name || ''
+  showStatusPicker.value = false
+  handleQuery()
+}
+// 鎵撳紑寮规
+const openForm = (type, row) => {
+  if (!row) return
+  if ((Number(row.pendingFinishNum) || 0) === 0) {
+    uni.showToast({ title: '鏃犻渶鍐嶆姤宸�', icon: 'none' })
+    return
+  }
+  nextTick(() => { formDia.value?.openDialog(type, row) })
+};
+
+// 鐘舵�佹枃鏈�/绫诲瀷
+const statusText = (s) => {
+  if (s == 3) return '宸叉姤宸�'
+  if (s == 1) return '寰呯敓浜�'
+  return '鐢熶骇涓�'
+}
+const statusType = (s) => {
+  if (s == 3) return 'success'
+  if (s == 1) return 'primary'
+  return 'warning'
+}
+
+// 鏃犲垎椤�
+
+// 鏄庣粏浜哄憳/鏃ユ湡閫夋嫨
+const openChildUserPicker = (index) => {
+  if (!expandData.value[index]?.editType) return
+  childUserPicker.value.index = index
+  childUserPicker.value.show = true
+}
+const onChildUserSelect = (item) => {
+  if (item && childUserPicker.value.index > -1) {
+    const row = expandData.value[childUserPicker.value.index]
+    row.schedulingUserId = item.value
+    row.schedulingUserName = item.name
+  }
+  childUserPicker.value.show = false
+}
+const openChildDatePicker = (index) => {
+  if (!expandData.value[index]?.editType) return
+  childDatePicker.value.index = index
+  childDatePicker.value.value = Date.now()
+  childDatePicker.value.show = true
+}
+const onChildDateConfirm = (e) => {
+  const d = new Date(e.value)
+  const y = d.getFullYear(); const m = String(d.getMonth()+1).padStart(2, '0'); const day = String(d.getDate()).padStart(2, '0')
+  const str = `${y}-${m}-${day}`
+  if (childDatePicker.value.index > -1) {
+    expandData.value[childDatePicker.value.index].schedulingDate = str
+  }
+  childDatePicker.value.show = false
+}
+
+onMounted(() => {
+  getList();
+});
+</script>
+
+<style scoped lang="scss">
+.prod-reporting { padding-bottom: 12px; }
+.search_form { margin: 12px; background: #fff; border-radius: 8px; padding: 10px; }
+.form-row { display: flex; gap: 12px; }
+.form-actions { display: flex; justify-content: flex-end; }
+.list_container { padding: 0 12px; }
+.empty { text-align: center; color: #888; padding: 20px 0; }
+.card_list { display: flex; flex-direction: column; gap: 10px; }
+.card_item { background: #fff; border-radius: 10px; padding: 10px; box-shadow: 0 2px 8px rgba(0,0,0,0.05); }
+.card_header { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; }
+.card_title { font-weight: 500; color: #333; margin-left: auto; }
+.card_body .row { display: flex; justify-content: space-between; padding: 4px 0; }
+.card_body .row.inline { display: flex; gap: 10px; flex-wrap: wrap; }
+.card_body .row.inline .col { min-width: 45%; display: flex; justify-content: space-between; }
+.label { color: #666; font-size: 12px; }
+.value { color: #333; font-size: 12px; }
+.card_actions { display: flex; justify-content: flex-end; gap: 8px; padding-top: 8px; }
+.ml8 { margin-left: 8px; }
+
+</style>
diff --git a/src/pages/sales/salesAccount/detail.vue b/src/pages/sales/salesAccount/detail.vue
index 62bff3d..27d9f43 100644
--- a/src/pages/sales/salesAccount/detail.vue
+++ b/src/pages/sales/salesAccount/detail.vue
@@ -223,6 +223,18 @@
 								></up-icon>
 							</template>
 						</up-form-item>
+						<!-- 缁戝畾鏈哄櫒 -->
+						<up-form-item
+							label="缁戝畾鏈哄櫒"
+							prop="speculativeTradingName"
+							required
+						>
+							<up-input
+							disabled
+								v-model="product.speculativeTradingName"
+								placeholder="璇疯緭鍏�"
+							/>
+						</up-form-item>
 						
 						<!-- 鍗曚綅 -->
 						<up-form-item
@@ -437,7 +449,8 @@
 	return modelOptions.value.map(model => ({
 		name: model.text,
 		value: model.value,
-		unit: model.unit
+		unit: model.unit,
+		speculativeTradingName: model.speculativeTradingName
 	}))
 })
 
@@ -521,6 +534,7 @@
     specificationModel: '',
 		productModelId: '',
     unit: '',
+    speculativeTradingName: '',
     taxRate: '',
     taxInclusiveUnitPrice: '',
     quantity: '',
@@ -603,14 +617,17 @@
 			text: user.model,
 			value: user.id,
 			unit: user.unit,
+			speculativeTradingName: user.speculativeTradingName,
 		}));
 	});
 };
 // 瑙勬牸鍨嬪彿閫夋嫨浜嬩欢
 const onSpecificationSelect = (item) => {
+console.log('selected item---', item);
 	productData.value[currentProductIndex.value].specificationModel = item.name
 	productData.value[currentProductIndex.value].productModelId = item.value
 	productData.value[currentProductIndex.value].unit = item.unit
+	productData.value[currentProductIndex.value].speculativeTradingName = item.speculativeTradingName
 }
 // 绋庣巼閫夋嫨浜嬩欢
 const onTaxRateSelect = (item) => {
diff --git a/src/pages/sales/salesAccount/index.vue b/src/pages/sales/salesAccount/index.vue
index 83ed3dd..acc8783 100644
--- a/src/pages/sales/salesAccount/index.vue
+++ b/src/pages/sales/salesAccount/index.vue
@@ -22,7 +22,7 @@
 		</view>
 		
 		<!-- 閿�鍞彴璐︾�戝竷娴� -->
-		<view class="ledger-list" v-if="total > 0">
+		<view class="ledger-list" v-if="ledgerList.length > 0">
 			<view v-for="(item, index) in ledgerList" :key="index">
 				<view class="ledger-item" @click="handleInfo('edit', item)">
 					<view class="item-header">
@@ -115,7 +115,6 @@
 
 // 閿�鍞彴璐︽暟鎹�
 const ledgerList = ref([]);
-const total = ref(0);
 
 // 杩斿洖涓婁竴椤�
 const goBack = () => {
@@ -129,8 +128,8 @@
 		size: -1
 	}
 	ledgerListPage({...page, salesContractNo: salesContractNo.value}).then((res) => {
+		console.log('閿�鍞彴璐�----', res);
 		ledgerList.value = res.records;
-		total.value = res.total;
 		closeToast()
 	}).catch(() => {
 		closeToast()
diff --git a/src/pages/sales/salesAccount/view.vue b/src/pages/sales/salesAccount/view.vue
index acfb6e0..326fb32 100644
--- a/src/pages/sales/salesAccount/view.vue
+++ b/src/pages/sales/salesAccount/view.vue
@@ -69,6 +69,10 @@
               <text class="info-value">{{ product.specificationModel }}</text>
             </view>
             <view class="info-item">
+              <text class="info-label">缁戝畾鏈哄櫒</text>
+              <text class="info-value">{{ product.speculativeTradingName }}</text>
+            </view>
+            <view class="info-item">
               <text class="info-label">鍗曚綅</text>
               <text class="info-value">{{ product.unit }}</text>
             </view>
diff --git a/src/utils/request.ts b/src/utils/request.ts
index 23752c2..7e40c06 100644
--- a/src/utils/request.ts
+++ b/src/utils/request.ts
@@ -22,12 +22,12 @@
     config.url = url
   }
   // 璁板綍璇锋眰鍙傛暟
-  console.log('璇锋眰鍙戦�佸弬鏁�:', {
-    url: (config.baseUrl || baseUrl) + config.url,
-    method: config.method || 'GET',
-    headers: config.header,
-    data: config.data
-  })
+  // console.log('璇锋眰鍙戦�佸弬鏁�:', {
+  //   url: (config.baseUrl || baseUrl) + config.url,
+  //   method: config.method || 'GET',
+  //   headers: config.header,
+  //   data: config.data
+  // })
   return new Promise((resolve, reject) => {
     uni.request({
       method: config.method || 'GET',
@@ -49,11 +49,11 @@
       // @ts-ignore
       const msg: string = errorCode[code] || data.msg || errorCode['default']
       // 璁板綍鎺ユ敹鍒扮殑鍙傛暟
-      console.log('鎺ユ敹鍒扮殑鍙傛暟:', {
-        url: (config.baseUrl || baseUrl) + config.url,
-        code: code,
-        data: data
-      })
+      // console.log('鎺ユ敹鍒扮殑鍙傛暟:', {
+      //   url: (config.baseUrl || baseUrl) + config.url,
+      //   code: code,
+      //   data: data
+      // })
       if (code === 401) {
         showConfirm('鐧诲綍鐘舵�佸凡杩囨湡锛屾偍鍙互缁х画鐣欏湪璇ラ〉闈紝鎴栬�呴噸鏂扮櫥褰�?').then(res => {
           if (res.confirm) {

--
Gitblit v1.9.3