index.vue 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. <template>
  2. <div class="page-container column-container">
  3. <!-- 搜索区 -->
  4. <el-form class="list-search-container" :model="queryParams" ref="queryRef" :inline="true" style="margin-right: 0px">
  5. <el-form-item label="单据号:" prop="formCode">
  6. <el-input v-model="queryParams.formCode" placeholder="请输入单据号" style="width: 144px" clearable />
  7. </el-form-item>
  8. <el-form-item label="表单日期:" prop="startTime">
  9. <el-date-picker
  10. v-model="queryParams.formStartDate"
  11. type="date"
  12. style="width: 144px"
  13. value-format="YYYY-MM-DD"
  14. placeholder="选择起始日期"
  15. clearable
  16. />
  17. <span style="margin: 0 4px">~</span>
  18. <el-date-picker
  19. v-model="queryParams.endTime"
  20. type="date"
  21. style="width: 144px"
  22. value-format="YYYY-MM-DD"
  23. placeholder="选择结束日期"
  24. clearable
  25. />
  26. </el-form-item>
  27. <el-form-item label="批次号:">
  28. <el-input
  29. placeholder="请输入关键字"
  30. v-model.trim="queryParams.lotCode"
  31. @keydown.enter.prevent
  32. clearable
  33. style="width: 130px"
  34. />
  35. </el-form-item>
  36. <el-form-item label="产品描述:">
  37. <el-input
  38. placeholder="请输入关键字"
  39. v-model.trim="queryParams.productDescription"
  40. @keydown.enter.prevent
  41. clearable
  42. style="width: 130px"
  43. />
  44. </el-form-item>
  45. <el-form-item style="margin-left: 0">
  46. <el-button type="info" icon="Search" @click="getList">搜索 </el-button>
  47. </el-form-item>
  48. </el-form>
  49. <div class="el-table-container">
  50. <div class="el-table-inner-container">
  51. <el-table
  52. ref="dataTable"
  53. :data="dataList"
  54. :span-method="rowSpanMethod"
  55. v-loading="loading"
  56. highlight-current-row
  57. border
  58. height="100%"
  59. >
  60. <el-table-column label="外协单号" align="center" prop="formCode" width="120" />
  61. <el-table-column label="外协日期" align="center" prop="formDate" width="120" />
  62. <el-table-column label="批次号" align="center" prop="lotCode" width="120" />
  63. <el-table-column label="产品描述" align="center" prop="productDescription" />
  64. <el-table-column label="产品数量" align="center" prop="productNum" width="80" />
  65. <el-table-column label="工序名称" align="center" prop="processAlias" width="80" />
  66. <el-table-column label="工序序号" align="center" prop="processStepNumber" width="80" />
  67. <el-table-column label="投产数" align="center" prop="productionNum" width="120">
  68. <template #default="scope">
  69. <el-input-number
  70. v-if="scope.row.editStatus"
  71. v-model="scope.row.productionNum"
  72. :min="1"
  73. controls-position="right"
  74. style="width: 100%"
  75. />
  76. <span v-else>{{ scope.row.productionNum }}</span>
  77. </template>
  78. </el-table-column>
  79. <el-table-column label="合格数" align="center" prop="qualifiedNum" width="120">
  80. <template #default="scope">
  81. <el-input-number
  82. v-if="scope.row.editStatus"
  83. v-model="scope.row.qualifiedNum"
  84. :min="1"
  85. controls-position="right"
  86. style="width: 100%"
  87. @change="handleChangeloss(scope.row)"
  88. />
  89. <span v-else>{{ scope.row.qualifiedNum }}</span>
  90. </template>
  91. </el-table-column>
  92. <el-table-column label="料损率" align="center" prop="loss" width="120">
  93. <template #default="scope">
  94. <span v-if="scope.row.loss > scope.row.lossLimit" style="color: red">{{ scope.row.loss }}</span>
  95. <span v-else>{{ scope.row.loss }}</span>
  96. </template>
  97. </el-table-column>
  98. <el-table-column label="操作" align="center" width="104">
  99. <template #default="scope">
  100. <template v-if="scope.row.editStatus">
  101. <el-button type="success" icon="Finished" circle @click="handleSaveRow(scope.row)" />
  102. <el-button type="danger" icon="Close" circle @click="handleCancelRow(scope.row)" />
  103. </template>
  104. <el-button v-else type="primary" icon="Bell" @click="handleStartReport(scope.row)">报工</el-button>
  105. </template>
  106. </el-table-column>
  107. </el-table>
  108. </div>
  109. </div>
  110. <!-- 分页 -->
  111. <pagination
  112. v-show="total > 0"
  113. :total="total"
  114. v-model:page="queryParams.pageNum"
  115. v-model:limit="queryParams.pageSize"
  116. @pagination="getList"
  117. />
  118. </div>
  119. </template>
  120. <script setup>
  121. import { listProcess,editOutsourcedOrderDetailProcess } from '@/api/business/outsourcedOrderDetailProcess.js'
  122. const { proxy } = getCurrentInstance()
  123. /** 生产批次 */
  124. const dataList = ref([])
  125. const dataTable = ref(null)
  126. const currentDaywork = ref({})
  127. const spanProps = ref([])
  128. const loading = ref(false)
  129. const total = ref(0)
  130. // 用于计算合并行的计数器
  131. const spanArr = ref([])
  132. /** 查询对象 */
  133. const queryParams = ref({
  134. formCode: '',
  135. formStartDate: null,
  136. formEndDate: null,
  137. lotCode: '',
  138. productDescription: '',
  139. pageNum: 1,
  140. pageSize: 10
  141. })
  142. /*********************** 工段相关事件 ****************************/
  143. const getList = () => {
  144. loading.value = true
  145. listProcess(queryParams.value).then((res) => {
  146. dataList.value = res.rows
  147. total.value = res.total
  148. loading.value = false
  149. if (dataList.value.length > 0) {
  150. // getSpanArr(dataList.value, 'formCode')
  151. // getSpanArr(dataList.value, 'formDate')
  152. // getSpanArr(dataList.value, 'lotCode')
  153. // getSpanArr(dataList.value, 'productDescription')
  154. spanProps.value = ['formCode', 'formDate','lotCode','productDescription'];
  155. spanPropGroup(dataList.value)
  156. }
  157. })
  158. }
  159. const handleChangeloss = (row) => {
  160. let percent = (row.productionNum - row.qualifiedNum)/row.productionNum * 100;
  161. row.loss = Math.ceil(percent * 100) / 100;
  162. }
  163. const handleSaveRow = (row) => {
  164. var flag = true
  165. if(row.productionNum < row.qualifiedNum) {
  166. flag = false
  167. proxy.$modal.msgError('合格数不能大于投产数')
  168. }else {
  169. var tempList = dataList.value.filter(item => {
  170. return item.detailId ==row.detailId
  171. })
  172. var index = tempList.indexOf(row)
  173. if(index>0 && row.productionNum > tempList[index-1].qualifiedNum) {
  174. flag = false
  175. proxy.$modal.msgError('投产数不能大于上一道序合格数')
  176. }
  177. }
  178. if(flag) {
  179. editOutsourcedOrderDetailProcess(row).then((res) => {
  180. if(res.code == 200) {
  181. row.editStatus = false
  182. proxy.$modal.msgSuccess('报工成功')
  183. getList()
  184. }
  185. })
  186. }
  187. }
  188. const handleCancelRow = (row) => {
  189. row.editStatus = false
  190. getList()
  191. }
  192. const handleStartReport = (row) => {
  193. //如果收回单已经被审核,则不能让他报工
  194. if(row.status == 1) {
  195. proxy.$modal.msgError('该外协单已被审核,不能再报工')
  196. }else{
  197. let tempList = dataList.value.filter(item => {
  198. return item.detailId ==row.detailId
  199. })
  200. let index = tempList.indexOf(row)
  201. if(index > 0) {
  202. //判断如果上一道序没有报工,不允许报此道序
  203. if(tempList[index-1].productionNum == 0) {
  204. proxy.$modal.msgError('上一道序未报工,不允许报此道序')
  205. }else {
  206. row.editStatus = true
  207. row.productionNum = tempList[index-1].qualifiedNum
  208. }
  209. }else {
  210. row.editStatus = true
  211. row.productionNum = row.productNum
  212. }
  213. }
  214. }
  215. let rowSpansMap = new Map(); //存需要开始合并的行号,向下合并多少行
  216. const spanPropGroup = (data) => {
  217. let oldRow = null; //需要合并的行
  218. rowSpansMap = new Map(); //重置Map
  219. oldRow = data[0]; //默认第0行为需要合并的行
  220. rowSpansMap.set(0, 1); //第0行,向下合并一行(其实就是自己单独一行)
  221. let spanRow = 0; //记录需要开始合并的行号
  222. for (let i = 1; i < data.length; i++) {
  223. const item = data[i];
  224. let isSame = true;
  225. //遍历需要判断的属性判断对应值是否全部相等
  226. for (let j = 0; j < spanProps.value.length; j++) {
  227. const prop = spanProps.value[j];
  228. //只要有一个属性值不相等则记录新的需要合并的行号
  229. if (item[prop] != oldRow[prop]) {
  230. oldRow = item;
  231. rowSpansMap.set(i, 1);
  232. spanRow = i;
  233. isSame = false;
  234. break;
  235. }
  236. }
  237. //如果所有属性值相同则所需要合并的行数+1
  238. if (isSame) {
  239. let span = rowSpansMap.get(spanRow);
  240. rowSpansMap.set(spanRow, span + 1);
  241. }
  242. }
  243. };
  244. const rowSpanMethod =({ row, column, rowIndex, columnIndex }) => {
  245. //采样值5-9列所对应的行不需要合并
  246. if (columnIndex != 5 && columnIndex != 6 && columnIndex != 7 && columnIndex != 8 && columnIndex != 9 && columnIndex != 10) {
  247. //根据当前行号从map中获取开始合并的行根据当前行号从map中获取开始合并的行号,向下合并多少行
  248. const span = rowSpansMap.get(rowIndex);
  249. if (span != null) {
  250. return {
  251. rowspan: span, //向下合并span行
  252. colspan: 1,
  253. };
  254. } else {
  255. return {
  256. rowspan: 0,
  257. colspan: 0,
  258. };
  259. }
  260. }
  261. };
  262. // const rowSpanMethod = ({ row, column, rowIndex, columnIndex }) => {
  263. // if (columnIndex === 0 || columnIndex === 1 || columnIndex === 2 || columnIndex === 3 || columnIndex === 4) {
  264. // const _row = spanArr.value[rowIndex]
  265. // const _col = _row > 0 ? 1 : 0
  266. // return {
  267. // rowspan: _row,
  268. // colspan: _col
  269. // }
  270. // }
  271. // }
  272. // // groupBy 数组
  273. // const groupBy = (data, params) => {
  274. // const groups = {}
  275. // data.forEach((v) => {
  276. // const group = JSON.stringify(v[params])
  277. // groups[group] = groups[group] || []
  278. // groups[group].push(v)
  279. // })
  280. // return Object.values(groups)
  281. // }
  282. // // 计算 数据合并 索引
  283. // const getSpanArr = (data, params) => {
  284. // // 接收重构数组
  285. // let arr = []
  286. // // 设置索引
  287. // let pos = 0
  288. // // 控制合并的数组
  289. // spanArr.value = []
  290. // // arr 处理
  291. // groupBy(data, params).map((v) => (arr = arr.concat(v)))
  292. // arr.map((res) => {
  293. // data.shift()
  294. // data.push(res)
  295. // })
  296. // // spanArr 处理
  297. // const redata = arr.map((v) => v[params])
  298. // redata.reduce((old, cur, i) => {
  299. // if (i === 0) {
  300. // spanArr.value.push(1)
  301. // pos = 0
  302. // } else {
  303. // if (cur === old) {
  304. // spanArr.value[pos] += 1
  305. // spanArr.value.push(0)
  306. // } else {
  307. // spanArr.value.push(1)
  308. // pos = i
  309. // }
  310. // }
  311. // return cur
  312. // }, {})
  313. // }
  314. onMounted(() => {
  315. getList()
  316. })
  317. </script>
  318. <style scoped>
  319. .el-form--inline .el-form-item {
  320. margin-right: 20px;
  321. }
  322. </style>