pull/1/head
z 2024-01-05 17:33:18 +08:00
parent 29b4c7d2ba
commit 1fc7e96f0d
19 changed files with 435 additions and 52 deletions

72
package-lock.json generated
View File

@ -8,10 +8,10 @@
"name": "vue3_template",
"version": "0.0.0",
"dependencies": {
"@element-plus/icons-vue": "^2.1.0",
"@element-plus/icons-vue": "^2.3.1",
"@icon-park/vue-next": "^1.4.2",
"@vueuse/core": "^9.13.0",
"@vueuse/integrations": "^10.7.0",
"@vueuse/integrations": "^10.7.1",
"animate.css": "^4.1.1",
"axios": "^1.6.3",
"dayjs": "^1.11.10",
@ -20,40 +20,41 @@
"mitt": "^3.0.1",
"normalize.css": "^8.0.1",
"pinia": "^2.1.7",
"pinia-plugin-persistedstate": "^3.2.0",
"pinia-plugin-persistedstate": "^3.2.1",
"qrcode": "^1.5.3",
"qs": "^6.11.2",
"throttle-debounce": "^5.0.0",
"v-viewer": "^3.0.11",
"vue": "^3.3.13",
"vue": "^3.4.3",
"vue-router": "^4.2.5",
"vue3-pdfjs": "^0.1.6",
"vue3-print-nb": "^0.1.4",
"vue3-puzzle-vcode": "^1.0.16"
"vue3-puzzle-vcode": "^1.1.5"
},
"devDependencies": {
"@our-patches/postcss-px-to-viewport": "^1.2.0",
"@types/node": "^18.18.4",
"@vitejs/plugin-basic-ssl": "^1.0.1",
"@vitejs/plugin-vue": "^4.4.0",
"@types/node": "^18.19.4",
"@vitejs/plugin-basic-ssl": "^1.0.2",
"@vitejs/plugin-vue": "^4.6.2",
"@vue/eslint-config-prettier": "^7.1.0",
"autoprefixer": "^10.4.16",
"eslint": "^8.51.0",
"eslint": "^8.56.0",
"eslint-config-prettier": "^8.10.0",
"eslint-config-standard": "^17.1.0",
"eslint-plugin-import": "^2.28.1",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-n": "^15.7.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-promise": "^6.1.1",
"eslint-plugin-vue": "^9.17.0",
"eslint-plugin-vue": "^9.19.2",
"prettier": "^2.8.8",
"sass": "^1.69.0",
"unplugin-auto-import": "^0.12.2",
"unplugin-vue-components": "^0.22.12",
"vite": "^4.4.11",
"vite": "^4.5.1",
"vite-plugin-enhance-log": "^0.5.2",
"vite-plugin-eslint": "^1.8.1",
"vite-plugin-remove-console": "^2.1.1",
"vue-eslint-parser": "^9.3.1"
"vite-plugin-remove-console": "^2.2.0",
"vue-eslint-parser": "^9.3.2"
}
},
"node_modules/@aashutoshrathi/word-wrap": {
@ -2323,6 +2324,12 @@
"node": ">=6.0.0"
}
},
"node_modules/dommatrix": {
"version": "1.0.3",
"resolved": "https://registry.npmmirror.com/dommatrix/-/dommatrix-1.0.3.tgz",
"integrity": "sha512-l32Xp/TLgWb8ReqbVJAFIvXmY7go4nTxxlWiAFyhoQw9RKEOHBZNnyGvJWqDVSPmq3Y9HlM4npqF/T6VMOXhww==",
"deprecated": "dommatrix is no longer maintained. Please use @thednp/dommatrix."
},
"node_modules/electron-to-chromium": {
"version": "1.4.617",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.617.tgz",
@ -4326,6 +4333,23 @@
"integrity": "sha512-d+RQGp0MAYTIaDBIMmOfMwz3E+LOZnxx1HZd5R18mmCZY0QBlK0LDZfPc8FW8Ed2DlvsuE6PRjroDY+wg4+j/Q==",
"dev": true
},
"node_modules/pdfjs-dist": {
"version": "2.16.105",
"resolved": "https://registry.npmmirror.com/pdfjs-dist/-/pdfjs-dist-2.16.105.tgz",
"integrity": "sha512-J4dn41spsAwUxCpEoVf6GVoz908IAA3mYiLmNxg8J9kfRXc2jxpbUepcP0ocp0alVNLFthTAM8DZ1RaHh8sU0A==",
"dependencies": {
"dommatrix": "^1.0.3",
"web-streams-polyfill": "^3.2.1"
},
"peerDependencies": {
"worker-loader": "^3.0.8"
},
"peerDependenciesMeta": {
"worker-loader": {
"optional": true
}
}
},
"node_modules/picocolors": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
@ -5546,6 +5570,18 @@
"vue": "^3.2.0"
}
},
"node_modules/vue3-pdfjs": {
"version": "0.1.6",
"resolved": "https://registry.npmmirror.com/vue3-pdfjs/-/vue3-pdfjs-0.1.6.tgz",
"integrity": "sha512-7UaWbsp8wNqB0y/rRlyo5yRb0S+XOkkSpmdUuS267Dhi07Pt4RFEetQ8inrpf/aTFJwGnW0Uc/UE4p376s+Zmw==",
"dependencies": {
"pdfjs-dist": "^2.10.377",
"vue": "^3.2.19"
},
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/vue3-print-nb": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/vue3-print-nb/-/vue3-print-nb-0.1.4.tgz",
@ -5559,6 +5595,14 @@
"resolved": "https://registry.npmjs.org/vue3-puzzle-vcode/-/vue3-puzzle-vcode-1.1.5.tgz",
"integrity": "sha512-JesxfEucupQYDHXcywVx5BGQ1Wjybtlj4dAeNw2tC1jfHt1FXoG0bpBSlLUS4TPyS+pHp++4zmTfBQZLf9ldXw=="
},
"node_modules/web-streams-polyfill": {
"version": "3.3.2",
"resolved": "https://registry.npmmirror.com/web-streams-polyfill/-/web-streams-polyfill-3.3.2.tgz",
"integrity": "sha512-3pRGuxRF5gpuZc0W+EpwQRmCD7gRqcDOMt688KmdlDAgAyaB1XlN0zq2njfDNm44XVdIouE7pZ6GzbdyH47uIQ==",
"engines": {
"node": ">= 8"
}
},
"node_modules/webpack-sources": {
"version": "3.2.3",
"resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz",

View File

@ -29,6 +29,7 @@
"v-viewer": "^3.0.11",
"vue": "^3.4.3",
"vue-router": "^4.2.5",
"vue3-pdfjs": "^0.1.6",
"vue3-print-nb": "^0.1.4",
"vue3-puzzle-vcode": "^1.1.5"
},

