JhHardwareWRS/pages/manageProducts/manageProducts.js
2026-06-24 15:19:14 +08:00

326 lines
8.9 KiB
JavaScript

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)
},
})