feat(integral-external): order/user list, integral log, wa selfBonus

- Fix ExternalIntegral order list (no double restPage); default 普通订单; UI columns for useIntegral and buyer uid/nickname/phone; enrich StoreOrderDetailResponse and admin query select.
- External user list: UserResponse.selfBonus and fillWaSelfBonus from wa_users.id=uid.
- Integral log: AdminIntegralSearchRequest nickName/phone; findAdminList filters and ordering; integralExternal API sends page/limit as query params.
- Integral detail page: linkType Chinese mapping including selfbonus; update docs/newpage.md.
- Dashboard grid menu entries for integral-external routes.

Made-with: Cursor
This commit is contained in:
apple
2026-04-09 15:10:16 +08:00
parent ee0886b800
commit f8ba25e7d5
13 changed files with 299 additions and 67 deletions

View File

@@ -5,8 +5,8 @@
<el-button size="small" icon="el-icon-arrow-left" @click="goBack">返回</el-button>
</div>
<!-- 用户概览卡片 -->
<el-card class="box-card overview-card">
<!-- 用户概览卡片从用户列表进入时展示 uid 时为全部明细模式 -->
<el-card v-if="uid" class="box-card overview-card">
<div class="overview-header">
<span class="user-title">
{{ userInfo.nickname || ('UID: ' + uid) }}
@@ -30,6 +30,12 @@
</el-col>
</el-row>
</el-card>
<el-card v-else class="box-card overview-card overview-card--all">
<div class="overview-header">
<span class="user-title">全部积分明细</span>
<span class="hint-text">未指定用户时将展示全部记录支持下方条件筛选</span>
</div>
</el-card>
<!-- 积分明细列表 -->
<el-card class="box-card mt10">
@@ -37,8 +43,41 @@
<span>积分明细</span>
</div>
<div class="container mb10">
<el-form inline size="small" :model="searchForm" label-width="80px">
<el-form inline size="small" :model="searchForm" label-width="96px">
<el-row>
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="6">
<el-form-item label="用户ID">
<el-input
v-model="searchForm.uidStr"
placeholder="可选,留空查全部"
clearable
class="filter-input"
@keyup.enter.native="handleSearch"
/>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="6">
<el-form-item label="用户名称:">
<el-input
v-model="searchForm.nickName"
placeholder="昵称模糊匹配"
clearable
class="filter-input"
@keyup.enter.native="handleSearch"
/>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="6">
<el-form-item label="手机号:">
<el-input
v-model="searchForm.phone"
placeholder="手机号模糊匹配"
clearable
class="filter-input"
@keyup.enter.native="handleSearch"
/>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="6">
<el-form-item label="时间选择:">
<el-date-picker
@@ -150,7 +189,9 @@ export default {
total: 0,
},
searchForm: {
uid: null,
uidStr: '',
nickName: '',
phone: '',
dateLimit: '',
page: 1,
limit: 15,
@@ -159,26 +200,38 @@ export default {
};
},
created() {
// 从路由 query 中注入 uid 及概览信息
const { uid, nickname, integral, selfBonus } = this.$route.query;
this.uid = uid ? Number(uid) : null;
this.userInfo.nickname = nickname || '';
this.userInfo.integral = integral !== '' && integral != null ? Number(integral) : null;
this.userInfo.selfBonus = selfBonus !== '' && selfBonus != null ? Number(selfBonus) : null;
this.searchForm.uid = this.uid;
if (this.uid) {
this.searchForm.uidStr = String(this.uid);
}
},
mounted() {
if (this.uid) {
this.getList();
} else {
this.$message.error('缺少用户ID无法加载积分明细');
}
this.getList();
},
methods: {
getList() {
this.listLoading = true;
const params = { ...this.searchForm };
if (!params.dateLimit) delete params.dateLimit;
const uidParsed = this.searchForm.uidStr === '' || this.searchForm.uidStr == null
? null
: parseInt(String(this.searchForm.uidStr).trim(), 10);
const uid = Number.isNaN(uidParsed) ? null : uidParsed;
const params = {
page: this.searchForm.page,
limit: this.searchForm.limit,
uid,
nickName: this.searchForm.nickName ? this.searchForm.nickName.trim() : undefined,
phone: this.searchForm.phone ? this.searchForm.phone.trim() : undefined,
dateLimit: this.searchForm.dateLimit || undefined,
};
Object.keys(params).forEach((k) => {
if (params[k] === undefined || params[k] === null || params[k] === '') {
delete params[k];
}
});
getExternalIntegralLog(params)
.then((res) => {
@@ -195,9 +248,14 @@ export default {
this.getList();
},
handleReset() {
this.searchForm.uidStr = '';
this.searchForm.nickName = '';
this.searchForm.phone = '';
this.searchForm.dateLimit = '';
this.searchForm.page = 1;
this.timeVal = [];
this.uid = null;
this.userInfo = { nickname: '', integral: null, selfBonus: null };
this.getList();
},
onchangeTime(e) {
@@ -217,8 +275,17 @@ export default {
this.$router.push('/integral-external/user');
},
linkTypeFilter(type) {
const typeMap = { order: '订单', sign: '签到', system: '系统' };
return typeMap[type] || type || '-';
if (type == null || type === '') return '-';
const raw = String(type).trim();
if (!raw) return '-';
const key = raw.toLowerCase();
const typeMap = {
order: '订单',
sign: '签到',
system: '系统',
selfbonus: '个人奖金',
};
return typeMap[key] || `其他(${raw}`;
},
statusFilter(status) {
const statusMap = { 1: '订单创建', 2: '冻结期', 3: '完成', 4: '失效' };
@@ -288,4 +355,14 @@ export default {
.block {
text-align: right;
}
.filter-input {
width: 180px;
}
.overview-card--all .hint-text {
display: block;
margin-top: 8px;
font-size: 13px;
color: #909399;
font-weight: normal;
}
</style>