| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306 |
- import dayjs from "dayjs";
- import { message } from "@/utils/message";
- import { addDialog } from "@/components/ReDialog";
- import type { PaginationProps } from "@pureadmin/table";
- import {
- ElForm,
- ElFormItem,
- ElInput,
- ElDescriptions,
- ElDescriptionsItem,
- ElImage,
- ElTable,
- ElTableColumn
- } from "element-plus";
- import {
- getRefundApplicationList,
- getRefundApplicationDetail,
- reviewRefundApplication
- } from "@/api/order";
- import type { RefundApplicationItem, RefundApplicationSearchForm } from "../../utils/types";
- import { type Ref, ref, reactive, onMounted } from "vue";
- import {
- initPagination,
- handlePageSizeChange,
- handleCurrentPageChange,
- resetPagination
- } from "@/utils/paginationHelper";
- export function useRefund(tableRef: Ref) {
- const form = reactive<RefundApplicationSearchForm>({
- orderNo: "",
- status: "",
- startDate: "",
- endDate: ""
- });
- const formRef = ref();
- const dataList = ref<RefundApplicationItem[]>([]);
- const loading = ref(true);
- const pagination = reactive<PaginationProps>(initPagination());
- const columns: TableColumnList = [
- { label: "申请编号", prop: "applicationNo", minWidth: 160 },
- { label: "订单编号", prop: "orderNo", minWidth: 160 },
- { label: "用户ID", prop: "userId", minWidth: 80 },
- {
- label: "退款金额",
- prop: "refundAmount",
- minWidth: 100,
- cellRenderer: ({ row }: any) => (
- <span style="color: #f56c6c; font-weight: 600;">¥{row.refundAmount || "0.00"}</span>
- )
- },
- {
- label: "申请原因",
- prop: "reason",
- minWidth: 180,
- formatter: ({ reason }: any) => reason || "-"
- },
- {
- label: "退款状态",
- prop: "status",
- minWidth: 90,
- cellRenderer: ({ row }: any) => {
- const statusMap: Record<number, { text: string; type: string }> = {
- 0: { text: "待审核", type: "warning" },
- 1: { text: "已通过", type: "success" },
- 2: { text: "已拒绝", type: "danger" }
- };
- const s = statusMap[row.status] || { text: "未知", type: "info" };
- return <el-tag type={s.type as any} size="small">{s.text}</el-tag>;
- }
- },
- {
- label: "申请时间",
- prop: "createTime",
- minWidth: 160,
- formatter: ({ createTime }: any) =>
- createTime ? dayjs(createTime).format("YYYY-MM-DD HH:mm:ss") : "-"
- },
- {
- label: "操作",
- fixed: "right",
- width: 200,
- slot: "operation"
- }
- ];
- async function onSearch() {
- loading.value = true;
- try {
- const searchParams: any = {
- page: pagination.currentPage,
- pageSize: pagination.pageSize
- };
- if (form.orderNo) searchParams.orderNo = form.orderNo;
- if (form.status !== "") searchParams.status = parseInt(form.status as string, 10);
- if (form.startDate) searchParams.startDate = form.startDate;
- if (form.endDate) searchParams.endDate = form.endDate;
- const { data } = await getRefundApplicationList(searchParams);
- dataList.value = data.list || [];
- pagination.total = Number(data.total) || 0;
- } catch (error) {
- console.error("获取退款申请列表失败:", error);
- dataList.value = [];
- pagination.total = 0;
- } finally {
- setTimeout(() => { loading.value = false; }, 300);
- }
- }
- function resetForm(formEl: any) {
- if (!formEl) return;
- formEl.resetFields();
- resetPagination(pagination, onSearch);
- }
- function handleSizeChange(val: number) {
- handlePageSizeChange(val, pagination, onSearch);
- }
- function handleCurrentChange(val: number) {
- handleCurrentPageChange(val, pagination, onSearch);
- }
- async function handleDetail(row: RefundApplicationItem) {
- try {
- const { data } = await getRefundApplicationDetail(row.id);
- const app = data;
- const statusMap: Record<number, { text: string; type: string }> = {
- 0: { text: "待审核", type: "warning" },
- 1: { text: "已通过", type: "success" },
- 2: { text: "已拒绝", type: "danger" }
- };
- const s = statusMap[app.status] || { text: "未知", type: "info" };
- addDialog({
- title: "退款申请详情 - " + app.applicationNo,
- width: "600px",
- draggable: true,
- closeOnClickModal: false,
- contentRenderer: () => (
- <div style="max-height: 70vh; overflow-y: auto; padding: 0 4px;">
- <div style="font-size: 15px; font-weight: 600; margin-bottom: 10px; color: var(--el-text-color-primary);">基本信息</div>
- <ElDescriptions column={2} border size="small">
- <ElDescriptionsItem label="申请编号">{app.applicationNo}</ElDescriptionsItem>
- <ElDescriptionsItem label="订单编号">{app.orderNo}</ElDescriptionsItem>
- <ElDescriptionsItem label="申请人用户ID">{app.userId}</ElDescriptionsItem>
- <ElDescriptionsItem label="退款金额">
- <span style="color: #f56c6c; font-weight: 600;">¥{(app.refundAmount || 0).toFixed(2)}</span>
- </ElDescriptionsItem>
- <ElDescriptionsItem label="退款状态">
- <el-tag type={s.type as any} size="small">{s.text}</el-tag>
- </ElDescriptionsItem>
- <ElDescriptionsItem label="申请时间">
- {app.createTime ? dayjs(app.createTime).format("YYYY-MM-DD HH:mm:ss") : "-"}
- </ElDescriptionsItem>
- <ElDescriptionsItem label="申请原因" span={2}>{app.reason || "-"}</ElDescriptionsItem>
- {app.reviewTime && (
- <ElDescriptionsItem label="审核时间">
- {dayjs(app.reviewTime).format("YYYY-MM-DD HH:mm:ss")}
- </ElDescriptionsItem>
- )}
- {app.reviewRemark && (
- <ElDescriptionsItem label="审核备注" span={2}>{app.reviewRemark}</ElDescriptionsItem>
- )}
- </ElDescriptions>
- {app.refundProducts && app.refundProducts.length > 0 && (
- <>
- <div style="font-size: 15px; font-weight: 600; margin: 14px 0 10px; color: var(--el-text-color-primary);">退款商品</div>
- <ElTable data={app.refundProducts} border size="small" style="width: 100%">
- <ElTableColumn label="商品名称" min-width={180}>
- {{
- default: ({ row: r }: any) => (
- <div style="display: flex; align-items: center; gap: 8px;">
- {r.pic ? (
- <ElImage
- src={r.pic}
- style="width: 40px; height: 40px; border-radius: 4px; flex-shrink: 0;"
- fit="cover"
- >
- {{
- error: () => (
- <div style="width: 40px; height: 40px; background: #f5f5f5; border-radius: 4px; display: flex; align-items: center; justify-content: center; font-size: 12px; color: #999;">暂无</div>
- )
- }}
- </ElImage>
- ) : (
- <div style="width: 40px; height: 40px; background: #f5f5f5; border-radius: 4px; display: flex; align-items: center; justify-content: center; font-size: 12px; color: #999; flex-shrink: 0;">暂无</div>
- )}
- <span>{r.productName}</span>
- </div>
- )
- }}
- </ElTableColumn>
- <ElTableColumn label="单价" width={100} align="right"
- v-slots={{ default: ({ row: r }: any) => <span>¥{(r.price || 0).toFixed(2)}</span> }}
- />
- <ElTableColumn label="退款数量" width={90} align="center"
- v-slots={{ default: ({ row: r }: any) => <span>×{r.quantity || 1}</span> }}
- />
- <ElTableColumn label="退款金额" width={110} align="right"
- v-slots={{
- default: ({ row: r }: any) => (
- <span style="color: #e6a23c; font-weight: 600;">
- ¥{((r.price || 0) * (r.quantity || 1)).toFixed(2)}
- </span>
- )
- }}
- />
- </ElTable>
- </>
- )}
- </div>
- ),
- hideFooter: true
- });
- } catch (error) {
- message("获取退款详情失败", { type: "error" });
- }
- }
- async function handleApprove(row: RefundApplicationItem) {
- try {
- const res = await reviewRefundApplication(row.id, { approved: true });
- if (res.code === 200) {
- message("退款申请已通过", { type: "success" });
- onSearch();
- } else {
- message(res.message || "操作失败", { type: "error" });
- }
- } catch (error) {
- message("操作失败", { type: "error" });
- }
- }
- function handleReject(row: RefundApplicationItem) {
- const remarkRef = ref("");
- const formRef2 = ref();
- addDialog({
- title: "拒绝退款 - " + row.applicationNo,
- width: "35%",
- draggable: true,
- closeOnClickModal: false,
- contentRenderer: () => (
- <ElForm ref={formRef2} model={{ remark: remarkRef.value }}>
- <ElFormItem
- label="拒绝原因"
- prop="remark"
- rules={[{ required: true, message: "请输入拒绝原因", trigger: "blur" }]}
- >
- <ElInput
- v-model={remarkRef.value}
- type="textarea"
- placeholder="请输入拒绝原因"
- rows={3}
- />
- </ElFormItem>
- </ElForm>
- ),
- beforeSure: async (done) => {
- const valid = await formRef2.value?.validate().catch(() => false);
- if (!valid) return;
- try {
- const res = await reviewRefundApplication(row.id, {
- approved: false,
- remark: remarkRef.value
- });
- if (res.code === 200) {
- message("退款申请已拒绝", { type: "success" });
- done();
- onSearch();
- } else {
- message(res.message || "操作失败", { type: "error" });
- }
- } catch (error) {
- message("操作失败", { type: "error" });
- }
- }
- });
- }
- onMounted(() => {
- onSearch();
- });
- return {
- form,
- loading,
- columns,
- dataList,
- pagination,
- onSearch,
- resetForm,
- handleDetail,
- handleApprove,
- handleReject,
- handleSizeChange,
- handleCurrentChange
- };
- }
|