View File

@ -73,6 +73,11 @@ export default [
},
],
},
{
path: "/enterprise_management/department",
meta: { title: "组织机构", isSubMenu: false },
component: "enterprise_management/department/index",
},
],
},
{

View File

@ -3,6 +3,7 @@ import {
getLevels,
getLevelsAndChildrenNumber,
getRegulatoryType,
getDepartmentTree,
} from "@/request/data_dictionary.js";
import { ref } from "vue";
@ -67,6 +68,11 @@ export const layoutFnGetRiskLevel = async () => {
});
return ref(resData.list);
};
// 部门树
export const layoutFnGetDepartmentTree = async () => {
const resData = await getDepartmentTree();
return ref(JSON.parse(resData.zTreeNodes));
};
// 无法确定DICTIONARIES_ID的数据字典
export const layoutFnGetLevels = async (DICTIONARIES_ID) => {
const resData = await getLevels({ DICTIONARIES_ID });

View File

@ -0,0 +1,65 @@
<template>
<el-tree-select
v-model="modelValue"
:data="departmentTree"
node-key="id"
:props="{
children: 'nodes',
label: 'name',
}"
:render-after-expand="false"
accordion
:check-strictly="checkStrictly"
:clearable="clearable"
:show-checkbox="showCheckbox"
:multiple="multiple"
:collapse-tags="collapseTags"
/>
</template>
<script setup>
import { layoutFnGetDepartmentTree } from "@/assets/js/data_dictionary";
import { useVModel } from "@vueuse/core";
defineOptions({
name: "LayoutDepartment",
});
const props = defineProps({
modelValue: {
type: [String, Array],
required: true,
default: "",
},
checkStrictly: {
type: Boolean,
default: true,
},
showCheckbox: {
type: Boolean,
default: false,
},
multiple: {
type: Boolean,
default: false,
},
collapseTags: {
type: Boolean,
default: false,
},
clearable: {
type: Boolean,
default: true,
},
rootDisable: {
type: String,
default: "Y",
},
});
const emits = defineEmits(["update:modelValue"]);
const modelValue = useVModel(props, "modelValue", emits);
const departmentTree = await layoutFnGetDepartmentTree({
ROOT_DISABLE: props.rootDisable,
});
</script>
<style scoped></style>

