fix: admin records filter by user_id instead of keyword search
- RecordView passes user_id as separate filter param, not as keyword - Admin records endpoint forwards user_id to DAO - treatmentDao.listAdmin supports exact user_id match filter - Added visible filter tag with clear button in RecordView
这个提交包含在:
@@ -2,6 +2,10 @@
|
|||||||
<view>
|
<view>
|
||||||
<view class="toolbar">
|
<view class="toolbar">
|
||||||
<view class="header-actions">
|
<view class="header-actions">
|
||||||
|
<view class="filter-tag" v-if="filterUserId">
|
||||||
|
<text class="filter-tag-text">用户: {{ filterUserId }}</text>
|
||||||
|
<text class="filter-tag-close" @click="clearUserFilter">x</text>
|
||||||
|
</view>
|
||||||
<input class="search-input date-input" v-model="dateFrom" placeholder="开始日期" />
|
<input class="search-input date-input" v-model="dateFrom" placeholder="开始日期" />
|
||||||
<text class="date-sep">~</text>
|
<text class="date-sep">~</text>
|
||||||
<input class="search-input date-input" v-model="dateTo" placeholder="结束日期" />
|
<input class="search-input date-input" v-model="dateTo" placeholder="结束日期" />
|
||||||
@@ -83,7 +87,8 @@ export default {
|
|||||||
pageSize: 20,
|
pageSize: 20,
|
||||||
keyword: '',
|
keyword: '',
|
||||||
dateFrom: '',
|
dateFrom: '',
|
||||||
dateTo: ''
|
dateTo: '',
|
||||||
|
filterUserId: ''
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@@ -95,9 +100,7 @@ export default {
|
|||||||
user_id: {
|
user_id: {
|
||||||
immediate: true,
|
immediate: true,
|
||||||
handler(val) {
|
handler(val) {
|
||||||
if (val) {
|
this.filterUserId = val || ''
|
||||||
this.keyword = val
|
|
||||||
}
|
|
||||||
this.loadRecords()
|
this.loadRecords()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -110,6 +113,7 @@ export default {
|
|||||||
page: this.page,
|
page: this.page,
|
||||||
page_size: this.pageSize,
|
page_size: this.pageSize,
|
||||||
keyword: this.keyword,
|
keyword: this.keyword,
|
||||||
|
user_id: this.filterUserId,
|
||||||
date_from: this.dateFrom,
|
date_from: this.dateFrom,
|
||||||
date_to: this.dateTo
|
date_to: this.dateTo
|
||||||
}
|
}
|
||||||
@@ -124,6 +128,11 @@ export default {
|
|||||||
this.page = 1
|
this.page = 1
|
||||||
this.loadRecords()
|
this.loadRecords()
|
||||||
},
|
},
|
||||||
|
clearUserFilter() {
|
||||||
|
this.filterUserId = ''
|
||||||
|
this.page = 1
|
||||||
|
this.loadRecords()
|
||||||
|
},
|
||||||
onPage(p) {
|
onPage(p) {
|
||||||
this.page = p
|
this.page = p
|
||||||
this.loadRecords()
|
this.loadRecords()
|
||||||
@@ -156,7 +165,7 @@ export default {
|
|||||||
formatDate: formatDateUtil,
|
formatDate: formatDateUtil,
|
||||||
async onExport() {
|
async onExport() {
|
||||||
try {
|
try {
|
||||||
const data = await get('/api/v1/admin/records', { page: 1, page_size: 9999, keyword: this.keyword, date_from: this.dateFrom, date_to: this.dateTo })
|
const data = await get('/api/v1/admin/records', { page: 1, page_size: 9999, keyword: this.keyword, user_id: this.filterUserId, date_from: this.dateFrom, date_to: this.dateTo })
|
||||||
var REGION_MAP = { 1: '左脸', 2: '右脸', 4: '额头', 8: '下巴', 16: '鼻', 32: '左眼', 64: '右眼' }
|
var REGION_MAP = { 1: '左脸', 2: '右脸', 4: '额头', 8: '下巴', 16: '鼻', 32: '左眼', 64: '右眼' }
|
||||||
const records = data.records || []
|
const records = data.records || []
|
||||||
exportCSV('records_' + new Date().toISOString().slice(0, 10) + '.csv',
|
exportCSV('records_' + new Date().toISOString().slice(0, 10) + '.csv',
|
||||||
@@ -192,4 +201,26 @@ export default {
|
|||||||
color: #999;
|
color: #999;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.filter-tag {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
background: #fff0f6;
|
||||||
|
border: 1px solid #E6508C;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 4px 8px;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-tag-text {
|
||||||
|
color: #E6508C;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-tag-close {
|
||||||
|
color: #E6508C;
|
||||||
|
cursor: pointer;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-left: 4px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -105,9 +105,13 @@ async function updateDevice(deviceId, battery, temperature) {
|
|||||||
* @param {number} opts.offset
|
* @param {number} opts.offset
|
||||||
* @returns {Promise<{records: Array, total: number}>}
|
* @returns {Promise<{records: Array, total: number}>}
|
||||||
*/
|
*/
|
||||||
async function listAdmin({ keyword, dateFrom, dateTo, pageSize, offset }) {
|
async function listAdmin({ keyword, userId, dateFrom, dateTo, pageSize, offset }) {
|
||||||
const conditions = []
|
const conditions = []
|
||||||
const params = {}
|
const params = {}
|
||||||
|
if (userId) {
|
||||||
|
conditions.push('r.user_id = :user_id')
|
||||||
|
params.user_id = userId
|
||||||
|
}
|
||||||
if (keyword) {
|
if (keyword) {
|
||||||
conditions.push('u.nickname LIKE :kw')
|
conditions.push('u.nickname LIKE :kw')
|
||||||
params.kw = '%' + keyword + '%'
|
params.kw = '%' + keyword + '%'
|
||||||
|
|||||||
@@ -227,6 +227,7 @@ router.get('/records', requireAdmin, wrap(async (req, res) => {
|
|||||||
const { page, pageSize, offset } = pageParams(req.query)
|
const { page, pageSize, offset } = pageParams(req.query)
|
||||||
const { records, total } = await treatmentDao.listAdmin({
|
const { records, total } = await treatmentDao.listAdmin({
|
||||||
keyword: req.query.keyword,
|
keyword: req.query.keyword,
|
||||||
|
userId: req.query.user_id,
|
||||||
dateFrom: req.query.date_from,
|
dateFrom: req.query.date_from,
|
||||||
dateTo: req.query.date_to,
|
dateTo: req.query.date_to,
|
||||||
pageSize,
|
pageSize,
|
||||||
|
|||||||
在新工单中引用
屏蔽一个用户