This commit is contained in:
oneao committed 2026-03-25 21:27:48 +08:00
1 parent a4e59dd5d1
commit c7240ea7c9
16 files changed
+598 -476

No files matched your search

+2 -4
View File
@@ -15,7 +15,6 @@ declare module 'vue' {
ElButton: typeof import('element-plus/es')['ElButton']
ElCard: typeof import('element-plus/es')['ElCard']
ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
ElDatePicker: typeof import('element-plus/es')['ElDatePicker']
ElDialog: typeof import('element-plus/es')['ElDialog']
ElDivider: typeof import('element-plus/es')['ElDivider']
@@ -34,8 +33,8 @@ declare module 'vue' {
ElPopover: typeof import('element-plus/es')['ElPopover']
ElRadio: typeof import('element-plus/es')['ElRadio']
ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
ElResult: typeof import('element-plus/es')['ElResult']
ElScrollbar: typeof import('element-plus/es')['ElScrollbar']
ElSegmented: typeof import('element-plus/es')['ElSegmented']
ElSelect: typeof import('element-plus/es')['ElSelect']
ElSplitter: typeof import('element-plus/es')['ElSplitter']
ElSplitterPanel: typeof import('element-plus/es')['ElSplitterPanel']
@@ -43,13 +42,12 @@ declare module 'vue' {
ElSwitch: typeof import('element-plus/es')['ElSwitch']
ElTable: typeof import('element-plus/es')['ElTable']
ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
ElTabPane: typeof import('element-plus/es')['ElTabPane']
ElTabs: typeof import('element-plus/es')['ElTabs']
ElText: typeof import('element-plus/es')['ElText']
ElTooltip: typeof import('element-plus/es')['ElTooltip']
ElTree: typeof import('element-plus/es')['ElTree']
G3Column: typeof import('./src/components/g3-table/g3-column.vue')['default']
G3Detail: typeof import('./src/components/g3-detail/index.vue')['default']
G3Error: typeof import('./src/components/g3-error/index.vue')['default']
G3File: typeof import('./src/components/g3-file/index.vue')['default']
G3Grid: typeof import('./src/components/g3-grid/g3-grid.vue')['default']
G3GridGroup: typeof import('./src/components/g3-grid/g3-grid-group.vue')['default']
@@ -1,15 +1,33 @@
import ErrorModal from "./index.vue";
let isShowingErrorModal = false;
let currentApp = null;
export const ErrorModalService = {
show(responseData) {
if (isShowingErrorModal && currentApp) {
currentApp._instance.props.responseData = responseData;
return;
}
isShowingErrorModal = true;
const container = document.createElement("div");
document.body.appendChild(container);
const app = createApp({
data() {
return {
data: responseData,
};
},
render() {
return h(ErrorModal, {
responseData: responseData,
responseData: this.data,
onClose: () => {
isShowingErrorModal = false;
currentApp = null;
app.unmount();
document.body.removeChild(container);
},
@@ -17,6 +35,7 @@ export const ErrorModalService = {
},
});
currentApp = app;
app.mount(container);
},
};
@@ -2,11 +2,13 @@
<div class="error-modal-wrapper" @click.self="handleClose">
<div v-if="visible" class="error-modal" @click.stop>
<div class="error-modal-header">
<span class="error-modal-title"
>⚠️ 系统异常提示 - {{ props.responseData.message }} -
{{ props.responseData.code || 500 }}</span
<span class="error-modal-title">⚠️ 系统异常提示 </span>
<div
class="error-modal-close-btn"
@click="handleClose"
role="button"
tabindex="0"
>
<div class="error-modal-close-btn" @click="handleClose" role="button" tabindex="0">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
@@ -25,9 +27,12 @@
<div class="log-item" v-for="item in logList" :key="item.label">
<div class="log-label">{{ item.label }}</div>
<div class="log-value">
<pre v-if="item.label === '堆栈跟踪' || item.label === '请求参数'" class="code-block">{{
item.value
}}</pre>
<pre
v-if="item.label === '堆栈跟踪' || item.label === '请求参数'"
class="code-block"
>
{{ item.value }}
</pre>
<div v-else>{{ item.value }}</div>
</div>
</div>
@@ -48,10 +53,21 @@
<line x1="12" y1="16" x2="12" y2="12" />
<line x1="12" y1="8" x2="12.01" y2="8" />
</svg>
<span>请将错误信息 导出 或 复制 发送给管理员!</span>
<span style="margin-left: 4px">
请将错误信息
<span class="highlight" @click="exportAsTxt">导出</span>
或
<span class="highlight" @click="copyInfo">复制</span>
发送给管理员!
</span>
</div>
<div class="error-modal-actions">
<div class="btn txt-btn" role="button" tabindex="0" @click="exportAsTxt">
<div
class="btn txt-btn"
role="button"
tabindex="0"
@click="exportAsTxt"
>
<svg
class="btn-icon"
viewBox="0 0 24 24"
@@ -61,14 +77,21 @@
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8l-6-6z" />
<path
d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8l-6-6z"
/>
<path d="M14 2v6h6m-9 4H9m3 3H9m6-9h-1" />
<path d="M12 18v-6m2 3h-4" />
</svg>
<span>导出TXT</span>
</div>
<div class="btn data-btn" role="button" tabindex="0" @click="copyInfo">
<div
class="btn data-btn"
role="button"
tabindex="0"
@click="copyInfo"
>
<svg
class="btn-icon"
viewBox="0 0 24 24"
@@ -79,12 +102,19 @@
stroke-linejoin="round"
>
<rect x="9" y="9" width="13" height="13" rx="2" />
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" />
<path
d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"
/>
</svg>
<span>复制信息</span>
</div>
<div class="btn cancel-btn" role="button" tabindex="0" @click="handleClose">
<div
class="btn cancel-btn"
role="button"
tabindex="0"
@click="handleClose"
>
<svg
class="btn-icon"
viewBox="0 0 24 24"
@@ -157,7 +187,9 @@ function handleClose() {
}
function exportAsTxt() {
const content = logList.value.map((item) => `${item.label}:\n${item.value}\n`).join("\n");
const content = logList.value
.map((item) => `${item.label}:\n${item.value}\n`)
.join("\n");
const blob = new Blob([content], { type: "text/plain;charset=utf-8" });
const url = URL.createObjectURL(blob);
@@ -177,6 +209,8 @@ function copyInfo() {
</script>
<style lang="scss" scoped>
@use "@/styles/mixins.scss" as *;
@keyframes modalFadeIn {
0% {
opacity: 0;
@@ -263,7 +297,6 @@ function copyInfo() {
.log-item {
display: grid;
grid-template-columns: 120px 1fr;
gap: 16px;
padding: 14px 0;
border-bottom: 1px solid #d9d9d9;
&:last-child {
@@ -274,6 +307,7 @@ function copyInfo() {
font-weight: 600;
text-align: right;
opacity: 0.9;
margin-right: 16px;
}
.log-value {
word-break: break-all;
@@ -302,12 +336,23 @@ function copyInfo() {
display: flex;
align-items: center;
color: #ff7d00;
gap: 8px;
font-size: 16px;
font-size: 14px;
background: #fff7e6;
padding: 8px 12px;
border-radius: 6px;
.highlight {
color: #fff;
background: #ff7d00;
padding: 2px 12px;
border-radius: 4px;
font-weight: 600;
cursor: pointer;
}
}
.error-modal-actions {
display: flex;
gap: 12px;
@include flexGapRow(12px);
margin-left: auto;
.btn {
@@ -17,6 +17,10 @@ const props = defineProps({
searchColumns: { type: Array, default: () => [] },
orderField: { type: String, default: "" },
sql: { type: String, default: "" },
keepInput: {
type: Boolean,
default: false,
},
});
// ===============================
@@ -42,12 +46,9 @@ const inputChange = ref(false); // 输入变化标记
const pagination = reactive({ page: 1, size: 10, total: 0 }); // 分页
const popperPaneRef = computed(() => popoverRef.value?.popperRef?.contentRef); // Popover 内容 DOM
const searchColumns = computed(() => [
props.labelKey,
props.valueKey,
...props.searchColumns,
]); // 搜索列
const searchColumns = computed(() => {
return [...new Set([props.labelKey, props.valueKey, ...props.searchColumns])];
});
// ===============================
// Watchers
// ===============================
@@ -76,14 +77,19 @@ function onPopoverAfterLeave() {
function onPopoverBeforeLeave() {
// 弹窗关闭前恢复或清空状态
if (props.label) {
if (innerInput.value === "") {
emits("update:label", "");
emits("update:modelValue", "");
emits("change", null);
} else {
innerInput.value = props.label;
if (!props.keepInput) {
if (props.label) {
if (innerInput.value === "") {
emits("update:label", "");
emits("update:modelValue", "");
emits("change", null);
} else {
innerInput.value = props.label;
}
}
} else {
emits("update:label", innerInput.value);
emits("update:modelValue", innerInput.value);
}
}
@@ -199,7 +205,7 @@ function _fetchOptions(searchTitle) {
: [...options.value, ...res.data.rows];
pagination.total = res.data.total;
popoverVisible.value = true
popoverVisible.value = true;
}
})
.finally(() => {
@@ -48,9 +48,9 @@ function onFullScreenChange(val) {
<el-splitter-panel>
<div class="g3-layout-right">
<Topbar
v-if="!fullScreen"
:collapse="isCollapse"
@collapse="handleCollapse"
:style="fullScreen ? { height: '0', border: 'none' } : {}"
/>
<Tab @full-screen-change="onFullScreenChange" />
<Content />
@@ -30,3 +30,7 @@
}
}
}
.el-message {
z-index: 99999 !important;
}
@@ -56,7 +56,9 @@ const viewName = "v_container";
const showPreview = ref(false);
const previewIndex = ref(-1);
const previewImageList = computed(() => {
return tableData.value.map((item) => item.b_container_img).filter((img) => img);
return tableData.value
.map((item) => item.b_container_img)
.filter((img) => img);
});
const currentRow = ref({});
@@ -189,9 +191,12 @@ async function deleteRows(rows = []) {
const safeDeleteIds = deleteIds.map((id) => Number(id));
// 使用安全的 SQL 查询
const fileRes = await loadDataApi("bf_file", `father IN (${safeDeleteIds.join(",")})`, "", [
"subid",
]);
const fileRes = await loadDataApi(
"bf_file",
`father IN (${safeDeleteIds.join(",")})`,
"",
["subid"],
);
if (!fileRes.success) {
return;
@@ -267,7 +272,11 @@ async function handleDownloadOne(data) {
});
try {
const fileRes = await loadDataApi("bf_file", `father = ${data.b_id}`, "mx_xh asc");
const fileRes = await loadDataApi(
"bf_file",
`father = ${data.b_id}`,
"mx_xh asc",
);
if (!fileRes.success) {
ElMessage.error("获取附件失败");
@@ -275,7 +284,11 @@ async function handleDownloadOne(data) {
}
const downloadFiles = fileRes.data.map((item, index) => ({
mx_filename: buildFileName(data.b_container_no, index + 1, item.mx_filename),
mx_filename: buildFileName(
data.b_container_no,
index + 1,
item.mx_filename,
),
mx_mapfilename: item.mx_mapfilename,
}));
@@ -338,7 +351,11 @@ async function handleDownloadBatch() {
// 👉 先统计总文件数(用于进度)
for (const item of records) {
const fileRes = await loadDataApi("bf_file", `father = '${item.b_id}'`, "");
const fileRes = await loadDataApi(
"bf_file",
`father = '${item.b_id}'`,
"",
);
if (fileRes.success) {
total += (fileRes.data || []).length;
}
@@ -350,7 +367,11 @@ async function handleDownloadBatch() {
const folder = zip.folder(folderName);
const fileRes = await loadDataApi("bf_file", `father = '${item.b_id}'`, "mx_xh asc");
const fileRes = await loadDataApi(
"bf_file",
`father = '${item.b_id}'`,
"mx_xh asc",
);
if (!fileRes.success) {
ElMessage.error("获取附件失败");
@@ -367,7 +388,8 @@ async function handleDownloadBatch() {
const blob = await res.blob();
const fileName =
buildFileName(item.b_container_no, index + 1, file.mx_filename) || "未命名文件";
buildFileName(item.b_container_no, index + 1, file.mx_filename) ||
"未命名文件";
folder.file(fileName, blob);
} catch (e) {
@@ -432,7 +454,15 @@ function buildFileName(containerNo, index, fileName) {
</G3GridItem>
<G3GridItem label="操作员">
<el-input v-model="searchForm.username" />
<G3Select
v-model="searchForm.username"
v-model:label="searchForm.username"
search-condition="b_id <> 'g3soft'"
view-name="b_user"
value-key="b_name"
label-key="b_name"
keep-input
/>
</G3GridItem>
</G3GridGroup>
</G3Grid>
@@ -470,7 +500,7 @@ function buildFileName(containerNo, index, fileName) {
<el-button
type="danger"
@click="handleDeleteRows"
:disabled="!permissionStore.hasActionPermission(2)"
:disabled="!permissionStore.hasActionPermission(2)"
>
<el-icon class="el-icon--left">
<G3Icon icon="lucide:trash-2" />
@@ -534,7 +564,14 @@ function buildFileName(containerNo, index, fileName) {
}"
height="100%"
>
<vxe-column field="seq" type="seq" width="50" align="center" title=" " fixed="left" />
<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"
@@ -555,7 +592,12 @@ function buildFileName(containerNo, index, fileName) {
/>
</template>
<template v-else>
{{ formatValueByFormat(row[column.col_FieldName], column.col_DisplayFormat) }}
{{
formatValueByFormat(
row[column.col_FieldName],
column.col_DisplayFormat,
)
}}
</template>
</template>
</vxe-column>
@@ -9,7 +9,11 @@ const dialogData = ref({});
const showFile = ref(false);
onMounted(async () => {
const loadRes = await loadDataApi("oa_notices", ` b_visible='1'`, "b_inputdate desc");
const loadRes = await loadDataApi(
"v_oa_notices",
` b_visible='1'`,
"b_inputdatetime desc",
);
if (loadRes.success) {
dataList.value = loadRes.data;
@@ -31,10 +35,18 @@ function handleShowDialog(data) {
</div>
</template>
<div v-for="item in dataList" class="notice-item" @click="handleShowDialog(item)">
<div
v-if="dataList.length > 0"
v-for="item in dataList"
class="notice-item"
@click="handleShowDialog(item)"
>
{{ item.b_subject }}
</div>
<el-result v-else icon="primary" title="空空如也" sub-title="快去发布公告吧">
</el-result>
<el-dialog v-model="showDialog" :title="dialogData.b_subject" :width="800">
<div class="section">
<div class="section-title">发布人</div>
@@ -45,7 +57,11 @@ function handleShowDialog(data) {
<div class="section">
<div class="section-title">发布时间</div>
<div class="section-value">
{{ formatToDateTime(dialogData.b_updatedatetime || dialogData.b_inputdatetime) }}
{{
formatToDateTime(
dialogData.b_updatedatetime || dialogData.b_inputdatetime,
)
}}
</div>
</div>
<div>
@@ -69,7 +85,12 @@ function handleShowDialog(data) {
</template>
</el-dialog>
<G3File v-model="showFile" :father="dialogData.b_id" module-id="oa_notices" readonly />
<G3File
v-model="showFile"
:father="dialogData.b_id"
module-id="oa_notices"
readonly
/>
</el-card>
</template>
@@ -1,30 +0,0 @@
<script setup lang="js">
import { saveAs } from "file-saver";
import JSZip from "jszip";
// 假设这些是文件数据和它们的路径
const files = [
{ name: "file1.txt", folder: "folder1", content: "This is file 1 content" },
{ name: "file2.txt", folder: "folder2", content: "This is file 2 content" },
{ name: "file3.txt", folder: "folder1", content: "This is file 3 content" },
{ name: "file4.txt", folder: "folder3", content: "This is file 4 content" },
];
async function createZip() {
const zip = new JSZip();
// 遍历文件列表,将文件按文件夹添加到 ZIP 文件中
files.forEach((file) => {
// 创建文件夹并将文件添加到对应的文件夹下
zip.folder(file.folder).file(file.name, file.content);
});
// 生成并下载 ZIP 文件
const content = await zip.generateAsync({ type: "blob" });
saveAs(content, "files.zip");
}
</script>
<template>
<el-button @click="createZip">测试</el-button>
</template>
@@ -2,7 +2,12 @@
import { ElMessage, ElMessageBox } from "element-plus";
import EditDrawer from "./edit-drawer.vue";
import CategoryDialog from "./category-dialog.vue";
import { loadDataBySqlApi, saveObjectApi } from "@/request/api";
import {
loadDataApi,
loadDataBySqlApi,
loadPageDataApi,
saveObjectApi,
} from "@/request/api";
const tableRef = ref(null);
@@ -15,7 +20,7 @@ const columnData = ref([
{ prop: "v_inputuser_name", label: "发布人", width: 120 },
{ prop: "b_inputdate", label: "发布日期", width: 140 },
]);
const treeId = ref("");
const treeId = ref(-1);
const tableData = ref([]);
const loading = reactive({
table: false,
@@ -24,12 +29,27 @@ const loading = reactive({
error: "",
});
const searchForm = ref({
username: "",
subject: "",
});
const pagination = reactive({
page: 0,
size: 20,
total: 0,
});
const defaultProps = {
children: "children",
label: "label",
isLeaf: "leaf",
};
onMounted(() => {
loadTableDatas();
});
async function handleNodeClick(node) {
if (!node.id) {
return;
@@ -122,7 +142,8 @@ async function handleEditRow(row) {
function handleEditChange() {
drawerVisible.value = false;
loadNodeData(treeId.value, "10");
// loadNodeData(treeId.value, "10");
loadTableDatas();
}
function handleEditClosed() {
@@ -130,6 +151,58 @@ function handleEditClosed() {
}
// -----------------------------------
function loadTableDatas() {
loading.table = true;
let searchCondition = "";
if (searchForm.value.subject) {
searchCondition += `b_subject LIKE '%${searchForm.value.subject}%' AND `;
}
if (searchForm.value.username) {
searchCondition += `v_inputuser_name LIKE '%${searchForm.value.username}%' AND `;
}
if (searchCondition.endsWith(" AND ")) {
searchCondition = searchCondition.slice(0, -4);
}
loadPageDataApi({
viewName: "v_oa_notices",
page: pagination.page,
size: pagination.size,
orderField: "b_updatedatetime desc",
searchCondition,
})
.then((res) => {
if (res.success) {
tableData.value = res.data.rows;
pagination.total = res.data.total;
}
})
.finally(() => {
loading.table = false;
});
}
const handleSizeChange = (val) => {
pagination.size = val;
loadTableDatas();
};
const handleCurrentChange = (val) => {
pagination.page = val;
loadTableDatas();
};
function handleSearch() {
pagination.page = 1;
loadTableDatas();
}
// 删除单行
async function handleDeleteRow(row) {
if (!row) return;
@@ -182,7 +255,8 @@ async function deleteRows(rows = []) {
if (res.success) {
ElMessage.success("删除成功");
loadNodeData(treeId.value, "10");
// loadNodeData(treeId.value, "10");
loadTableDatas()
}
});
}
@@ -190,16 +264,16 @@ async function deleteRows(rows = []) {
<template>
<div class="g3-flex-container">
<div class="g3-header">
<!-- <div class="g3-header">
<el-button type="primary" @click="showCategory = true">
<el-icon class="el-icon--left">
<G3Icon icon="lucide:settings" />
</el-icon>
分类设置
</el-button>
</div>
</div> -->
<div class="g3-container">
<el-splitter>
<!-- <el-splitter>
<el-splitter-panel size="220">
<div class="g3-container-left">
<div class="g3-title">
@@ -217,104 +291,150 @@ async function deleteRows(rows = []) {
@node-click="handleNodeClick"
/>
</div>
</el-splitter-panel>
</el-splitter-panel> -->
<el-splitter-panel>
<div class="g3-container-right">
<div style="width: 100%">
<div style="display: flex; height: 32px; margin-bottom: 8px">
<el-button type="primary" @click="handleAdd">
<el-icon class="el-icon--left">
<G3Icon icon="lucide:plus" />
</el-icon>
新增
</el-button>
<el-button type="danger" @click="handleDeleteRows">
<el-icon class="el-icon--left">
<G3Icon icon="lucide:trash-2" />
</el-icon>
批量删除
</el-button>
</div>
</div>
<div class="g3-table">
<vxe-table
ref="tableRef"
border
stripe
header-align="center"
:data="tableData"
:sort-config="{
// showIcon: false,
trigger: 'cell',
}"
:filter-config="{
showIcon: false,
}"
:column-drag-config="{
showIcon: false,
trigger: 'cell',
}"
:row-config="{
useKey: true,
keyField: 'b_id',
isCurrent: true,
isHover: true,
}"
:column-config="{
resizable: true,
drag: true,
}"
show-overflow
show-header-overflow
height="100%"
>
<vxe-column type="checkbox" width="50" align="center" />
<vxe-column
v-for="column in columnData"
:key="column.prop"
:field="column.prop"
:title="column.label"
:width="column.width"
sortable
>
<template #default="{ row }">
<template v-if="['b_visible'].includes(column.prop)">
<el-checkbox
v-model="row[column.prop]"
disabled
true-value="1"
false-value="0"
@change="handleCheckChange(row, column.prop)"
/>
</template>
<template v-else>
{{ row[column.prop] }}
</template>
</template>
</vxe-column>
<vxe-column
width="200"
align="center"
fixed="right"
title="操作"
>
<template #default="{ row }">
<el-button type="primary" link @click="handleEditRow(row)">
编辑
</el-button>
<el-button type="danger" link @click="handleDeleteRow(row)">
删除
</el-button>
</template>
</vxe-column>
</vxe-table>
</div>
<!-- <el-splitter-panel> -->
<div class="g3-container-right">
<div
style="
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 8px;
"
>
<div style="display: flex">
<el-button type="primary" @click="handleAdd">
<el-icon class="el-icon--left">
<G3Icon icon="lucide:plus" />
</el-icon>
新增
</el-button>
<el-button type="danger" @click="handleDeleteRows">
<el-icon class="el-icon--left">
<G3Icon icon="lucide:trash-2" />
</el-icon>
批量删除
</el-button>
</div>
</el-splitter-panel>
</el-splitter>
<div style="display: flex; align-items: center">
<G3Grid style="width: 400px">
<G3GridGroup :label-width="60" :column="2">
<G3GridItem label="主题">
<el-input v-model="searchForm.subject" />
</G3GridItem>
<G3GridItem label="发布人">
<G3Select
v-model="searchForm.username"
v-model:label="searchForm.username"
search-condition="b_id <> 'g3soft'"
view-name="b_user"
value-key="b_name"
label-key="b_name"
keep-input
/>
</G3GridItem>
</G3GridGroup>
</G3Grid>
<el-button
type="primary"
style="margin-left: 8px"
@click="handleSearch"
>
<el-icon class="el-icon--left">
<G3Icon icon="lucide:search" />
</el-icon>
搜索
</el-button>
</div>
</div>
<div class="g3-table">
<vxe-table
ref="tableRef"
border
stripe
header-align="center"
:data="tableData"
:sort-config="{
// showIcon: false,
trigger: 'cell',
}"
:filter-config="{
showIcon: false,
}"
:column-drag-config="{
showIcon: false,
trigger: 'cell',
}"
:row-config="{
useKey: true,
keyField: 'b_id',
isCurrent: true,
isHover: true,
}"
:column-config="{
resizable: true,
drag: true,
}"
show-overflow
show-header-overflow
height="100%"
>
<vxe-column type="checkbox" width="50" align="center" />
<vxe-column
v-for="column in columnData"
:key="column.prop"
:field="column.prop"
:title="column.label"
:width="column.width"
sortable
>
<template #default="{ row }">
<template v-if="['b_visible'].includes(column.prop)">
<el-checkbox
v-model="row[column.prop]"
disabled
true-value="1"
false-value="0"
@change="handleCheckChange(row, column.prop)"
/>
</template>
<template v-else>
{{ row[column.prop] }}
</template>
</template>
</vxe-column>
<vxe-column width="200" align="center" fixed="right" title="操作">
<template #default="{ row }">
<el-button type="primary" link @click="handleEditRow(row)">
编辑
</el-button>
<el-button type="danger" link @click="handleDeleteRow(row)">
删除
</el-button>
</template>
</vxe-column>
</vxe-table>
</div>
<div class="g3-pagination">
<el-pagination
v-model:current-page="pagination.page"
v-model:page-size="pagination.size"
:page-sizes="[20, 50, 100, 200]"
layout="total, sizes, prev, pager, next, jumper"
:total="pagination.total"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</div>
</div>
<!-- </el-splitter-panel> -->
<!-- </el-splitter> -->
</div>
<EditDrawer
@@ -390,6 +510,15 @@ async function deleteRows(rows = []) {
min-height: 0;
}
.g3-pagination {
margin-top: 8px;
display: flex;
align-items: center;
justify-content: flex-end;
flex-shrink: 0;
min-height: 0;
}
.g3-footer {
padding-top: 8px;
display: flex;