Commit b444b6cf by liangjianmin

feat(classify-price): 添加归类价格审批详情页面及样式

- 新增归类价格审批详情页面,包含基本结构和样式
- 更新页面路由配置,支持导航到详情页面
- 优化审批列表页面,增加搜索和标签功能
parent 69ab2196
.classify-price-detail-page {
min-height: 100vh;
background: #f3f6fb;
}
.classify-price-page { .classify-price-page {
min-height: 100vh; height: 100vh;
background: #f3f6fb;
display: flex;
flex-direction: column;
overflow: hidden;
.classify-fixed {
flex-shrink: 0;
background: #ffffff;
border-bottom: 1rpx solid #e9eef6;
position: relative;
z-index: 2;
}
.search-bar {
padding: 18rpx 28rpx 10rpx;
}
.tabs-wrap {
padding: 0 28rpx 18rpx;
.custom-tabs {
display: flex;
width: 100%;
background: #f5f7fa; background: #f5f7fa;
border-radius: 12rpx;
padding: 4rpx;
box-sizing: border-box;
}
.tab-item {
flex: 1;
min-width: 0;
min-height: 56rpx;
padding: 0 10rpx;
display: flex;
align-items: center;
justify-content: center;
position: relative;
border: 1rpx solid transparent;
border-radius: 10rpx;
transition: background 0.2s ease, color 0.2s ease;
.tab-text {
font-size: 26rpx;
font-weight: 500;
color: #59697c;
line-height: 1.2;
transition: all 0.2s ease;
}
.count-badge {
margin-left: 8rpx;
min-width: 26rpx;
height: 26rpx;
padding: 0 7rpx;
display: flex;
align-items: center;
justify-content: center;
background: #ff5470;
border-radius: 999rpx;
box-sizing: border-box;
.count-text {
font-size: 19rpx;
font-weight: 600;
color: #ffffff;
line-height: 1;
}
}
&.active {
background: #ffffff;
border-color: #e3e8ef;
.tab-text {
color: #2f73ff;
font-weight: 700;
}
}
}
}
.list-scroll {
flex: 1;
height: 0;
}
.list-wrap {
padding: 22rpx 28rpx 158rpx;
box-sizing: border-box;
.skeleton-card {
background: #ffffff;
border-radius: 14rpx;
margin-bottom: 22rpx;
padding: 28rpx;
box-shadow: 0 8rpx 22rpx rgba(30, 41, 59, 0.06);
}
}
.classify-card {
background: #ffffff;
border-radius: 14rpx;
margin-bottom: 22rpx;
overflow: hidden;
box-shadow: 0 8rpx 24rpx rgba(30, 41, 59, 0.07);
.card-header {
padding: 26rpx 28rpx 12rpx;
}
.card-title {
font-size: 30rpx;
font-weight: 700;
color: #172033;
}
.status-badge {
font-size: 22rpx;
font-weight: 600;
padding: 8rpx 16rpx;
border-radius: 999rpx;
&.approved {
color: #0f9f6e;
background: rgba(15, 159, 110, 0.1);
}
&.rejected {
color: #e5484d;
background: rgba(229, 72, 77, 0.1);
}
}
.card-body {
padding: 0 28rpx 22rpx;
.card-row {
margin-bottom: 10rpx;
.card-label {
font-size: 26rpx;
color: #8a97a8;
width: 160rpx;
flex-shrink: 0;
}
.card-value {
font-size: 26rpx;
color: #263447;
flex: 1;
word-break: break-all;
}
.card-time {
font-size: 24rpx;
color: #98a4b3;
}
.card-tag {
font-size: 24rpx;
color: #d8891d;
font-weight: 600;
max-width: 240rpx;
text-align: right;
word-break: break-all;
}
}
}
.card-footer {
border-top: 1rpx solid #edf1f6;
padding: 20rpx 28rpx;
.action-btn {
flex: 1;
text-align: center;
font-size: 28rpx;
font-weight: 600;
padding: 16rpx 0;
border-radius: 10rpx;
transition: all 0.2s ease;
&.detail {
color: #2563eb;
background: #edf4ff;
border: 1rpx solid #cfe0ff;
&:active {
background: #e2edff;
}
}
}
}
}
} }
...@@ -38,6 +38,12 @@ ...@@ -38,6 +38,12 @@
} }
}, },
{ {
"path": "pages/classify-price/detail",
"style": {
"navigationBarTitleText": "归类价格审批详情"
}
},
{
"path": "pages/logistics/index", "path": "pages/logistics/index",
"style": { "style": {
"navigationBarTitleText": "物流车辆申请" "navigationBarTitleText": "物流车辆申请"
......
<template>
<view class="classify-price-detail-page"></view>
</template>
<script>
export default {
data() {
return {};
}
};
</script>
<style lang="scss">
@import '@/assets/css/classify-price/detail.scss';
</style>
<template> <template>
<view class="classify-price-page"></view> <view class="classify-price-page">
<view class="classify-fixed">
<view class="search-bar">
<u-search v-model="order_sn" placeholder="订单号" shape="round" :showAction="false" bgColor="#f4f7fb" :inputStyle="{ fontSize: '24rpx' }" height="64" :searchIconSize="34" @change="onSearch"></u-search>
</view>
<view class="tabs-wrap">
<view class="custom-tabs row">
<view v-for="(tab, index) in tabList" :key="tab.value" class="tab-item row verCenter rowCenter" :class="{ active: currentTab === index }" @click="onTabChange(index)">
<text class="tab-text">{{ tab.name }}</text>
<view v-if="tab.count > 0" class="count-badge">
<text class="count-text">{{ tab.count > 99 ? '99+' : tab.count }}</text>
</view>
</view>
</view>
</view>
</view>
<scroll-view class="list-scroll" scroll-y @scrolltolower="loadMore">
<view class="list-wrap">
<view v-if="skeletonLoading">
<view class="skeleton-card" v-for="i in 3" :key="i">
<u-skeleton rows="3" title :animate="true" :loading="true" :rowsWidth="['100%', '60%', '40%']" rowsHeight="30"></u-skeleton>
</view>
</view>
<template v-else>
<view class="classify-card" v-for="item in currentList" :key="getItemKey(item)">
<view class="card-header row bothSide verCenter">
<text class="card-title">关务价格审批</text>
<view v-if="currentTab !== 0" :class="['status-badge', getStatusClass(item)]">
{{ item.approval_status_cn || '已处理' }}
</view>
</view>
<view class="card-body">
<view class="card-row row">
<text class="card-label">业务:</text>
<text class="card-value">{{ item.yw_name || '-' }}</text>
</view>
<view class="card-row row">
<text class="card-label">客户名称:</text>
<text class="card-value">{{ item.customer_name || '-' }}</text>
</view>
<view class="card-row row">
<text class="card-label">订单号:</text>
<text class="card-value">{{ item.order_sn || '-' }}</text>
</view>
<view class="card-row row verCenter bothSide">
<view class="row verCenter">
<text class="card-label">提交:</text>
<text class="card-time">{{ item.create_time || item.update_time || '-' }}</text>
</view>
<text class="card-tag">{{ item.node_name || '' }}</text>
</view>
</view>
<view class="card-footer row rowCenter">
<view class="action-btn detail" @click="handleDetail(item)">详情</view>
</view>
</view>
<u-empty v-if="!currentList.length" mode="data" :text="emptyText" iconSize="140" textSize="24"></u-empty>
<u-loadmore v-if="currentList.length >= limit" :status="loadStatus" @loadmore="loadMore" marginTop="10" marginBottom="30" fontSize="28" iconSize="25" :line="true" lineColor="#e4e7ed"></u-loadmore>
</template>
</view>
</scroll-view>
</view>
</template> </template>
<script> <script>
import { API } from '@/util/api';
export default { export default {
data() { data() {
return {}; return {
order_sn: '',
currentTab: 0,
tabList: [
{ name: '待处理', value: 'pending', count: 0 },
{ name: '已处理', value: 'done', count: 0 }
],
pendingList: [],
doneList: [],
pendingPage: 1,
donePage: 1,
limit: 15,
pendingTotal: 0,
doneTotal: 0,
skeletonLoading: false,
loadStatus: 'loadmore'
};
},
computed: {
/**
* 当前 tab 展示列表
* @return {Array} 列表数据
*/
currentList() {
var listMap = [this.pendingList, this.doneList];
return listMap[this.currentTab] || [];
},
/**
* 当前 tab 页码
* @return {number} 页码
*/
currentPage() {
var pageMap = [this.pendingPage, this.donePage];
return pageMap[this.currentTab] || 1;
},
/**
* 当前 tab 总数
* @return {number} 总数
*/
currentTotal() {
var totalMap = [this.pendingTotal, this.doneTotal];
return totalMap[this.currentTab] || 0;
},
/**
* 空状态文案
* @return {string} 文案
*/
emptyText() {
var textMap = ['暂无待处理关务审批', '暂无已处理关务审批'];
return textMap[this.currentTab] || '暂无关务审批数据';
}
},
onShow() {
this.resetAndLoad();
},
onReachBottom() {
this.loadMore();
},
methods: {
/**
* 重置当前 tab 分页并重新加载
* @return {void}
*/
resetAndLoad() {
this.resetCurrentList();
this.skeletonLoading = true;
this.loadStatus = 'loadmore';
this.getData();
},
/**
* 重置全部 tab 的列表与分页
* @return {void}
*/
resetAllList() {
this.resetPendingList();
this.resetDoneList();
},
/**
* 重置当前 tab 的列表与分页
* @return {void}
*/
resetCurrentList() {
var resetMap = [this.resetPendingList, this.resetDoneList];
resetMap[this.currentTab]();
},
/**
* 重置待处理列表
* @return {void}
*/
resetPendingList() {
this.pendingPage = 1;
this.pendingList = [];
},
/**
* 重置已处理列表
* @return {void}
*/
resetDoneList() {
this.donePage = 1;
this.doneList = [];
},
/**
* 获取关务审批列表
* @return {void}
*/
getData() {
var page = this.currentPage;
var params = this.getRequestParams(page);
this.request(API.orderApproveList, 'GET', params, !this.skeletonLoading).then(res => {
this.skeletonLoading = false;
if (res.code === 0) {
var pageData = this.formatPageData(res);
this.setCurrentList(pageData.list, pageData.total, page);
this.updateLoadStatus();
}
}).catch(() => {
this.skeletonLoading = false;
this.loadStatus = 'loadmore';
});
},
/**
* 组装列表请求参数
* @param {number} page - 当前页码
* @return {Object} 请求参数
*/
getRequestParams(page) {
var params = {
page,
limit: this.limit,
customer_type: 0
};
var status = this.getCurrentStatus();
if (status) params.approval_status = status;
if (this.order_sn) params.order_sn = this.order_sn;
return params;
},
/**
* 获取当前 tab 对应的审批状态
* @return {string} 状态参数
*/
getCurrentStatus() {
var statusMap = ['1', '-1,2'];
return statusMap[this.currentTab] || '';
},
/**
* 兼容 PC layui 接口与移动端列表接口返回结构
* @param {Object} res - 接口响应
* @return {Object} 标准分页数据
*/
formatPageData(res) {
var data = res.data || {};
var list = Array.isArray(data) ? data : (data.list || data.data || []);
var total = data.total || data.count || res.count || list.length;
return {
list,
total: Number(total) || 0
};
},
/**
* 写入当前 tab 的列表数据
* @param {Array} list - 接口返回列表
* @param {number} total - 接口返回总数
* @param {number} page - 当前页码
* @return {void}
*/
setCurrentList(list, total, page) {
var setterMap = [this.setPendingList, this.setDoneList];
setterMap[this.currentTab](list, total, page);
},
/**
* 写入待处理列表
* @param {Array} list - 接口返回列表
* @param {number} total - 接口返回总数
* @param {number} page - 当前页码
* @return {void}
*/
setPendingList(list, total, page) {
this.pendingList = page === 1 ? list : [...this.pendingList, ...list];
this.pendingTotal = total;
this.updateTabCount(0, total);
},
/**
* 写入已处理列表
* @param {Array} list - 接口返回列表
* @param {number} total - 接口返回总数
* @param {number} page - 当前页码
* @return {void}
*/
setDoneList(list, total, page) {
this.doneList = page === 1 ? list : [...this.doneList, ...list];
this.doneTotal = total;
this.updateTabCount(1, total);
},
/**
* 更新 tab 数量
* @param {number} index - tab 索引
* @param {number} total - 总数
* @return {void}
*/
updateTabCount(index, total) {
var tab = this.tabList[index];
this.$set(this.tabList, index, {
name: tab.name,
value: tab.value,
count: total
});
},
/**
* 根据当前数据量与总数更新底部加载状态
* @return {void}
*/
updateLoadStatus() {
var listLen = this.currentList.length;
var total = this.currentTotal;
this.loadStatus = listLen >= total ? 'nomore' : 'loadmore';
},
/**
* 加载下一页
* @return {void}
*/
loadMore() {
if (this.loadStatus !== 'loadmore') return;
this.loadStatus = 'loading';
this.addCurrentPage();
this.getData();
},
/**
* 当前 tab 页码加一
* @return {void}
*/
addCurrentPage() {
var pageMap = [this.addPendingPage, this.addDonePage];
pageMap[this.currentTab]();
},
/**
* 待处理页码加一
* @return {void}
*/
addPendingPage() {
this.pendingPage++;
},
/**
* 已处理页码加一
* @return {void}
*/
addDonePage() {
this.donePage++;
},
/**
* 搜索时重置分页
* @return {void}
*/
onSearch() {
this.resetAllList();
this.resetAndLoad();
},
/**
* 切换 tab
* @param {number} index - tab 索引
* @return {void}
*/
onTabChange(index) {
this.currentTab = index;
if (!this.currentList.length) {
this.resetAndLoad();
} else {
this.updateLoadStatus();
}
},
/**
* 获取列表唯一键
* @param {Object} item - 审批项
* @return {string|number} 唯一键
*/
getItemKey(item) {
return item.bill_id || item.order_id || item.order_sn;
},
/**
* 获取状态样式
* @param {Object} item - 审批项
* @return {string} 样式名
*/
getStatusClass(item) {
return Number(item.approval_status) === -1 ? 'rejected' : 'approved';
},
/**
* 跳转关务审批详情
* @param {Object} item - 审批项
* @return {void}
*/
handleDetail(item) {
uni.navigateTo({
url: `/pages/classify-price/detail?order_id=${item.order_id || ''}&bill_id=${item.bill_id || ''}`
});
}
} }
}; };
</script> </script>
<style scoped lang="scss"> <style lang="scss">
@import '@/assets/css/classify-price/index.scss'; @import '@/assets/css/classify-price/index.scss';
</style> </style>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment