diff --git a/backend/application/api/controller/Demand.php b/backend/application/api/controller/Demand.php index 0bbbc9f..dc329d3 100644 --- a/backend/application/api/controller/Demand.php +++ b/backend/application/api/controller/Demand.php @@ -7,6 +7,7 @@ use app\common\service\CommonService; use app\common\service\ContractService; use app\common\service\DemandBiddingService; use app\common\service\DemandService; +use app\common\service\OrderShipService; use think\exception\HttpResponseException; use think\Lang; use think\Validate; @@ -128,6 +129,13 @@ class Demand extends Api } } elseif ($item->status == 3 && $item->isMyWin && $item->winBidding->bidding_status == 2 && $item->winBidding->process_status == 2) { $button = ['name' => '工作完成', 'theme' => 'danger']; + } elseif ($item->status == 5 && $item->isMyWin && $item->winBidding->bidding_status == 2 && $item->winBidding->process_status == 2) { + //客户支付尾款后,开发者发货交付 + if ($item->hasDelivery) { + $button = ['name' => '已发货', 'theme' => 'light']; + } else { + $button = ['name' => '去发货', 'theme' => 'danger']; + } } elseif ($item->is_bid) { $button = ['name' => '已投标', 'theme' => 'light']; } elseif ($item->status == 1) { @@ -147,6 +155,13 @@ class Demand extends Api $button = ['name' => '工作完成', 'theme' => 'danger']; } elseif ($item->status == 4 && $item->accept_status == 1) { $button = ['name' => '待验收', 'theme' => 'light']; + } elseif ($item->status == 5 && $item->isMyWin && $item->winBidding->bidding_status == 2 && $item->winBidding->process_status == 2) { + //客户支付尾款后,开发者发货交付 + if ($item->hasDelivery) { + $button = ['name' => '已发货', 'theme' => 'light']; + } else { + $button = ['name' => '去发货', 'theme' => 'danger']; + } } elseif ($item->status == 5 && $item->accept_status == 2) { $button = ['name' => '待收货', 'theme' => 'light']; } @@ -166,12 +181,15 @@ class Demand extends Api return $button; }; $list = DemandService::getList($where, $page_size, 'id desc', '', ['user', 'demandContracts', 'demandBiddings', 'winBidding']); - $list = $list->each(function ($item, $key) use ($user_id, $opType, $btnNameFun) { + //已发货的需求集合(发货表),用于开发者视角的发货按钮展示 + $deliveredDemandIds = OrderShipService::where(['demand_id' => ['in', $list->column('id')]])->column('demand_id'); + $list = $list->each(function ($item, $key) use ($user_id, $opType, $btnNameFun, $deliveredDemandIds) { $demand_bidding = $item->demand_biddings; $bidUserIds = array_column($demand_bidding, 'user_id'); $item->demand_biddings_count = count($demand_bidding); $item->is_bid = in_array($user_id, $bidUserIds); $item->isMyWin = $item->winBidding && $item->winBidding->user_id == $user_id; + $item->hasDelivery = in_array($item->id, $deliveredDemandIds); $item->button = $btnNameFun($opType, $item); }); $this->success('', $list); @@ -229,6 +247,14 @@ class Demand extends Api 'url' => $fl, 'name' => urldecode(basename($fl)) ], $info->files); + //交付内容(订单发货表,开发者发货后展示) + $ship = OrderShipService::where(['demand_id' => $id])->order('id', 'desc')->find(); + $info->delivery = $ship ? [ + 'images' => json_decode($ship->images, true) ?: [], + 'files' => json_decode($ship->files, true) ?: [], + 'remark' => $ship->remark, + 'delivery_time' => $ship->createtime, + ] : null; $this->success('', $info); } catch (\Exception $e) { diff --git a/backend/application/common/command/DemandDeal.php b/backend/application/common/command/DemandDeal.php index c5be525..c28a84a 100644 --- a/backend/application/common/command/DemandDeal.php +++ b/backend/application/common/command/DemandDeal.php @@ -6,6 +6,7 @@ use app\common\service\AccountLogService; use app\common\service\AccountService; use app\common\service\EasyWeChatService; use app\common\service\OrderService; +use app\common\service\OrderShipService; use app\common\service\SubscribeMessageService; use think\console\Command; use think\console\Input; @@ -45,8 +46,13 @@ class DemandDeal extends Command foreach ($demandList as $item) { try { Db::transaction(function () use ($item, $confirmReceiptTimeoutDay) { - //如果七天未确认收货,则自动确认收货 - if (time() > strtotime("+$confirmReceiptTimeoutDay day", $item->accept_time)) { + //未发货的需求不自动确认收货,等待开发者发货交付 + $ship = OrderShipService::where(['demand_id' => $item->id])->order('id', 'desc')->find(); + if (!$ship) { + return; + } + //发货后N天未确认收货,则自动确认收货 + if (time() > strtotime("+$confirmReceiptTimeoutDay day", intval($ship->createtime))) { $item->status = DemandService::STATUS_FINISHED; $item->settle_status = DemandService::$Common::ONGOING; $saveRes = $item->save(); diff --git a/backend/application/common/service/DemandService.php b/backend/application/common/service/DemandService.php index 109d7fe..2c39093 100644 --- a/backend/application/common/service/DemandService.php +++ b/backend/application/common/service/DemandService.php @@ -70,6 +70,7 @@ class DemandService const BUTTON_COMPLETE_WORK = 'completeWork'; //完成工作 const BUTTON_ACCEPT_PASSED = 'acceptPassed'; //验收通过 const BUTTON_CONFIRM_RECEIPT = 'confirmReceipt'; //确认收货 + const BUTTON_DELIVER_GOODS = 'deliverGoods'; //开发者发货 /** * 创建需求 @@ -130,6 +131,9 @@ class DemandService case self::BUTTON_CONFIRM_RECEIPT: $res = self::confirmReceipt($requestData, $userId); break; + case self::BUTTON_DELIVER_GOODS: + $res = self::deliverGoods($requestData, $userId); + break; default: throw new \Exception('非法操作'); } @@ -434,6 +438,70 @@ class DemandService } } + /** + * 开发者发货(交付开发成果) + * 凭证截图、交付附件与备注写入订单发货表,尾款订单转为已发货(待收货) + * @param $requestData + * @param $userId + * @return bool + * @throws Exception + */ + public static function deliverGoods($requestData, $userId) + { + try { + $demandId = $requestData['demandId'] ?? 0; + $images = array_values($requestData['images'] ?? []); + $files = array_values($requestData['files'] ?? []); + $remark = trim($requestData['remark'] ?? ''); + Db::startTrans(); + if (!$images || !$files) { + throw new \Exception('请上传开发完成的凭证截图和交付附件'); + } + $demand = self::getOne(['id' => $demandId], ['winBidding']); + if (!$demand) { + throw new \Exception('该需求不存在'); + } + if ($demand->status != self::STATUS_CONFIRM_RECEIPT) { + throw new \Exception('该需求为' . self::STATUS_MAP[$demand->status] . ',不能发货'); + } + if (!$demand->winBidding || $demand->winBidding->user_id != $userId) { + throw new \Exception('只有中标开发者才能发货'); + } + //尾款订单必须已支付(待发货)才能发货 + $finalOrder = OrderService::getDemandOrder($demand->parent_order_no, OrderService::ORDER_TYPE_FINAL_PAYMENT); + if (!$finalOrder) { + throw new \Exception('获取尾款订单失败'); + } + if ($finalOrder->order_status != OrderService::ORDER_STATUS_WAIT_SHIP) { + throw new \Exception('该订单为' . OrderService::ORDER_STATUS_MAP[$finalOrder->order_status] . ',不能发货'); + } + //交付内容写入订单发货表 + $spuId = $finalOrder->orderGoods[0]->spu_id ?? 0; + OrderShipService::createDemandDelivery($finalOrder->order_no, $spuId, $demandId, $images, $files, $remark); + //尾款订单改为已发货(待收货) + $upRes = OrderService::where(['id' => $finalOrder->id])->update(['order_status' => OrderService::ORDER_STATUS_SHIPPED]); + if (!$upRes) { + exception('更新发货状态失败'); + } + Db::commit(); + //给客户发送发货通知 + $msgData = [ + 'values' => [ + $finalOrder->order_no, + mb_substr($demand->title, 0, 20), + '已发货', + '开发成果已交付,请到需求详情查看交付内容并确认收货', + ] + ]; + (new EasyWeChatService)->sendMsg($demand->user_id, SubscribeMessageService::MSG_TEMP_ORDER_SHIPPED, $msgData); + + return true; + } catch (\Exception $e) { + Db::rollback(); + throw $e; + } + } + /** * 确认收货 * @param $requestData @@ -461,6 +529,11 @@ class DemandService if (!$saveRes) { exception('更新需求状态失败'); } + //关联订单状态改为已完成 + $upRes = OrderService::where(['parent_order_no' => $demand->parent_order_no])->update(['order_status' => OrderService::ORDER_STATUS_FINISHED]); + if (!$upRes) { + exception('更新订单状态失败'); + } Db::commit(); return $demand; } catch (\Exception $e) { diff --git a/backend/application/common/service/OrderService.php b/backend/application/common/service/OrderService.php index 801cde7..f8f2407 100644 --- a/backend/application/common/service/OrderService.php +++ b/backend/application/common/service/OrderService.php @@ -398,6 +398,23 @@ class OrderService if (!$upRes) { throw new \Exception('更新订单状态失败'); } + //需求订单(首付款/尾款):同步需求状态与关联订单 + if (in_array($order->order_type, [self::ORDER_TYPE_FIRST_PAYMENT, self::ORDER_TYPE_FINAL_PAYMENT])) { + $demand = DemandService::getOne(['parent_order_no' => $order->parent_order_no]); + if ($demand && $demand->status == DemandService::STATUS_CONFIRM_RECEIPT) { + $demand->status = DemandService::STATUS_FINISHED; + $demand->settle_status = CommonService::ONGOING; //结算中 + $saveRes = $demand->save(); + if (!$saveRes) { + throw new \Exception('更新需求状态失败'); + } + //同一需求下的关联订单全部改为已完成 + $upRes = self::where(['parent_order_no' => $order->parent_order_no])->update(['order_status' => self::ORDER_STATUS_FINISHED]); + if (!$upRes) { + throw new \Exception('更新关联订单状态失败'); + } + } + } Db::commit(); $info = OrderService::getOne(['id' => $orderId]); diff --git a/backend/application/common/service/OrderShipService.php b/backend/application/common/service/OrderShipService.php index e0d4d30..b66af90 100644 --- a/backend/application/common/service/OrderShipService.php +++ b/backend/application/common/service/OrderShipService.php @@ -35,4 +35,38 @@ class OrderShipService return $res; } + + /** + * 需求交付发货单(开发者发货:凭证截图+交付附件+备注) + * @param $order_no + * @param $order_goods_spu_id + * @param $demand_id + * @param array $images + * @param array $files + * @param string $remark + * @return mixed + * @throws \Exception + */ + public static function createDemandDelivery($order_no, $order_goods_spu_id, $demand_id, array $images, array $files, $remark = '') + { + $imagesStr = json_encode($images, JSON_UNESCAPED_UNICODE); + $filesStr = json_encode($files, JSON_UNESCAPED_UNICODE); + if (mb_strlen($imagesStr) > 1000 || mb_strlen($filesStr) > 1000) { + exception('附件内容过多,请精简后重新发货'); + } + $data = [ + 'order_no' => $order_no, + 'order_goods_spu_id' => $order_goods_spu_id, + 'demand_id' => $demand_id, + 'images' => $imagesStr, + 'files' => $filesStr, + 'remark' => $remark, + ]; + $res = self::create($data); + if (!$res) { + exception('创建发货单数据失败'); + } + + return $res; + } } \ No newline at end of file diff --git a/frontend/miniapp/app.json b/frontend/miniapp/app.json index 3c46d9a..e1518fb 100644 --- a/frontend/miniapp/app.json +++ b/frontend/miniapp/app.json @@ -35,6 +35,7 @@ "pages/demand/list/index", "pages/demand/detail/index", "pages/demand/contract/index", + "pages/demand/deliver/index", "pages/demand/agreement/index", "pages/usercenter/balance/index" ], diff --git a/frontend/miniapp/pages/demand/deliver/index.js b/frontend/miniapp/pages/demand/deliver/index.js new file mode 100644 index 0000000..0b5a013 --- /dev/null +++ b/frontend/miniapp/pages/demand/deliver/index.js @@ -0,0 +1,299 @@ +// pages/demand/deliver/index.js +import { demandOperate } from '../../../services/demand/fetchDemand'; +Page({ + + /** + * 页面的初始数据 + */ + data: { + demandId: 0, + remark: '', + // 开发完成凭证截图(软件成品展示图等) + imageFiles: [], + imageMax: 9, + imageSizeLimit: { + size: 20, unit: 'MB', message: '图片大小不超过 {sizeLimit} MB' + }, + // 交付附件(源码或软件成品文件) + attachFiles: [], + attachMax: 5, + attachConfig: { + count: 5, + }, + attachSizeLimit: { + size: 20, unit: 'MB', message: '附件大小不超过 {sizeLimit} MB' + }, + gridConfig: { + column: 4, + width: 160, + height: 160, + }, + }, + + /** + * 生命周期函数--监听页面加载 + */ + onLoad(options) { + const demandId = options?.demandId; + this.setData({ demandId }); + }, + + // 备注变更 + onRemarkChange(e) { + this.setData({ remark: e.detail.value }); + }, + + // 凭证截图选择成功 + handleSuccessImage(e) { + const files = e.detail?.files || []; + const { imageFiles, imageMax } = this.data; + const remain = imageMax - imageFiles.length; + const accepted = files.slice(0, remain); + if (files.length > remain) { + wx.showToast({ + title: `最多上传${imageMax}张截图`, + icon: 'none' + }); + } + if (!accepted.length) { + return; + } + this.setData({ + imageFiles: [...imageFiles, ...accepted] + }); + this.uploadFiles(accepted, 'image'); + }, + + // 移除凭证截图 + handleRemoveImage(e) { + const { index } = e.detail; + const { imageFiles } = this.data; + imageFiles.splice(index, 1); + this.setData({ imageFiles }); + }, + + // 交付附件选择成功 + handleSuccessAttach(e) { + 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 } + }); + this.uploadFiles(accepted, 'attach'); + }, + + // 移除交付附件 + handleRemoveAttach(e) { + const { index } = e.currentTarget.dataset; + const { attachFiles, attachMax } = this.data; + attachFiles.splice(index, 1); + this.setData({ + attachFiles, + attachConfig: { count: attachMax - attachFiles.length } + }); + }, + + // 上传文件到服务器 + uploadFiles(files, type) { + 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.removeFileByUrl(file.url, type); + return; + } + let response = {}; + try { + response = JSON.parse(res.data); + } catch (err) { + response = {}; + } + if (response.code === 1 && response.data && response.data.length > 0) { + this.updateFile(type, { + ...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.removeFileByUrl(file.url, type); + } + }, + fail: () => { + wx.showToast({ + title: '上传失败', + icon: 'none' + }); + this.removeFileByUrl(file.url, type); + } + }); + }); + }, + + // 上传完成后回写 + updateFile(type, newFile) { + if (type === 'image') { + const { imageFiles } = this.data; + const idx = imageFiles.findIndex(item => item.url === newFile.url); + if (idx === -1) { + return; + } + const list = [...imageFiles]; + list[idx] = newFile; + this.setData({ imageFiles: list }); + } else { + 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 } + }); + } + }, + + // 上传失败时移除 + removeFileByUrl(url, type) { + if (type === 'image') { + this.setData({ + imageFiles: this.data.imageFiles.filter(item => item.url !== url) + }); + } else { + const { attachFiles, attachMax } = this.data; + const list = attachFiles.filter(item => item.url !== url); + this.setData({ + attachFiles: list, + attachConfig: { count: attachMax - list.length } + }); + } + }, + + // 表单验证 + validateForm() { + const { imageFiles, attachFiles } = this.data; + if (!imageFiles.length) { + wx.showToast({ + title: '请上传开发完成的凭证截图', + icon: 'none' + }); + return false; + } + if (!attachFiles.length) { + wx.showToast({ + title: '请上传源码或软件附件', + icon: 'none' + }); + return false; + } + if (imageFiles.some(item => item.status !== 'done') || attachFiles.some(item => item.status !== 'done')) { + wx.showToast({ + title: '文件上传中,请稍候', + icon: 'none' + }); + return false; + } + return true; + }, + + // 提交发货 + onSubmit() { + if (!this.validateForm()) { + return; + } + wx.showLoading({ + title: '提交中...' + }); + const { demandId, imageFiles, attachFiles, remark } = this.data; + // 只提交服务端地址与文件名,避免提交本地临时路径 + const params = { + demandId, + opType: 'deliverGoods', + images: imageFiles.map(file => ({ + url: file.fullUrl || file.url, + name: file.name || '' + })), + files: attachFiles.map(file => ({ + url: file.fullUrl || file.url, + name: file.name + })), + remark + }; + demandOperate(params).then( + (res) => { + console.log(res); + wx.hideLoading(); + if (res.code == 1) { + wx.showModal({ + title: '提示', + showCancel: false, + content: '发货成功,等待客户确认收货', + success: (res2) => { + if (res2.confirm) { + //返回上一页(需求详情)并刷新 + wx.$util.backAndRefresh(); + console.log('用户点击确定'); + } + } + }); + } else { + wx.showToast({ + title: res.msg || '发货失败', + icon: 'none' + }); + } + }, + () => { + //接口异常处理 + wx.hideLoading(); + wx.showToast({ + title: '操作失败', + icon: 'none' + }); + }, + ); + } +}) diff --git a/frontend/miniapp/pages/demand/deliver/index.json b/frontend/miniapp/pages/demand/deliver/index.json new file mode 100644 index 0000000..3227b1d --- /dev/null +++ b/frontend/miniapp/pages/demand/deliver/index.json @@ -0,0 +1,8 @@ +{ + "navigationBarTitleText": "发货", + "usingComponents": { + "t-upload": "tdesign-miniprogram/upload/upload", + "t-tag": "tdesign-miniprogram/tag/tag", + "t-textarea": "tdesign-miniprogram/textarea/textarea" + } +} diff --git a/frontend/miniapp/pages/demand/deliver/index.wxml b/frontend/miniapp/pages/demand/deliver/index.wxml new file mode 100644 index 0000000..be42d43 --- /dev/null +++ b/frontend/miniapp/pages/demand/deliver/index.wxml @@ -0,0 +1,81 @@ + + + + + + + 开发完成凭证截图 + * + 最多 {{imageMax}} 张 + + 上传软件成品展示图等开发完成凭证,供客户核对 + + + + + + + 交付附件(源码或软件成品) + * + {{attachFiles.length}}/{{attachMax}} + + 上传源码或软件成品文件,客户确认收货后可下载,从聊天记录选择文件 + + {{item.name}} + + + + + + + + 发货备注 + 选填 + + + + + + + + + + + 确认发货 + + + diff --git a/frontend/miniapp/pages/demand/deliver/index.wxss b/frontend/miniapp/pages/demand/deliver/index.wxss new file mode 100644 index 0000000..d7181ca --- /dev/null +++ b/frontend/miniapp/pages/demand/deliver/index.wxss @@ -0,0 +1,103 @@ +/* pages/demand/deliver/index.wxss */ +.page-content { + padding: 24rpx 24rpx calc(112rpx + env(safe-area-inset-bottom) + 24rpx); + box-sizing: border-box; +} + +/* ================= 分组卡片 ================= */ +.form-card { + background: var(--bg-card); + border-radius: var(--radius-lg); + padding: 32rpx; + margin-bottom: 24rpx; + box-shadow: var(--shadow-card); +} + +.form-card__head { + display: flex; + align-items: baseline; + margin-bottom: 16rpx; +} + +.form-card__title { + font-size: 30rpx; + font-weight: 600; + line-height: 44rpx; + color: var(--text-primary); +} + +.form-card__require { + margin-left: 4rpx; + font-size: 28rpx; + line-height: 44rpx; + color: var(--error); +} + +.form-card__extra { + margin-left: auto; + font-size: 22rpx; + line-height: 40rpx; + color: var(--text-tertiary); +} + +.form-card__desc { + margin-bottom: 24rpx; + font-size: 24rpx; + line-height: 36rpx; + color: var(--text-tertiary); +} + +/* ================= 附件标签 ================= */ +.attach-list { + display: flex; + flex-wrap: wrap; +} + +.file-tag-margin { + margin: 8rpx 16rpx 8rpx 0; +} + +/* ================= 底部提交栏 ================= */ +.wx-pay-cover { + position: fixed; + left: 0; + bottom: 0; + right: 0; + z-index: 10; + background: var(--bg-card); + height: 112rpx; + padding-bottom: env(safe-area-inset-bottom); + box-shadow: 0 -4rpx 20rpx rgba(29, 33, 41, 0.05); +} + +.wx-pay-cover .wx-pay { + width: 100%; + height: 100rpx; + box-sizing: border-box; + padding: 0rpx 32rpx; + display: flex; + justify-content: center; + align-items: center; +} + +.wx-pay-cover .wx-pay .submit-btn { + height: 80rpx; + width: 50%; + border-radius: 40rpx; + background: var(--brand-gradient); + box-shadow: var(--shadow-brand); + color: #ffffff; + line-height: 80rpx; + font-weight: 500; + font-size: 28rpx; + text-align: center; +} + +.wx-pay-cover .wx-pay .submit-btn:active { + opacity: 0.88; +} + +.wx-pay-cover .wx-pay .btn-gray { + background: var(--text-disabled); + box-shadow: none; +} diff --git a/frontend/miniapp/pages/demand/detail/index.js b/frontend/miniapp/pages/demand/detail/index.js index 2de8e20..681bd6d 100644 --- a/frontend/miniapp/pages/demand/detail/index.js +++ b/frontend/miniapp/pages/demand/detail/index.js @@ -11,7 +11,7 @@ Page({ needDays: '', remark: '', actualAccount: 0, - activeValues: [0, 1, 2, 3], + activeValues: [0, 1, 2, 3, 4], demandInfo: null }, @@ -103,6 +103,24 @@ Page({ urls: images }); }, + //交付凭证截图预览 + onDeliveryImagePreview(e) { + const { images, index } = e.currentTarget.dataset; + const urls = (images || []).map(item => item.url); + if (!urls.length) { + return; + } + wx.previewImage({ + current: urls[index], + urls + }); + }, + //去发货(交付开发成果) + deliverGoods() { + wx.navigateTo({ + url: `/pages/demand/deliver/index?demandId=${this.data.id}`, + }); + }, //参与竞标 submitBidding() { const { id, quotedPrice, needDays, remark } = this.data; diff --git a/frontend/miniapp/pages/demand/detail/index.wxml b/frontend/miniapp/pages/demand/detail/index.wxml index e423852..94ccbbb 100644 --- a/frontend/miniapp/pages/demand/detail/index.wxml +++ b/frontend/miniapp/pages/demand/detail/index.wxml @@ -53,6 +53,33 @@ + + + + + 开发完成凭证截图 + + + + 交付附件 + + + + {{item.name}} + + + + + + + + + 发货备注 + {{_calc.getDelivery(demandInfo).remark}} + + + + @@ -73,6 +100,10 @@ 完成失败 工作完成 + + 去发货 + + 已发货(等待客户确认收货) diff --git a/frontend/miniapp/pages/demand/detail/index.wxs b/frontend/miniapp/pages/demand/detail/index.wxs index 5783916..2d6ef53 100644 --- a/frontend/miniapp/pages/demand/detail/index.wxs +++ b/frontend/miniapp/pages/demand/detail/index.wxs @@ -64,6 +64,36 @@ var canConfirmReceipt = function (demandInfo) { demandInfo.accept_status == 2; } +// 获取交付内容(订单发货表,后端 detail 接口挂载的 delivery 字段,未发货返回 null) +var getDelivery = function (demandInfo) { + if (!demandInfo) { + return null; + } + return demandInfo.delivery || null; +} + +// 开发者待发货:需求待收货(客户已付尾款)、自己中标且尚未交付 +var canDeliverGoods = function (demandInfo) { + if (!demandInfo) return false; + return demandInfo.status == 5 && + demandInfo.isMyWin && + demandInfo.winBidding && + demandInfo.winBidding.bidding_status == 2 && + demandInfo.winBidding.process_status == 2 && + !getDelivery(demandInfo); +} + +// 开发者已发货、等待客户确认收货 +var isDelivered = function (demandInfo) { + if (!demandInfo) return false; + return demandInfo.status == 5 && + demandInfo.isMyWin && + demandInfo.winBidding && + demandInfo.winBidding.bidding_status == 2 && + demandInfo.winBidding.process_status == 2 && + !!getDelivery(demandInfo); +} + // 数值拼接单位,空值时不显示单位 var withUnit = function (value, unit) { if (value === undefined || value === null || value === '') { @@ -81,5 +111,8 @@ module.exports = { canCompleteWork: canCompleteWork, canAcceptPassed: canAcceptPassed, canConfirmReceipt: canConfirmReceipt, + getDelivery: getDelivery, + canDeliverGoods: canDeliverGoods, + isDelivered: isDelivered, withUnit: withUnit, }; \ No newline at end of file diff --git a/frontend/miniapp/pages/demand/detail/index.wxss b/frontend/miniapp/pages/demand/detail/index.wxss index d808d00..a66971a 100644 --- a/frontend/miniapp/pages/demand/detail/index.wxss +++ b/frontend/miniapp/pages/demand/detail/index.wxss @@ -68,6 +68,40 @@ page { color: var(--text-tertiary); } +/* 交付内容 */ +.delivery-section { + padding-bottom: 8rpx; +} + +.delivery-title { + margin: 16rpx 0 12rpx; + font-size: 26rpx; + font-weight: 500; + color: var(--text-primary); +} + +.delivery-images { + display: flex; + flex-wrap: wrap; + margin-right: -16rpx; +} + +.delivery-image { + width: 160rpx; + height: 160rpx; + margin: 0 16rpx 16rpx 0; + border-radius: var(--radius-md, 12rpx); + background: var(--bg-grey); +} + +.delivery-remark { + font-size: 26rpx; + line-height: 40rpx; + color: var(--text-tertiary); + white-space: pre-wrap; + word-break: break-all; +} + .button-submit { margin: 32rpx; }