|
|
|
|
@ -25,6 +25,22 @@
|
|
|
|
|
</view>
|
|
|
|
|
</picker>
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
<view class="filter-row" style="margin-top: 20rpx;">
|
|
|
|
|
<text class="filter-label">阅读状态</text>
|
|
|
|
|
<picker
|
|
|
|
|
mode="selector"
|
|
|
|
|
:range="noticeReadOptions"
|
|
|
|
|
range-key="label"
|
|
|
|
|
:value="selectedNoticeReadIndex"
|
|
|
|
|
@change="onNoticeReadChange"
|
|
|
|
|
>
|
|
|
|
|
<view class="filter-picker">
|
|
|
|
|
<text class="picker-text">{{ selectedNoticeReadLabel }}</text>
|
|
|
|
|
<text class="picker-arrow">▼</text>
|
|
|
|
|
</view>
|
|
|
|
|
</picker>
|
|
|
|
|
</view>
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
<!-- 列表 -->
|
|
|
|
|
@ -48,7 +64,12 @@
|
|
|
|
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
<text class="time">{{ item.noticeTime }}</text>
|
|
|
|
|
<view class="time-wrap">
|
|
|
|
|
<text class="time">{{ item.noticeTime }}</text>
|
|
|
|
|
<view class="read-badge" v-if="isUnread(item.isRead)">
|
|
|
|
|
<view class="red-dot"></view>
|
|
|
|
|
</view>
|
|
|
|
|
</view>
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
<view class="card-body">
|
|
|
|
|
@ -92,6 +113,8 @@ export default {
|
|
|
|
|
query: {
|
|
|
|
|
noticeTitle: '',
|
|
|
|
|
noticeType: '',
|
|
|
|
|
// 1=已读,0=未读,''=全部
|
|
|
|
|
isRead: '',
|
|
|
|
|
},
|
|
|
|
|
records: [],
|
|
|
|
|
page: 1,
|
|
|
|
|
@ -124,6 +147,23 @@ export default {
|
|
|
|
|
const current = this.noticeTypeOptions[this.selectedNoticeTypeIndex];
|
|
|
|
|
return current ? current.label : '全部';
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
noticeReadOptions() {
|
|
|
|
|
// 后端约定:空=全部,0=未读,1=已读
|
|
|
|
|
return [
|
|
|
|
|
{ label: '全部', value: '' },
|
|
|
|
|
{ label: '未读', value: 0 },
|
|
|
|
|
{ label: '已读', value: 1 },
|
|
|
|
|
];
|
|
|
|
|
},
|
|
|
|
|
selectedNoticeReadIndex() {
|
|
|
|
|
const index = this.noticeReadOptions.findIndex(item => item.value === this.query.isRead);
|
|
|
|
|
return index >= 0 ? index : 0;
|
|
|
|
|
},
|
|
|
|
|
selectedNoticeReadLabel() {
|
|
|
|
|
const current = this.noticeReadOptions[this.selectedNoticeReadIndex];
|
|
|
|
|
return current ? current.label : '全部';
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
methods: {
|
|
|
|
|
onNoticeTypeChange(e) {
|
|
|
|
|
@ -132,6 +172,13 @@ export default {
|
|
|
|
|
this.query.noticeType = current ? current.value : '';
|
|
|
|
|
this.refreshList();
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
onNoticeReadChange(e) {
|
|
|
|
|
const index = Number(e?.detail?.value);
|
|
|
|
|
const current = this.noticeReadOptions[index];
|
|
|
|
|
this.query.isRead = current ? current.value : '';
|
|
|
|
|
this.refreshList();
|
|
|
|
|
},
|
|
|
|
|
async refreshList() {
|
|
|
|
|
this.page = 1;
|
|
|
|
|
this.records = [];
|
|
|
|
|
@ -157,6 +204,9 @@ export default {
|
|
|
|
|
// 兼容后端仍使用 type 字段筛选的场景
|
|
|
|
|
params.type = this.query.noticeType;
|
|
|
|
|
}
|
|
|
|
|
if (this.query.isRead !== '' && this.query.isRead !== undefined && this.query.isRead !== null) {
|
|
|
|
|
params.isRead = this.query.isRead;
|
|
|
|
|
}
|
|
|
|
|
return params;
|
|
|
|
|
},
|
|
|
|
|
async fetchList() {
|
|
|
|
|
@ -190,6 +240,20 @@ export default {
|
|
|
|
|
},
|
|
|
|
|
openDetail(noticeId) {
|
|
|
|
|
if (!noticeId) return;
|
|
|
|
|
|
|
|
|
|
// 点击列表进入详情:只更新列表本地状态(乐观展示)
|
|
|
|
|
const current = this.records?.find((r) => r.noticeId === noticeId);
|
|
|
|
|
if (current) {
|
|
|
|
|
// Vue2 响应式兜底:属性不存在时用 $set
|
|
|
|
|
if (Object.prototype.hasOwnProperty.call(current, 'isRead')) {
|
|
|
|
|
current.isRead = 1;
|
|
|
|
|
} else if (this.$set) {
|
|
|
|
|
this.$set(current, 'isRead', 1);
|
|
|
|
|
} else {
|
|
|
|
|
current.isRead = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uni.navigateTo({
|
|
|
|
|
url: `/pages/supply_chain/notice_detail/index?noticeId=${noticeId}`,
|
|
|
|
|
});
|
|
|
|
|
@ -204,6 +268,22 @@ export default {
|
|
|
|
|
return s.length > 80 ? s.slice(0, 80) + '...' : s;
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
getReadStatusText(isRead) {
|
|
|
|
|
if (isRead === 1 || isRead === '1') return '已读';
|
|
|
|
|
if (isRead === 0 || isRead === '0') return '未读';
|
|
|
|
|
return '';
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
getReadStatusClass(isRead) {
|
|
|
|
|
if (isRead === 1 || isRead === '1') return 'read-status--read';
|
|
|
|
|
if (isRead === 0 || isRead === '0') return 'read-status--unread';
|
|
|
|
|
return '';
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
isUnread(isRead) {
|
|
|
|
|
return isRead === 0 || isRead === '0';
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
</script>
|
|
|
|
|
@ -295,6 +375,7 @@ export default {
|
|
|
|
|
padding: 24rpx 26rpx;
|
|
|
|
|
margin-bottom: 20rpx;
|
|
|
|
|
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.06);
|
|
|
|
|
position: relative;
|
|
|
|
|
|
|
|
|
|
.card-header {
|
|
|
|
|
display: flex;
|
|
|
|
|
@ -323,6 +404,30 @@ export default {
|
|
|
|
|
color: #999;
|
|
|
|
|
white-space: nowrap;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.time-wrap {
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
white-space: nowrap;
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
align-self: center;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 未读标识(红点)
|
|
|
|
|
.read-badge {
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
margin-left: 12rpx;
|
|
|
|
|
|
|
|
|
|
.red-dot {
|
|
|
|
|
width: 14rpx;
|
|
|
|
|
height: 14rpx;
|
|
|
|
|
border-radius: 50%;
|
|
|
|
|
background-color: #f56c6c;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.card-body {
|
|
|
|
|
|