feat: 重构后台服务字典与商品独立定价体系及前后端交互优化

这个提交包含在:
2026-11-10 11:01:05 +08:00
父节点 3ebd795cbb
当前提交 e2b0044b64
共有 66 个文件被更改,包括 6628 次插入 和 2137 次删除

查看文件

@@ -155,4 +155,138 @@ class Base extends Api
{
return date('YmdHis') . str_pad((string)mt_rand(0, 999999), 6, '0', STR_PAD_LEFT);
}
/**
* 同步写入或隐藏独立晒单表 fa_showcase(仅存储脱敏后的必要公开信息)
* @param array $order 订单行
* @param int $isShowcase 1=公开晒单, 0=取消晒单
* @return int 晒单表主键 ID(取消时返回 0)
*/
protected function syncOrderShowcase(array $order, $isShowcase = 1)
{
$orderId = (int)$order['id'];
$now = time();
if (!$isShowcase) {
Db::name('showcase')->where('order_id', $orderId)->update([
'status' => 'hidden',
'updatetime' => $now,
]);
return 0;
}
$rev = Db::name('review')->where('order_id', $orderId)->where('status', 'normal')->find();
$u = Db::name('user')->where('id', (int)$order['user_id'])->find();
$cat = Db::name('service_cat')->where('id', (int)$order['cat_id'])->find();
$service = Db::name('service')->where('id', (int)$order['service_id'])->find();
$isAnon = $rev ? (int)$rev['is_anonymous'] : 0;
$userName = '匿名业主';
$userAvatar = '';
if (!$isAnon && $u) {
$nick = trim((string)$u['nickname']);
if ($nick !== '' && !preg_match('/^[0-9]/', $nick)) {
$userName = mb_substr($nick, 0, 1) . '业主';
} else {
$userName = '优匠业主';
}
$userAvatar = !empty($u['avatar']) ? (string)$u['avatar'] : '';
}
// 地区仅保留区县或城市,绝不保存具体街道/小区/门牌
$district = trim((string)$order['district']);
$city = trim((string)$order['city']);
$region = $district ?: ($city ?: '同城服务');
// 收集晒单实拍图(评价晒图 > 完工实况图,过滤无效测试域名)
$imgList = [];
if ($rev && !empty($rev['images'])) {
$dec = json_decode((string)$rev['images'], true);
$arr = is_array($dec) ? $dec : array_filter(explode(',', (string)$rev['images']));
foreach ($arr as $it) {
$it = trim((string)$it);
if ($it !== '' && substr($it, -4) !== '.svg' && strpos($it, 'example.com') === false) {
$imgList[] = $it;
}
}
}
if (empty($imgList)) {
$mediaUrls = Db::name('order_media')->where('order_id', $orderId)->order('id desc')->limit(6)->column('url');
foreach ($mediaUrls as $mu) {
$mu = trim((string)$mu);
if ($mu !== '' && substr($mu, -4) !== '.svg' && strpos($mu, 'example.com') === false) {
$imgList[] = $mu;
}
}
}
// 封面图提取
$cover = !empty($imgList) ? $imgList[0] : '';
if ($cover === '' && !empty($order['service_image']) && substr($order['service_image'], -4) !== '.svg') {
$cover = (string)$order['service_image'];
}
if ($cover === '' && $service && !empty($service['image']) && substr($service['image'], -4) !== '.svg') {
$cover = (string)$service['image'];
}
if ($cover === '') {
$fallback = Db::name('service')
->where('cat_id', (int)$order['cat_id'])
->where('image', '<>', '')
->where('image', 'not like', '%.svg%')
->order('weigh desc, id asc')
->value('image');
if ($fallback) {
$cover = (string)$fallback;
}
}
// 师傅脱敏称呼与评分
$masterName = '优匠师傅';
$masterScore = 5.00;
if ((int)$order['master_id'] > 0) {
$m = Db::name('master')->where('id', (int)$order['master_id'])->find();
if ($m) {
$rName = trim((string)$m['realname']);
if ($rName !== '' && strpos($rName, '师傅') === false) {
$masterName = mb_substr($rName, 0, 1) . '师傅';
} elseif ($rName !== '') {
$masterName = $rName;
}
$masterScore = (float)$m['score'] > 0 ? round((float)$m['score'], 2) : 5.00;
}
}
$score = $rev ? max(1, min(5, (int)$rev['score'])) : 5;
$tags = ($rev && !empty($rev['tags'])) ? (string)$rev['tags'] : '准时,专业,值得推荐';
$content = ($rev && !empty($rev['content'])) ? (string)$rev['content'] : '师傅准时上门,施工专业细致,安装效果很满意!';
$payload = [
'order_id' => $orderId,
'user_id' => (int)$order['user_id'],
'user_name' => $userName,
'user_avatar' => $userAvatar,
'cat_id' => (int)$order['cat_id'],
'cat_name' => $cat ? (string)$cat['name'] : '上门服务',
'service_id' => (int)$order['service_id'],
'service_name' => $order['service_name'] ?: ($service ? (string)$service['name'] : '上门服务'),
'region' => $region,
'cover_image' => $cover,
'images' => !empty($imgList) ? json_encode(array_values($imgList), JSON_UNESCAPED_UNICODE) : '',
'score' => $score,
'tags' => $tags,
'content' => mb_substr($content, 0, 500),
'master_name' => $masterName,
'master_score' => $masterScore,
'status' => 'normal',
'updatetime' => $now,
];
$existing = Db::name('showcase')->where('order_id', $orderId)->find();
if ($existing) {
Db::name('showcase')->where('id', (int)$existing['id'])->update($payload);
return (int)$existing['id'];
} else {
$payload['createtime'] = !empty($order['showcase_time']) ? (int)$order['showcase_time'] : $now;
return (int)Db::name('showcase')->insertGetId($payload);
}
}
}