View File

@ -0,0 +1,52 @@
<template>
<el-dialog title="文档" v-model="visible">
<div v-if="visible">
<vue-pdf
ref="pdfRef"
v-for="page in numOfPages"
:key="page"
:src="src"
:page="page"
/>
</div>
</el-dialog>
</template>
<script setup>
import { watchEffect, ref } from "vue";
import { VuePdf, createLoadingTask } from "vue3-pdfjs/esm";
import { ElMessage } from "element-plus";
import { useVModel } from "@vueuse/core";
defineOptions({
name: "LayoutPdf",
});
const props = defineProps({
src: {
type: String,
required: true,
},
visible: {
type: Boolean,
default: false,
required: true,
},
});
const emits = defineEmits(["update:visible"]);
const visible = useVModel(props, "visible", emits);
const pdfRef = ref(null);
const numOfPages = ref(0);
watchEffect(() => {
if (props.visible) {
const loadingTask = createLoadingTask(props.src);
loadingTask.promise
.then((pdf) => {
numOfPages.value = pdf.numPages;
})
.catch(() => {
visible.value = false;
ElMessage.error("文件加载失败");
});
}
});
</script>

View File

@ -0,0 +1,35 @@
<template>
<el-dialog title="文本文档" v-model="visible">
<el-input autosize :model-value="value" readonly type="textarea" />
</el-dialog>
</template>
<script setup>
import { useVModel } from "@vueuse/core";
import { ref, watchEffect } from "vue";
import { readTxtDocument } from "@/assets/js/utils.js";
defineOptions({
name: "LayoutTxt",
});
const props = defineProps({
visible: {
type: Boolean,
required: true,
default: false,
},
src: {
type: String,
required: true,
default: "",
},
});
const value = ref("");
const emits = defineEmits(["update:visible"]);
const visible = useVModel(props, "visible", emits);
watchEffect(async () => {
if (props.src) value.value = await readTxtDocument(props.src);
});
</script>
<style lang="scss" scoped></style>

View File

@ -30,3 +30,9 @@ export const getUserListAllByCorp = (params) =>
loading: false,
...params,
});
// 部门树
export const getDepartmentTree = (params) =>
post("/department/listTree", {
loading: false,
...params,
});

View File

@ -0,0 +1,5 @@
import { post } from "@/request/axios.js";
export const getDepartmentList = (params) => post("/department/list", params); // 组织机构列表
export const setDepartmentDelete = (params) =>
post("/department/delete", params); // 组织机构删除

View File

