diff --git a/backend/application/api/controller/Demand.php b/backend/application/api/controller/Demand.php index 7f516fa..e135942 100644 --- a/backend/application/api/controller/Demand.php +++ b/backend/application/api/controller/Demand.php @@ -244,10 +244,12 @@ class Demand extends Api // $info->winBidding = DemandBiddingService::getOne(['demand_id' => $id, 'bidding_status' => DemandBiddingService::STATUS_BIDDING_WIN]); $info->isMy = $user_id == $info->user_id;//我发布 $info->isMyWin = $info->winBidding && $info->winBidding->user_id == $user_id;//我中标 + //小程序内无法直接识别二维码,需先长按保存再用微信扫一扫 + $qrcodeText = '长按保存二维码,微信扫一扫进群'; if ($user_id == $info->user_id) { - $info->contactText = !empty($info->demand_group_chat->qr_code) ? '请识别二维码进群沟通' : '******开发接单后可见'; + $info->contactText = !empty($info->demand_group_chat->qr_code) ? $qrcodeText : '******开发接单后可见'; } else { - $info->contactText = $info->isMyWin && !empty($info->demand_group_chat->qr_code) ? '请识别二维码进群沟通' : '******确认接单后可见'; + $info->contactText = $info->isMyWin && !empty($info->demand_group_chat->qr_code) ? $qrcodeText : '******确认接单后可见'; } $info->images = array_filter($info->images); $info->files = array_map(fn($fl) => [ diff --git a/backend/application/api/controller/Message.php b/backend/application/api/controller/Message.php index 406d00a..924f8a9 100644 --- a/backend/application/api/controller/Message.php +++ b/backend/application/api/controller/Message.php @@ -47,8 +47,10 @@ class Message extends Api } $list = MessageService::getList($where, $page_size, 'id desc')->toArray(); - $list['unread_count'] = $unreadCount; - $list['unread_map'] = $unreadMap; + $list['unread_count'] = $unreadCount; //当前筛选类型的未读数 + $list['unread_map'] = $unreadMap; //分类未读数(tab角标) + //全量未读总数:由后端统计所有类型,避免前端只累加 0/1/2 导致未知类型漏算 + $list['unread_total'] = (int)array_sum($unreadMap); $this->success('', $list); } catch (\Exception $e) { diff --git a/backend/application/common/service/MessageService.php b/backend/application/common/service/MessageService.php index e8b9e42..bbc48b6 100644 --- a/backend/application/common/service/MessageService.php +++ b/backend/application/common/service/MessageService.php @@ -75,10 +75,12 @@ class MessageService $lines[] = $name . ':' . $values[$key]; } } - // 各发送点已把 remark 作为最后一个 value 传入(对应 valueNames 末位的「备注」字段), - // 此处仅在正文尚未包含 remark 时才追加,避免出现两行重复的「备注」 + // 备注处理:避免正文出现两行「备注」或语义冲突 + // 1) 模板字段里已含「备注」时,发送方自定义了备注文案,不再追加模板默认 remark + // 2) 否则仅在正文尚未包含 remark 时追加,避免重复 $remark = $template['remark'] ?? ''; - if ($remark !== '') { + $hasRemarkField = in_array('备注', $valueNames, true); + if ($remark !== '' && !$hasRemarkField) { $content = implode("\n", $lines); if (mb_strpos($content, $remark) === false) { $lines[] = '备注:' . $remark; diff --git a/frontend/miniapp/app.js b/frontend/miniapp/app.js index 859fd4f..138e6d2 100644 --- a/frontend/miniapp/app.js +++ b/frontend/miniapp/app.js @@ -34,6 +34,7 @@ App({ onHide: function () {}, globalData: { unread: 0, //未读消息数(tabbar红点共享缓存) + refreshDemandId: 0, //操作后需要刷新状态的需求ID(跨页面通知列表页) }, /** diff --git a/frontend/miniapp/pages/demand/contract/index.js b/frontend/miniapp/pages/demand/contract/index.js index 10c376a..deae751 100644 --- a/frontend/miniapp/pages/demand/contract/index.js +++ b/frontend/miniapp/pages/demand/contract/index.js @@ -547,6 +547,8 @@ Page({ if (detailPage) { detailPage.setData({ freshPage: true }); } + //标记该需求需要刷新,返回列表时同步最新状态与按钮 + wx.$util.markDemandRefresh(this.data.demandId); wx.$util.backAndRefresh(2); }, diff --git a/frontend/miniapp/pages/demand/detail/index.js b/frontend/miniapp/pages/demand/detail/index.js index 2f6c8bd..9792bf2 100644 --- a/frontend/miniapp/pages/demand/detail/index.js +++ b/frontend/miniapp/pages/demand/detail/index.js @@ -302,6 +302,8 @@ Page({ content: agree ? '确认接单成功,请通过联系方式与客户沟通开发细节' : '已拒绝成功', success: (res) => { if (res.confirm) { + //标记该需求需要刷新,返回列表时同步最新状态与按钮 + wx.$util.markDemandRefresh(this.data.id); if (agree) { //刷新当前页面,等沟通群二维码渲染完成后再回到顶部,方便直接看到 this.loadDemandDetail(this.data.id).then(() => { diff --git a/frontend/miniapp/pages/demand/detail/index.wxml b/frontend/miniapp/pages/demand/detail/index.wxml index 2633d8d..0292549 100644 --- a/frontend/miniapp/pages/demand/detail/index.wxml +++ b/frontend/miniapp/pages/demand/detail/index.wxml @@ -90,8 +90,8 @@ - - + + 立即报名 diff --git a/frontend/miniapp/pages/demand/detail/index.wxs b/frontend/miniapp/pages/demand/detail/index.wxs index c3ccdbd..f82c005 100644 --- a/frontend/miniapp/pages/demand/detail/index.wxs +++ b/frontend/miniapp/pages/demand/detail/index.wxs @@ -104,6 +104,17 @@ var isDelivered = function (demandInfo) { !!getDelivery(demandInfo); } +// 是否开发者视角(决定按钮区渲染开发者操作还是需求方操作) +// 列表页会带 opType(quote=开发者视角,view=需求方视角); +// 站内消息等入口跳转不带 opType,此时按身份判断:需求发布者为需求方视角,其余为开发者视角 +var isDevView = function (demandInfo, opType) { + if (opType === 'view') return false; + if (opType === 'quote') return true; + // 数据未加载前先不渲染按钮,避免短暂闪成错误视角 + if (!demandInfo) return false; + return !demandInfo.isMy; +} + // 数值拼接单位,空值时不显示单位 var withUnit = function (value, unit) { if (value === undefined || value === null || value === '') { @@ -125,5 +136,6 @@ module.exports = { getDelivery: getDelivery, canDeliverGoods: canDeliverGoods, isDelivered: isDelivered, + isDevView: isDevView, withUnit: withUnit, }; \ No newline at end of file diff --git a/frontend/miniapp/pages/demand/list/index.js b/frontend/miniapp/pages/demand/list/index.js index f90a59d..a5e5561 100644 --- a/frontend/miniapp/pages/demand/list/index.js +++ b/frontend/miniapp/pages/demand/list/index.js @@ -149,6 +149,40 @@ Page({ } }, + /** + * 保持当前分页与滚动位置重新拉取列表 + * 用于「详情页/签约页操作后返回」时刷新该条数据的状态与按钮: + * 一次拉回已加载的全部条目,避免像 loadDemandList(true) 那样回到第一页 + */ + async refreshListKeepPosition() { + const { status, keywords, opType, demandList } = this.data; + const loadedCount = demandList.length; + if (!loadedCount) { + await this.loadDemandList(true); + return; + } + try { + const res = await fetchDemandList({ + page: 1, + pageSize: loadedCount, + status, + keywords, + opType + }); + const nextList = res.data.data || []; + //只替换数据,不动 page / hasMore,保持原有的分页进度 + this.setData({ + demandList: nextList, + isEmpty: nextList.length === 0 + }); + wx.nextTick(() => { + this.checkDescOverflow(); + }); + } catch (err) { + console.error('Failed to refresh demand list:', err); + } + }, + // 检查每条内容是否超出最大高度,决定是否显示“查看全文” checkDescOverflow() { const query = this.createSelectorQuery(); @@ -253,6 +287,15 @@ Page({ } return; } + //详情页/签约页操作完成后会写入该标记,回到列表时刷新对应条目的状态与按钮 + const app = getApp(); + const refreshDemandId = app && app.globalData ? app.globalData.refreshDemandId : 0; + if (refreshDemandId) { + //先清除标记,避免同一条被重复处理 + app.globalData.refreshDemandId = 0; + this.refreshListKeepPosition(); + return; + } if (this.data.freshPage) { this.setData({ freshPage: false }); this.loadDemandList(true); diff --git a/frontend/miniapp/pages/message/list/index.js b/frontend/miniapp/pages/message/list/index.js index 60ed512..5a1e83c 100644 --- a/frontend/miniapp/pages/message/list/index.js +++ b/frontend/miniapp/pages/message/list/index.js @@ -45,7 +45,11 @@ Page({ let newList = res.data.data; let hasMore = res.data.current_page < res.data.last_page; let unreadMap = res.data.unread_map || { '0': 0, '1': 0, '2': 0 }; - let totalUnread = Number(unreadMap['0'] || 0) + Number(unreadMap['1'] || 0) + Number(unreadMap['2'] || 0); + //直接用后端统计的全量未读总数(含所有类型), + //不再由前端累加 0/1/2,避免 message_type 超出这三个值时漏算 + let totalUnread = res.data.unread_total !== undefined && res.data.unread_total !== null + ? Number(res.data.unread_total) || 0 + : Number(unreadMap['0'] || 0) + Number(unreadMap['1'] || 0) + Number(unreadMap['2'] || 0); this.setData({ list: refresh ? newList : list.concat(newList), page: page + 1, diff --git a/frontend/miniapp/utils/util.js b/frontend/miniapp/utils/util.js index 194c649..6dbd48e 100644 --- a/frontend/miniapp/utils/util.js +++ b/frontend/miniapp/utils/util.js @@ -490,6 +490,18 @@ const obj2Params = (obj = {}, encode = false) => { return result.join('&'); }; +/** + * 标记某条需求需要在列表页刷新状态 + * 用 globalData 传递,不依赖页面栈深度(backAndRefresh 的 delta 在多层跳转后容易算错上一页) + * @param {number|string} demandId 需求ID + */ +function markDemandRefresh(demandId) { + const app = getApp(); + if (app && app.globalData) { + app.globalData.refreshDemandId = Number(demandId) || 0; + } +} + function backAndRefresh(delta = 1, freshField = 'freshPage') { const pages = getCurrentPages(); // 获取页面栈 const prevPage = pages[pages.length - (delta + 1)]; // 上一页实例 @@ -567,6 +579,7 @@ module.exports = { transferBoxShadow, obj2Params, backAndRefresh, + markDemandRefresh, checkSubscriptionsSetting, getUid }; \ No newline at end of file