Files
workspace/code/新建文件夹/cw/yf/list.vue
T
2026-08-03 17:33:57 +08:00

829 lines
20 KiB
Vue
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="js">
import g3filter from "@/components/query-conditions/g3filter.vue";
import G3ExcelExport from "@/components/g3-excel-export/index.vue";
import { ArrowDown } from "@element-plus/icons-vue";
import dayjs from "dayjs";
import { ElMessage, ElMessageBox } from "element-plus";
import { computed, onMounted, reactive, ref } from "vue";
import { useRouter, useRoute } from "vue-router";
import { useUserStore } from "@/store/user";
import axios from "@/utils/axios";
import { formatValueByFormat, getAlignByFormat, updateTableFooterData } from "@/utils/column";
import { getTablePage, getTableColumns, handleSaveColumn } from "@/utils/dodata";
import { getQxSql } from "@/utils/auth";
import { ExportVxeTableExcel } from "@/utils/excel";
import { openFeeLink, generateBill, generateInvoice, generateSfd } from "../components";
import { handleYsYfSummary } from "@/utils/g3Funlib";
import math from "@/utils/math";
import { morePermission } from "@/utils/auth";
import { loaddataApi } from "@/utils/doSql";
defineOptions({
name: "Yflist",
});
const userStore = useUserStore();
const showExcelExport = ref(false);
const tableRef = ref();
const router = useRouter();
const route = useRoute();
const moduleid = computed(() => currentModule.value?.b_codemoduleid);
const columns = ref([]);
const tableData = ref([]);
const tableFooterData = computed(() => {
return updateTableFooterData(columns.value, tableData.value);
});
const saving = ref(false);
const loading = ref(false);
const error = ref(null);
const searchCondition = ref("");
const ysyfSummary = handleYsYfSummary(tableData, "[]");
const selectedsummary = computed(() => {
if (!tableRef.value) {
return "";
}
const rows = tableRef.value.getCheckboxRecords();
if (!rows.length) {
return "";
}
const ys = {};
const yf = {};
let total_rmb = math.add(0);
rows.forEach((row) => {
const moneytype = row.mx_moneytype_id || "";
const amount = row.mx_amount || 0;
const rmb = row.mx_amount_rmb || 0;
if (row.mx_type_id === "应收") {
ys[moneytype] = math.add(ys[moneytype] || 0, amount);
total_rmb = math.subtract(total_rmb, rmb);
} else if (row.mx_type_id === "应付") {
yf[moneytype] = math.add(yf[moneytype] || 0, amount);
total_rmb = math.add(total_rmb, rmb);
}
});
const formatMoney = (data) => {
return Object.entries(data)
.map(([moneytype, amount]) => `${moneytype} ${amount.toFixed()}`)
.join(" ");
};
const result = [];
const ysText = formatMoney(ys);
const yfText = formatMoney(yf);
if (ysText) {
result.push(`应收:${ysText}`);
}
if (yfText) {
result.push(`应付:${yfText}`);
}
// result.push(`折本币合计:${total_rmb.toFixed()}`);
return result.join(" ");
});
// 分页参数
const pagination = reactive({
currentPage: 1,
pageSize: 50,
total: 0,
});
// 列配置
async function addColumn() {
const result = await getTableColumns(currentModule.value?.b_viewtable);
if (result.success) {
columns.value = result.data;
} else {
ElMessage.error(`加载失败: ${result.error}`);
}
}
async function loadTableData(whereClause = "") {
loading.value = true;
try {
await getTablePage({
tableName: currentModule.value?.b_viewtable,
whereClause,
page: pagination.currentPage,
size: pagination.pageSize,
pkColumn: "father desc",
moduleId: moduleid.value,
targetRef: tableData,
paginationTarget: pagination,
errorRef: error,
});
} finally {
loading.value = false;
}
}
function handleRowDblClick({ row }) {
handleEditClick(row);
}
function handleEditId(row) {
handleEditClick(row);
}
// 点击行显示详情
function handleEditClick(row) {
router.push({
name: "businessdetail",
query: { id: row.father, op: "mod" },
});
}
async function handleToBillByFee() {
if (!tableRef.value) return;
const rows = tableRef.value.getCheckboxRecords();
const subids = rows.map((row) => row.subid);
try {
await generateBill(subids, "应付");
ElMessage.success("保存成功");
} catch (error) {
console.error(error);
ElMessage.warning(error.message || "操作失败");
}
}
async function handleToInvoiceByFee() {
if (!tableRef.value) return;
const rows = tableRef.value.getCheckboxRecords();
const subids = rows.map((row) => row.subid);
try {
await generateInvoice(subids, "应付");
ElMessage.success("保存成功");
} catch (error) {
console.error(error);
ElMessage.warning(error.message || "操作失败");
}
}
async function handleToSfdByFee() {
if (!tableRef.value) return;
const rows = tableRef.value.getCheckboxRecords();
const subids = rows.map((row) => row.subid);
try {
await generateSfd(subids, "应付");
ElMessage.success("保存成功");
} catch (error) {
console.error(error);
ElMessage.warning(error.message || "操作失败");
}
}
async function buildSqlWhere() {
let sql = searchCondition.value;
const qxsql = await getQxSql(moduleid.value, userStore.getUserId());
if (qxsql) {
sql += qxsql;
}
return sql;
}
async function handlefilter(filtersql) {
pagination.currentPage = 1;
searchCondition.value = filtersql;
await loadTableData(await buildSqlWhere());
}
// 每页条数变化
async function handleSizeChange(val) {
pagination.pageSize = val;
await loadTableData(await buildSqlWhere());
}
// 当前页变化
async function handleCurrentChange(val) {
pagination.currentPage = val;
await loadTableData(await buildSqlWhere());
}
async function approveRows(rows) {
if (!rows || !rows.length) {
ElMessage.warning("请选择要审核的数据");
return;
}
const toApprove = [];
const alreadyApproved = [];
for (const row of rows) {
if (row.mx_sh === "1") {
alreadyApproved.push(row);
} else {
toApprove.push({
subid: row.subid,
mx_sh: "1",
mx_shman_id: userStore.userInfo.userid,
mx_shdate: dayjs().format("YYYY-MM-DD HH:mm:ss"),
});
}
}
// 统一确认弹框
await ElMessageBox.confirm(
`本次共选择 ${rows.length} 条数据:
可审核 ${toApprove.length} 条
已审核 ${alreadyApproved.length} 条
是否继续?`,
"提示",
{
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
},
);
if (!toApprove.length) {
ElMessage.info("没有可审核的数据");
return;
}
const requestData = [
{
tableName: "bs_business_cw",
keyField: "subid",
inserts: [],
updates: toApprove,
deletes: [],
},
];
try {
saving.value = true;
error.value = "";
await axios.post("/saveobjectV2", requestData, {
headers: { "Content-Type": "application/json" },
});
await loadTableData(await buildSqlWhere());
ElMessage.success(`审核完成:已成功审核 ${toApprove.length} 条记录`);
} catch (err) {
error.value = `审核失败: ${err.message}`;
console.error("审核错误:", err);
ElMessage.error("审核失败");
} finally {
saving.value = false;
}
}
function psh(row) {
approveRows([row]);
}
function batchPsh() {
const $table = tableRef.value;
if (!$table) return;
const rows = $table.getCheckboxRecords();
approveRows(rows);
}
async function revokeApproveRows(rows) {
if (!rows || !rows.length) {
ElMessage.warning("请选择要撤销审核的数据");
return;
}
const toRevoke = [];
const cannotRevoke = [];
// 分类
for (const row of rows) {
if (row.mx_zdorderid) {
cannotRevoke.push(row);
} else if (row.alreadyamount && Number.parseFloat(row.alreadyamount) !== 0) {
cannotRevoke.push(row);
} else {
toRevoke.push(row);
}
}
// 统一确认提示
await ElMessageBox.confirm(
`本次共选择 ${rows.length} 条数据:
可撤销 ${toRevoke.length} 条
不可撤销 ${cannotRevoke.length} 条(已开账单或已销账)
是否继续?`,
"提示",
{
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
},
);
if (!toRevoke.length) {
ElMessage.info("没有可撤销的数据");
return;
}
const updates = toRevoke.map((row) => ({
subid: row.subid,
mx_sh: "0",
mx_shman_id: "",
mx_shdate: "",
}));
const requestData = [
{
tableName: "bs_business_cw",
keyField: "subid",
inserts: [],
updates,
deletes: [],
},
];
try {
saving.value = true;
error.value = "";
await axios.post("/saveobjectV2", requestData, {
headers: { "Content-Type": "application/json" },
});
await loadTableData(await buildSqlWhere());
ElMessage.success(`撤销完成:成功 ${toRevoke.length} 条`);
} catch (err) {
error.value = `撤销审核失败: ${err.message}`;
console.error("撤销审核错误:", err);
ElMessage.error("撤销审核失败");
} finally {
saving.value = false;
}
}
function punsh(row) {
revokeApproveRows([row]);
}
function batchPunsh() {
const $table = tableRef.value;
if (!$table) return;
const rows = $table.getCheckboxRecords();
revokeApproveRows(rows);
}
// --------行颜色
function rowStyle({ row }) {
if (row.mx_type_id === "应付") {
return {
color: "red",
};
}
return {};
}
// --------
const moduleList = ref([]);
const currentModule = ref(null);
async function loadModules() {
const modules = await loaddataApi(
"s_module_config",
`b_type = 'cw_fee' and b_cwtype = '应付' and b_canuse='1'`,
);
moduleList.value = modules;
if (modules.length > 0) {
currentModule.value = modules[0];
} else {
currentModule.value = null;
}
}
async function handleModuleChange(value) {
currentModule.value = value;
await addColumn();
pagination.currentPage = 1;
pagination.pageSize = 50;
pagination.total = 0;
await loadTableData("");
}
onMounted(async () => {
await loadModules();
await addColumn();
});
</script>
<template>
<div class="g3pagecontainer">
<div class="g3container">
<div class="g3modulebar">
<span>业务模块:</span>
<el-select
v-model="currentModule"
placeholder="请选择模块"
size="small"
value-key="b_id"
@change="handleModuleChange"
>
<el-option
v-for="item in moduleList"
:key="item.b_id"
:label="item.b_name"
:value="item"
/>
</el-select>
</div>
<div class="g3query">
<g3filter :module-id="moduleid" @update:search="handlefilter" />
<div class="g3buttonright">
<el-button
:disabled="morePermission(20)"
type="primary"
class="g3mright10 g3button"
@click="handleToBillByFee"
>
应付账单
</el-button>
<el-dropdown>
<el-button class="g3button">
更多<el-icon class="el-icon--right"><ArrowDown /></el-icon>
</el-button>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item :disabled="morePermission(7)" @click="batchPsh">
审核
</el-dropdown-item>
<el-dropdown-item :disabled="morePermission(7)" @click="batchPunsh">
反审
</el-dropdown-item>
<el-dropdown-item
:disabled="morePermission(21)"
divided
@click="handleToInvoiceByFee"
>
应付发票
</el-dropdown-item>
<el-dropdown-item :disabled="morePermission(22)" @click="handleToSfdByFee">
付款登记
</el-dropdown-item>
<el-dropdown-item
:disabled="morePermission(6)"
divided
@click="ExportVxeTableExcel(tableRef)"
>
导出Excel
</el-dropdown-item>
<el-dropdown-item :disabled="morePermission(6)" @click="showExcelExport = true">
导出所有页
</el-dropdown-item>
<el-dropdown-item
divided
:disabled="morePermission(9)"
@click="() => handleSaveColumn(tableRef, 'v_cw_fee_f')"
>
栏位设定
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</div>
<div class="g3main">
<div class="g3grid">
<vxe-table
ref="tableRef"
border
stripe
header-align="center"
:data="tableData"
:show-footer="true"
:footer-data="tableFooterData"
:loading="loading"
:sort-config="{
// showIcon: false,
trigger: 'cell',
}"
:filter-config="{
showIcon: false,
}"
:column-drag-config="{
showIcon: false,
trigger: 'cell',
}"
:row-config="{
useKey: true,
isCurrent: true,
isHover: true,
}"
size="small"
:cell-config="{
height: 26,
}"
:column-config="{
resizable: true,
drag: true,
}"
show-overflow
show-header-overflow
show-footer-overflow
height="100%"
@cell-dblclick="handleRowDblClick"
:row-style="rowStyle"
>
<vxe-column field="seq" type="seq" width="50" align="center" title=" " fixed="left" />
<vxe-column type="checkbox" width="50" align="center" fixed="left" />
<vxe-column
v-for="column in columns"
:key="column.prop"
:field="column.prop"
:title="column.label"
:width="column.width"
:align="getAlignByFormat(column.displayFormat)"
:params="column"
sortable
>
<template #default="{ row }">
<template v-if="column.edit_type == 'checkbox'">
<el-checkbox v-model="row[column.prop]" disabled true-value="1" false-value="0" />
</template>
<template v-else-if="['father', 'b_ywno'].includes(column.prop)">
<span class="g3-color" @click="handleEditId(row)">
{{ row[column.prop] }}
</span>
</template>
<template v-else>
{{ formatValueByFormat(row[column.prop], column.displayFormat) }}
</template>
</template>
<template v-if="column.showSummary === '1'" #footer="{ row }">
{{ formatValueByFormat(row[column.prop], column.displayFormat) }}
</template>
</vxe-column>
<vxe-column width="180" align="center" fixed="right" title="操作">
<template #default="{ row }">
<div class="tableactions">
<el-button
link
type="primary"
size="small"
style="font-size: 14px"
@click="handleEditClick(row)"
>
查看
</el-button>
<el-dropdown>
<span class="el-dropdown-link">
更多
<el-icon class="el-icon--right">
<ArrowDown />
</el-icon>
</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item :disabled="morePermission(7)" @click="psh(row)">
审核
</el-dropdown-item>
<el-dropdown-item :disabled="morePermission(7)" @click="punsh(row)">
反审
</el-dropdown-item>
<el-dropdown-item @click="openFeeLink(row.subid, row.mx_type_id)">
费用详情
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</template>
</vxe-column>
</vxe-table>
</div>
<div class="g3pagination">
<div>
<div class="g3summary" v-if="selectedsummary">
<div>选中金额</div>
{{ selectedsummary }}
</div>
<div
class="g3footerfeesum"
v-if="ysyfSummary?.allHtml"
v-html="ysyfSummary?.allHtml"
></div>
</div>
<el-pagination
:current-page="pagination.currentPage"
:page-sizes="[50, 100, 200, 500, 1000]"
:page-size="pagination.pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="pagination.total"
size="small"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</div>
</div>
<el-alert v-if="error" :title="error" type="error" show-icon closable @close="error = ''" />
<G3ExcelExport
v-model="showExcelExport"
:view-name="moduleid"
:footer-data="tableFooterData"
:total="pagination.total"
:search-condition="searchCondition"
/>
</div>
</div>
</template>
<style lang="scss" scoped>
.g3pagecontainer {
box-sizing: border-box;
display: flex;
background-color: #f2f3f5;
width: 100%;
height: 100%;
}
.g3container {
display: flex;
flex-direction: column;
min-width: 0;
height: 100%;
width: 100%;
}
.g3query {
display: flex;
align-items: center;
padding: 10px 10px 8px 10px;
margin-bottom: 6px;
background-color: #ffffff;
border: 1px solid #e4e7ed;
border-radius: 6px;
box-shadow: 0 0 12px #0000000d;
}
.g3buttonright {
display: flex;
align-items: center;
height: 32px;
margin-left: 15px;
border-radius: 8px;
}
.g3main {
display: flex;
flex: 1;
flex-direction: column;
height: 100%;
padding: 10px;
background-color: #ffffff;
border: 1px solid #e4e7ed;
border-radius: 6px;
box-shadow: 0 0 12px #0000000d;
box-sizing: border-box;
min-height: 0;
}
.g3containerheader {
display: flex;
justify-content: space-between;
height: 32px;
margin-bottom: 8px;
width: 100%;
}
.g3flex {
display: flex;
}
.g3mright10 {
margin-right: 10px;
}
.g3button {
border-radius: 8px;
height: 34px;
}
.g3grid {
flex: 1;
display: flex;
flex-direction: column;
min-height: 0;
width: 100%;
}
.g3pagination {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 10px;
}
.g3pagination > div {
display: flex;
}
.g3summary {
display: flex;
align-items: center;
gap: 4px;
font-size: 12px;
margin-right: 20px;
}
.g3-svg-query {
display: flex;
justify-content: center;
align-items: center;
border-radius: 50%;
padding: 8px;
white-space: nowrap;
cursor: pointer;
border: 1px solid #dcdfe6;
}
.g3-svg-query:hover {
border-color: #badeff;
background-color: #e8f4ff;
}
.tableactions {
display: flex;
align-items: center;
justify-content: center;
}
/**下拉 */
.el-dropdown-link {
cursor: pointer;
display: flex;
color: #409eff;
align-items: center;
margin-left: 14px;
}
/* 查询日期图标 */
:deep(.g3-prefix .el-input__prefix) {
display: none !important;
}
.el-dropdown .g3-svg-query:focus,
.el-dropdown-link:focus {
outline: none !important;
}
.g3-color {
color: #409eff;
cursor: pointer;
}
/* ---------------添加disabled 修改效果 */
:deep(.el-input.is-disabled .el-input__inner) {
cursor: default;
}
:deep(.el-button.is-disabled) {
cursor: default;
}
/* ------------------ */
/* -------------------- */
:deep(.vxe-cell--wrapper) {
overflow: hidden;
/* 隐藏溢出 */
text-overflow: ellipsis;
/* 文本溢出显示省略号 */
white-space: nowrap;
/* 不换行 */
}
/* -------------------- */
.g3modulebar {
height: 40px;
display: flex;
align-items: center;
padding: 0 10px;
background: #fff;
border-bottom: 1px solid #ebeef5;
font-size: 14px;
}
.g3modulebar .el-select {
width: 160px;
}
</style>