@ -148,10 +148,10 @@ const stateList = [
{ ID: "-6", NAME: "待验收打回" },
];
const router = useRouter();
const listData = useListData(getBlindPlatePluggingList, {
otherParams: props.entrance === "archive" ? { APPLY_STATUS: "6" } : {},
});
const { list, pagination, searchForm, fnGetData, fnResetPagination } = listData;
const { list, pagination, searchForm, fnGetData, fnResetPagination } =
useListData(getBlindPlatePluggingList, {
otherParams: props.entrance === "archive" ? { APPLY_STATUS: "6" } : {},
});
const data = reactive({
flowChartDialog: {
visible: false,

View File

@ -129,10 +129,10 @@ const stateList = [
{ ID: "-98", NAME: "已作废(未进行气体检测)" },
];
const router = useRouter();
const listData = useListData(getConfinedSpaceList, {
otherParams: props.entrance === "archive" ? { APPLY_STATUS: "6" } : {},
});
const { list, pagination, searchForm, fnGetData, fnResetPagination } = listData;
const { list, pagination, searchForm, fnGetData, fnResetPagination } =
useListData(getConfinedSpaceList, {
otherParams: props.entrance === "archive" ? { APPLY_STATUS: "6" } : {},
});
const data = reactive({
flowChartDialog: {
visible: false,

View File

@ -0,0 +1,164 @@
<template>
<div>
<layout-card>
<el-row :gutter="12">
<el-col :span="5">
<el-input
v-model="filterText"
placeholder="输入关键字进行过滤"
class="mb-10"
/>
<el-tree
ref="treeRef"
:props="{
children: 'nodes',
label: 'name',
}"
accordion
:data="data.treeData"
:filter-node-method="fnFilterNode"
@node-click="fnResetPagination({ DEPARTMENT_ID: $event.id })"
/>
</el-col>
<el-col :span="19">
<el-button class="mb-10">结构图</el-button>
<layout-table
:data="list"
v-model:pagination="pagination"
@get-data="fnGetDataTransfer"
>
<el-table-column label="序号" width="70">
<template v-slot="{ $index }">
{{ serialNumber(pagination, $index) }}
</template>
</el-table-column>
<el-table-column label="名称">
<template v-slot="{ row }">
<el-button
type="primary"
text
link
@click="
router.push({
path: '/enterprise_management/department',
query: {
DEPARTMENT_ID: row.DEPARTMENT_ID,
DEPARTMENT_NAME: row.NAME,
},
})
"
>
{{ row.NAME }}<el-icon><ArrowRight /></el-icon>
</el-button>
</template>
</el-table-column>
<template v-if="DEPARTMENT_ID !== '0'">
<el-table-column prop="HEADMAN" label="负责人" />
<el-table-column prop="leName" label="部门级别" />
<el-table-column prop="DEP_ORDER" label="排序" width="100" />
<el-table-column label="操作" width="100">
<template v-slot="{ row }">
<el-button
type="primary"
text
link
@click="fnAddOrEdit(row.DEPARTMENT_ID, 'edit')"
>
编辑
</el-button>
<el-button
type="primary"
text
link
@click="fnDelete(row.DEPARTMENT_ID, row.NAME)"
>
删除
</el-button>
</template>
</el-table-column>
</template>
<template #button>
<el-button type="primary" @click="fnAddOrEdit('', 'add')">
新增
</el-button>
</template>
</layout-table>
</el-col>
</el-row>
</layout-card>
</div>
</template>
<script setup>
import { serialNumber } from "@/assets/js/utils.js";
import useListData from "@/assets/js/useListData.js";
import {
getDepartmentList,
setDepartmentDelete,
} from "@/request/department.js";
import { layoutFnGetDepartmentTree } from "@/assets/js/data_dictionary.js";
import { reactive, ref, watch } from "vue";
import { onBeforeRouteUpdate, useRoute, useRouter } from "vue-router";
import { ArrowRight } from "@element-plus/icons-vue";
import { debounce } from "throttle-debounce";
import { ElMessage, ElMessageBox } from "element-plus";
const router = useRouter();
const route = useRoute();
const parentIdDefault = "0";
const parentNameDefault = "(无)此项为顶级部门";
const DEPARTMENT_ID = ref(route.query.DEPARTMENT_ID || parentIdDefault);
const DEPARTMENT_NAME = ref(route.query.DEPARTMENT_NAME || parentNameDefault);
const treeRef = ref(null);
const filterText = ref("");
const { list, pagination, fnGetData, fnResetPagination } = useListData(
getDepartmentList,
{
otherParams: {
DEPARTMENT_ID: DEPARTMENT_ID.value,
},
}
);
const data = reactive({
treeData: [],
});
watch(filterText, (val) => {
treeRef.value.filter(val);
});
const fnFilterNode = (value, data) => {
if (!value) return true;
return data.name.includes(value);
};
const fnGetTreeData = async () => {
const treeData = await layoutFnGetDepartmentTree();
data.treeData = treeData.value;
};
fnGetTreeData();
const fnGetDataTransfer = () => {
fnGetData({
DEPARTMENT_ID: DEPARTMENT_ID.value,
});
};
const fnResetPaginationTransfer = () => {
fnResetPagination({
DEPARTMENT_ID: DEPARTMENT_ID.value,
});
};
onBeforeRouteUpdate((to) => {
DEPARTMENT_ID.value = to.query.DEPARTMENT_ID || parentIdDefault;
DEPARTMENT_NAME.value = to.query.DEPARTMENT_NAME || parentNameDefault;
fnResetPaginationTransfer();
});
const fnDelete = debounce(
1000,
async (DEPARTMENT_ID, NAME) => {
await ElMessageBox.confirm(`确定要删除[${NAME}]吗?`, { type: "warning" });
await setDepartmentDelete({ DEPARTMENT_ID });
ElMessage.success("删除成功");
await fnResetPaginationTransfer();
},
{ atBegin: true }
);
</script>
<style scoped lang="scss"></style>

View File

@ -141,16 +141,16 @@ import useListData from "@/assets/js/useListData.js";
const FILE_URL = import.meta.env.VITE_FILE_URL;
const router = useRouter();
const listData = useListData(getIndustryQualificationsList);
const { list, pagination, searchForm, fnGetData, fnResetPagination } = listData;
const fnGetDataTransfer = async () => {
await fnGetData({
const { list, pagination, searchForm, fnGetData, fnResetPagination } =
useListData(getIndustryQualificationsList);
const fnGetDataTransfer = () => {
fnGetData({
STARTTIME: searchForm.value.dates?.[0],
ENDTIME: searchForm.value.dates?.[1],
});
};
const fnResetPaginationTransfer = async () => {
await fnResetPagination({
const fnResetPaginationTransfer = () => {
fnResetPagination({
STARTTIME: searchForm.value.dates?.[0],
ENDTIME: searchForm.value.dates?.[1],
});

View File

@ -154,10 +154,10 @@ const stateList = [
{ ID: "-6", NAME: "验收打回" },
];
const router = useRouter();
const listData = useListData(getGroundbreakingList, {
otherParams: props.entrance === "archive" ? { APPLY_STATUS: "6" } : {},
});
const { list, pagination, searchForm, fnGetData, fnResetPagination } = listData;
const { list, pagination, searchForm, fnGetData, fnResetPagination } =
useListData(getGroundbreakingList, {
otherParams: props.entrance === "archive" ? { APPLY_STATUS: "6" } : {},
});
const data = reactive({
flowChartDialog: {
visible: false,

View File

@ -152,10 +152,10 @@ const stateList = [
{ ID: "-6", NAME: "验收打回" },
];
const router = useRouter();
const listData = useListData(getHighList, {
otherParams: props.entrance === "archive" ? { APPLY_STATUS: "6" } : {},
});
const { list, pagination, searchForm, fnGetData, fnResetPagination } = listData;
const { list, pagination, searchForm, fnGetData, fnResetPagination } =
useListData(getHighList, {
otherParams: props.entrance === "archive" ? { APPLY_STATUS: "6" } : {},
});
const data = reactive({
flowChartDialog: {
visible: false,

View File

@ -152,10 +152,10 @@ const stateList = [
{ ID: "-6", NAME: "验收打回" },
];
const router = useRouter();
const listData = useListData(getHoistingList, {
otherParams: props.entrance === "archive" ? { APPLY_STATUS: "6" } : {},
});
const { list, pagination, searchForm, fnGetData, fnResetPagination } = listData;
const { list, pagination, searchForm, fnGetData, fnResetPagination } =
useListData(getHoistingList, {
otherParams: props.entrance === "archive" ? { APPLY_STATUS: "6" } : {},
});
const data = reactive({
flowChartDialog: {
visible: false,

View File

@ -151,10 +151,10 @@ const stateList = [
{ ID: "-98", NAME: "已作废(未进行气体检测)" },
];
const router = useRouter();
const listData = useListData(getHotWorkList, {
otherParams: props.entrance === "archive" ? { APPLY_STATUS: "8" } : {},
});
const { list, pagination, searchForm, fnGetData, fnResetPagination } = listData;
const { list, pagination, searchForm, fnGetData, fnResetPagination } =
useListData(getHotWorkList, {
otherParams: props.entrance === "archive" ? { APPLY_STATUS: "8" } : {},
});
const data = reactive({
flowChartDialog: {
visible: false,

View File

@ -156,10 +156,10 @@ const stateList = [
{ ID: "-6", NAME: "验收打回" },
];
const router = useRouter();
const listData = useListData(getOpenCircuitList, {
otherParams: props.entrance === "archive" ? { APPLY_STATUS: "6" } : {},
});
const { list, pagination, searchForm, fnGetData, fnResetPagination } = listData;
const { list, pagination, searchForm, fnGetData, fnResetPagination } =
useListData(getOpenCircuitList, {
otherParams: props.entrance === "archive" ? { APPLY_STATUS: "6" } : {},
});
const data = reactive({
flowChartDialog: {
visible: false,

View File

@ -131,10 +131,10 @@ const stateList = [
{ ID: "-99", NAME: "已作废" },
];
const router = useRouter();
const listData = useListData(getTemporaryElectricityUsageList, {
otherParams: props.entrance === "archive" ? { APPLY_STATUS: "5" } : {},
});
const { list, pagination, searchForm, fnGetData, fnResetPagination } = listData;
const { list, pagination, searchForm, fnGetData, fnResetPagination } =
useListData(getTemporaryElectricityUsageList, {
otherParams: props.entrance === "archive" ? { APPLY_STATUS: "5" } : {},
});
const data = reactive({
flowChartDialog: {
visible: false,