更新一键审批
parent
3d3af1867b
commit
8c3cf68639
|
|
@ -1,18 +1,18 @@
|
||||||
import http from '@/utils/http'
|
import http from '@/utils/http'
|
||||||
import type { ApiResponse, Order, OrderDetailResponse, ListParams, ApprovalParams, CompletedApprovalItem, CompletedListParams } from '@/types'
|
import type { ApiResponse, Order, OrderDetailResponse, ListParams, CompletedApprovalItem, CompletedListParams, BatchApprovalParams } from '@/types'
|
||||||
import type { AxiosResponse } from 'axios'
|
import type { AxiosResponse } from 'axios'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取订单列表
|
* 获取待审批订单列表
|
||||||
*/
|
*/
|
||||||
export const getOrderList = (params: ListParams): Promise<AxiosResponse<ApiResponse<{
|
export const getOrderList = (params: ListParams): Promise<AxiosResponse<ApiResponse<{
|
||||||
total: number
|
total: number
|
||||||
rows: Order[]
|
rows: Order[]
|
||||||
}>>> => {
|
}>>> => {
|
||||||
// 创建FormData对象
|
// 创建一个新的FormData对象
|
||||||
const formData = new FormData()
|
const formData = new FormData()
|
||||||
|
|
||||||
// 添加参数到FormData
|
// 动态地将params中的所有键值对添加到formData中
|
||||||
if (params.approve) formData.append('approve', params.approve)
|
if (params.approve) formData.append('approve', params.approve)
|
||||||
formData.append('page', params.page.toString())
|
formData.append('page', params.page.toString())
|
||||||
formData.append('pageSize', params.pageSize.toString())
|
formData.append('pageSize', params.pageSize.toString())
|
||||||
|
|
@ -29,23 +29,23 @@ export const getOrderDetail = (id: string | number): Promise<AxiosResponse<ApiRe
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 提交审批结果
|
* 提交审批
|
||||||
*/
|
*/
|
||||||
export const submitApproval = (params: any): Promise<AxiosResponse<ApiResponse<any>>> => {
|
export const submitApproval = (params: any): Promise<AxiosResponse<ApiResponse<any>>> => {
|
||||||
// 创建FormData对象
|
// 创建一个新的FormData对象
|
||||||
const formData = new FormData()
|
const formData = new FormData()
|
||||||
|
|
||||||
// 将所有参数添加到FormData中
|
// 动态地将params中的所有键值对添加到formData中
|
||||||
Object.keys(params).forEach(key => {
|
Object.keys(params).forEach(key => {
|
||||||
if (params[key] !== undefined && params[key] !== null) {
|
if (params[key] !== undefined && params[key] !== null) {
|
||||||
// 特殊处理variables参数,它应该是一个对象
|
// 如果字段是variables,它是一个对象,需要特殊处理
|
||||||
if (key === 'variables' && typeof params[key] === 'object' && params[key] !== null) {
|
if (key === 'variables' && typeof params[key] === 'object' && params[key] !== null) {
|
||||||
// 将variables对象的每个属性单独添加到FormData中
|
// 将variables对象中的每个键值对添加到formData
|
||||||
Object.keys(params[key]).forEach(variableKey => {
|
Object.keys(params[key]).forEach(variableKey => {
|
||||||
if (params[key][variableKey] !== undefined && params[key][variableKey] !== null) {
|
if (params[key][variableKey] !== undefined && params[key][variableKey] !== null) {
|
||||||
formData.append(`variables[${variableKey}]`, params[key][variableKey].toString())
|
formData.append(`variables[${variableKey}]`, params[key][variableKey].toString());
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
} else if (key === 'taxRateData' && Array.isArray(params[key])) {
|
} else if (key === 'taxRateData' && Array.isArray(params[key])) {
|
||||||
// 特殊处理taxRateData数组
|
// 特殊处理taxRateData数组
|
||||||
params[key].forEach((item: any, index: number) => {
|
params[key].forEach((item: any, index: number) => {
|
||||||
|
|
@ -71,14 +71,21 @@ export const getCompletedOrderList = (params: CompletedListParams): Promise<Axio
|
||||||
total: number
|
total: number
|
||||||
rows: CompletedApprovalItem[]
|
rows: CompletedApprovalItem[]
|
||||||
}>>> => {
|
}>>> => {
|
||||||
// 创建FormData对象
|
// 创建一个新的FormData对象
|
||||||
const formData = new FormData()
|
const formData = new FormData()
|
||||||
|
|
||||||
// 添加参数到FormData
|
// 动态地将params中的所有键值对添加到formData中
|
||||||
formData.append('page', params.page.toString())
|
formData.append('page', params.page.toString())
|
||||||
formData.append('pageSize', params.pageSize.toString())
|
formData.append('pageSize', params.pageSize.toString())
|
||||||
if (params.businessName) formData.append('businessName', params.businessName)
|
if (params.businessName) formData.append('businessName', params.businessName)
|
||||||
if (params.processKeyList) formData.append('processKeyList', params.processKeyList)
|
if (params.processKeyList) formData.append('processKeyList', params.processKeyList.join(','))
|
||||||
|
|
||||||
return http.post('/flow/completed/list', formData)
|
return http.post('/flow/completed/list', formData)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量审批
|
||||||
|
*/
|
||||||
|
export const batchApproval = (params: BatchApprovalParams): Promise<AxiosResponse<ApiResponse<any>>> => {
|
||||||
|
return http.post('/project/order/order/approve/batch', params)
|
||||||
}
|
}
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
import type { Order, OrderDetailResponse, ListParams, CompletedApprovalItem, CompletedListParams } from '@/types'
|
import type { Order, OrderDetailResponse, ListParams, CompletedApprovalItem, CompletedListParams, BatchApprovalParams } from '@/types'
|
||||||
import { getOrderList, getOrderDetail, getCompletedOrderList } from '@/api/order'
|
import { getOrderList, getOrderDetail, getCompletedOrderList, batchApproval } from '@/api/order'
|
||||||
|
|
||||||
interface OrderState {
|
interface OrderState {
|
||||||
// 待审批列表相关
|
// 待审批列表相关
|
||||||
|
|
@ -220,6 +220,18 @@ export const useOrderStore = defineStore('order', {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量审批
|
||||||
|
*/
|
||||||
|
async batchApproval(params: BatchApprovalParams) {
|
||||||
|
try {
|
||||||
|
const response = await batchApproval(params)
|
||||||
|
return response
|
||||||
|
} catch (error) {
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 搜索已审批订单
|
* 搜索已审批订单
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -242,6 +242,14 @@ export interface CompletedListParams {
|
||||||
processKeyList: Array<string>
|
processKeyList: Array<string>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 批量审批参数
|
||||||
|
export interface BatchApprovalParams {
|
||||||
|
variables: {
|
||||||
|
approveBtn: ApproveBtn
|
||||||
|
comment: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ============= 采购相关类型定义 =============
|
// ============= 采购相关类型定义 =============
|
||||||
|
|
||||||
// 采购订单信息类型
|
// 采购订单信息类型
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,9 @@ class HttpClient {
|
||||||
message = data?.msg || `请求失败 (${status})`
|
message = data?.msg || `请求失败 (${status})`
|
||||||
}
|
}
|
||||||
} else if (error.request) {
|
} else if (error.request) {
|
||||||
message = '网络连接失败'
|
message = '会话已过期,请重新登录'
|
||||||
|
localStorage.removeItem('isAuthenticated')
|
||||||
|
window.location.href = '/login'
|
||||||
}
|
}
|
||||||
|
|
||||||
showFailToast(message)
|
showFailToast(message)
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@
|
||||||
待审批
|
待审批
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="order-info">
|
<div class="order-info">
|
||||||
<div class="info-row">
|
<div class="info-row">
|
||||||
<span class="label">项目名称:</span>
|
<span class="label">项目名称:</span>
|
||||||
|
|
@ -81,7 +81,7 @@
|
||||||
{{ getCompletedStatusText(item.approveStatus) }}
|
{{ getCompletedStatusText(item.approveStatus) }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="order-info">
|
<div class="order-info">
|
||||||
<div class="info-row">
|
<div class="info-row">
|
||||||
<span class="label">合同名称:</span>
|
<span class="label">合同名称:</span>
|
||||||
|
|
@ -114,16 +114,98 @@
|
||||||
</van-pull-refresh>
|
</van-pull-refresh>
|
||||||
</van-tab>
|
</van-tab>
|
||||||
</van-tabs>
|
</van-tabs>
|
||||||
|
|
||||||
|
<!-- 一键审批操作悬浮框 -->
|
||||||
|
<div v-if="currentTab === 'pending' && orderList.length > 0" class="batch-actions-footer">
|
||||||
|
<div class="footer-content">
|
||||||
|
<van-button
|
||||||
|
type="primary"
|
||||||
|
size="large"
|
||||||
|
@click="showBatchApprovalDialog"
|
||||||
|
:loading="batchSubmitting"
|
||||||
|
class="batch-approve-btn"
|
||||||
|
>
|
||||||
|
一键审批
|
||||||
|
</van-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 批量审批意见弹窗 -->
|
||||||
|
<van-popup
|
||||||
|
v-model:show="batchApprovalDialogVisible"
|
||||||
|
position="bottom"
|
||||||
|
round
|
||||||
|
:style="{ height: '50%' }"
|
||||||
|
>
|
||||||
|
<div class="approval-dialog">
|
||||||
|
<div class="dialog-header">
|
||||||
|
<span>审批意见</span>
|
||||||
|
<van-icon name="cross" @click="batchApprovalDialogVisible = false"/>
|
||||||
|
</div>
|
||||||
|
<div class="dialog-body">
|
||||||
|
<!-- 默认意见标签 -->
|
||||||
|
<div class="opinion-tags">
|
||||||
|
<div class="tags-title">常用意见</div>
|
||||||
|
<div class="tags-container">
|
||||||
|
<van-tag
|
||||||
|
v-for="tag in getBatchOpinionTags()"
|
||||||
|
:key="tag"
|
||||||
|
:type="selectedBatchTag === tag ? 'primary' : 'default'"
|
||||||
|
size="medium"
|
||||||
|
@click="selectBatchTag(tag)"
|
||||||
|
class="opinion-tag"
|
||||||
|
>
|
||||||
|
{{ tag }}
|
||||||
|
</van-tag>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="opinion-input">
|
||||||
|
<van-field
|
||||||
|
v-model="batchApprovalOpinion"
|
||||||
|
type="textarea"
|
||||||
|
placeholder="请输入审批意见"
|
||||||
|
rows="4"
|
||||||
|
autosize
|
||||||
|
maxlength="500"
|
||||||
|
show-word-limit
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="dialog-footer">
|
||||||
|
<div class="footer-buttons">
|
||||||
|
<van-button
|
||||||
|
type="default"
|
||||||
|
block
|
||||||
|
@click="submitBatchApproval(0)"
|
||||||
|
:loading="batchSubmitting"
|
||||||
|
class="action-btn reject-btn"
|
||||||
|
>
|
||||||
|
驳回
|
||||||
|
</van-button>
|
||||||
|
<van-button
|
||||||
|
type="primary"
|
||||||
|
block
|
||||||
|
@click="submitBatchApproval(1)"
|
||||||
|
:loading="batchSubmitting"
|
||||||
|
class="action-btn approve-btn"
|
||||||
|
>
|
||||||
|
通过
|
||||||
|
</van-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</van-popup>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted, watch } from 'vue'
|
import { ref, onMounted } from 'vue'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import { storeToRefs } from 'pinia'
|
import { storeToRefs } from 'pinia'
|
||||||
import { useOrderStore } from '@/store/order'
|
import { useOrderStore } from '@/store/order'
|
||||||
import { formatOrderStatus, formatAmount, formatDate } from '@/utils'
|
import { formatAmount, formatDate } from '@/utils'
|
||||||
import type { OrderStatus, ApprovalStatus } from '@/types'
|
import type { ApprovalStatus, ApproveBtn, BatchApprovalParams } from '@/types'
|
||||||
|
import { showToast, showSuccessToast } from 'vant'
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const orderStore = useOrderStore()
|
const orderStore = useOrderStore()
|
||||||
|
|
@ -142,15 +224,11 @@ const searchKeyword = ref('')
|
||||||
const refreshing = ref(false)
|
const refreshing = ref(false)
|
||||||
const completedRefreshing = ref(false)
|
const completedRefreshing = ref(false)
|
||||||
|
|
||||||
// 获取状态样式类
|
// 批量审批相关
|
||||||
const getStatusClass = (status: OrderStatus) => {
|
const batchApprovalDialogVisible = ref(false)
|
||||||
const classMap = {
|
const batchApprovalOpinion = ref('')
|
||||||
'0': 'pending',
|
const batchSubmitting = ref(false)
|
||||||
'1': 'approved',
|
const selectedBatchTag = ref('')
|
||||||
'2': 'rejected'
|
|
||||||
}
|
|
||||||
return classMap[status] || 'pending'
|
|
||||||
}
|
|
||||||
|
|
||||||
// 加载数据
|
// 加载数据
|
||||||
const onLoad = async () => {
|
const onLoad = async () => {
|
||||||
|
|
@ -178,27 +256,16 @@ const onTabChange = (name: string) => {
|
||||||
searchKeyword.value = ''
|
searchKeyword.value = ''
|
||||||
|
|
||||||
if (name === 'completed' && completedList.value.length === 0) {
|
if (name === 'completed' && completedList.value.length === 0) {
|
||||||
// 首次加载已审批列表
|
|
||||||
onCompletedLoad()
|
onCompletedLoad()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 已审批列表加载
|
// 已审批列表加载
|
||||||
const onCompletedLoad = async () => {
|
const onCompletedLoad = async () => {
|
||||||
console.log('=== van-list 触发 onCompletedLoad ===')
|
|
||||||
console.log('当前状态:', {
|
|
||||||
loading: completedLoading.value,
|
|
||||||
finished: completedFinished.value,
|
|
||||||
listLength: completedList.value.length,
|
|
||||||
currentPage: orderStore.completedCurrentPage
|
|
||||||
})
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await orderStore.loadCompletedOrderList()
|
await orderStore.loadCompletedOrderList()
|
||||||
console.log('onCompletedLoad 执行完成')
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('加载已审批列表失败:', error)
|
console.error('加载已审批列表失败:', error)
|
||||||
// 确保在出错时也能重置loading状态
|
|
||||||
orderStore.completedLoading = false
|
orderStore.completedLoading = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -244,19 +311,13 @@ const handleClear = async () => {
|
||||||
|
|
||||||
// 已审批状态文本转换
|
// 已审批状态文本转换
|
||||||
const getCompletedStatusText = (status: ApprovalStatus) => {
|
const getCompletedStatusText = (status: ApprovalStatus) => {
|
||||||
const statusMap = {
|
const statusMap = { 2: '驳回', 3: '通过' }
|
||||||
2: '驳回',
|
|
||||||
3: '通过'
|
|
||||||
}
|
|
||||||
return statusMap[status] || '提交'
|
return statusMap[status] || '提交'
|
||||||
}
|
}
|
||||||
|
|
||||||
// 已审批状态样式类
|
// 已审批状态样式类
|
||||||
const getCompletedStatusClass = (status: ApprovalStatus) => {
|
const getCompletedStatusClass = (status: ApprovalStatus) => {
|
||||||
const classMap = {
|
const classMap = { 2: 'rejected', 3: 'approved' }
|
||||||
2: 'rejected',
|
|
||||||
3: 'approved'
|
|
||||||
}
|
|
||||||
return classMap[status] || 'pending'
|
return classMap[status] || 'pending'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -265,16 +326,68 @@ const goToDetail = (id: number) => {
|
||||||
router.push({ path: `/detail/${id}`, query: { from: 'order' } })
|
router.push({ path: `/detail/${id}`, query: { from: 'order' } })
|
||||||
}
|
}
|
||||||
|
|
||||||
// 跳转到已审批详情页(只读模式)
|
// 跳转到已审批详情页
|
||||||
const goToCompletedDetail = (businessId: number) => {
|
const goToCompletedDetail = (businessId: number) => {
|
||||||
router.push({
|
router.push({ path: `/detail/${businessId}`, query: { readonly: 'true', from: 'order' } })
|
||||||
path: `/detail/${businessId}`,
|
}
|
||||||
query: { readonly: 'true', from: 'order' }
|
|
||||||
})
|
// 显示批量审批弹窗
|
||||||
|
const showBatchApprovalDialog = () => {
|
||||||
|
batchApprovalOpinion.value = ''
|
||||||
|
selectedBatchTag.value = ''
|
||||||
|
batchApprovalDialogVisible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取默认通过意见标签
|
||||||
|
const getBatchOpinionTags = () => {
|
||||||
|
return [
|
||||||
|
'所有信息已阅,审核通过',
|
||||||
|
'经审查有问题,驳回'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
// 选择标签
|
||||||
|
const selectBatchTag = (tag: string) => {
|
||||||
|
if (selectedBatchTag.value === tag) {
|
||||||
|
selectedBatchTag.value = ''
|
||||||
|
batchApprovalOpinion.value = ''
|
||||||
|
} else {
|
||||||
|
selectedBatchTag.value = tag
|
||||||
|
batchApprovalOpinion.value = tag
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提交批量审批
|
||||||
|
const submitBatchApproval = async (approveStatus: ApproveBtn) => {
|
||||||
|
const opinion = batchApprovalOpinion.value.trim()
|
||||||
|
if (approveStatus === 0 && !opinion) {
|
||||||
|
showToast('请输入驳回原因')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
batchSubmitting.value = true
|
||||||
|
try {
|
||||||
|
const params: BatchApprovalParams = {
|
||||||
|
variables: {
|
||||||
|
approveBtn: approveStatus+'',
|
||||||
|
comment: opinion || (approveStatus === 1 ? '同意' : '')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await orderStore.batchApproval(params)
|
||||||
|
|
||||||
|
showSuccessToast(approveStatus === 1 ? '一键审批通过成功' : '一键驳回成功')
|
||||||
|
batchApprovalDialogVisible.value = false
|
||||||
|
await onRefresh()
|
||||||
|
} catch (error) {
|
||||||
|
console.error('一键审批失败:', error)
|
||||||
|
showToast('一键审批失败,请稍后重试')
|
||||||
|
} finally {
|
||||||
|
batchSubmitting.value = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
// 重置状态并加载数据
|
|
||||||
orderStore.resetListState()
|
orderStore.resetListState()
|
||||||
orderStore.resetCompletedListState()
|
orderStore.resetCompletedListState()
|
||||||
onLoad()
|
onLoad()
|
||||||
|
|
@ -285,6 +398,7 @@ onMounted(() => {
|
||||||
.order-list-page {
|
.order-list-page {
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
background-color: var(--van-background-color);
|
background-color: var(--van-background-color);
|
||||||
|
padding-bottom: 80px; /* 为底部批量操作栏留出空间 */
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tab相关样式
|
// Tab相关样式
|
||||||
|
|
@ -302,11 +416,11 @@ onMounted(() => {
|
||||||
background: #f5f5f5;
|
background: #f5f5f5;
|
||||||
min-height: calc(100vh - 56px);
|
min-height: calc(100vh - 56px);
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.van-tab) {
|
:deep(.van-tab) {
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.van-tab--active) {
|
:deep(.van-tab--active) {
|
||||||
color: var(--van-primary-color);
|
color: var(--van-primary-color);
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
|
|
@ -322,7 +436,7 @@ onMounted(() => {
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
|
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
|
||||||
border: 1px solid #f0f0f0;
|
border: 1px solid #f0f0f0;
|
||||||
|
|
||||||
&:active {
|
&:active {
|
||||||
transform: translateY(1px);
|
transform: translateY(1px);
|
||||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
|
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
|
||||||
|
|
@ -349,19 +463,19 @@ onMounted(() => {
|
||||||
padding: 4px 12px;
|
padding: 4px 12px;
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
|
|
||||||
&.pending {
|
&.pending {
|
||||||
background: #FFF3E0;
|
background: #FFF3E0;
|
||||||
color: #FF9800;
|
color: #FF9800;
|
||||||
border: 1px solid #FFE0B2;
|
border: 1px solid #FFE0B2;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.approved {
|
&.approved {
|
||||||
background: #E8F5E8;
|
background: #E8F5E8;
|
||||||
color: #4CAF50;
|
color: #4CAF50;
|
||||||
border: 1px solid #C8E6C9;
|
border: 1px solid #C8E6C9;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.rejected {
|
&.rejected {
|
||||||
background: #FFEBEE;
|
background: #FFEBEE;
|
||||||
color: #F44336;
|
color: #F44336;
|
||||||
|
|
@ -374,11 +488,11 @@ onMounted(() => {
|
||||||
display: flex;
|
display: flex;
|
||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
&:last-child {
|
&:last-child {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.label {
|
.label {
|
||||||
width: 80px;
|
width: 80px;
|
||||||
color: #666666;
|
color: #666666;
|
||||||
|
|
@ -386,7 +500,7 @@ onMounted(() => {
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.value {
|
.value {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
color: #333333;
|
color: #333333;
|
||||||
|
|
@ -394,7 +508,7 @@ onMounted(() => {
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
line-height: 1.4;
|
line-height: 1.4;
|
||||||
|
|
||||||
&.amount {
|
&.amount {
|
||||||
color: #1976D2;
|
color: #1976D2;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
|
|
@ -407,7 +521,7 @@ onMounted(() => {
|
||||||
padding: 80px 20px;
|
padding: 80px 20px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
:deep(.van-empty) {
|
:deep(.van-empty) {
|
||||||
.van-empty__image {
|
.van-empty__image {
|
||||||
width: 160px;
|
width: 160px;
|
||||||
|
|
@ -415,7 +529,7 @@ onMounted(() => {
|
||||||
filter: drop-shadow(0 8px 32px rgba(102, 126, 234, 0.2));
|
filter: drop-shadow(0 8px 32px rgba(102, 126, 234, 0.2));
|
||||||
animation: float 3s ease-in-out infinite;
|
animation: float 3s ease-in-out infinite;
|
||||||
}
|
}
|
||||||
|
|
||||||
.van-empty__description {
|
.van-empty__description {
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
color: rgba(255, 255, 255, 0.9);
|
color: rgba(255, 255, 255, 0.9);
|
||||||
|
|
@ -442,21 +556,21 @@ onMounted(() => {
|
||||||
background: rgba(255, 255, 255, 0.95);
|
background: rgba(255, 255, 255, 0.95);
|
||||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
|
|
||||||
&:focus-within {
|
&:focus-within {
|
||||||
transform: translateY(-2px);
|
transform: translateY(-2px);
|
||||||
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.15), 0 4px 12px rgba(0, 0, 0, 0.1);
|
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.15), 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
.van-search__content {
|
.van-search__content {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
padding: 12px 16px;
|
padding: 12px 16px;
|
||||||
|
|
||||||
.van-field__control {
|
.van-field__control {
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
color: #333;
|
color: #333;
|
||||||
|
|
||||||
&::placeholder {
|
&::placeholder {
|
||||||
color: #999;
|
color: #999;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
|
|
@ -471,4 +585,94 @@ onMounted(() => {
|
||||||
color: #666;
|
color: #666;
|
||||||
margin-right: 8px;
|
margin-right: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.batch-actions-footer {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
background-color: #fff;
|
||||||
|
padding: 10px 16px;
|
||||||
|
box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.1);
|
||||||
|
z-index: 100;
|
||||||
|
|
||||||
|
.footer-content {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.batch-approve-btn {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.approval-dialog {
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.dialog-header {
|
||||||
|
padding: 16px;
|
||||||
|
border-bottom: 1px solid #ebedf0;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-body {
|
||||||
|
flex: 1;
|
||||||
|
padding: 16px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-footer {
|
||||||
|
padding: 16px;
|
||||||
|
border-top: 1px solid #ebedf0;
|
||||||
|
.footer-buttons {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.opinion-tags {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
|
||||||
|
.tags-title {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #646566;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tags-container {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 8px;
|
||||||
|
|
||||||
|
.opinion-tag {
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.opinion-input {
|
||||||
|
.van-field {
|
||||||
|
border: 1px solid #ebedf0;
|
||||||
|
border-radius: 8px;
|
||||||
|
background: #f7f8fa;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
Loading…
Reference in New Issue