const api = require('../../utils/api') const emptyForm = { attendancePointName: '', projectNo: '', profileNo: '', productName: '', materialCode: '', materialName: '', supplier: '', productNetWeightKg: '', productGrossWeightKg: '', allowedScrapRate: '', wastePriceYuanPerKg: '', process: '', stampingMethod: '', operatorCount: 1, processUnitPriceYuan: '', standardBeat: '', } Page({ data: { readonly: false, keyword: '', rows: [], page: 1, pageInput: '1', totalPages: 1, scrollTop: 0, form: { ...emptyForm }, formVisible: false, formTitle: '新增产品', attendancePoints: [], attendancePointLabels: [], attendancePointIndex: 0, stampingMethodSuggestions: ['清洗', '连续模'], stampingSuggestionVisible: false, importFileName: '', refreshing: false, }, onLoad(options) { this.setData({ readonly: options.readonly === '1', }) }, onShow() { this.init() }, async init() { await this.loadAttendancePoints() await this.load() }, async loadAttendancePoints() { try { const points = await api.listAccessibleAttendancePoints() const attendancePoints = points || [] this.setData({ attendancePoints, attendancePointLabels: attendancePoints.map(item => item.name), }) if (!this.data.form.attendancePointName && attendancePoints.length) { this.setData({ 'form.attendancePointName': attendancePoints[0].name, attendancePointIndex: 0, }) } } catch (error) { wx.showToast({ title: error.message || '加载考勤点失败', icon: 'none' }) } }, async load(page = this.data.page) { try { const result = await api.listProducts({ keyword: this.data.keyword, page, pageSize: 8, }) this.setData({ rows: (result.rows || []).map(item => ({ ...item, processDisplay: item.processDisplay || api.processDisplayName(item.process), })), page: result.page, pageInput: String(result.page || 1), totalPages: result.totalPages, scrollTop: 0, }) } catch (error) { wx.showToast({ title: error.message, icon: 'none' }) } }, async onPullDownRefresh() { this.setData({ refreshing: true }) try { await this.load(1) } finally { this.setData({ refreshing: false }) if (wx.stopPullDownRefresh) { wx.stopPullDownRefresh() } } }, onKeywordInput(e) { this.setData({ keyword: e.detail.value, page: 1 }) this.load(1) }, onInput(e) { const field = e.currentTarget.dataset.field let value = e.detail.value if (field === 'process') { value = this.normalizeProcessInput(value) } if (field === 'stampingMethod') { this.setData({ stampingSuggestionVisible: false, [`form.${field}`]: value, }) return } this.setData({ [`form.${field}`]: value, }) }, onStampingFocus() { this.setData({ stampingSuggestionVisible: true }) }, chooseStampingSuggestion(e) { const value = e.currentTarget.dataset.value this.setData({ 'form.stampingMethod': value, stampingSuggestionVisible: false, }) }, hideStampingSuggestion() { setTimeout(() => { this.setData({ stampingSuggestionVisible: false }) }, 150) }, normalizeProcessInput(value) { const text = String(value || '').trim() if (text.includes('杂活')) { return '杂活' } return text.replace(/\D/g, '') }, validateProcess(form) { const process = String(form.process || '').trim() if (!process) { wx.showToast({ title: '请输入工序数字', icon: 'none' }) return false } if (process === '杂活') { if (String(form.stampingMethod || '').trim() !== '处理杂活') { wx.showToast({ title: '只有处理杂活的工序可以填写杂活', icon: 'none' }) return false } return true } if (!/^\d+$/.test(process) || Number(process) <= 0) { wx.showToast({ title: '工序只能填写正整数', icon: 'none' }) return false } if (String(form.stampingMethod || '').trim() === '处理杂活') { wx.showToast({ title: '处理杂活的工序必须填写杂活', icon: 'none' }) return false } return true }, onAttendancePointChange(e) { const attendancePointIndex = Number(e.detail.value) const point = this.data.attendancePoints[attendancePointIndex] this.setData({ attendancePointIndex, 'form.attendancePointName': point ? point.name : '', }) }, noop() {}, openCreate() { const firstPoint = this.data.attendancePoints[0] this.setData({ form: { ...emptyForm, attendancePointName: firstPoint ? firstPoint.name : '' }, attendancePointIndex: 0, formTitle: '新增产品', formVisible: true, }) }, closeForm() { this.setData({ formVisible: false, form: { ...emptyForm, attendancePointName: this.data.attendancePoints[0] ? this.data.attendancePoints[0].name : '' }, }) }, async save() { try { const form = { ...this.data.form } form.stampingMethod = String(form.stampingMethod || '').trim() if (!form.attendancePointName) { wx.showToast({ title: '请选择考勤点', icon: 'none' }) return } if (!this.validateProcess(form)) { return } if (['清洗', '处理杂活'].includes(String(form.stampingMethod || '').trim())) { form.standardBeat = 0 } await api.saveProduct(form) wx.showToast({ title: '已保存', icon: 'success' }) this.setData({ form: { ...emptyForm }, formVisible: false }) await this.load(1) } catch (error) { wx.showToast({ title: error.message, icon: 'none' }) } }, edit(e) { const index = e.currentTarget.dataset.index const product = this.data.rows[index] const attendancePointIndex = Math.max(0, this.data.attendancePoints.findIndex(item => item.name === product.attendancePointName)) this.setData({ form: { ...product, originalAttendancePointName: product.attendancePointName, originalProjectNo: product.projectNo, originalProductName: product.productName, originalDeviceNo: product.deviceNo || '', originalProcess: product.rawProcess || product.process || '', }, attendancePointIndex, formTitle: '编辑产品', formVisible: true, }) }, remove(e) { const index = e.currentTarget.dataset.index const product = this.data.rows[index] wx.showModal({ title: '删除产品', content: product.productName, success: async res => { if (res.confirm) { try { await api.deleteProduct(product) await this.load(1) } catch (error) { wx.showToast({ title: error.message, icon: 'none' }) } } }, }) }, clearForm() { const firstPoint = this.data.attendancePoints[0] this.setData({ form: { ...emptyForm, attendancePointName: firstPoint ? firstPoint.name : '' }, attendancePointIndex: 0, }) }, chooseFile() { wx.chooseMessageFile({ count: 1, type: 'file', extension: ['xlsx', 'xls'], success: async res => { const file = res.tempFiles[0] this.setData({ importFileName: file.name }) wx.showLoading({ title: '导入中' }) try { const result = await api.importProducts(file.path) wx.showToast({ title: `导入${result.imported}条`, icon: 'success' }) await this.load(1) } catch (error) { wx.showModal({ title: '导入失败', content: error.message, showCancel: false, }) } finally { wx.hideLoading() } }, }) }, async exportFile() { wx.showLoading({ title: '导出中' }) try { const filePath = await api.exportProducts() wx.openDocument({ filePath, fileType: 'xlsx', showMenu: true, }) } catch (error) { wx.showToast({ title: error.message, icon: 'none' }) } finally { wx.hideLoading() } }, prevPage() { if (this.data.page > 1) { this.setData({ scrollTop: 0 }) this.load(this.data.page - 1) } }, nextPage() { if (this.data.page < this.data.totalPages) { this.setData({ scrollTop: 0 }) this.load(this.data.page + 1) } }, onPageInput(e) { this.setData({ pageInput: e.detail.value }) }, jumpToPage(e) { wx.hideKeyboard() const inputValue = e && e.detail && e.detail.value !== undefined ? e.detail.value : this.data.pageInput const target = Math.max(1, Math.min(Number(inputValue) || this.data.page, this.data.totalPages)) if (target === this.data.page) { this.setData({ pageInput: String(this.data.page || 1) }) return } this.setData({ scrollTop: 0 }) this.load(target) }, })