fix FundRecordDetail.vue style
This commit is contained in:
@@ -2,35 +2,109 @@
|
|||||||
<div v-can="permissionCodes.fundRecord.read" class="package-record-detail">
|
<div v-can="permissionCodes.fundRecord.read" class="package-record-detail">
|
||||||
<template v-if="record">
|
<template v-if="record">
|
||||||
<section class="hero" v-entrance-transition>
|
<section class="hero" v-entrance-transition>
|
||||||
|
<div class="header">
|
||||||
<span class="eyebrow" v-text="'资金流水'" />
|
<span class="eyebrow" v-text="'资金流水'" />
|
||||||
<div class="hero-title">
|
|
||||||
<h1 v-text="getFundOperationText(record.operationType)" />
|
|
||||||
<t-tag :content="getFundStatusText(record.status)" :theme="getStatusTheme(record.status)" variant="light-outline" />
|
<t-tag :content="getFundStatusText(record.status)" :theme="getStatusTheme(record.status)" variant="light-outline" />
|
||||||
</div>
|
</div>
|
||||||
<strong class="amount" v-text="formatPackageAmount(record.amount)" />
|
<h1 class="title" v-text="getFundOperationText(record.operationType)" />
|
||||||
|
<div class="amount">
|
||||||
|
<span class="red">¥</span>
|
||||||
|
<strong class="value red text-bold" v-text="formatPackageAmount(record.amount)" />
|
||||||
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<t-cell-group title="资金记录" theme="card" v-entrance-transition>
|
<t-cell-group title="资金记录" theme="card" v-entrance-transition>
|
||||||
<t-cell title="操作类型" :note="getFundOperationText(record.operationType)" />
|
<t-cell title="操作类型" :note="getFundOperationText(record.operationType)" />
|
||||||
<t-cell title="状态"><template #note><t-tag :content="getFundStatusText(record.status)" :theme="getStatusTheme(record.status)" variant="light-outline" /></template></t-cell>
|
<t-cell title="状态">
|
||||||
|
<template #note>
|
||||||
|
<t-tag
|
||||||
|
:content="getFundStatusText(record.status)"
|
||||||
|
:theme="getStatusTheme(record.status)"
|
||||||
|
variant="light-outline"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</t-cell>
|
||||||
<t-cell title="金额" :note="formatPackageAmount(record.amount)" />
|
<t-cell title="金额" :note="formatPackageAmount(record.amount)" />
|
||||||
<t-cell title="销售订单" :note="record.bizId || '未知'" />
|
|
||||||
<t-cell title="发生时间" :note="record.occurredAt ? Time.toDateTime(record.occurredAt) : '未知'" />
|
|
||||||
<t-cell title="提交人" :note="record.operator?.name || record.operator?.nick || record.operatorUserId || '未知'" />
|
|
||||||
<t-cell title="处理人" :note="record.verifier?.name || record.verifier?.nick || record.verifierUserId || '未处理'" />
|
|
||||||
<t-cell v-if="record.sourceRecordId" title="原资金记录" :note="record.sourceRecordId" />
|
<t-cell v-if="record.sourceRecordId" title="原资金记录" :note="record.sourceRecordId" />
|
||||||
<t-cell v-if="record.reason" title="原因" :note="record.reason" />
|
<t-cell title="备注" :note="Text.display(record.remark)" />
|
||||||
<t-cell v-if="record.remark" title="备注" :note="record.remark" />
|
<t-cell v-if="record.reason" title="拒绝/撤销原因" :note="Text.display(record.reason)" />
|
||||||
|
<t-cell
|
||||||
|
title="销售订单详情"
|
||||||
|
:arrow="!!record.bizId && canReadSalesOrder"
|
||||||
|
@click="toSalesOrder"
|
||||||
|
/>
|
||||||
|
<div class="photo-wrap bg-white">
|
||||||
|
<photo-scroller
|
||||||
|
:model-value="photoURLList"
|
||||||
|
:photo-items="photoItems"
|
||||||
|
title="业务照片"
|
||||||
|
:show-add="false"
|
||||||
|
:show-remove="false"
|
||||||
|
:show-viewer-actions="false"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</t-cell-group>
|
</t-cell-group>
|
||||||
<photo-scroller :model-value="photoURLList" :photo-items="photoItems" title="业务照片" :show-add="false" :show-remove="false" :show-viewer-actions="false" />
|
<t-cell-group theme="card">
|
||||||
<section v-if="isPendingReceive || canRevoke" class="actions" v-entrance-transition="70">
|
<t-cell
|
||||||
<t-button v-if="canVerifyReceive" theme="primary" @click="verifyReceive">核销收款</t-button>
|
title="发起人"
|
||||||
<t-button v-if="canVerifyReceive" theme="default" variant="outline" @click="openReasonDialog('reject')">拒绝收款</t-button>
|
:note="record.operator?.name || record.operator?.nick || '未知'"
|
||||||
<t-button v-if="canCancelReceive" theme="default" variant="outline" @click="openReasonDialog('cancel')">撤销收款</t-button>
|
/>
|
||||||
<t-button v-if="canRevoke" theme="danger" variant="outline" @click="toRevoke">资金冲正</t-button>
|
<t-cell title="发起时间">
|
||||||
|
<template #note>
|
||||||
|
<pass-time-label :timestamp="record.occurredAt" underline />
|
||||||
|
</template>
|
||||||
|
</t-cell>
|
||||||
|
<t-cell
|
||||||
|
title="处理人"
|
||||||
|
:note="record.verifier?.name || record.verifier?.nick || '未处理'"
|
||||||
|
/>
|
||||||
|
<t-cell title="处理时间">
|
||||||
|
<template #note>
|
||||||
|
<pass-time-label :timestamp="record.verifiedAt" underline />
|
||||||
|
</template>
|
||||||
|
</t-cell>
|
||||||
|
</t-cell-group>
|
||||||
|
<section
|
||||||
|
v-if="isPendingReceive || canRevoke"
|
||||||
|
class="actions"
|
||||||
|
v-entrance-transition="70"
|
||||||
|
>
|
||||||
|
<div class="pair">
|
||||||
|
<t-button
|
||||||
|
v-if="canVerifyReceive"
|
||||||
|
theme="primary"
|
||||||
|
content="核销收款"
|
||||||
|
@click="verifyReceive"
|
||||||
|
/>
|
||||||
|
<t-button
|
||||||
|
v-if="canVerifyReceive"
|
||||||
|
theme="danger"
|
||||||
|
content="拒绝收款"
|
||||||
|
@click="openReasonDialog('reject')"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<t-button
|
||||||
|
v-if="canCancelReceive"
|
||||||
|
theme="default"
|
||||||
|
content="撤销收款"
|
||||||
|
@click="openReasonDialog('cancel')"
|
||||||
|
/>
|
||||||
|
<t-button
|
||||||
|
v-if="canRevoke"
|
||||||
|
theme="danger"
|
||||||
|
content="资金冲正"
|
||||||
|
@click="toRevoke"
|
||||||
|
/>
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
<t-empty v-else :description="isLoading ? '正在加载资金记录' : '资金记录不存在'" />
|
<t-empty v-else :description="isLoading ? '正在加载资金记录' : '资金记录不存在'" />
|
||||||
<t-dialog v-model:visible="reasonDialogVisible" :title="reasonTitle" :confirm-btn="reasonActionText" @confirm="submitReason">
|
<t-dialog
|
||||||
|
v-model:visible="reasonDialogVisible"
|
||||||
|
:title="reasonTitle"
|
||||||
|
cancel-btn="取消"
|
||||||
|
:confirm-btn="reasonActionText"
|
||||||
|
@cancel="reasonDialogVisible = false"
|
||||||
|
@confirm="submitReason"
|
||||||
|
>
|
||||||
<t-textarea v-model.trim="reasonText" borderless autosize placeholder="请输入原因" />
|
<t-textarea v-model.trim="reasonText" borderless autosize placeholder="请输入原因" />
|
||||||
</t-dialog>
|
</t-dialog>
|
||||||
</div>
|
</div>
|
||||||
@@ -38,7 +112,7 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { DialogPlugin } from "tdesign-mobile-vue";
|
import { DialogPlugin } from "tdesign-mobile-vue";
|
||||||
import { Time } from "timi-web";
|
import { PassTimeLabel, Text } from "timi-web";
|
||||||
import { useUserStore } from "timi-web-api";
|
import { useUserStore } from "timi-web-api";
|
||||||
import SalesOrderAPI from "@/api/SalesOrderAPI";
|
import SalesOrderAPI from "@/api/SalesOrderAPI";
|
||||||
import PhotoScroller from "@/components/PhotoScroller.vue";
|
import PhotoScroller from "@/components/PhotoScroller.vue";
|
||||||
@@ -56,30 +130,21 @@ type ReasonAction = "reject" | "cancel";
|
|||||||
|
|
||||||
defineOptions({ name: "FundRecordDetail" });
|
defineOptions({ name: "FundRecordDetail" });
|
||||||
|
|
||||||
|
// 公共变量
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
const navBarStore = useNavBarStore();
|
const navBarStore = useNavBarStore();
|
||||||
|
const isOperating = ref(false);
|
||||||
|
|
||||||
|
// ---------- 资金记录 ----------
|
||||||
|
|
||||||
const record = ref<FundRecord>();
|
const record = ref<FundRecord>();
|
||||||
const isLoading = ref(false);
|
const isLoading = ref(false);
|
||||||
const isOperating = ref(false);
|
|
||||||
const reasonDialogVisible = ref(false);
|
|
||||||
const reasonText = ref("");
|
|
||||||
const reasonAction = ref<ReasonAction>("reject");
|
|
||||||
const isPendingReceive = computed(() => record.value?.operationType === "RECEIVE" && record.value.status === "PENDING");
|
const isPendingReceive = computed(() => record.value?.operationType === "RECEIVE" && record.value.status === "PENDING");
|
||||||
const canVerifyReceive = computed(() => isPendingReceive.value && userStore.hasPermissions(permissionCodes.fundReceive.verify));
|
const canVerifyReceive = computed(() => isPendingReceive.value && userStore.hasPermissions(permissionCodes.fundReceive.verify));
|
||||||
const canCancelReceive = computed(() => isPendingReceive.value && userStore.hasPermissions(permissionCodes.fundReceive.create));
|
const canCancelReceive = computed(() => isPendingReceive.value && userStore.hasPermissions(permissionCodes.fundReceive.create));
|
||||||
const canRevoke = computed(() => record.value?.status === "VERIFIED" && record.value.operationType !== "REVOKE" && userStore.hasPermissions(permissionCodes.fund.revoke));
|
const canRevoke = computed(() => record.value?.status === "VERIFIED" && record.value.operationType !== "REVOKE" && userStore.hasPermissions(permissionCodes.fund.revoke));
|
||||||
const reasonTitle = computed(() => reasonAction.value === "reject" ? "拒绝收款" : "撤销收款");
|
|
||||||
const reasonActionText = computed(() => reasonAction.value === "reject" ? "拒绝" : "撤销");
|
|
||||||
const photoItems = computed<PhotoItem[]>(() => (record.value?.attachmentList || [])
|
|
||||||
.filter(item => !!item.id)
|
|
||||||
.map(item => ({
|
|
||||||
attachment: item,
|
|
||||||
attachType: item.attachType || "PHOTO",
|
|
||||||
url: getAttachmentReadURL(item.id || "")
|
|
||||||
})));
|
|
||||||
const photoURLList = computed(() => photoItems.value.map(item => item.url));
|
|
||||||
|
|
||||||
function getStatusTheme(status?: FundRecordStatus): "success" | "warning" | "danger" | "default" {
|
function getStatusTheme(status?: FundRecordStatus): "success" | "warning" | "danger" | "default" {
|
||||||
return status === "VERIFIED" ? "success" : status === "PENDING" ? "warning" : status === "REJECTED" ? "danger" : "default";
|
return status === "VERIFIED" ? "success" : status === "PENDING" ? "warning" : status === "REJECTED" ? "danger" : "default";
|
||||||
@@ -100,6 +165,44 @@ async function loadData(): Promise<void> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---------- 订单详情 ----------
|
||||||
|
|
||||||
|
const canReadSalesOrder = computed(() => userStore.hasPermissions(permissionCodes.salesOrder.read));
|
||||||
|
|
||||||
|
async function toSalesOrder(): Promise<void> {
|
||||||
|
if (!record.value?.bizId || !canReadSalesOrder.value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await router.push({
|
||||||
|
path: `/management/sales-orders/${record.value.bizId}`,
|
||||||
|
query: { transitionDepth: String(getCurrentRouteDepth() + 1) }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCurrentRouteDepth(): number {
|
||||||
|
const transitionDepth = Array.isArray(route.query.transitionDepth)
|
||||||
|
? route.query.transitionDepth[0]
|
||||||
|
: route.query.transitionDepth;
|
||||||
|
const depth = Number(transitionDepth);
|
||||||
|
if (transitionDepth && Number.isInteger(depth) && 0 <= depth && depth <= 20) {
|
||||||
|
return depth;
|
||||||
|
}
|
||||||
|
return Number(route.meta.depth ?? 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------- 业务照片 ----------
|
||||||
|
|
||||||
|
const photoItems = computed<PhotoItem[]>(() => (record.value?.attachmentList || [])
|
||||||
|
.filter(item => !!item.id)
|
||||||
|
.map(item => ({
|
||||||
|
attachment: item,
|
||||||
|
attachType: item.attachType || "PHOTO",
|
||||||
|
url: getAttachmentReadURL(item.id || "")
|
||||||
|
})));
|
||||||
|
const photoURLList = computed(() => photoItems.value.map(item => item.url));
|
||||||
|
|
||||||
|
// ---------- 收款操作 ----------
|
||||||
|
|
||||||
async function refreshRelatedPackage(): Promise<void> {
|
async function refreshRelatedPackage(): Promise<void> {
|
||||||
if (record.value?.bizId) {
|
if (record.value?.bizId) {
|
||||||
await SalesOrderAPI.detail(record.value.bizId);
|
await SalesOrderAPI.detail(record.value.bizId);
|
||||||
@@ -131,6 +234,14 @@ async function verifyReceive(): Promise<void> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---------- 收款原因 ----------
|
||||||
|
|
||||||
|
const reasonDialogVisible = ref(false);
|
||||||
|
const reasonText = ref("");
|
||||||
|
const reasonAction = ref<ReasonAction>("reject");
|
||||||
|
const reasonTitle = computed(() => reasonAction.value === "reject" ? "拒绝收款" : "撤销收款");
|
||||||
|
const reasonActionText = computed(() => reasonAction.value === "reject" ? "拒绝" : "撤销");
|
||||||
|
|
||||||
function openReasonDialog(action: ReasonAction): void {
|
function openReasonDialog(action: ReasonAction): void {
|
||||||
if (!isPendingReceive.value || isOperating.value) {
|
if (!isPendingReceive.value || isOperating.value) {
|
||||||
return;
|
return;
|
||||||
@@ -163,12 +274,16 @@ async function submitReason(): Promise<void> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---------- 资金冲正 ----------
|
||||||
|
|
||||||
async function toRevoke(): Promise<void> {
|
async function toRevoke(): Promise<void> {
|
||||||
if (record.value?.id && canRevoke.value) {
|
if (record.value?.id && canRevoke.value) {
|
||||||
await router.push(`/management/fund-records/${record.value.id}/revoke`);
|
await router.push(`/management/fund-records/${record.value.id}/revoke`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---------- 生命周期 ----------
|
||||||
|
|
||||||
onMounted(loadData);
|
onMounted(loadData);
|
||||||
onUnmounted(() => navBarStore.clearRight());
|
onUnmounted(() => navBarStore.clearRight());
|
||||||
</script>
|
</script>
|
||||||
@@ -187,6 +302,11 @@ onUnmounted(() => navBarStore.clearRight());
|
|||||||
box-shadow: var(--td-shadow-1);
|
box-shadow: var(--td-shadow-1);
|
||||||
border-radius: 1.25rem;
|
border-radius: 1.25rem;
|
||||||
|
|
||||||
|
.header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
.eyebrow {
|
.eyebrow {
|
||||||
color: #2563eb;
|
color: #2563eb;
|
||||||
display: block;
|
display: block;
|
||||||
@@ -194,42 +314,51 @@ onUnmounted(() => navBarStore.clearRight());
|
|||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
letter-spacing: .08em;
|
letter-spacing: .08em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hero-title {
|
|
||||||
gap: .5rem;
|
|
||||||
display: flex;
|
|
||||||
margin-top: .35rem;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
h1 {
|
.title {
|
||||||
margin: 0;
|
margin: .5rem 0;
|
||||||
font-size: 1.2rem;
|
font-size: 1.2rem;
|
||||||
line-height: 1.35;
|
line-height: 1.35;
|
||||||
}
|
}
|
||||||
|
|
||||||
.amount {
|
.amount {
|
||||||
color: #0f766e;
|
|
||||||
display: block;
|
display: block;
|
||||||
margin-top: .75rem;
|
margin-top: .75rem;
|
||||||
font-size: 1.5rem;
|
|
||||||
line-height: 1.2;
|
line-height: 1.2;
|
||||||
|
|
||||||
|
.value {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.photo-scroller) {
|
.photo-wrap {
|
||||||
padding: 0 1rem;
|
padding: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.actions {
|
.actions {
|
||||||
|
--td-button-border-radius: 1rem;
|
||||||
|
|
||||||
gap: .5rem;
|
gap: .5rem;
|
||||||
padding: 0 1rem;
|
padding: 0 1rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
|
||||||
|
.pair {
|
||||||
|
gap: .5rem;
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
|
||||||
.t-button {
|
.t-button {
|
||||||
flex: 1 1 8rem;
|
width: calc(50% - .25rem);
|
||||||
|
margin: 0;
|
||||||
|
flex: 1 1 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.t-button {
|
||||||
|
flex: 1 1 auto;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,13 +16,53 @@ function meta(title: string, depth = 3, background = "#F5F5F8"): RouteRecordRaw[
|
|||||||
|
|
||||||
export default [
|
export default [
|
||||||
{ path: "/management/sales-orders", name: "SalesOrderList", component: SalesOrderList, meta: meta("销售订单") },
|
{ path: "/management/sales-orders", name: "SalesOrderList", component: SalesOrderList, meta: meta("销售订单") },
|
||||||
{ path: "/management/sales-orders/create", name: "SalesOrderCreate", component: SalesOrderCreate, meta: meta("直接产品下单", 4) },
|
{
|
||||||
{ path: "/management/sales-orders/:id", name: "SalesOrderDetail", component: SalesOrderDetail, meta: meta("销售订单详情", 4) },
|
path: "/management/sales-orders/create",
|
||||||
{ path: "/management/sales-orders/:id/payment", name: "SalesOrderPayment", component: SalesOrderPayment, meta: meta("登记收款", 5) },
|
name: "SalesOrderCreate",
|
||||||
{ path: "/management/sales-orders/:id/refund", name: "SalesOrderRefund", component: SalesOrderRefund, meta: meta("登记退款", 5) },
|
component: SalesOrderCreate,
|
||||||
{ path: "/management/sales-orders/:id/no-refund", name: "SalesOrderNoRefund", component: SalesOrderNoRefund, meta: meta("确认无需退款", 5) },
|
meta: meta("直接产品下单", 4)
|
||||||
{ path: "/management/sales-orders/:id/cancel", name: "SalesOrderCancel", component: SalesOrderCancel, meta: meta("取消销售订单", 5) },
|
},
|
||||||
|
{
|
||||||
|
path: "/management/sales-orders/:id",
|
||||||
|
name: "SalesOrderDetail",
|
||||||
|
component: SalesOrderDetail,
|
||||||
|
meta: meta("销售订单详情", 4)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/management/sales-orders/:id/payment",
|
||||||
|
name: "SalesOrderPayment",
|
||||||
|
component: SalesOrderPayment,
|
||||||
|
meta: meta("登记收款", 5)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/management/sales-orders/:id/refund",
|
||||||
|
name: "SalesOrderRefund",
|
||||||
|
component: SalesOrderRefund,
|
||||||
|
meta: meta("登记退款", 5)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/management/sales-orders/:id/no-refund",
|
||||||
|
name: "SalesOrderNoRefund",
|
||||||
|
component: SalesOrderNoRefund,
|
||||||
|
meta: meta("确认无需退款", 5)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/management/sales-orders/:id/cancel",
|
||||||
|
name: "SalesOrderCancel",
|
||||||
|
component: SalesOrderCancel,
|
||||||
|
meta: meta("取消销售订单", 5)
|
||||||
|
},
|
||||||
{ path: "/management/fund-records", name: "FundRecordList", component: FundRecordList, meta: meta("资金流水") },
|
{ path: "/management/fund-records", name: "FundRecordList", component: FundRecordList, meta: meta("资金流水") },
|
||||||
{ path: "/management/fund-records/:id", name: "FundRecordDetail", component: FundRecordDetail, meta: meta("资金记录详情", 4, "#FFF") },
|
{
|
||||||
{ path: "/management/fund-records/:id/revoke", name: "FundRecordRevoke", component: FundRecordRevoke, meta: meta("资金冲正", 5) }
|
path: "/management/fund-records/:id",
|
||||||
|
name: "FundRecordDetail",
|
||||||
|
component: FundRecordDetail,
|
||||||
|
meta: meta("资金记录详情", 4)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/management/fund-records/:id/revoke",
|
||||||
|
name: "FundRecordRevoke",
|
||||||
|
component: FundRecordRevoke,
|
||||||
|
meta: meta("资金冲正", 5)
|
||||||
|
}
|
||||||
] as RouteRecordRaw[];
|
] as RouteRecordRaw[];
|
||||||
|
|||||||
Reference in New Issue
Block a user