// components/filter-picker/filter-picker.js
Component({
properties: {
options: Array,
value: [String, Number],
placeholder: String,
disabled: Boolean,
maxHeight: {
type: Number,
value: 300
}
},
data: {
dropdownVisible: false,
searchText: '',
filteredOptions: [],
displayText: '',
isActive: false // 新增激活状态
},
methods: {
/**
* 安全更新筛选后的选项列表
* 1. 确保options是数组
* 2. 过滤掉非对象元素
* 3. 处理label属性缺失的情况
*/
updateFilteredOptions() {
let { options, searchText } = this.data;
// 确保options是数组,如果不是则重置为空数组
if (!Array.isArray(options)) {
options = [];
this.setData({ options });
}
// 过滤掉非对象元素
const validOptions = options.filter(item =>
item && typeof item === 'object' && 'label' in item
);
// 如果没有搜索文本,显示所有有效选项
if (!searchText) {
this.setData({ filteredOptions: validOptions });
return;
}
// 安全过滤:确保item有label属性
const filtered = validOptions.filter(item => {
const label = item.label || '';
return label.toString().toLowerCase().includes(searchText.toLowerCase());
});
this.setData({ filteredOptions: filtered });
},
/**
* 安全更新显示文本
* 1. 处理无效值
* 2. 处理找不到匹配项的情况
*/
updateDisplayText() {
const { value, options } = this.data;
// 确保options是有效数组
if (!Array.isArray(options) || options.length === 0) {
this.setData({ displayText: '' });
return;
}
// 处理空值
if (!value) {
this.setData({ displayText: '' });
return;
}
// 查找匹配项,忽略非对象元素
const selected = options.find(item =>
item && typeof item === 'object' &&
item.value === value
);
if (selected) {
this.setData({
displayText: selected.label || '',
searchText: selected.label || ''
});
} else {
this.setData({ displayText: '' });
}
},
/**
* 处理输入事件
* @param {Object} e - 事件对象
* @param {string} e.detail.value - 输入框的值
*/
onInput(e) {
const searchText = e.detail.value;
this.setData({ searchText }, () => {
this.updateFilteredOptions();
});
},
/**
* 当输入框获得焦点时的处理函数
* - 如果组件被禁用则直接返回
* - 设置下拉框可见状态、搜索文本和激活状态
* - 更新过滤后的选项列表
*/
onFocus() {
console.log('Picker focused'); // 调试日志
if (this.data.disabled) return;
this.setData({
dropdownVisible: true,
searchText: this.data.displayText,
isActive: true
}, () => {
this.updateFilteredOptions();
});
},
/**
* 处理输入框失去焦点事件
* 延迟200毫秒后隐藏下拉框并取消激活状态
*/
onBlur() {
setTimeout(() => {
this.setData({
dropdownVisible: false,
isActive: false
});
}, 200);
},
/**
* 切换下拉框的显示/隐藏状态
* 如果组件被禁用则不做任何操作
* 当下拉框显示时会触发更新过滤选项的操作
*/
toggleDropdown() {
console.log('Toggling dropdown'); // 调试日志
if (this.data.disabled) return;
this.setData({
dropdownVisible: !this.data.dropdownVisible,
isActive: !this.data.dropdownVisible
}, () => {
if (this.data.dropdownVisible) {
this.updateFilteredOptions();
}
});
},
/**
* 处理选择项事件
* @param {Object} e - 事件对象
* @param {Object} e.currentTarget.dataset - 事件目标数据
* @param {string} e.currentTarget.dataset.value - 选中项的值
* @param {Object} e.currentTarget.dataset.item - 选中项对象
* @param {string} e.currentTarget.dataset.item.label - 选中项的显示文本
* @fires change - 触发change事件,传递选中项的值和对象
*/
selectItem(e) {
const { value, item } = e.currentTarget.dataset;
this.setData({
value,
displayText: item.label,
searchText: item.label,
dropdownVisible: false,
isActive: false
});
this.triggerEvent('change', { value, item });
}
},
observers: {
// 监听options变化
'options': function() {
this.updateFilteredOptions();
this.updateDisplayText();
},
// 监听value变化
'value': function() {
this.updateDisplayText();
}
},
ready() {
this.updateFilteredOptions();
this.updateDisplayText();
}
});
// pages/tianjia/tianjia.js
Page({
data: {
dingdans: [],
chanpins: [],
zujians: [],
bancais: [],
currentDingdan: null,
currentChanpin: null,
currentZujian: null,
currentBancai: null,
currentDingdanId: null,
currentDingdanChanpinId: null,
currentChanpinZujianId: null,
orderQuantity: '',
canSubmit: false,
modalVisible: false,
modalTitle: '',
modalType: '',
modalData: {},
modalConfig: {},
// 控制下拉框可用状态
chanpinDisabled: true,
zujianDisabled: true,
bancaiDisabled: false
},
onLoad: function() {
if (!this.checkPermission()) return;
this.initPage();
},
checkPermission: function() {
const role = parseInt(wx.getStorageSync('role') || '0');
if (role <= 1) {
wx.showModal({
title: '权限不足',
content: '抱歉,您没有访问此页面的权限。',
showCancel: false,
success: () => { wx.navigateBack() }
});
return false;
}
return true;
},
initPage: function() {
this.dataManager = getApp().globalData.dataManager;
this.dataManager.registerCallback('all', this.handleDataUpdate.bind(this));
console.log(this.dataManager.data.dingdans)
this.refreshDingdanList();
this.refreshBancaiList();
},
/**
* 处理数据更新事件
* @param {string} operation - 操作类型,包括 'refresh', 'add', 'update', 'delete'
* @param {string} entity - 实体类型,包括 'dingdan', 'dingdan_chanpin', 'chanpin_zujian', 'bancai'
* @param {Object} data - 更新的数据对象
* @description 根据不同的操作类型和实体类型,调用对应的刷新方法更新列表数据
*/
handleDataUpdate: function (operation, entity, data) {
if (['refresh', 'add', 'update', 'delete'].includes(operation)) {
if (entity === 'dingdan') {
this.refreshDingdanList(data.id);
} else if (entity === 'dingdan_chanpin') {
this.refreshChanpinList(data.dingdan?.id, data.chanpin?.id);
} else if (entity === 'chanpin_zujian') {
this.refreshZujianList(data.chanpin?.id, data.id);
} else if (entity === 'bancai') {
this.refreshBancaiList(null, data.id);
}
}
},
/**
* 刷新订单列表
* @param {string} [dingdanId] - 可选参数,指定当前选中的订单ID
* @description
* 1. 获取并排序订单数据(按下单时间降序)
* 2. 格式化订单数据为{label, value}格式
* 3. 更新页面数据,若指定了dingdanId则刷新对应产品列表
*/
refreshDingdanList: function(dingdanId) {
const dingdans = this.dataManager.data.dingdans || [];
dingdans.sort((a, b) => new Date(b.xiadan) - new Date(a.xiadan));
const formattedDingdans = dingdans.map(d => ({
...d,
label: `${d.number} (${this.formatDate(d.xiadan)})`,
value: d.id
}));
this.setData({
dingdans: formattedDingdans,
currentDingdanId: dingdanId || (dingdans.length > 0 ? dingdans[0].id : null)
}, () => {
if (dingdanId) {
this.refreshChanpinList(dingdanId);
}
});
},
refreshChanpinList: function(dingdanId, chanpinId) {
if (!dingdanId) return;
const dingdanChanpins = this.dataManager.data.dingdan_chanpins || [];
const relatedChanpins = dingdanChanpins.filter(dc => dc.dingdan?.id == dingdanId);
const formattedChanpins = relatedChanpins.map(dc => ({
...dc.chanpin,
label: dc.chanpin ? `${dc.chanpin.bianhao} (数量: ${dc.shuliang})` : '',
value: dc.chanpin?.id
}));
this.setData({
chanpins: formattedChanpins,
chanpinDisabled: false // 启用产品下拉框
});
},
refreshZujianList: function(dingdanChanpinId, zujianId) {
if (!dingdanChanpinId) return;
const dingdanChanpin = this.dataManager.data.dingdan_chanpins.find(dc => dc.id == dingdanChanpinId);
if (!dingdanChanpin?.chanpin) return;
const chanpinId = dingdanChanpin.chanpin.id;
const chanpinZujians = this.dataManager.data.chanpin_zujians.filter(cz => cz.chanpin?.id == chanpinId);
const formattedZujians = chanpinZujians.map(cz => ({
...cz,
label: cz.zujian ? `${cz.zujian.name} (产量: ${cz.one_howmany})` : '',
value: cz.id
}));
this.setData({
zujians: formattedZujians,
zujianDisabled: false // 启用组件下拉框
});
if (zujianId) {
const cz = chanpinZujians.find(cz => cz.id == zujianId);
if (cz) {
const index = formattedZujians.findIndex(z => z.id === cz.id);
if (index !== -1) {
this.setData({
currentZujianIndex: index,
currentZujian: formattedZujians[index],
currentChanpinZujianId: cz.id
});
this.refreshBancaiList(cz.id);
}
}
}
},
refreshBancaiList: function(chanpinZujianId, bancaiId) {
if (chanpinZujianId) {
// 选择了组件,锁定板材为组件绑定的板材
const chanpinZujian = this.dataManager.data.chanpin_zujians.find(cz => cz.id == chanpinZujianId);
if (!chanpinZujian?.bancai) return;
const formattedBancai = {
...chanpinZujian.bancai,
label: this.formatBancaiInfo(chanpinZujian.bancai),
value: chanpinZujian.bancai.id
};
this.setData({
bancais: [formattedBancai],
currentBancai: formattedBancai,
currentBancaiIndex: 0,
bancaiDisabled: true // 禁用板材下拉框(已锁定)
});
} else {
// 未选择组件,显示所有板材
const bancais = this.dataManager.data.bancais || [];
const formattedBancais = bancais.map(b => ({
...b,
label: this.formatBancaiInfo(b),
value: b.id
}));
this.setData({
bancais: formattedBancais,
bancaiDisabled: false // 启用板材下拉框
});
if (bancaiId) {
const index = formattedBancais.findIndex(b => b.id === bancaiId);
if (index !== -1) {
this.setData({
currentBancaiIndex: index,
currentBancai: formattedBancais[index]
});
}
}
}
this.checkSubmitCondition();
},
resetSelections: function() {
this.setData({
chanpins: [],
zujians: [],
bancais: [],
currentChanpin: null,
currentZujian: null,
currentBancai: null,
currentDingdanChanpinId: null,
currentChanpinZujianId: null,
currentChanpinIndex: -1,
currentZujianIndex: -1,
currentBancaiIndex: -1,
orderQuantity: '',
canSubmit: false,
chanpinDisabled: true, // 禁用产品下拉框
zujianDisabled: true, // 禁用组件下拉框
bancaiDisabled: false // 启用板材下拉框
});
this.refreshBancaiList();
},
formatBancaiInfo: function(bancai) {
let info = `厚度: ${bancai.houdu}mm, 材质: ${bancai.caizhi?.name || ''}`;
if (bancai.mupi1) info += `, 木皮1: ${bancai.mupi1.name}${bancai.mupi1.you ? ' (油)' : ''}`;
if (bancai.mupi2) info += `, 木皮2: ${bancai.mupi2.name}${bancai.mupi2.you ? ' (油)' : ''}`;
return info;
},
formatDate: function(dateString) {
if (!dateString) return '';
const date = new Date(dateString);
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
return `${year}-${month}-${day}`;
},
checkSubmitCondition: function() {
const canSubmit = this.data.currentBancai && parseInt(this.data.orderQuantity) > 0;
this.setData({ canSubmit });
},
onDingdanChange: function(e) {
const { value, item } = e.detail;
this.setData({
currentDingdanId: value,
currentDingdan: item
});
this.resetSelections();
this.refreshChanpinList(value);
},
onChanpinChange: function(e) {
const { value, item } = e.detail;
this.setData({
currentDingdanChanpinId: value,
currentChanpin: item
});
this.setData({
zujians: [],
currentZujian: null,
currentZujianIndex: -1,
currentChanpinZujianId: null,
zujianDisabled: false
});
this.refreshZujianList(value);
},
onZujianChange: function(e) {
const { value, item } = e.detail;
this.setData({
currentChanpinZujianId: value,
currentZujian: item
});
this.refreshBancaiList(value);
},
onBancaiChange: function(e) {
const { value, item } = e.detail;
this.setData({
currentBancai: item
});
this.checkSubmitCondition();
},
onQuantityInput: function(e) {
this.setData({ orderQuantity: e.detail.value });
this.checkSubmitCondition();
},
// 模态框相关方法
showAddDingdanModal: function() {
modalService.showModal('addDingdan', {
xiadan: new Date().toISOString().split('T')[0]
});
},
showAddChanpinModal: function() {
if (!this.data.currentDingdanId) {
wx.showToast({
title: '请先选择订单',
icon: 'none'
});
return;
}
modalService.showModal('addChanpin', {
dingdan: { id: this.data.currentDingdanId }
});
},
showAddZujianModal: function() {
if (!this.data.currentDingdanChanpinId) {
wx.showToast({
title: '请先选择产品',
icon: 'none'
});
return;
}
const dingdanChanpin = this.dataManager.data.dingdan_chanpins.find(
dc => dc.id == this.data.currentDingdanChanpinId
);
if (!dingdanChanpin?.chanpin) return;
modalService.showModal('addZujian', {
chanpin: { id: dingdanChanpin.chanpin.id }
});
},
showAddBancaiModal: function() {
modalService.showModal('addBancai', { houdu: 0.0 });
},
// 保存数据方法
saveDingdan: function(data) {
return this.dataManager.addDingdan(data).then(() => {
wx.showToast({ title: '订单添加成功' });
return data;
});
},
saveChanpin: function(data) {
return this.dataManager.addDingdanChanpin({
dingdan: { id: this.data.currentDingdanId },
chanpin: { id: data.chanpin },
shuliang: data.shuliang
}).then(() => {
wx.showToast({ title: '产品添加成功' });
return data;
});
},
saveZujian: function(data) {
return this.dataManager.addChanpinZujian({
chanpin: { id: data.chanpin },
zujian: { id: data.zujian },
bancai: { id: data.bancai },
one_howmany: data.one_howmany
}).then(() => {
wx.showToast({ title: '组件添加成功' });
return data;
});
},
saveBancai: function(data) {
return this.dataManager.addBancai(data).then(() => {
wx.showToast({ title: '板材添加成功' });
return data;
});
},
// 模态框事件处理
handleModalCancel: function() {
modalService.handleCancel();
},
handleModalConfirm: function() {
modalService.handleConfirm();
},
handleModalUpdate: function(e) {
const { path, value } = e.detail;
this.setData({
[`modalData.${path}`]: value
});
},
// 提交订单
submitOrder: function() {
if (!this.data.canSubmit) {
wx.showToast({
title: '请选择板材并输入数量',
icon: 'none'
});
return;
}
// 构建提交数据
const orderData = {
chanpin_zujian_id: this.data.currentChanpinZujianId,
bancai_id: this.data.currentBancai.id,
quantity: parseInt(this.data.orderQuantity)
};
// 调用API提交数据
wx.showLoading({ title: '提交中...' });
this.dataManager.submitOrder(orderData).then(() => {
wx.hideLoading();
wx.showToast({ title: '提交成功' });
// 重置表单
this.setData({ orderQuantity: '', canSubmit: false });
}).catch(err => {
wx.hideLoading();
wx.showToast({ title: `提交失败: ${err.message}`, icon: 'none' });
});
}
});
(9) [Proxy, Proxy, Proxy, Proxy, Proxy, Proxy, Proxy, Proxy, Proxy]0: Proxy {number: "2025-31", xiadan: "2025-06-28T00:00:00.000+00:00", jiaohuo: null, dingdan_chanpin: Array(0), id: 1, …}1: Proxy {number: "2025-33", xiadan: null, jiaohuo: null, dingdan_chanpin: Array(3), id: 2, …}2: Proxy {number: "2025-034", xiadan: "2025-07-01T00:00:00.000+00:00", jiaohuo: null, dingdan_chanpin: Array(5), id: 3, …}3: Proxy {number: "2025-034增加单", xiadan: "2025-07-02T00:00:00.000+00:00", jiaohuo: null, dingdan_chanpin: Array(1), id: 4, …}4: Proxy {number: "2025-031", xiadan: "2025-07-02T00:00:00.000+00:00", jiaohuo: null, dingdan_chanpin: Array(1), id: 5, …}5: Proxy {number: "2025-036", xiadan: "2025-06-13T00:00:00.000+00:00", jiaohuo: "2025-07-13T00:00:00.000+00:00", dingdan_chanpin: Array(2), id: 6, …}6: Proxy {number: "2025-037", xiadan: "2025-06-16T00:00:00.000+00:00", jiaohuo: "2025-07-16T00:00:00.000+00:00", dingdan_chanpin: Array(1), id: 7, …}7: Proxy {number: "2025-038", xiadan: "2025-06-17T00:00:00.000+00:00", jiaohuo: "2025-08-17T00:00:00.000+00:00", dingdan_chanpin: Array(1), id: 8, …}8: Proxy {number: "梦5", xiadan: "2025-07-03T00:00:00.000+00:00", jiaohuo: "2025-08-03T00:00:00.000+00:00", dingdan_chanpin: Array(1), id: 44, …}length: 9nv_length: (...)__proto__: Array(0)
TypeError: 44 is not a function
at li.filter (<anonymous>)
at Function.o.safeCallback (VM872 WASubContext.js:1)
at l.<anonymous> (VM872 WASubContext.js:1)
at c.doUpdates (VM872 WASubContext.js:1)
at Mn (VM872 WASubContext.js:1)
at no (VM872 WASubContext.js:1)
at oo (VM872 WASubContext.js:1)
at no (VM872 WASubContext.js:1)
at oo (VM872 WASubContext.js:1)
at no (VM872 WASubContext.js:1)(env: Windows,mp,1.06.2504010; lib: 3.8.10)
refreshDingdanList @ tianjia.js? [sm]:97
initPage @ tianjia.js? [sm]:55
onLoad @ tianjia.js? [sm]:33
[pages/tianjia/tianjia] Some selectors are not allowed in component wxss, including tag name selectors, ID selectors, and attribute selectors.(./components/custom-form-modal/index.wxss:27:16)
filter-picker.js? [sm]:114 Picker focused
filter-picker.js? [sm]:145 Toggling dropdown
filter-picker.js? [sm]:114 Picker focused
filter-picker.js? [sm]:145 Toggling dropdown
最新发布