feat: 累积功能变更 — 聊天集成、租户管理、小程序更新、ETL 增强、迁移脚本

包含多个会话的累积代码变更:
- backend: AI 聊天服务、触发器调度、认证增强、WebSocket、调度器最小间隔
- admin-web: ETL 状态页、任务管理、调度配置、登录优化
- miniprogram: 看板页面、聊天集成、UI 组件、导航更新
- etl: DWS 新任务(finance_area_daily/board_cache)、连接器增强
- tenant-admin: 项目初始化
- db: 19 个迁移脚本(etl_feiqiu 11 + zqyy_app 8)
- packages/shared: 枚举和工具函数更新
- tools: 数据库工具、报表生成、健康检查
- docs: PRD/架构/部署/合约文档更新

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Neo
2026-04-06 00:03:48 +08:00
parent 70324d8542
commit 6f8f12314f
515 changed files with 76604 additions and 7456 deletions

View File

@@ -15,11 +15,12 @@ Component({
score(val: number) {
const s = val < 0 ? 0 : val > 10 ? 10 : val
let emoji: string
// 分档对齐后端 compute_heart_icon>8.5 💖 / >7 🧡 / >5 💛 / ≤5 💙
if (s > 8.5) {
emoji = '💖' // 粉红色 - 很好
} else if (s >= 6) {
} else if (s > 7) {
emoji = '🧡' // 橙色 - 良好
} else if (s >= 3.5) {
} else if (s > 5) {
emoji = '💛' // 黄色 - 一般
} else {
emoji = '💙' // 蓝色 - 待发展

View File

@@ -1,5 +1,5 @@
.heart-icon {
font-size: 22rpx;
font-size: 24rpx;
line-height: 1;
position: relative;
top: -4rpx;

View File

@@ -65,14 +65,17 @@ Component({
}
},
// 任意评分或内容变化时重新计算 canSave
'serviceScore, returnScore, content, showRating'(
'serviceScore, returnScore, content, showRating, ratingExpanded'(
serviceScore: number,
returnScore: number,
content: string,
showRating: boolean
showRating: boolean,
ratingExpanded: boolean
) {
// 如果不显示评分,只需有内容即可保存;否则需要评分和内容都有
const canSave = showRating
// CHANGE 2026-03-27 | 评分区域收起时不要求评分,只需有内容即可保存
// 评分区域展开时才要求两个评分都 > 0
const needRating = showRating && ratingExpanded
const canSave = needRating
? serviceScore > 0 && returnScore > 0 && content.trim().length > 0
: content.trim().length > 0
this.setData({ canSave })

View File

@@ -1,22 +1,24 @@
<wxs src="../../utils/format.wxs" module="fmt" />
<!-- service-record-card 组件 —— 60天内服务记录单条卡片 -->
<view class="svc-card {{type === 'recharge' ? 'svc-card--recharge' : ''}}" hover-class="svc-card--hover">
<!-- 第一行:左=时间,右=课程+台桌+小时数 -->
<view class="svc-row svc-row1">
<text class="svc-time">{{time}}</text>
<text class="svc-time">{{fmt.safe(time)}}</text>
<view class="svc-right1">
<text class="svc-course-tag svc-course-{{typeClass}}">{{type === 'recharge' ? '充值' : courseLabel}}</text>
<text class="svc-course-tag svc-course-{{typeClass}}">{{type === 'recharge' ? '充值' : fmt.safe(courseLabel)}}</text>
<text class="svc-table-label" wx:if="{{tableNo && type !== 'recharge'}}">{{tableNo}}</text>
<text class="svc-hours" wx:if="{{hours && type !== 'recharge'}}">{{hours}}h</text>
<text class="svc-hours-raw" wx:if="{{hoursRaw && hoursRaw !== hours && type !== 'recharge'}}">折前{{hoursRaw}}h</text>
<text class="svc-hours" wx:if="{{hours && type !== 'recharge'}}">{{fmt.hoursH(hours)}}</text>
<!-- CHANGE 2026-03-27 | 任务B: 折前时长仅在 hoursRaw 有值且与 hours 不同时显示 -->
<text class="svc-hours-raw" wx:if="{{hoursRaw && hoursRaw !== hours && type !== 'recharge'}}">折前{{fmt.hoursH(hoursRaw)}}</text>
</view>
</view>
<!-- 第二行:左=商品,右=金额(含预估/提成) -->
<view class="svc-row svc-row2">
<text class="svc-drinks">{{drinks || '—'}}</text>
<text class="svc-drinks" wx:if="{{drinks}}">🍹 {{fmt.safe(drinks)}}</text>
<view class="svc-income-wrap">
<text class="svc-income-est" wx:if="{{isEstimate && type !== 'recharge'}}">预估</text>
<text class="svc-income-label">{{type === 'recharge' ? '提成' : '到手'}}</text>
<text class="svc-income {{type === 'recharge' ? 'svc-income--recharge' : ''}}">¥{{income}}</text>
<text class="svc-income {{type === 'recharge' ? 'svc-income--recharge' : ''}}">{{fmt.money(income)}}</text>
</view>
</view>
</view>

View File

@@ -90,15 +90,18 @@
color: #b9b9b9;
}
/* 第二行左:商品 */
/* 第二行左:商品最多2行超出省略 */
.svc-drinks {
font-size: 22rpx;
line-height: 29rpx;
color: #8b8b8b;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
max-width: 340rpx;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
margin-right: 20rpx;
}
/* 第二行右:金额 */
@@ -107,6 +110,7 @@
align-items: baseline;
gap: 20rpx;
flex-shrink: 0;
margin-left: auto;
}
.svc-income-label {