Files
code-bang/frontend/miniapp/pages/demand/contract/index.js
T

652 lines
17 KiB
JavaScript

import { fetchDemandContractDetail, demandOperate } from '../../../services/demand/fetchDemand';
// pages/demand/contract/index.js
Page({
/**
* 页面的初始数据
*/
data: {
demandId: 0,
actualAccount: 0,
contract: null,
agreementUrl: '', // 签约条款URL
phoneError: '', // 个人联系电话错误提示
companyPhoneError: '', // 企业联系电话错误提示
// 附件上传
attachFiles: [],
attachMax: 5, // 最多上传5个附件
attachConfig: {
count: 5,
},
attachSizeLimit: {
size: 20, unit: 'MB', message: '附件大小不超过 {sizeLimit} MB'
},
gridConfig: {
column: 4,
width: 160,
height: 160,
},
formData: {
contractType: 'personal', // 默认选择个人签约
// 个人签约信息
name: '',
phone: '',
idCard: '',
// 企业签约信息
companyName: '',
legalPerson: '',
companyPhone: '',
// 开发信息
taskContent: '',
needDays: '',
totalCost: '',
attachFiles: [],
// 签约条款
agreementChecked: false
}
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
// 设置签约条款URL(进行编码)
const source = options?.source;
const demandId = options?.demandId;
const agreementUrl = encodeURIComponent(wx.$api.ApiRoot + '/assets/h5/terms/platform_contract_service_terms.html');
this.setData({
source,
demandId,
agreementUrl
});
this.getContractDetail();
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady() {
},
/**
* 生命周期函数--监听页面显示
*/
onShow() {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide() {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload() {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh() {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom() {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage() {
},
// 签约类型切换
onContractTypeChange(e) {
console.log(e.detail.value)
this.setData({
'formData.contractType': e.detail.value
});
},
// 个人签约信息变更
onNameChange(e) {
this.setData({
'formData.name': e.detail.value
});
},
onPhoneChange(e) {
this.setData({
'formData.phone': e.detail.value
});
// 输入过程中若已修正为合法手机号,立即清除错误提示
if (this.data.phoneError && this.isPhone(e.detail.value)) {
this.setData({ phoneError: '' });
}
},
onPhoneBlur(e) {
this.setData({
phoneError: this.getPhoneError(e.detail.value)
});
},
onIdCardChange(e) {
this.setData({
'formData.idCard': e.detail.value
});
},
// 企业签约信息变更
onCompanyNameChange(e) {
this.setData({
'formData.companyName': e.detail.value
});
},
onLegalPersonChange(e) {
this.setData({
'formData.legalPerson': e.detail.value
});
},
onCompanyPhoneChange(e) {
this.setData({
'formData.companyPhone': e.detail.value
});
if (this.data.companyPhoneError && this.isPhone(e.detail.value)) {
this.setData({ companyPhoneError: '' });
}
},
onCompanyPhoneBlur(e) {
this.setData({
companyPhoneError: this.getPhoneError(e.detail.value)
});
},
// 开发信息变更
onDevelopmentContentChange(e) {
this.setData({
'formData.taskContent': e.detail.value
});
},
onDevelopmentPeriodChange(e) {
this.setData({
'formData.needDays': e.detail.value
});
},
onTotalCostChange(e) {
const number = Number(e.detail.value * 0.9);
this.setData({
'formData.totalCost': e.detail.value,
'actualAccount': Math.round(e.detail.value * 0.9)
});
},
// 附件选择成功(仅开发者可上传)
handleSuccessAttach(e) {
if (this.data.source != 'dev') {
return;
}
const files = e.detail?.files || [];
const { attachFiles, attachMax } = this.data;
const remain = attachMax - attachFiles.length;
const accepted = files.slice(0, remain);
if (files.length > remain) {
wx.showToast({
title: `最多上传${attachMax}个附件`,
icon: 'none'
});
}
if (!accepted.length) {
return;
}
const list = [...attachFiles, ...accepted];
this.setData({
attachFiles: list,
attachConfig: { count: attachMax - list.length },
'formData.attachFiles': list
});
this.uploadAttachFiles(accepted);
},
// 移除附件(仅开发者可移除;客户侧附件为开发者上传,只读)
handleRemoveAttach(e) {
if (this.data.source != 'dev') {
return;
}
const { index } = e.currentTarget.dataset;
const { attachFiles, attachMax } = this.data;
attachFiles.splice(index, 1);
this.setData({
attachFiles,
attachConfig: { count: attachMax - attachFiles.length },
'formData.attachFiles': attachFiles
});
},
// 附件预览:客户点击开发者上传的附件进行查看
handlePreviewAttach(e) {
// 仅客户侧可预览;开发者侧附件可删除,避免删除时误触预览
if (this.data.source == 'dev') {
return;
}
const { index } = e.currentTarget.dataset;
const file = this.data.attachFiles[index];
const fileUrl = file ? (file.fullUrl || file.url) : '';
if (!fileUrl) {
return;
}
// 图片直接预览
if (/\.(jpe?g|png|gif|webp|bmp)$/i.test(fileUrl)) {
wx.previewImage({
urls: [fileUrl]
});
return;
}
// 其他文件下载后打开
wx.showLoading({ title: '加载中...' });
wx.downloadFile({
url: fileUrl,
success: (res) => {
wx.hideLoading();
if (res.statusCode === 200) {
wx.openDocument({
filePath: res.tempFilePath,
showMenu: true,
fail: () => {
wx.showToast({ title: '该文件类型暂不支持预览', icon: 'none' });
}
});
} else {
wx.showToast({ title: '附件加载失败', icon: 'none' });
}
},
fail: () => {
wx.hideLoading();
wx.showToast({ title: '附件加载失败', icon: 'none' });
}
});
},
// 上传附件到服务器
uploadAttachFiles(files) {
files.forEach((file, index) => {
if (file.status === 'done') {
return;
}
wx.uploadFile({
url: wx.$api.UploadFile,
filePath: file.url,
name: 'file',
formData: {
'name': file.name,
'type': file.type
},
header: {
'Accept': 'application/json',
'token': wx.getStorageSync('token')
},
success: (res) => {
if (res.statusCode == 413) {
wx.showToast({
title: '附件大小超出限制',
icon: 'none'
});
this.removeAttachByUrl(file.url);
return;
}
let response = {};
try {
response = JSON.parse(res.data);
} catch (err) {
response = {};
}
if (response.code === 1 && response.data && response.data.length > 0) {
this.updateAttachFile({
...file,
fullUrl: response.data[0].url,
status: 'done'
});
if (index === files.length - 1) {
wx.showToast({
title: '附件上传成功',
icon: 'success'
});
}
} else {
wx.showToast({
title: response.msg || '附件上传失败',
icon: 'none'
});
this.removeAttachByUrl(file.url);
}
},
fail: () => {
wx.showToast({
title: '附件上传失败',
icon: 'none'
});
this.removeAttachByUrl(file.url);
}
});
});
},
// 更新单个附件(上传完成后回写)
updateAttachFile(newFile) {
const { attachFiles, attachMax } = this.data;
const idx = attachFiles.findIndex(item => item.url === newFile.url);
if (idx === -1) {
return;
}
const list = [...attachFiles];
list[idx] = newFile;
this.setData({
attachFiles: list,
attachConfig: { count: attachMax - list.length },
'formData.attachFiles': list
});
},
// 上传失败时移除附件
removeAttachByUrl(url) {
const { attachFiles, attachMax } = this.data;
const list = attachFiles.filter(item => item.url !== url);
this.setData({
attachFiles: list,
attachConfig: { count: attachMax - list.length },
'formData.attachFiles': list
});
},
// 签约条款变更
onAgreementChange(e) {
console.log('checkbox', e);
this.setData({
'formData.agreementChecked': e.detail.checked
});
},
// 是否为合法手机号(复用项目内置正则)
isPhone(phone) {
const value = String(phone === undefined || phone === null ? '' : phone).trim();
if (!value) {
return false;
}
return wx.$util.phoneRegCheck(value);
},
// 手机号错误提示文案,合法或为空时返回空串(为空由必填校验负责提示)
getPhoneError(phone) {
const value = String(phone === undefined || phone === null ? '' : phone).trim();
if (!value || this.isPhone(value)) {
return '';
}
return '手机号格式不正确,请输入11位手机号';
},
// 提交时校验手机号:写入错误态并 toast,返回是否存在错误
hasPhoneError(phone, errorField) {
const error = this.getPhoneError(phone);
this.setData({
[errorField]: error
});
if (error) {
wx.showToast({
title: error,
icon: 'none'
});
}
return !!error;
},
// 表单验证
validateForm() {
const { formData } = this.data;
const contractType = formData.contractType;
if (contractType === 'personal') {
// 身份证号暂不采集
if (!formData.name || !formData.phone) {
wx.showToast({
title: '请填写完整的个人信息',
icon: 'none'
});
return false;
}
if (this.hasPhoneError(formData.phone, 'phoneError')) {
return false;
}
} else {
if (!formData.companyName || !formData.legalPerson || !formData.companyPhone) {
wx.showToast({
title: '请填写完整的企业信息',
icon: 'none'
});
return false;
}
if (this.hasPhoneError(formData.companyPhone, 'companyPhoneError')) {
return false;
}
}
if (!formData.taskContent || !formData.needDays || !formData.totalCost) {
wx.showToast({
title: '请填写完整的开发信息',
icon: 'none'
});
return false;
}
if (this.data.attachFiles.some(item => item.status !== 'done')) {
wx.showToast({
title: '附件上传中,请稍候',
icon: 'none'
});
return false;
}
if (!formData.agreementChecked) {
wx.showToast({
title: '请阅读并同意签约条款',
icon: 'none'
});
return false;
}
return true;
},
//获取签约详情
getContractDetail() {
let { demandId, formData } = this.data;
let params = {
demandId,
}
fetchDemandContractDetail(params).then(
(res) => {
console.log(res);
if (res.code == 1) {
let resData = res.data;
const isDev = this.data.source == 'dev';
let resFormData = isDev ? resData.data_json.devData : resData.data_json.customData;
this.setData({
contract: resData,
formData: resFormData,
'formData.contractType': resFormData?.contractType || 'personal',
'formData.taskContent': resData.task_content,
'formData.needDays': resData.need_days,
'formData.totalCost': resData.total_amount,
});
// 客户签约时,附件展示开发者签约时上传的附件,仅可预览,不可删除和上传
const rawAttachFiles = isDev
? (resFormData?.attachFiles || [])
: (resData.data_json?.devData?.attachFiles || []);
// 统一补齐 fullUrl 与上传状态,便于预览取地址、提交时跳过上传中校验
const attachFiles = rawAttachFiles.map((file) => ({
...file,
fullUrl: file.fullUrl || file.url,
status: file.status || 'done'
}));
this.setData({
attachFiles,
'formData.attachFiles': attachFiles,
attachConfig: { count: this.data.attachMax - attachFiles.length }
});
}
}
);
},
// 返回列表页并刷新,同时给中间的详情页打刷新标记(详情页 onShow 检测 freshPage 重新拉取)
backAndRefreshAll() {
const pages = getCurrentPages();
const detailPage = pages.length >= 2 ? pages[pages.length - 2] : null;
if (detailPage) {
detailPage.setData({ freshPage: true });
}
wx.$util.backAndRefresh(2);
},
//签约订单支付
onPay(order) {
let goodsList = [];
let storeId = order.store_id;
order.order_goods.forEach((data) => {
let query = {
quantity: data.buy_quantity,
storeId: storeId,
spuId: data.spu_id,
goodsName: data.goods_name,
available: 1,
price: data.goods_payment_price,
primaryImage: data.goods_picture_url,
skuId: data.sku_id,
thumb: data.goods_picture_url,
title: data.goods_name,
};
goodsList.push(query);
});
console.log(goodsList);
console.log(JSON.stringify(goodsList));
let urlQueryStr = wx.$util.obj2Params({
orderNo: order.order_no,
goodsRequestList: JSON.stringify(goodsList),
}, true);
console.log(urlQueryStr);
urlQueryStr = urlQueryStr ? `?${urlQueryStr}` : '';
const path = `/pages/order/order-confirm/index${urlQueryStr}`;
wx.navigateTo({
url: path,
});
},
// 提交表单
onSubmit() {
if (!this.validateForm()) {
return;
}
// TODO: 调用后端API提交签约信息
wx.showLoading({
title: '提交中...'
});
const { demandId, formData, source } = this.data;
// 附件只提交服务端地址与文件名,避免提交本地临时路径
const submitFormData = {
...formData,
attachFiles: (formData.attachFiles || []).map(file => ({
url: file.fullUrl || file.url,
name: file.name
}))
};
let params = {
demandId,
formData: submitFormData,
source,
'agree': 1,
'contractType': 1,
'opType': source == 'dev' ? 'contractDev' : 'contractCustomer',
}
demandOperate(params).then(
(res) => {
console.log(res);
wx.hideLoading();
if (res.code == 1) {
if (source == 'dev') {
wx.showModal({
title: '提示',
showCancel: false,
content: '签约已提交,等待客户签约确认',
success: (res2) => {
if (res2.confirm) {
//返回上一页
// wx.navigateBack({ delta: 2 });
this.backAndRefreshAll();
console.log('用户点击确定');
}
}
});
} else {
if (res.data.order_status == 20) {
wx.showModal({
title: '提示',
showCancel: false,
content: '签约完成,等待开发者开始工作,返回我的需求列表',
success: (res3) => {
if (res3.confirm) {
// wx.navigateBack({ delta: 2 });
this.backAndRefreshAll();
console.log('用户点击确定');
}
}
});
return;
}
wx.showModal({
title: '提示',
showCancel: false,
content: '签约完成,去支付首付款(总金额的50%)',
success: (res2) => {
if (res2.confirm) {
//支付预付款
this.onPay(res.data);
console.log('用户点击确定');
}
}
});
}
} else {
wx.showToast({
title: res.msg,
icon: 'none'
});
}
},
() => {
//接口异常处理
wx.showToast({
title: '操作失败',
icon: 'none'
});
},
);
}
})