20260808172946

This commit is contained in:
oneao committed 2026-08-08 17:29:51 +08:00
1 parent 4fbfea82f2
commit d72ca4193d
293 files changed
+37523 -73467

No files matched your search

@@ -0,0 +1,66 @@
<template>
<!-- UPDATE -->
<el-table
v-if="data.action === 'UPDATE'"
:data="data.diffs"
size="small"
border
show-header
class="diff-table"
>
<el-table-column prop="field" label="字段" width="200" />
<el-table-column label="旧值">
<template #default="{ row }">
<span class="old-value">
{{ row.old == null ? "" : row.old }}
</span>
</template>
</el-table-column>
<el-table-column label="新值">
<template #default="{ row }">
<span class="new-value">
{{ row.new == null ? "" : row.new }}
</span>
</template>
</el-table-column>
</el-table>
<!-- INSERT / DELETE -->
<el-descriptions v-else :column="2" border size="small" class="snapshot">
<el-descriptions-item
v-for="(val, key) in data.values"
:key="key"
:label="key"
>
{{ val == null ? "" : val }}
</el-descriptions-item>
</el-descriptions>
</template>
<script setup>
const props = defineProps({
data: {
type: Object,
required: true,
},
});
</script>
<style scoped>
.diff-table {
margin-top: 6px;
}
.old-value {
color: #f56c6c;
text-decoration: line-through;
}
.new-value {
color: #67c23a;
}
.snapshot {
margin-top: 6px;
}
</style>
@@ -0,0 +1,256 @@
<template>
<el-dialog
v-model="visible"
title="变更详情"
width="920px"
@close="onClose"
>
<div class="timeline" v-loading="loading">
<div
v-for="(item, index) in logList"
:key="index"
class="timeline-item"
>
<!-- 左侧圆点 + 竖线 -->
<div class="timeline-left">
<div class="dot" :class="dotClass(item.action)"></div>
<div
class="line"
v-if="index < logList.length - 1"
></div>
</div>
<!-- 右侧内容 -->
<div class="timeline-right">
<!-- 摘要行 -->
<div class="summary">
<span class="time">{{ formatTime(item.operateTime) }}</span>
<el-tag :type="tagType(item.action)" size="small">
{{ item.action }}
</el-tag>
<span class="operator">{{ item.operator }}</span>
<span class="table">{{ item.table }}</span>
<span class="row-id">ID: {{ item.rowId }}</span>
</div>
<!-- 展开/折叠 diff -->
<div class="diff-wrapper">
<AuditLogDetail :data="item" />
</div>
</div>
</div>
</div>
<el-empty
v-if="!loading && logList.length === 0"
description="暂无变更记录"
/>
</el-dialog>
</template>
<script setup>
import { ref, watch } from "vue";
import { ElMessage } from "element-plus";
import axios from "@/utils/axios";
import AuditLogDetail from "./AuditLogDetail.vue";
const props = defineProps({
modelValue: Boolean,
bizNo: String, // ✅ 业务单据号(loggroupid)
});
const emit = defineEmits(["update:modelValue"]);
const visible = ref(false);
const loading = ref(false);
const logList = ref([]);
watch(
() => props.modelValue,
(val) => {
visible.value = val;
if (val) {
loadLog();
}
}
);
watch(visible, (val) => {
emit("update:modelValue", val);
});
const loadLog = async () => {
if (!props.bizNo) {
ElMessage.warning("bizNo 不能为空");
return;
}
loading.value = true;
try {
const response = await axios.get("/logdetail", {
params: {
bizNo: props.bizNo,
},
});
const result = response.data;
if (!result?.data || result.data.length === 0) {
logList.value = [];
return;
}
const parsedList = [];
for (const raw of result.data) {
try {
const changeData =
typeof raw.changeData === "string"
? JSON.parse(raw.changeData)
: raw.changeData;
changeData.table = changeData.table || raw.tableName;
changeData.operator = changeData.operator || raw.operator;
changeData.operateTime =
changeData.operateTime || raw.operateTime;
parsedList.push(changeData);
} catch (e) {
console.error("changeData 解析失败", e);
}
}
logList.value = parsedList;
} catch (e) {
console.error(e);
ElMessage.error("加载变更日志失败");
} finally {
loading.value = false;
}
};
const onClose = () => {
logList.value = [];
};
const tagType = (action) => {
switch (action) {
case "INSERT":
return "success";
case "UPDATE":
return "primary";
case "DELETE":
return "danger";
default:
return "info";
}
};
const dotClass = (action) => {
switch (action) {
case "INSERT":
return "dot-green";
case "UPDATE":
return "dot-blue";
case "DELETE":
return "dot-red";
default:
return "dot-gray";
}
};
const formatTime = (time) => {
if (!time) return "";
if (typeof time === "string" && time.includes("T")) {
return time.replace("T", " ").split(".")[0];
}
return time;
};
</script>
<style scoped>
.timeline {
padding: 8px 0;
}
.timeline-item {
display: flex;
align-items: flex-start;
}
.timeline-left {
width: 24px;
display: flex;
flex-direction: column;
align-items: center;
margin-right: 12px;
}
.dot {
width: 12px;
height: 12px;
border-radius: 50%;
margin-top: 6px;
flex-shrink: 0;
}
.dot-green {
background-color: #67c23a;
}
.dot-blue {
background-color: #409eff;
}
.dot-red {
background-color: #f56c6c;
}
.dot-gray {
background-color: #909399;
}
.line {
width: 2px;
flex: 1;
background-color: #e4e7ed;
margin-top: 4px;
min-height: 24px;
}
.timeline-right {
flex: 1;
padding-bottom: 16px;
}
.summary {
display: flex;
align-items: center;
gap: 10px;
font-size: 13px;
color: #606266;
}
.summary .time {
font-weight: bold;
color: #303133;
}
.summary .operator {
color: #409eff;
}
.summary .table {
font-weight: bold;
}
.summary .row-id {
color: #909399;
}
.diff-wrapper {
background-color: #fafafa;
border-radius: 4px;
padding: 8px 12px;
margin-top: 6px;
}
</style>
@@ -1,184 +0,0 @@
<script lang="js" setup>
import dayjs from "dayjs";
import { ElMessage } from "element-plus";
import { computed, ref } from "vue";
import { useUserStore } from "@/store/user.js";
import axios from "@/utils/axios";
import { getTableBatchEditColumns } from "@/utils/dodata";
import G3EditField from "../table/G3EditField.vue";
const props = defineProps({
viewname: {
type: String,
required: true,
},
tablename: {
type: String,
required: true,
},
keyField: {
type: String,
default: "b_id",
},
selectedValue: {
type: Array,
required: false,
default: () => [],
},
// 选中全部,该属性留着备用修改表中的全部数据(不用单指选中的数据)
checkedAll: {
type: Boolean,
default: false,
},
});
const userStore = useUserStore();
const _visible = defineModel(false);
const disabledConfirm = computed(() => !(props.checkedAll || props.selectedValue.length > 0));
const loading = ref(true);
const tablename = ref("");
const columns = ref([]);
const selectedField = ref(null);
const selectedFieldName = ref(null);
const inputValue = ref("");
async function onOpened() {
loading.value = true;
if (props.viewname === "" || props.tablename === "") {
ElMessage.warning("必传参数不能为空");
return;
}
const result = await getTableBatchEditColumns(props.viewname);
if (result.success) {
columns.value = result.data;
if (columns.value.length > 0) {
selectedFieldName.value = columns.value[0].col_FieldName;
selectedField.value = columns.value[0];
}
loading.value = false;
} else {
ElMessage.error(`加载失败: ${result.error}`);
}
}
async function onClosed() {
loading.value = true;
tablename.value = "";
columns.value = [];
selectedField.value = null;
selectedFieldName.value = null;
inputValue.value = "";
}
function onFieldChange() {
inputValue.value = "";
selectedField.value = columns.value.find(
(item) => item.col_FieldName === selectedFieldName.value,
);
}
async function handleConfirm() {
if (selectedField.value.col_AllowNull !== "1" && inputValue.value === "") {
ElMessage.warning("请输入更新值");
return;
}
const updateRows = props.selectedValue.map((item) => {
return item[props.keyField];
});
const columnsData = {
[selectedFieldName.value]: inputValue.value,
b_updateuser_id: userStore.userInfo.userid,
b_updatedatetime: dayjs().format("YYYY-MM-DD HH:mm:ss"),
};
const requestData = {
tableName: props.tablename,
keyField: props.keyField,
updateRows,
columns: columnsData,
};
try {
const response = await axios.post("/batchUpdate", requestData, {
headers: { "Content-Type": "application/json" },
});
if (response.data?.success) {
ElMessage.success("保存成功");
maintableorigina.value = { ...maintable.value };
} else {
throw new Error(response.data?.message || "保存失败");
}
} catch (error) {
// Catch network or server errors
console.error("Request failed:", error);
ElMessage.error(error.message || "请求失败,请稍后再试");
}
}
</script>
<template>
<el-dialog
v-model="_visible"
title="批量更新"
width="500"
v-bind="$attrs"
@opened="onOpened"
@closed="onClosed"
>
<div v-loading="loading" class="g3-container">
<el-select
v-model="selectedFieldName"
placeholder="请选择需要修改的列"
style="width: 100px"
@change="onFieldChange"
>
<el-option
v-for="item in columns"
:key="item.col_FieldName"
:label="item.col_Caption"
:value="item.col_FieldName"
/>
</el-select>
<el-divider direction="vertical" />
<G3EditField
v-model="inputValue"
:field="selectedField"
placeholder="请输入需要修改的值"
style="flex: 1"
/>
</div>
<template #footer>
<div class="dialog-footer">
<el-button @click="_visible = false"> 取消 </el-button>
<el-button
type="primary"
:disabled="disabledConfirm"
:loading="loading"
@click="handleConfirm"
>
确认
</el-button>
</div>
</template>
</el-dialog>
</template>
<style lang="css" scoped>
.g3-container {
display: flex;
gap: 16px;
align-items: center;
height: 60px;
}
</style>
@@ -0,0 +1,43 @@
import { app } from "@/main";
import { createVNode, render, ref } from "vue";
import BatchUpdate from './index.vue'
import { ElMessage } from "element-plus";
export function showbatchupdate(viewname, tablename, keyfield, rows) {
if (!rows || rows.length === 0) {
ElMessage.warning("请选择操作行");
return;
}
const container = document.createElement("div");
document.body.appendChild(container);
const visible = ref(true);
const vnode = createVNode(BatchUpdate, {
viewname,
tablename,
keyfield,
rows,
modelValue: visible.value,
"onUpdate:modelValue": (val) => {
visible.value = val;
if (!val) {
render(null, container);
container.remove();
}
},
onClose() {
render(null, container);
container.remove();
},
});
vnode.appContext = app._context;
render(vnode, container);
}
@@ -0,0 +1,257 @@
<script setup>
import { ElMessage } from "element-plus";
import { computed, ref } from "vue";
import { getTableBatchEditColumns } from "@/utils/dodata";
import G3DatePicker from "@/components/g3-date-picker/G3DatePicker.vue";
import G3DateTimePicker from "@/components/g3-date-picker/G3DateTimePicker.vue";
import g3Select from "@/components/g3Select.vue";
import G3Memo from "@/components/g3Memo.vue";
import G3Number from "@/components/g3Number.vue";
import { saveobjtApi } from "@/utils/doSql";
const props = defineProps({
viewname: {
type: String,
required: true,
},
tablename: {
type: String,
required: true,
},
keyfield: {
type: String,
default: "b_id",
},
rows: {
type: Array,
required: false,
default: () => [],
},
});
const _visible = defineModel(false);
const disabledConfirm = computed(() => !(props.rows.length > 0));
const loading = ref(true);
const tablename = ref("");
const columns = ref([]);
const selectedField = ref(null);
const selectedFieldName = ref(null);
const inputId = ref("");
const inputValue = ref("");
async function onOpened() {
loading.value = true;
if (props.viewname === "" || props.tablename === "") {
ElMessage.warning("必传参数不能为空");
return;
}
const result = await getTableBatchEditColumns(props.viewname);
if (result.success) {
columns.value = result.data;
if (columns.value.length > 0) {
selectedFieldName.value = columns.value[0].col_FieldName;
selectedField.value = columns.value[0];
console.log(selectedField.value);
}
loading.value = false;
} else {
ElMessage.error(`加载失败: ${result.error}`);
}
}
async function onClosed() {
loading.value = true;
tablename.value = "";
columns.value = [];
selectedField.value = null;
selectedFieldName.value = null;
inputValue.value = "";
inputId.value = "";
}
function onFieldChange() {
inputValue.value = "";
selectedField.value = columns.value.find(
(item) => item.col_FieldName === selectedFieldName.value
);
}
async function handleConfirm() {
try {
if (selectedField.value.col_AllowNull !== "1" && inputValue.value === "") {
ElMessage.warning("请输入更新值");
return;
}
let columnsData = {
[selectedFieldName.value]: inputValue.value,
};
if (selectedField.value.col_edit_type === "selectid") {
columnsData = {
...columnsData,
[selectedField.value.col_Field_id]: inputId.value,
};
}
let updaterows = [];
props.rows.forEach((row) => {
let columnsData = {
[props.keyfield]: row[props.keyfield],
[selectedFieldName.value]: inputValue.value,
};
if (selectedField.value.col_edit_type === "selectid") {
columnsData = {
...columnsData,
[selectedField.value.col_Field_id]: inputId.value,
};
}
updaterows.push(columnsData);
});
if (updaterows.length === 0) {
ElMessage.warning("无有效数据可更新");
return;
}
let requestData = [
{
tableName: props.tablename,
keyField: props.keyfield,
inserts: [],
updates: updaterows,
deletes: [],
},
];
saveobjtApi(requestData);
ElMessage.success("更新成功");
} catch (error) {
console.log(error);
ElMessage.error(`更新失败:${error.message || "未知错误"}`);
}
}
function handleCancel() {
_visible.value = false;
}
</script>
<template>
<el-dialog
v-model="_visible"
title="批量更新"
width="500"
v-bind="$attrs"
@opened="onOpened"
@closed="onClosed"
>
<div v-loading="loading" class="g3-container">
<el-select
v-model="selectedFieldName"
placeholder="请选择需要修改的列"
style="width: 100px"
@change="onFieldChange"
>
<el-option
v-for="item in columns"
:key="item.col_FieldName"
:label="item.col_Caption"
:value="item.col_FieldName"
/>
</el-select>
<el-divider direction="vertical" />
<!-- <G3EditField
v-model="inputValue"
:field="selectedField"
placeholder="请输入需要修改的值"
style="flex: 1"
/> -->
<div v-if="selectedField" style="flex: 1; min-height: 0">
<template v-if="selectedField.col_edit_type === 'selectid'">
<g3Select
v-model="inputValue"
v-model:model-id="inputId"
:query-params="{ dataset: selectedField.col_edit_source_table }"
:mustmatch="true"
:pycode="selectedField.pycode"
/>
</template>
<template v-else-if="selectedField.col_edit_type === 'selectname'">
<g3Select
v-model="inputValue"
:query-params="{ dataset: selectedField.col_edit_source_table }"
:in-table="true"
:mustmatch="true"
/>
</template>
<template v-else-if="selectedField.col_edit_type === 'checkbox'">
<el-checkbox
v-model="inputValue"
true-value="1"
false-value="0"
size="large"
/>
</template>
<template v-else-if="selectedField.col_edit_type === 'datetime'">
<G3DateTimePicker v-model="inputValue" />
</template>
<template v-else-if="selectedField.col_edit_type === 'date'">
<G3DatePicker v-model="inputValue" />
</template>
<template v-else-if="selectedField.col_edit_type === 'g3memo'">
<G3Memo v-model="inputValue" />
</template>
<template v-else-if="selectedField.col_edit_type === 'g3Number'">
<G3Number v-model="inputValue" size="small" />
</template>
<template v-else>
<el-input v-model="inputValue" size="small" />
</template>
</div>
</div>
<template #footer>
<div class="dialog-footer">
<el-button @click="handleCancel"> 取消 </el-button>
<el-button
type="primary"
:disabled="disabledConfirm"
:loading="loading"
@click="handleConfirm"
>
确认
</el-button>
</div>
</template>
</el-dialog>
</template>
<style lang="scss" scoped>
.g3-container {
display: flex;
gap: 16px;
align-items: center;
height: 60px;
::deep(.g3-input) {
height: 32px;
}
}
</style>
@@ -35,7 +35,7 @@ import {
import { computed, nextTick, ref, watch } from "vue";
import { useUserStore } from "@/store/user";
import axios from "@/utils/axios";
import { compareAndClassifyData } from "@/utils/dataDiffUtils";
import { compareAndClassifyData, diffData } from "@/utils/dataDiffUtils";
import {
compressImage,
deleteFileApi,
@@ -45,6 +45,7 @@ import {
getFileExtension,
uploadFile,
} from "@/utils/file";
import { loaddataApi } from "@/utils/doSql";
import G3Icon from "@/components/g3-icon/index.vue";
import { VxeTable, VxeColumn } from "vxe-table";
@@ -81,6 +82,34 @@ const displayMode = ref(0);
const userStore = useUserStore();
// 根据 moduleid 查询主表状态,自动判断是否可编辑
const editable = ref(true);
const isReadonly = computed(() => props.readonly || !editable.value);
async function loadEditableStatus() {
try {
const modules = await loaddataApi("s_module", `b_id = '${props.moduleid}'`);
if (!modules?.length) {
editable.value = true;
return;
}
const saveTable = modules[0].b_SaveTable;
if (!saveTable) {
editable.value = true;
return;
}
const records = await loaddataApi(saveTable, `b_id = '${props.father}'`);
if (!records?.length) {
editable.value = true;
return;
}
const state = records[0].b_state;
editable.value = ["草拟", "审核驳回"].includes(state) || !state;
} catch {
editable.value = true;
}
}
const containerRef = ref(null);
const fileInputRef = ref(null);
@@ -234,6 +263,7 @@ watch(
function onOpened() {
loadFiles();
loadEditableStatus();
}
async function loadFiles() {
@@ -291,7 +321,7 @@ function formatTime(date) {
}
// 手动上传
function handleClickUpload() {
if (props.readonly) {
if (isReadonly.value) {
return;
}
fileInputRef.value.click();
@@ -306,7 +336,7 @@ function handleFileInputChange(event) {
}
function handlePaste(e) {
if (props.readonly) {
if (isReadonly.value) {
return;
}
@@ -335,10 +365,9 @@ function handleDrop(e) {
e.preventDefault();
e.stopPropagation();
if (props.readonly) {
if (isReadonly.value) {
return;
}
const files = e.dataTransfer.files;
// 过滤掉文件夹,只处理文件
@@ -570,6 +599,13 @@ function handleBatchDelete() {
}
async function deleteFiles(files) {
await loadEditableStatus();
if (isReadonly.value) {
ElMessage.warning("当前单据已审核,不允许删除附件");
loadFiles();
return;
}
// 收集文件的 mx_filename
const filenames = files.map((file) => file.mx_filename).join(", ");
@@ -608,24 +644,31 @@ async function deleteFiles(files) {
}).then((action) => {
if (action === "confirm") {
loadFiles();
loadEditableStatus();
}
});
}
// 保存
async function handleSave() {
await loadEditableStatus();
if (isReadonly.value) {
ElMessage.warning("当前单据已审核,不允许上传附件");
loadFiles();
return;
}
loading.value = true;
loadingTip.value = "正在保存中 . . .";
const { insertdata, updatedata, deletedata, hasChanges } = compareAndClassifyData(
fileList.value,
oldFileList.value,
"subid",
["_content", "_status", "checked"],
);
const data = compareAndClassifyData(fileList.value, oldFileList.value, "subid", [
"_content",
"_status",
"checked",
]);
// 处理新增的文件
for (const item of insertdata) {
for (const item of data.inserts) {
try {
await uploadFile(
item._content,
@@ -649,6 +692,7 @@ async function handleSave() {
loading.value = false;
loadFiles();
loadEditableStatus();
}
async function handleDownloadZip() {
@@ -709,7 +753,7 @@ function handleTreeNodeClick(data) {
<div class="g3-title">
附件管理({{ fileList.length }})
<template v-if="!props.readonly"> 未上传 ({{ pendingFileList.length }}) </template>
<template v-if="!isReadonly"> 未上传 ({{ pendingFileList.length }}) </template>
</div>
</template>
<input
@@ -753,7 +797,7 @@ function handleTreeNodeClick(data) {
</el-button>
<el-button
v-if="!props.readonly"
v-if="!isReadonly"
size="small"
type="danger"
:disabled="checkedFiles.length === 0 || loading"
@@ -840,7 +884,7 @@ function handleTreeNodeClick(data) {
</div>
<div class="g3-file-actions">
<el-button
v-if="!props.readonly"
v-if="!isReadonly"
type="danger"
:icon="Delete"
size="small"
@@ -854,7 +898,7 @@ function handleTreeNodeClick(data) {
circle
@click.stop="handleDownloadFile(file)"
/>
<el-dropdown v-if="!props.readonly" placement="top" trigger="click">
<el-dropdown v-if="!isReadonly" placement="top" trigger="click">
<el-button
type="info"
:icon="More"
@@ -936,7 +980,7 @@ function handleTreeNodeClick(data) {
<template #default="{ row }">
<div style="display: flex; align-items: center; justify-content: center">
<el-button
v-if="!props.readonly"
v-if="!isReadonly"
type="danger"
link
@click.stop="handleDeleteOne(row)"
@@ -946,7 +990,7 @@ function handleTreeNodeClick(data) {
<el-button type="primary" link @click.stop="handleDownloadFile(row)">
下载
</el-button>
<el-dropdown v-if="!props.readonly" placement="top" trigger="click">
<el-dropdown v-if="!isReadonly" placement="top" trigger="click">
<el-button type="info" link style="margin-left: 12px"> 更多 </el-button>
<el-icon class="el-icon--right">
<ArrowDown />
@@ -969,7 +1013,7 @@ function handleTreeNodeClick(data) {
</div>
</div>
<template v-if="!props.readonly" #footer>
<template v-if="!isReadonly" #footer>
<el-button type="primary" :icon="HelpFilled" :disabled="loading" @click="handleClickUpload">
选择
</el-button>
@@ -0,0 +1,44 @@
import { createVNode, render } from "vue";
import { app } from "@/main";
import G3SelectDlg from "../g3SelectDlg.vue";
export function showselectdlg(options = {}) {
const container = document.createElement("div");
document.body.appendChild(container);
const vnode = createVNode(G3SelectDlg, {
...options,
visible: true,
"onUpdate:visible"(val) {
if (!val) {
render(null, container);
container.remove();
}
},
onConfirm(data) {
options.onConfirm?.(data);
render(null, container);
container.remove();
},
onClose() {
render(null, container);
container.remove();
},
});
vnode.appContext = app._context;
render(vnode, container);
return {
close() {
render(null, container);
container.remove();
},
};
}
+13 -3
View File
@@ -4,6 +4,7 @@ import G3DatePicker from "@/components/g3-date-picker/G3DatePicker.vue";
import G3DateTimePicker from "@/components/g3-date-picker/G3DateTimePicker.vue";
import G3Select from "@/components/g3Select.vue";
import G3Memo from "@/components/g3Memo.vue";
import G3Number from "@/components/g3Number.vue";
const props = defineProps({
label: { type: String, required: true },
@@ -17,6 +18,7 @@ const props = defineProps({
required: { type: Boolean, default: false },
readonly: { type: Boolean, default: false },
maxlength: { type: Number, default: 1000 },
field: { type: String, default: "" },
});
const emit = defineEmits(["update:modelValue", "update:modelId", "select"]);
@@ -27,7 +29,7 @@ function onInput(val) {
</script>
<template>
<div class="g3field">
<div class="g3field" :field="props.field">
<!-- 标签 -->
<div class="label">
<span v-if="required" class="req">*</span>
@@ -81,11 +83,19 @@ function onInput(val) {
v-else-if="type === 'checkbox'"
class="g3checkbox"
type="checkbox"
:checked="modelValue == 1"
:checked="String(modelValue) === '1'"
:disabled="disabled"
:readonly="readonly"
@change="onInput($event.target.checked ? 1 : 0)"
@change="onInput($event.target.checked ? '1' : '0')"
/>
<G3Number
v-else-if="type === 'g3Number'"
:model-value="modelValue"
:disabled="disabled"
:readonly="readonly"
@update:model-value="emit('update:modelValue', $event)"
/>
<G3Memo
v-else-if="type === 'g3memo'"
:model-value="modelValue"
@@ -0,0 +1,256 @@
<script setup>
import { nextTick, ref, watch } from "vue";
import G3Field from "@/components/g3Field.vue";
import g3OtherCompanyType from "@/components/other/g3OtherCompanyType.vue";
import { getDataBySql } from "@/utils/doSql";
const props = defineProps({
modelValue: {
type: Object,
default: () => ({}),
},
viewtable: { type: String, required: true },
groupName: {
type: String,
default: "",
},
showGroupTitle: {
type: Boolean,
default: false,
},
leftBgColor: {
type: String,
default: "#f1b408",
},
});
const emit = defineEmits(["update:modelValue", "select", "field-input"]);
// 更新字段
function updateFields(fields) {
// console.log(fields);
emit("update:modelValue", {
...props.modelValue,
...fields,
});
console.log("===1===");
}
// function updateField(prop, value) {
// emit("update:modelValue", {
// ...props.modelValue,
// [prop]: value,
// });
// }
function getFieldType(column) {
if (column.edit_type === "selectid") {
return "select";
}
if (column.edit_type === "selectname") {
return "select";
}
if (column.edit_type === "calculate") {
return "input";
}
return column.edit_type || "input";
}
function getFieldProps(column) {
return {
field: column.prop,
disabled: String(column.readOnly) === "1",
required: String(column.allowNull) !== "1",
class: column.edit_type === "textarea" ? "fieldremark" : "",
};
}
const handleSelect = (column, val) => {
if (column.edit_type === "selectid") {
updateFields({
[column.prop]: val?.b_name || "",
[column.field_id]: val?.b_id || "",
});
}
console.log(column);
console.log(val);
emit("select", {
column,
value: val,
});
};
const columns = ref([]);
watch(
() => [props.viewtable, props.groupName],
async ([table, group]) => {
if (!table) return;
columns.value = [];
await addColumns(table, group);
},
{ immediate: true },
);
async function addColumns(viwetable, groupName) {
try {
let sql = `SELECT col_FieldName as prop,col_Field_id as field_id, col_Caption as label, col_Width as width, col_edit_type as edit_type,col_edit_width as edit_width,col_ReadOnly as readOnly,col_AllowNull as allowNull,col_edit_source_table as edit_source_table,col_edit_height as edit_height,col_DisplayFormat as displayFormat,col_edit_pycode as pycode FROM s_columnLib WHERE col_TableName = '${viwetable}' and col_edit= '1' `;
if (groupName !== null && groupName !== undefined && groupName !== "") {
sql += ` AND col_edit_grouping='${groupName}'`;
}
sql += ` ORDER BY col_edit_position`;
let datas = await getDataBySql(sql);
if (!datas.records || datas.records.length === 0) {
ElMessage.warning("返回数据格式异常");
return;
}
columns.value = datas.records;
} catch (err) {
console.log(err);
ElMessage.warning(err.message || "加载列配置失败");
}
}
</script>
<template>
<div :class="props.showGroupTitle ? 'g3group' : ''">
<div
v-if="props.showGroupTitle"
class="g3grouptitle"
:style="{ backgroundColor: props.leftBgColor }"
>
<span v-for="(char, index) in props.groupName" :key="index">
{{ char }}
</span>
</div>
<div class="g3panel" :class="{ g3marginleft15: props.showGroupTitle }">
<template v-for="column in columns" :key="column.prop">
<template v-if="column.edit_type === 'selectid'">
<G3Field
:model-value="modelValue[column.prop]"
:model-id="modelValue[column.field_id]"
@update:model-value="
updateFields({
[column.prop]: $event,
})
"
@update:model-id="
updateFields({
[column.field_id]: $event,
})
"
:label="column.label"
:type="getFieldType(column)"
:pycode="column.pycode == 'true'"
:mustmatch="true"
:query-params="{ dataset: column.edit_source_table }"
v-bind="getFieldProps(column)"
@select="handleSelect(column, $event)"
/>
</template>
<template v-else-if="column.edit_type === 'selectname'">
<G3Field
:model-value="modelValue[column.prop]"
@update:model-value="
updateFields({
[column.prop]: $event,
})
"
:label="column.label"
:type="getFieldType(column)"
:query-params="{ dataset: column.edit_source_table }"
v-bind="getFieldProps(column)"
@select="handleSelect(column, $event)"
/>
</template>
<template v-else-if="column.edit_type === 'othercompanytype'">
<g3OtherCompanyType
:model-value="modelValue[column.prop]"
:label="column.label"
@update:model-value="
updateFields({
[column.prop]: $event,
})
"
v-bind="getFieldProps(column)"
/>
</template>
<template v-else>
<G3Field
:model-value="modelValue[column.prop]"
@update:model-value="
updateFields({
[column.prop]: $event,
})
"
:label="column.label"
:type="getFieldType(column)"
v-bind="getFieldProps(column)"
@input="
emit('field-input', {
column,
value: $event,
})
"
/>
</template>
</template>
</div>
</div>
</template>
<style lang="scss" scoped>
.g3group {
background: #fff;
padding: 4px 4px;
display: flex;
}
.g3grouptitle {
display: flex;
flex-direction: column;
justify-content: space-evenly;
align-items: center;
text-align: center;
color: #fff;
font-size: 14px;
padding: 0px 5px;
background-color: #f1b408;
width: 30px;
white-space: normal;
word-break: break-all;
min-height: 100%;
}
.g3panel {
width: 620px;
height: auto;
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 2px;
align-content: start;
}
.g3panel .fieldremark {
grid-column: span 2;
height: 72px;
}
.g3panel .fieldremark :deep(textarea) {
height: 100%;
min-height: 100%;
resize: none;
box-sizing: border-box;
}
.g3panel .fieldremark :deep(.g3content) {
width: 100%;
}
.g3marginleft15 {
margin-left: 15px;
}
</style>
@@ -0,0 +1,234 @@
<script setup>
import { nextTick, ref, watch } from "vue";
import G3Field from "@/components/g3Field.vue";
import g3OtherCompanyType from "@/components/other/g3OtherCompanyType.vue";
import { getDataBySql } from "@/utils/doSql";
const props = defineProps({
modelValue: {
type: Object,
default: () => ({}),
},
viewtable: { type: String, required: true },
groupName: {
type: String,
default: "",
},
showGroupTitle: {
type: Boolean,
default: false,
},
});
const emit = defineEmits(["update:modelValue", "select", "field-input"]);
// 更新字段
function updateFields(fields) {
console.log(fields);
emit("update:modelValue", fields);
console.log("===1===");
}
// function updateField(prop, value) {
// emit("update:modelValue", {
// ...props.modelValue,
// [prop]: value,
// });
// }
function getFieldType(column) {
if (column.edit_type === "selectid") {
return "select";
}
if (column.edit_type === "selectname") {
return "select";
}
if (column.edit_type === "calculate") {
return "input";
}
return column.edit_type || "input";
}
function getFieldProps(column) {
return {
field: column.prop,
disabled: String(column.readOnly) === "1",
required: String(column.allowNull) !== "1",
class: column.edit_type === "textarea" ? "fieldremark" : "",
};
}
const handleSelect = (column, val) => {
emit("select", {
column,
value: val,
});
};
const columns = ref([]);
watch(
() => [props.viewtable, props.groupName],
async ([table, group]) => {
if (!table) return;
columns.value = [];
await addColumns(table, group);
},
{ immediate: true },
);
async function addColumns(viwetable, groupName) {
try {
let sql = `SELECT col_FieldName as prop,col_Field_id as field_id, col_Caption as label, col_Width as width, col_edit_type as edit_type,col_edit_width as edit_width,col_ReadOnly as readOnly,col_AllowNull as allowNull,col_edit_source_table as edit_source_table,col_edit_height as edit_height,col_DisplayFormat as displayFormat,col_edit_pycode as pycode FROM s_columnLib WHERE col_TableName = '${viwetable}' and col_edit= '1' `;
if (groupName !== null && groupName !== undefined && groupName !== "") {
sql += ` AND col_edit_grouping='${groupName}'`;
}
sql += ` ORDER BY col_edit_position`;
let datas = await getDataBySql(sql);
if (!datas.records || datas.records.length === 0) {
ElMessage.warning("返回数据格式异常");
return;
}
columns.value = datas.records;
} catch (err) {
console.log(err);
ElMessage.warning(err.message || "加载列配置失败");
}
}
</script>
<template>
<div :class="props.showGroupTitle ? 'g3group' : ''">
<div v-if="props.showGroupTitle" class="g3grouptitle">
<span v-for="(char, index) in props.groupName" :key="index">
{{ char }}
</span>
</div>
<div class="g3panel" :class="{ g3marginleft15: props.showGroupTitle }">
<template v-for="column in columns" :key="column.prop">
<template v-if="column.edit_type === 'selectid'">
<G3Field
:model-value="modelValue[column.prop]"
:model-id="modelValue[column.field_id]"
@update:model-value="
updateFields({
[column.prop]: $event,
})
"
@update:model-id="
updateFields({
[column.field_id]: $event,
})
"
:label="column.label"
:type="getFieldType(column)"
:pycode="column.pycode == 'true'"
:mustmatch="true"
:query-params="{ dataset: column.edit_source_table }"
v-bind="getFieldProps(column)"
@select="handleSelect(column, $event)"
/>
</template>
<template v-else-if="column.edit_type === 'selectname'">
<G3Field
:model-value="modelValue[column.prop]"
@update:model-value="
updateFields({
[column.prop]: $event,
})
"
:label="column.label"
:type="getFieldType(column)"
:query-params="{ dataset: column.edit_source_table }"
v-bind="getFieldProps(column)"
@select="handleSelect(column, $event)"
/>
</template>
<template v-else-if="column.edit_type === 'othercompanytype'">
<g3OtherCompanyType
:model-value="modelValue[column.prop]"
:label="column.label"
@update:model-value="
updateFields({
[column.prop]: $event,
})
"
v-bind="getFieldProps(column)"
/>
</template>
<template v-else>
<G3Field
:model-value="modelValue[column.prop]"
@update:model-value="
updateFields({
[column.prop]: $event,
})
"
:label="column.label"
:type="getFieldType(column)"
v-bind="getFieldProps(column)"
@input="
emit('field-input', {
column,
value: $event,
})
"
/>
</template>
</template>
</div>
</div>
</template>
<style lang="scss" scoped>
.g3group {
background: #fff;
padding: 4px 4px;
display: flex;
}
.g3grouptitle {
display: flex;
flex-direction: column;
justify-content: space-evenly;
align-items: center;
text-align: center;
color: #fff;
font-size: 14px;
padding: 0px 5px;
background-color: #f1b408;
width: 30px;
white-space: normal;
word-break: break-all;
min-height: 100%;
}
.g3panel {
width: 620px;
height: auto;
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 2px;
align-content: start;
}
.g3panel .fieldremark {
grid-column: span 2;
height: 72px;
}
.g3panel .fieldremark :deep(textarea) {
height: 100%;
min-height: 100%;
resize: none;
box-sizing: border-box;
}
.g3panel .fieldremark :deep(.g3content) {
width: 100%;
}
.g3marginleft15 {
margin-left: 15px;
}
</style>
+1 -1
View File
@@ -3,7 +3,7 @@ import { ref, nextTick, onMounted, onBeforeUnmount } from "vue";
const props = defineProps({
modelValue: {
type: String,
type: [String, Number],
default: "",
},
+15 -6
View File
@@ -29,17 +29,17 @@ const props = defineProps({
precision: {
type: Number,
default: 2,
default: -1,
},
allowNegative: {
type: Boolean,
default: false,
default: true,
},
thousand: {
type: Boolean,
default: false,
default: true,
},
min: {
@@ -66,9 +66,13 @@ const props = defineProps({
type: String,
default: "",
},
align: {
type: String,
default: "right",
},
});
const emit = defineEmits(["update:modelValue", "change", "blur", "focus"]);
const emit = defineEmits(["update:modelValue", "input", "change", "blur", "focus"]);
const inputRef = ref();
@@ -164,6 +168,7 @@ function onInput(e) {
text.value = value;
emit("update:modelValue", value);
emit("input", value);
}
/**
@@ -179,6 +184,7 @@ function onPaste(e) {
text.value = value;
emit("update:modelValue", value);
emit("input", value);
}
/**
@@ -307,6 +313,7 @@ const showSuffix = computed(() => {
:placeholder="placeholder"
:disabled="disabled"
:readonly="readonly"
:style="{ textAlign: align }"
autocomplete="off"
spellcheck="false"
@input="onInput"
@@ -410,6 +417,8 @@ const showSuffix = computed(() => {
line-height: 22px;
box-sizing: border-box;
text-align: right; /* 默认右对齐 */
}
/* ============================
@@ -461,13 +470,13 @@ const showSuffix = computed(() => {
.g3-number.disabled .g3-number-input {
background: #f5f7fa;
cursor: not-allowed;
cursor: default;
}
.g3-number.disabled input {
color: #a8abb2;
cursor: not-allowed;
cursor: default;
}
/* ============================
File diff suppressed because it is too large. Load diff
+112 -99
View File
@@ -18,6 +18,14 @@ const props = defineProps({
type: Function,
default: null,
},
multiple: {
type: Boolean,
default: true,
},
disabledSum: {
type: Boolean,
default: true,
},
});
const emit = defineEmits(["update:visible", "confirm"]);
const loading = ref(false);
@@ -58,9 +66,12 @@ function handleClose() {
}
const tableRef = ref();
// 点击确认
async function handleConfirm() {
const rows = tableRef.value?.getCheckboxRecords?.() || [];
const rows = props.multiple
? tableRef.value?.getCheckboxRecords?.() || []
: tableRef.value?.getRadioRecord()
? [tableRef.value.getRadioRecord()]
: [];
if (!rows.length) {
ElMessage.warning("请选择数据!");
@@ -76,16 +87,24 @@ async function handleConfirm() {
}
}
const subidCondition = `AND subid IN (${rows.map((r) => `'${r.subid}'`).join(",")})`;
// 判断条件字段
const field = rows[0].hasOwnProperty("b_id") ? "b_id" : "subid";
tableData.value = tableData.value.filter(
(item) => !rows.some((r) => r.subid === item.subid),
);
const condition = `AND ${field} IN (${rows.map((r) => `'${r[field]}'`).join(",")})`;
// 移除已选择数据
tableData.value = tableData.value.filter((item) => !rows.some((r) => r[field] === item[field]));
// 清除选择
if (props.multiple) {
tableRef.value.clearCheckboxRow();
} else {
tableRef.value.clearRadioRow();
}
tableRef.value.clearCheckboxRow();
handleTableFooterData();
emit("confirm", subidCondition);
emit("confirm", condition);
}
let filterSql = ref("");
@@ -107,6 +126,7 @@ function buildSql() {
async function loadData() {
loading.value = true;
try {
const result = await getDataBySqlPageMapping(
buildSql(),
props.moduleId,
@@ -172,7 +192,7 @@ function computeFooter() {
}
const selectSql = ref("");
const selectOrder = ref("");
const selectOrder = ref("");
async function getselectSQLbyid(selectid) {
let data_selectsql = await getDataBySql(
`select * from s_selectsql where selectid='${selectid}' `,
@@ -183,12 +203,11 @@ async function getselectSQLbyid(selectid) {
}
}
// 初始化加载数据
onMounted(async () => {
async function handleOpened(){
await getselectSQLbyid(props.selectid);
await getSelectColumns(props.selectid, columns);
await handleSearch();
});
// await handleSearch();
}
</script>
<template>
@@ -200,95 +219,92 @@ onMounted(async () => {
align-center
class="g3-dialog"
draggable
@opened="handleOpened"
>
<div class="g3pagecontainer">
<div class="g3main">
<div class="g3container">
<div class="g3toolbar">
<g3filter :module-id="props.selectid" @update:search="handlefilter" />
<el-button @click="handleConfirm"> 选取 </el-button>
<!-- <el-button @click="handleClose">取消</el-button> -->
</div>
<!-- 表格 -->
<div class="g3container">
<div>
<div class="g3subgrid">
<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="{
keyField: 'subid',
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%"
@checkbox-change="computeFooter"
@checkbox-all="computeFooter"
<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="{
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%"
@checkbox-change="computeFooter"
@checkbox-all="computeFooter"
>
<vxe-column field="seq" type="seq" width="38" align="center" title=" " fixed="left" />
<vxe-column
:type="props.multiple ? 'checkbox' : 'radio'"
width="38"
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
>
<vxe-column
field="seq"
type="seq"
width="38"
align="center"
title=" "
fixed="left"
/>
<vxe-column type="checkbox" width="30" 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.displayFormat === 'checkbox'">
<el-checkbox :checked="row[column.prop] === '1'" />
</template>
<template v-else>
{{ formatValueByFormat(row[column.prop], column.displayFormat) }}
</template>
<template #default="{ row }">
<template v-if="column.displayFormat === 'checkbox'">
<el-checkbox :checked="row[column.prop] === '1'" />
</template>
<template v-if="column.showSummary === '1'" #footer="{ row }">
<template v-else>
{{ formatValueByFormat(row[column.prop], column.displayFormat) }}
</template>
</vxe-column>
</vxe-table>
</div>
</template>
<template v-if="column.showSummary === '1'" #footer="{ row }">
{{ formatValueByFormat(row[column.prop], column.displayFormat) }}
</template>
</vxe-column>
</vxe-table>
</div>
<div class="g3footer">
<div>
<div class="g3footer" :style="{ justifyContent: props.disabledSum ? 'right' : '' }">
<div v-if="!props.disabledSum">
{{ footerText }}
</div>
<div>
@@ -321,7 +337,7 @@ onMounted(async () => {
padding: 2px 2px;
}
.g3main {
.g3container {
display: flex;
flex-direction: column;
min-width: 0;
@@ -343,7 +359,7 @@ onMounted(async () => {
height: 34px;
}
.g3container {
.g3main {
display: flex;
flex: 1;
flex-direction: column;
@@ -356,15 +372,12 @@ onMounted(async () => {
min-height: 0;
}
.g3subgrid {
height: 100%;
overflow: hidden;
}
.g3container > div:first-child {
display: flex;
.g3grid {
flex: 1;
overflow: auto;
display: flex;
flex-direction: column;
min-height: 0;
width: 100%;
}
.g3footer {
@@ -0,0 +1,94 @@
<script setup>
import { ref, computed, onMounted } from "vue";
import axios from "@/utils/axios";
const props = defineProps({
modelValue: { type: [String, Number], default: "" },
label: String,
disabled: { type: Boolean, default: false },
required: { type: Boolean, default: false },
field: { type: String, default: "" },
});
const emit = defineEmits(["update:modelValue"]);
const options = ref([]);
const typeArray = computed({
get: () => (props.modelValue ? props.modelValue.split(",") : []),
set: (val) => emit("update:modelValue", val.join(",")),
});
async function loadData() {
if (options.value.length) return;
const res = await axios.get("/pagtable", {
params: {
tableName: "b_othercompany_partner_type",
pkColumn: "b_id",
page: 1,
size: 100,
whereClause: "2>1",
},
});
options.value =
res.data?.data?.records?.map((item) => ({
b_id: item.b_id,
b_name: item.b_name,
})) || [];
}
onMounted(loadData);
</script>
<template>
<div class="g3cell" :field="props.field">
<div class="g3label">
<span v-if="required" class="req">*</span>
{{ label }}
</div>
<el-select
v-model="typeArray"
multiple
filterable
size="small"
:disabled="disabled"
class="g3elselect"
>
<el-option v-for="item in options" :key="item.b_id" :label="item.b_name" :value="item.b_id" />
</el-select>
</div>
</template>
<style lang="scss" scoped>
.g3cell {
display: flex;
grid-column: span 2;
height: 52px;
}
.g3label {
width: 104px;
padding-right: 8px;
font-size: 14px;
text-align: right;
}
.req {
color: #d32f2f;
margin-right: 2px;
}
.g3elselect {
width: 100%;
height: 50px;
}
.g3elselect :deep(.el-select__wrapper) {
height: 100%;
align-items: flex-start;
}
:deep(.el-select__wrapper.is-disabled) {
cursor: unset;
}
</style>
@@ -3,6 +3,7 @@ import { ElMessage } from "element-plus";
import { onMounted, ref, watch } from "vue";
import axios from "@/utils/axios";
import { isNotEmpty } from "@/utils/g3Funlib.js";
import { getDataBySql } from "@/utils/doSql";
const props = defineProps({
moduleId: { type: String },
@@ -16,14 +17,12 @@ const sqlvalue = ref("");
// 列配置
async function addQuery(moduleId) {
let searchsql = `select ROW_NUMBER() OVER (ORDER BY col_SearchOrder) AS b_id,col_caption as lable, col_fieldname from s_columnlib where col_TableName='${moduleId}' and col_CanSearch ='1' and isnull(col_type,'') <> 'date' order by col_SearchOrder`;
const response = await axios.get("/selectlistbysql", { params: { sql: searchsql } });
if (response.data?.success) {
const records = response.data.data.records || [];
if (records.length > 0) {
querys.value = records;
sqllable.value = records[0].lable;
} else {
try {
let searchsql = `select ROW_NUMBER() OVER (ORDER BY col_SearchOrder) AS b_id,col_caption as lable, col_fieldname from s_columnlib where col_TableName='${moduleId}' and col_CanSearch ='1' and isnull(col_type,'') <> 'date' order by col_SearchOrder`;
let datas = await getDataBySql(searchsql);
if (!datas.records || datas.records.length === 0) {
const columnsDefault = [
{ b_id: 1, col_fieldname: "b_id", lable: "代码" },
{ b_id: 2, col_fieldname: "b_name", lable: "名称" },
@@ -31,7 +30,13 @@ async function addQuery(moduleId) {
querys.value = columnsDefault;
sqllable.value = columnsDefault[0].lable;
ElMessage.warning("没有查询条件,默认条件");
return;
}
querys.value = datas.records;
sqllable.value = datas.records[0].lable;
} catch (error) {
console.log(error);
ElMessage.warning(error || "没有查询条件,默认条件");
}
}
@@ -2,10 +2,10 @@
import dayjs from "dayjs";
import { ElMessage } from "element-plus";
import { onMounted, ref } from "vue";
import { watch, ref } from "vue";
import g3Select from "@/components/g3Select.vue";
import axios from "@/utils/axios";
import { Search } from "@element-plus/icons-vue";
import { getDataBySql } from "@/utils/doSql";
const props = defineProps({
moduleId: { type: String },
@@ -27,7 +27,7 @@ const colNum = ref(4);
// 列配置
async function addQuery(moduleId) {
let searchsql = `select ROW_NUMBER() OVER (ORDER BY col_position) AS b_id,subid,col_caption as lable,col_fieldname,col_operator,col_option,col_type,col_pycode,col_source_field,col_source_table,col_defaultvalue_end,col_defaultvalue_start from s_search_sub where mx_module_id='${moduleId}' and col_visible ='1' order by col_position`;
const response = await axios.get("/selectlistbysql", { params: { sql: searchsql } });
const response = await axios.post("/selectlistbysql", { sql: searchsql });
if (response.data?.success) {
const records = response.data.data.records || [];
// console.log('records=-=-=-=-=-')
@@ -144,6 +144,7 @@ function handleSearch() {
}
});
let sql = whereList.length > 0 ? " " + whereList.join(" AND ") : "";
emit("update:search", sql, querys.value);
}
function handleReset() {
@@ -230,15 +231,19 @@ function parseDateConfig(configStr) {
}
async function addSQL(moduleId) {
let searchsql = `select * from s_search where b_module_id='${moduleId}'`;
const response = await axios.get("/selectlistbysql", { params: { sql: searchsql } });
if (response.data?.success) {
const records = response.data.data.records || [];
if (records.length > 0) {
colNum.value = records[0].b_col_num;
} else {
try {
let searchsql = `select * from s_search where b_module_id='${moduleId}'`;
let datas = await getDataBySql(searchsql);
if (!datas.records || datas.records.length === 0) {
ElMessage.warning("没有查询语句");
return;
}
colNum.value = datas.records[0].b_col_num;
} catch (err) {
console.log(err);
ElMessage.warning(err.message || "没有查询语句");
}
}
@@ -250,10 +255,18 @@ const handleSetdata = (val, col_fieldname) => {
query._value = val;
};
onMounted(async () => {
await addSQL(props.moduleId);
await addQuery(props.moduleId);
});
watch(
() => props.moduleId,
async (newVal) => {
if (!newVal) return;
await addSQL(newVal);
await addQuery(newVal);
},
{
immediate: true,
},
);
</script>
<template>
@@ -529,4 +542,8 @@ onMounted(async () => {
border-radius: 8px;
}
/* -------------------------- */
/* 查询日期图标 */
:deep(.g3-prefix .el-input__prefix) {
display: none !important;
}
</style>
@@ -23,16 +23,26 @@ const tableRef = ref();
const currentRow = ref(null);
const isDisabled = computed(() => currentRow.value === null);
function handleCurrentChange({ newValue }) {
currentRow.value = newValue;
console.log(currentRow.value);
// function handleCurrentChange({ newValue }) {
// currentRow.value = newValue;
// console.log(currentRow.value);
// }
function handleRadioChange({ row }) {
currentRow.value = row;
}
const loading = ref({
table: true,
});
const tableData = ref([]);
async function initData() {
console.log("============报表信息============");
console.log("cateid:", props.cateid);
console.log("valuesql:", props.valuesql);
console.log("djid:", props.djid);
const { data: reportRes } = await axios.get("/getReport", {
params: {
cateId: props.cateid,
@@ -42,8 +52,6 @@ async function initData() {
ElMessage.error(`获取报表列表失败:${reportRes.message}`);
return;
}
console.log("tableData.value=-=-=-=-");
console.log(tableData.value);
tableData.value = reportRes.data;
loading.value.table = false;
@@ -141,7 +149,7 @@ function downloadFromResponse(res, type, defaultFileName = "") {
title="打印报表"
width="530px"
class="g3dialogfooter"
@open="initData"
@opened="initData"
draggable
align-center
>
@@ -154,6 +162,10 @@ function downloadFromResponse(res, type, defaultFileName = "") {
:data="tableData"
:show-footer="true"
:loading="loading.table"
:radio-config="{
highlight: true,
trigger: 'row',
}"
:sort-config="{
// showIcon: false,
trigger: 'cell',
@@ -180,10 +192,10 @@ function downloadFromResponse(res, type, defaultFileName = "") {
show-overflow
show-header-overflow
height="100%"
@current-row-change="handleCurrentChange"
@radio-change="handleRadioChange"
>
<vxe-column field="seq" type="seq" width="30" align="center" title=" " fixed="left" />
<vxe-column title="报表名称" width="452" field="b_name" align="center" />
<vxe-column type="radio" width="60" align="center" />
<vxe-column title="报表名称" width="400" field="b_name" align="center" />
</vxe-table>
</div>
</div>
@@ -274,4 +286,4 @@ function downloadFromResponse(res, type, defaultFileName = "") {
width: 38px;
height: 42px;
}
</style>
</style>
@@ -1,39 +1,72 @@
import { createApp } from "vue";
import { createVNode, render } from "vue";
import UploadProgress from "./index.vue";
let app: ReturnType<typeof createApp> | null = null;
let instance: any = null;
let container: HTMLElement | null = null;
let vnode: any = null;
export function showUploadProgress(
status: ProgressStatus = "uploading"
) {
if (!container) {
container = document.createElement("div");
container.className = "upload-progress-container";
export function showUploadProgress(status: ProgressStatus = "uploading") {
if (!app) {
const container = document.createElement("div");
document.body.appendChild(container);
app = createApp(UploadProgress);
instance = app.mount(container);
vnode = createVNode(UploadProgress);
render(vnode, container);
instance = vnode.component?.proxy;
}
instance.open();
instance.setStatus(status); // 外部传入状态
}
export function updateUploadProgress(percent: number, status: ProgressStatus = "uploading") {
if (instance) {
instance.setPercent(percent);
instance.setStatus(status); // 外部传入状态
if (percent >= 100) {
setTimeout(() => {
closeUploadProgress();
}, 800); // 100%后等一下再关闭,显得自然
}
instance.open();
instance.setStatus(status);
}
}
export function updateUploadProgress(
percent: number,
status: ProgressStatus = "uploading"
) {
if (!instance) return;
instance.setPercent(percent);
instance.setStatus(status);
if (percent >= 100) {
setTimeout(() => {
closeUploadProgress();
}, 800);
}
}
export function closeUploadProgress() {
if (instance) {
instance.close();
}
if (!instance) return;
instance.close();
// 等关闭动画结束后销毁 Vue 节点
setTimeout(() => {
if (container) {
render(null, container);
container.remove();
}
instance = null;
vnode = null;
container = null;
}, 300);
}
// 如果你有 ProgressStatus 类型的需求,确保你导出它
export type ProgressStatus = "uploading" | "completed" | "failed";
export type ProgressStatus =
| "uploading"
| "completed"
| "failed";