需求变更
parent
6af9840234
commit
bb5295e084
|
@ -4,7 +4,7 @@
|
||||||
title="对接数据项维护管理"
|
title="对接数据项维护管理"
|
||||||
:before-close="fnClose"
|
:before-close="fnClose"
|
||||||
>
|
>
|
||||||
<el-form ref="formRef" v-model="form" label-width="160px">
|
<el-form ref="formRef" :model="form" label-width="160px">
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col :span="10">
|
<el-col :span="10">
|
||||||
<el-form-item label="平台名称">
|
<el-form-item label="平台名称">
|
||||||
|
@ -55,16 +55,16 @@
|
||||||
<el-table-column label="是否必填">
|
<el-table-column label="是否必填">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-radio-group v-model="row.isRequired">
|
<el-radio-group v-model="row.isRequired">
|
||||||
<el-radio :label="1">是</el-radio>
|
<el-radio :value="1">是</el-radio>
|
||||||
<el-radio :label="0">否</el-radio>
|
<el-radio :value="0">否</el-radio>
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="是否需要">
|
<el-table-column label="是否需要">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-radio-group v-model="row.isNeed">
|
<el-radio-group v-model="row.isNeed">
|
||||||
<el-radio :label="1">是</el-radio>
|
<el-radio :value="1">是</el-radio>
|
||||||
<el-radio :label="0">否</el-radio>
|
<el-radio :value="0">否</el-radio>
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
@ -86,7 +86,7 @@ import {
|
||||||
getFindByMenuId,
|
getFindByMenuId,
|
||||||
setDataSave,
|
setDataSave,
|
||||||
} from "@/request/database.js";
|
} from "@/request/database.js";
|
||||||
const formRef = ref(null);
|
const formRef = ref("formRef");
|
||||||
const visible = defineModel("visible", { type: Boolean, required: true });
|
const visible = defineModel("visible", { type: Boolean, required: true });
|
||||||
const platformName = defineModel("platformName", {
|
const platformName = defineModel("platformName", {
|
||||||
type: String,
|
type: String,
|
||||||
|
|
|
@ -8,11 +8,7 @@
|
||||||
label-width="160px"
|
label-width="160px"
|
||||||
>
|
>
|
||||||
<template #area>
|
<template #area>
|
||||||
<el-cascader
|
<app-area-cascader v-model="form.area" check-strictly />
|
||||||
v-model="form.area"
|
|
||||||
:options="dictionariesList"
|
|
||||||
:props="{ value: 'name', label: 'name', children: 'list' }"
|
|
||||||
></el-cascader>
|
|
||||||
</template>
|
</template>
|
||||||
</app-form-builder>
|
</app-form-builder>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
|
@ -33,15 +29,13 @@ import {
|
||||||
setBusThirdPlatformUpdate,
|
setBusThirdPlatformUpdate,
|
||||||
getBusThirdPlatform,
|
getBusThirdPlatform,
|
||||||
} from "@/request/database.js";
|
} from "@/request/database.js";
|
||||||
import { getAreaListTree } from "@/request/data_dictionary.js";
|
|
||||||
import { STATUS_LIST } from "@/assets/js/constant.js";
|
import { STATUS_LIST } from "@/assets/js/constant.js";
|
||||||
|
import AppAreaCascader from "@/components/area_cascader/index.vue";
|
||||||
const visible = defineModel("visible", { type: Boolean, required: true });
|
const visible = defineModel("visible", { type: Boolean, required: true });
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
corpInfoId: { type: Number, required: false },
|
corpInfoId: { type: Number, required: false },
|
||||||
title: { type: String, required: true },
|
title: { type: String, required: true },
|
||||||
});
|
});
|
||||||
const { dictionariesList } = await getAreaListTree();
|
|
||||||
const emits = defineEmits(["getData"]);
|
const emits = defineEmits(["getData"]);
|
||||||
const { formRef, validate, reset } = useForm();
|
const { formRef, validate, reset } = useForm();
|
||||||
const form = ref({
|
const form = ref({
|
||||||
|
|
|
@ -2,17 +2,18 @@
|
||||||
<el-dialog v-model="visible" title="查看" :before-close="fnClose">
|
<el-dialog v-model="visible" title="查看" :before-close="fnClose">
|
||||||
<app-form-builder ref="formRef" v-model="form" :options label-width="160px">
|
<app-form-builder ref="formRef" v-model="form" :options label-width="160px">
|
||||||
<template #area>
|
<template #area>
|
||||||
<el-cascader
|
<!-- <el-cascader
|
||||||
v-model="form.area"
|
v-model="form.area"
|
||||||
:options="dictionariesList"
|
:options="dictionariesList"
|
||||||
:props="{ value: 'name', label: 'name', children: 'list' }"
|
:props="{ value: 'name', label: 'name', children: 'list' }"
|
||||||
></el-cascader>
|
></el-cascader> -->
|
||||||
|
<app-area-cascader v-model="form.area" check-strictly />
|
||||||
</template>
|
</template>
|
||||||
</app-form-builder>
|
</app-form-builder>
|
||||||
<el-row v-if="form.menuList && form.menuList.length > 0">
|
<el-row v-if="form.menuList && form.menuList.length > 0">
|
||||||
<el-col :span="12" style="padding-left: 160px">
|
<el-col :span="12" style="padding-left: 160px">
|
||||||
<template v-for="(item, index) in form.menuList" :key="index">
|
<template v-for="(item, index) in form.menuList" :key="index">
|
||||||
<template
|
<div
|
||||||
v-for="(itemChild, indexChild) in item.children"
|
v-for="(itemChild, indexChild) in item.children"
|
||||||
:key="indexChild"
|
:key="indexChild"
|
||||||
>
|
>
|
||||||
|
@ -22,7 +23,7 @@
|
||||||
>
|
>
|
||||||
{{ `${item.menuName}-${itemChild.menuName}` }}
|
{{ `${item.menuName}-${itemChild.menuName}` }}
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
@ -34,14 +35,14 @@ import useForm from "@/hooks/useForm.js";
|
||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
import AppFormBuilder from "@/components/form_builder/index.vue";
|
import AppFormBuilder from "@/components/form_builder/index.vue";
|
||||||
import { getBusThirdPlatform } from "@/request/database.js";
|
import { getBusThirdPlatform } from "@/request/database.js";
|
||||||
import { getAreaListTree } from "@/request/data_dictionary.js";
|
// import { getAreaListTree } from "@/request/data_dictionary.js";
|
||||||
import { STATUS_LIST } from "@/assets/js/constant.js";
|
import { STATUS_LIST } from "@/assets/js/constant.js";
|
||||||
|
import AppAreaCascader from "@/components/area_cascader/index.vue";
|
||||||
const visible = defineModel("visible", { type: Boolean, required: true });
|
const visible = defineModel("visible", { type: Boolean, required: true });
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
corpInfoId: { type: Number, required: true },
|
corpInfoId: { type: Number, required: true },
|
||||||
});
|
});
|
||||||
const { dictionariesList } = await getAreaListTree();
|
// const { dictionariesList } = await getAreaListTree();
|
||||||
const { formRef } = useForm();
|
const { formRef } = useForm();
|
||||||
const form = ref({
|
const form = ref({
|
||||||
platformName: "",
|
platformName: "",
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="platformName" label="平台名称" />
|
<el-table-column prop="platformName" label="平台名称" />
|
||||||
<el-table-column prop="url" label="平台地址" />
|
<!-- <el-table-column prop="url" label="平台地址" /> -->
|
||||||
<el-table-column prop="fieldCount" label="涉及推送字段数" />
|
<el-table-column prop="fieldCount" label="涉及推送字段数" />
|
||||||
<el-table-column prop="runTime" label="运行时间" />
|
<el-table-column prop="runTime" label="运行时间" />
|
||||||
<el-table-column prop="frequency" label="推送频率"
|
<el-table-column prop="frequency" label="推送频率"
|
||||||
|
@ -142,6 +142,8 @@ const fnDataItems = (row) => {
|
||||||
dataItemVisible.value.visible = true;
|
dataItemVisible.value.visible = true;
|
||||||
dataItemVisible.value.platformName = row.platformName;
|
dataItemVisible.value.platformName = row.platformName;
|
||||||
dataItemVisible.value.edit = 1;
|
dataItemVisible.value.edit = 1;
|
||||||
|
dataItemVisible.value.resourceId = "";
|
||||||
|
dataItemVisible.value.menuId = "";
|
||||||
};
|
};
|
||||||
const infoDialog = ref({
|
const infoDialog = ref({
|
||||||
visible: false,
|
visible: false,
|
||||||
|
|
|
@ -142,7 +142,7 @@ import useForm from "@/hooks/useForm.js";
|
||||||
import {
|
import {
|
||||||
setRouteAdd,
|
setRouteAdd,
|
||||||
setRouteEdit,
|
setRouteEdit,
|
||||||
getDataRouteKeyDuplication,
|
// getDataRouteKeyDuplication,
|
||||||
} from "@/request/system_management.js";
|
} from "@/request/system_management.js";
|
||||||
import { ElMessage } from "element-plus";
|
import { ElMessage } from "element-plus";
|
||||||
|
|
||||||
|
@ -175,16 +175,16 @@ const fnSubmit = debounce(
|
||||||
1000,
|
1000,
|
||||||
async () => {
|
async () => {
|
||||||
await validate();
|
await validate();
|
||||||
if (form.value.routeKey) {
|
// if (form.value.routeKey) {
|
||||||
const { menu } = await getDataRouteKeyDuplication({
|
// const { menu } = await getDataRouteKeyDuplication({
|
||||||
routeKey: form.value.routeKey,
|
// routeKey: form.value.routeKey,
|
||||||
menuId: form.value.menuId,
|
// menuId: form.value.menuId,
|
||||||
});
|
// });
|
||||||
if (menu) {
|
// if (menu) {
|
||||||
ElMessage.error("路由名称(唯一标识)重复,请修改!");
|
// ElMessage.error("路由名称(唯一标识)重复,请修改!");
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
const meta = {
|
const meta = {
|
||||||
title: form.value.title,
|
title: form.value.title,
|
||||||
model: form.value.model,
|
model: form.value.model,
|
||||||
|
|
|
@ -0,0 +1,207 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<el-form ref="formRef" :model="form" :rules="rules" label-width="110px">
|
||||||
|
<el-row :gutter="24">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="上级部门">
|
||||||
|
<el-tag>{{ parentName }}</el-tag>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="名称" prop="name">
|
||||||
|
<el-input v-model="form.name" placeholder="这里输入名称..." />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="行政区域级别" prop="level">
|
||||||
|
<el-select
|
||||||
|
v-model="form.level"
|
||||||
|
placeholder="请选择"
|
||||||
|
@change="fnChangeLevel"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in ADMINISTRATIVE_REGION_LEVEL_LIST"
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.name"
|
||||||
|
:value="item.id"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col v-if="form.level" :span="12">
|
||||||
|
<el-form-item :key="form.level" label="所属区域" prop="area">
|
||||||
|
<app-area-cascader
|
||||||
|
v-model="form.area"
|
||||||
|
control-level
|
||||||
|
:level="form.level"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col v-if="type === '2'" :span="12">
|
||||||
|
<el-form-item label="部门类别" prop="category">
|
||||||
|
<el-select v-model="form.category" placeholder="请选择">
|
||||||
|
<el-option
|
||||||
|
v-for="item in categoryList"
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.name"
|
||||||
|
:value="item.id"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col v-if="parentId === '0'" :span="12">
|
||||||
|
<el-form-item label="是否监管部门" prop="supervisory">
|
||||||
|
<el-select v-model="form.supervisory" placeholder="请选择">
|
||||||
|
<el-option
|
||||||
|
v-for="item in WHETHER_LIST"
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.name"
|
||||||
|
:value="item.id"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<template v-if="!!departmentId">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="主管负责人" prop="headman">
|
||||||
|
<app-user v-model="form.headman" splicing-label />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="分管领导" prop="lrman">
|
||||||
|
<app-user v-model="form.lrman" splicing-label />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</template>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="排序" prop="depOrder">
|
||||||
|
<el-input
|
||||||
|
v-model.number="form.depOrder"
|
||||||
|
placeholder="这里输入排序..."
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form>
|
||||||
|
<div class="mt-10 tc">
|
||||||
|
<el-button type="primary" @click="fnSubmit">保存</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref } from "vue";
|
||||||
|
import useForm from "@/hooks/useForm.js";
|
||||||
|
import { useRoute, useRouter } from "vue-router";
|
||||||
|
import AppAreaCascader from "@/components/area_cascader/index.vue";
|
||||||
|
import AppUser from "@/components/user/index.vue";
|
||||||
|
import {
|
||||||
|
ADMINISTRATIVE_REGION_LEVEL_LIST,
|
||||||
|
WHETHER_LIST,
|
||||||
|
} from "@/assets/js/constant.js";
|
||||||
|
import { debounce } from "throttle-debounce";
|
||||||
|
import {
|
||||||
|
getDepartmentInfo,
|
||||||
|
setDepartmentAdd,
|
||||||
|
setDepartmentUpdate,
|
||||||
|
} from "@/request/user_management.js";
|
||||||
|
import { ElMessage } from "element-plus";
|
||||||
|
|
||||||
|
const route = useRoute();
|
||||||
|
const router = useRouter();
|
||||||
|
const { parentId, parentName, type, departmentId } = route.query;
|
||||||
|
const { formRef, validate } = useForm();
|
||||||
|
const form = ref({
|
||||||
|
name: "",
|
||||||
|
level: "",
|
||||||
|
area: [],
|
||||||
|
category: "",
|
||||||
|
supervisory: "",
|
||||||
|
headman: "",
|
||||||
|
lrman: "",
|
||||||
|
depOrder: "",
|
||||||
|
});
|
||||||
|
const parentInfo = {
|
||||||
|
parentIds: "",
|
||||||
|
parentNames: "",
|
||||||
|
treeIds: "",
|
||||||
|
treeNames: "",
|
||||||
|
};
|
||||||
|
const rules = {
|
||||||
|
name: [{ required: true, message: "请输入部门名称", trigger: "blur" }],
|
||||||
|
level: [{ required: true, message: "请选择部门级别", trigger: "change" }],
|
||||||
|
area: [{ required: true, message: "请选择所属区域", trigger: "change" }],
|
||||||
|
category: [{ required: true, message: "请选择部门类别", trigger: "change" }],
|
||||||
|
supervisory: [
|
||||||
|
{ required: true, message: "请选择是否监管部门", trigger: "change" },
|
||||||
|
],
|
||||||
|
depOrder: [{ required: true, message: "请输入排序", trigger: "blur" }],
|
||||||
|
};
|
||||||
|
const categoryList = [
|
||||||
|
{ id: "1", name: "行业监管" },
|
||||||
|
{ id: "2", name: "综合监管" },
|
||||||
|
];
|
||||||
|
const fnGetData = async () => {
|
||||||
|
if (!departmentId) return;
|
||||||
|
const { data } = await getDepartmentInfo(departmentId);
|
||||||
|
form.value = data;
|
||||||
|
form.value.area = [
|
||||||
|
data.province,
|
||||||
|
data.city,
|
||||||
|
data.county,
|
||||||
|
data.village,
|
||||||
|
data.street,
|
||||||
|
].filter(Boolean);
|
||||||
|
parentInfo.parentIds = data.parentIds;
|
||||||
|
parentInfo.parentNames = data.parentNames;
|
||||||
|
parentInfo.treeIds = data.treeIds;
|
||||||
|
parentInfo.treeNames = data.treeNames;
|
||||||
|
};
|
||||||
|
fnGetData();
|
||||||
|
const fnGetDataParent = async () => {
|
||||||
|
if (parentId === "0" || departmentId) return;
|
||||||
|
const { data } = await getDepartmentInfo(parentId);
|
||||||
|
const parentIds = data.parentIds.split(",");
|
||||||
|
const parentNames = data.parentNames.split(",");
|
||||||
|
const treeIds = data.treeIds.split(",");
|
||||||
|
const treeNames = data.treeNames.split(",");
|
||||||
|
parentIds.push(parentId);
|
||||||
|
parentNames.push(parentName);
|
||||||
|
parentInfo.parentIds = parentIds.filter(Boolean).join(",");
|
||||||
|
parentInfo.parentNames = parentNames.filter(Boolean).join(",");
|
||||||
|
parentInfo.treeIds = treeIds.filter(Boolean).join(",");
|
||||||
|
parentInfo.treeNames = treeNames.filter(Boolean).join(",");
|
||||||
|
};
|
||||||
|
fnGetDataParent();
|
||||||
|
const fnChangeLevel = (event) => {
|
||||||
|
if (event === 1) form.value.area = ["130000", "130300"];
|
||||||
|
else form.value.area = [];
|
||||||
|
};
|
||||||
|
const fnSubmit = debounce(
|
||||||
|
1000,
|
||||||
|
async () => {
|
||||||
|
await validate();
|
||||||
|
const [province = "", city = "", county = "", village = "", street = ""] =
|
||||||
|
form.value.area;
|
||||||
|
const params = {
|
||||||
|
...form.value,
|
||||||
|
...parentInfo,
|
||||||
|
province,
|
||||||
|
city,
|
||||||
|
county,
|
||||||
|
village,
|
||||||
|
street,
|
||||||
|
type,
|
||||||
|
parentId,
|
||||||
|
};
|
||||||
|
!departmentId
|
||||||
|
? await setDepartmentAdd(params)
|
||||||
|
: await setDepartmentUpdate(params);
|
||||||
|
ElMessage.success("操作成功");
|
||||||
|
router.back();
|
||||||
|
},
|
||||||
|
{ atBegin: true }
|
||||||
|
);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss"></style>
|
|
@ -1,10 +1,210 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div style="display: flex; gap: 20px">
|
||||||
1
|
<div style="width: 300px">
|
||||||
|
<app-area-view-tree
|
||||||
|
:default-expanded-keys="code"
|
||||||
|
@node-click="fnNavigation({ code: $event.bianma, level: $event.level })"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div style="flex: 1">
|
||||||
|
<el-tabs v-model="activeTab" @tab-change="fnNavigation({ type: $event })">
|
||||||
|
<el-tab-pane
|
||||||
|
v-for="tab in tabs"
|
||||||
|
:key="tab.id"
|
||||||
|
:name="tab.id"
|
||||||
|
:label="tab.name"
|
||||||
|
/>
|
||||||
|
</el-tabs>
|
||||||
|
<app-table
|
||||||
|
v-model:pagination="pagination"
|
||||||
|
:data="list"
|
||||||
|
@get-data="getData"
|
||||||
|
>
|
||||||
|
<el-table-column v-slot="{ row }" label="名称" width="180">
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
text
|
||||||
|
link
|
||||||
|
@click="
|
||||||
|
fnNavigation({
|
||||||
|
parentId: row.departmentId,
|
||||||
|
parentName: row.name,
|
||||||
|
})
|
||||||
|
"
|
||||||
|
>
|
||||||
|
{{ row.name }}
|
||||||
|
</el-button>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column v-slot="{ row }" prop="category" label="部门类型">
|
||||||
|
<div v-if="row.category === '1'">行业监管</div>
|
||||||
|
<div v-if="row.category === '2'">综合监管</div>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="headmanName" label="部门负责人" />
|
||||||
|
<el-table-column v-slot="{ row }" label="属地">
|
||||||
|
{{
|
||||||
|
[
|
||||||
|
row.provinceName,
|
||||||
|
row.cityName,
|
||||||
|
row.countyName,
|
||||||
|
row.villageName,
|
||||||
|
row.streetName,
|
||||||
|
]
|
||||||
|
.filter(Boolean)
|
||||||
|
.join("--")
|
||||||
|
}}
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column v-slot="{ row }" label="操作" width="120">
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
text
|
||||||
|
link
|
||||||
|
@click="
|
||||||
|
router.push({
|
||||||
|
path: '/user_management/department/add',
|
||||||
|
query: {
|
||||||
|
parentId,
|
||||||
|
parentName,
|
||||||
|
type: activeTab,
|
||||||
|
departmentId: row.departmentId,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
"
|
||||||
|
>
|
||||||
|
修改
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
v-if="parentId !== '0' || isRootAdd"
|
||||||
|
type="danger"
|
||||||
|
text
|
||||||
|
link
|
||||||
|
@click="fnDelete(row.departmentId, row.name)"
|
||||||
|
>
|
||||||
|
删除
|
||||||
|
</el-button>
|
||||||
|
</el-table-column>
|
||||||
|
<template #button>
|
||||||
|
<el-button
|
||||||
|
v-if="parentId !== '0' || isRootAdd"
|
||||||
|
type="primary"
|
||||||
|
@click="
|
||||||
|
router.push({
|
||||||
|
path: '/user_management/department/add',
|
||||||
|
query: { parentId, parentName, type: activeTab },
|
||||||
|
})
|
||||||
|
"
|
||||||
|
>
|
||||||
|
新增
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
v-if="parentId !== '0'"
|
||||||
|
:icon="ArrowLeft"
|
||||||
|
@click="router.back()"
|
||||||
|
>
|
||||||
|
返回
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</app-table>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
|
import AppAreaViewTree from "@/components/area_view_tree/index.vue";
|
||||||
|
import { ref } from "vue";
|
||||||
|
import { useUserStore } from "@/pinia/user.js";
|
||||||
|
import useListData from "@/hooks/useListData.js";
|
||||||
|
import {
|
||||||
|
getDepartmentList,
|
||||||
|
setDepartmentDelete,
|
||||||
|
} from "@/request/user_management.js";
|
||||||
|
import AppTable from "@/components/table/index.vue";
|
||||||
|
import { ArrowLeft } from "@element-plus/icons-vue";
|
||||||
|
import { onBeforeRouteUpdate, useRoute, useRouter } from "vue-router";
|
||||||
|
import { ElMessage, ElMessageBox } from "element-plus";
|
||||||
|
import { DEPARTMENT_CATEGORY_LIST } from "@/assets/js/constant.js";
|
||||||
|
|
||||||
|
const userStore = useUserStore();
|
||||||
|
const userInfo = userStore.getUserInfo;
|
||||||
|
const router = useRouter();
|
||||||
|
const route = useRoute();
|
||||||
|
const defaultQuery = {
|
||||||
|
parentId: "0",
|
||||||
|
parentName: "(无)此项为顶级部门",
|
||||||
|
type: "1",
|
||||||
|
code: "",
|
||||||
|
level: "",
|
||||||
|
};
|
||||||
|
const parentId = ref(route.query.parentId || defaultQuery.parentId);
|
||||||
|
const parentName = ref(route.query.parentName || defaultQuery.parentName);
|
||||||
|
const activeTab = ref(route.query.type || defaultQuery.type);
|
||||||
|
const code = ref(route.query.code || defaultQuery.code);
|
||||||
|
const level = ref(route.query.level || defaultQuery.level);
|
||||||
|
const isRootAdd = ref(true);
|
||||||
|
const tabs = ref(
|
||||||
|
DEPARTMENT_CATEGORY_LIST.map((item) => ({
|
||||||
|
...item,
|
||||||
|
show: true,
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
const fnInitTabs = () => {
|
||||||
|
if (userInfo.userId === "1") return;
|
||||||
|
const roleId = "6084ca2e939f4fa6bed93ce01786df35";
|
||||||
|
const roleIndex = userInfo.rolesId?.indexOf(roleId);
|
||||||
|
if (roleIndex !== -1) {
|
||||||
|
activeTab.value = "1";
|
||||||
|
tabs.value.forEach((item, index) => {
|
||||||
|
item.show = index !== 3;
|
||||||
|
});
|
||||||
|
} else if (userInfo.type === 2) {
|
||||||
|
isRootAdd.value = false;
|
||||||
|
activeTab.value = "2";
|
||||||
|
tabs.value.forEach((item, index) => {
|
||||||
|
item.show = index === 1;
|
||||||
|
});
|
||||||
|
} else if (userInfo.type === 3) {
|
||||||
|
isRootAdd.value = false;
|
||||||
|
activeTab.value = "3";
|
||||||
|
tabs.value.forEach((item, index) => {
|
||||||
|
item.show = index === 2;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
tabs.value = tabs.value.filter((item) => item.show);
|
||||||
|
};
|
||||||
|
fnInitTabs();
|
||||||
|
const { list, pagination, getData, resetPagination } = useListData(
|
||||||
|
getDepartmentList,
|
||||||
|
{
|
||||||
|
params: () => ({
|
||||||
|
type: activeTab.value,
|
||||||
|
code: code.value,
|
||||||
|
level: level.value,
|
||||||
|
departmentId: parentId.value,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
onBeforeRouteUpdate((to) => {
|
||||||
|
parentId.value = to.query.parentId || defaultQuery.parentId;
|
||||||
|
parentName.value = to.query.parentName || defaultQuery.parentName;
|
||||||
|
activeTab.value = to.query.type || defaultQuery.type;
|
||||||
|
code.value = to.query.code || defaultQuery.code;
|
||||||
|
level.value = to.query.level || defaultQuery.level;
|
||||||
|
resetPagination();
|
||||||
|
});
|
||||||
|
const fnNavigation = (query) => {
|
||||||
|
router.push({
|
||||||
|
path: "/user_management/department",
|
||||||
|
query: {
|
||||||
|
...route.query,
|
||||||
|
...query,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
const fnDelete = async (departmentId, name) => {
|
||||||
|
await ElMessageBox.confirm(`确定要删除【${name}】吗?`, { type: "warning" });
|
||||||
|
await setDepartmentDelete({ ids: [departmentId] });
|
||||||
|
ElMessage.success("删除成功");
|
||||||
|
resetPagination();
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped></style>
|
<style scoped></style>
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
<template>
|
|
||||||
<div>1</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup></script>
|
|
||||||
|
|
||||||
<style scoped></style>
|
|
|
@ -0,0 +1,199 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<el-form ref="formRef" :rules="rules" :model="form" label-width="110px">
|
||||||
|
<el-row :gutter="12">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="角色" prop="roleId">
|
||||||
|
<el-select v-model="form.roleId">
|
||||||
|
<el-option
|
||||||
|
v-for="item in roleList"
|
||||||
|
:key="item.roleId"
|
||||||
|
:label="item.roleName"
|
||||||
|
:value="item.roleId"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col v-if="form.roleId" :span="12">
|
||||||
|
<el-form-item label="行政区域级别" prop="level">
|
||||||
|
<el-select v-model="form.level">
|
||||||
|
<el-option
|
||||||
|
v-for="item in ADMINISTRATIVE_REGION_LEVEL_LIST"
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.name"
|
||||||
|
:value="item.id"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col
|
||||||
|
v-if="form.roleId && form.level && form.level !== '-1'"
|
||||||
|
:span="12"
|
||||||
|
>
|
||||||
|
<el-form-item :key="form.level" label="所属区域" prop="area">
|
||||||
|
<app-area-cascader v-model="form.area" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col
|
||||||
|
v-if="form.roleId && form.level && form.area.length > 0"
|
||||||
|
:span="12"
|
||||||
|
>
|
||||||
|
<el-form-item label="部门类别" prop="type">
|
||||||
|
<el-select v-model="form.type">
|
||||||
|
<el-option
|
||||||
|
v-for="item in DEPARTMENT_CATEGORY_LIST"
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.name"
|
||||||
|
:value="item.id"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col
|
||||||
|
v-if="form.roleId && form.level && form.area.length > 0 && pd.type"
|
||||||
|
:span="12"
|
||||||
|
>
|
||||||
|
<el-form-item label="部门" prop="departmentId">
|
||||||
|
<app-department v-model="form.departmentId" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col v-if="form.roleId && form.level && form.type === 1" :span="12">
|
||||||
|
<el-form-item label="安委会部门" prop="departmentCommission">
|
||||||
|
<app-department v-model="form.departmentCommission" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="职务" prop="duty">
|
||||||
|
<el-select v-model="form.duty" allow-create default-first-option>
|
||||||
|
<el-option
|
||||||
|
v-for="item in dutyList"
|
||||||
|
:key="item.bianma"
|
||||||
|
:label="item.name"
|
||||||
|
:value="item.bianma"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col
|
||||||
|
v-if="
|
||||||
|
form.type === 3 &&
|
||||||
|
(form.level === '2' || form.level === '3' || form.level === '4')
|
||||||
|
"
|
||||||
|
:span="12"
|
||||||
|
>
|
||||||
|
<el-form-item label="网格" prop="grid">
|
||||||
|
<el-select v-model="form.grid">
|
||||||
|
<el-option label="网格长" value="0" />
|
||||||
|
<el-option v-if="form.level === '4'" label="网格员" value="1" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="用户名" prop="username">
|
||||||
|
<el-input v-model="form.username" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="姓名" prop="name">
|
||||||
|
<el-input v-model="form.name" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="手机号" prop="phone">
|
||||||
|
<el-input v-model="form.phone" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="邮箱" prop="email">
|
||||||
|
<el-input v-model="form.email" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="备注" prop="bz">
|
||||||
|
<el-input v-model="form.bz" type="textarea" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref } from "vue";
|
||||||
|
import useForm from "@/hooks/useForm.js";
|
||||||
|
import { getRoleListAll } from "@/request/system_management.js";
|
||||||
|
import AppAreaCascader from "@/components/area_cascader/index.vue";
|
||||||
|
import AppDepartment from "@/components/department/index.vue";
|
||||||
|
import { MOBILE_PHONE } from "@/assets/js/regular.js";
|
||||||
|
import { hasUser } from "@/request/user_management.js";
|
||||||
|
import {
|
||||||
|
ADMINISTRATIVE_REGION_LEVEL_LIST,
|
||||||
|
DEPARTMENT_CATEGORY_LIST,
|
||||||
|
} from "@/assets/js/constant.js";
|
||||||
|
|
||||||
|
const fnHasUser = async (_, value, callback) => {
|
||||||
|
const { user } = await hasUser({
|
||||||
|
username: value,
|
||||||
|
userId: form.value.userId,
|
||||||
|
});
|
||||||
|
if (!user) callback();
|
||||||
|
else callback(new Error("用户名重复"));
|
||||||
|
};
|
||||||
|
const form = ref({
|
||||||
|
roleId: "",
|
||||||
|
level: "",
|
||||||
|
area: [],
|
||||||
|
type: "",
|
||||||
|
departmentId: "",
|
||||||
|
departmentCommission: "",
|
||||||
|
duty: "",
|
||||||
|
grid: "",
|
||||||
|
username: "",
|
||||||
|
name: "",
|
||||||
|
phone: "",
|
||||||
|
email: "",
|
||||||
|
bz: "",
|
||||||
|
});
|
||||||
|
const rules = {
|
||||||
|
roleId: [{ required: true, message: "角色不能为空", trigger: "blur" }],
|
||||||
|
area: [{ required: true, message: "所属区域不能为空", trigger: "blur" }],
|
||||||
|
type: [{ required: true, message: "部门类别不能为空", trigger: "change" }],
|
||||||
|
level: [{ required: true, message: "行政区域级别不能为空", trigger: "blur" }],
|
||||||
|
departmentId: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: "部门不能为空",
|
||||||
|
trigger: ["input", "change"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
departmentCommission: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: "安委会部门不能为空",
|
||||||
|
trigger: ["input", "change"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
username: [
|
||||||
|
{ required: true, message: "用户名不能为空", trigger: "blur" },
|
||||||
|
{ min: 2, max: 30, message: "长度在 2 到 30 个字符", trigger: "blur" },
|
||||||
|
{ validator: fnHasUser, trigger: "blur" },
|
||||||
|
],
|
||||||
|
name: [
|
||||||
|
{ required: true, message: "姓名不能为空", trigger: "blur" },
|
||||||
|
{ min: 2, max: 30, message: "长度在 2 到 30 个字符", trigger: "blur" },
|
||||||
|
],
|
||||||
|
phone: [
|
||||||
|
{ required: true, message: "手机号码不能为空", trigger: "blur" },
|
||||||
|
{ pattern: MOBILE_PHONE, message: "请输入正确的手机号码", trigger: "blur" },
|
||||||
|
],
|
||||||
|
};
|
||||||
|
const roleList = ref([]);
|
||||||
|
const dutyList = ref([]);
|
||||||
|
const { formRef } = useForm();
|
||||||
|
(async () => {
|
||||||
|
const resData = await getRoleListAll();
|
||||||
|
roleList.value = resData.roleList;
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss"></style>
|
|
@ -1,7 +1,203 @@
|
||||||
<template>
|
<template>
|
||||||
<div>1</div>
|
<div style="display: flex; gap: 20px">
|
||||||
|
<div
|
||||||
|
v-if="userType === 3 && (userLevel === 2 || userLevel === 3)"
|
||||||
|
style="width: 300px"
|
||||||
|
>
|
||||||
|
<app-area-view-tree
|
||||||
|
:default-expanded-keys="code"
|
||||||
|
@node-click="fnNavigation({ code: $event.bianma, level: $event.level })"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div style="flex: 1">
|
||||||
|
<app-search v-model="searchForm" :options @submit="resetPagination" />
|
||||||
|
<app-table
|
||||||
|
ref="tableRef"
|
||||||
|
v-model:pagination="pagination"
|
||||||
|
:data="list"
|
||||||
|
row-key="userId"
|
||||||
|
show-selection
|
||||||
|
@get-data="getData"
|
||||||
|
>
|
||||||
|
<el-table-column prop="username" label="用户名" />
|
||||||
|
<el-table-column prop="name" label="姓名" />
|
||||||
|
<el-table-column prop="roleName" label="角色" />
|
||||||
|
<el-table-column v-slot="{ row }" label="部门">
|
||||||
|
{{ row.DEPARTMENT_FULL_NAME.replace(",", "/") }}
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="dutyName" label="职务" />
|
||||||
|
<el-table-column v-slot="{ row }" label="用户类别" width="90">
|
||||||
|
<div v-if="row.type === 1">安委会用户</div>
|
||||||
|
<div v-else-if="row.type === 2">行业用户</div>
|
||||||
|
<div v-else-if="row.type === 3">
|
||||||
|
<div v-if="row.grid === '0'">
|
||||||
|
<div v-if="row.gridLevel === '1'">一级网格长</div>
|
||||||
|
<div v-else-if="row.gridLevel === '2'">二级网格长</div>
|
||||||
|
<div v-else-if="row.gridLevel === '3'">三级网格长</div>
|
||||||
|
</div>
|
||||||
|
<div v-else-if="row.grid === '1'">网格员</div>
|
||||||
|
<div v-else>属地用户</div>
|
||||||
|
</div>
|
||||||
|
<div v-else>其它用户</div>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="lastLogin" label="最近登录" width="140" />
|
||||||
|
<el-table-column prop="ip" label="上次登录IP" width="120" />
|
||||||
|
<el-table-column v-slot="{ row }" label="操作" width="150">
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
text
|
||||||
|
link
|
||||||
|
@click="
|
||||||
|
router.push({
|
||||||
|
url: '/user_management/user/add',
|
||||||
|
query: { userId: row.userId },
|
||||||
|
})
|
||||||
|
"
|
||||||
|
>
|
||||||
|
修改
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
text
|
||||||
|
link
|
||||||
|
@click="fnResetPassword(row.userId, row.username)"
|
||||||
|
>
|
||||||
|
重置密码
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
type="danger"
|
||||||
|
text
|
||||||
|
link
|
||||||
|
@click="fnDelete(row.userId, row.username)"
|
||||||
|
>
|
||||||
|
删除
|
||||||
|
</el-button>
|
||||||
|
</el-table-column>
|
||||||
|
<template #button>
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
@click="router.push({ path: '/user_management/user/add' })"
|
||||||
|
>
|
||||||
|
新建
|
||||||
|
</el-button>
|
||||||
|
<el-button type="danger" @click="fnDelete('', '')">
|
||||||
|
批量删除
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</app-table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup></script>
|
<script setup>
|
||||||
|
import AppSearch from "@/components/search/index.vue";
|
||||||
|
import { useUserStore } from "@/pinia/user.js";
|
||||||
|
import { getRoleListAll } from "@/request/system_management.js";
|
||||||
|
import { ref } from "vue";
|
||||||
|
import AppAreaViewTree from "@/components/area_view_tree/index.vue";
|
||||||
|
import { onBeforeRouteUpdate, useRoute, useRouter } from "vue-router";
|
||||||
|
import useListData from "@/hooks/useListData.js";
|
||||||
|
import {
|
||||||
|
getUserList,
|
||||||
|
setUserDelete,
|
||||||
|
setUserResetPassword,
|
||||||
|
} from "@/request/user_management.js";
|
||||||
|
import AppTable from "@/components/table/index.vue";
|
||||||
|
import { ElMessage, ElMessageBox } from "element-plus";
|
||||||
|
import { DEPARTMENT_CATEGORY_LIST } from "@/assets/js/constant.js";
|
||||||
|
|
||||||
|
const userStore = useUserStore();
|
||||||
|
const {
|
||||||
|
rolesId,
|
||||||
|
userId,
|
||||||
|
type: userType,
|
||||||
|
level: userLevel,
|
||||||
|
} = userStore.getUserInfo;
|
||||||
|
const router = useRouter();
|
||||||
|
const route = useRoute();
|
||||||
|
const defaultQuery = {
|
||||||
|
code: "",
|
||||||
|
level: "",
|
||||||
|
};
|
||||||
|
const code = ref(route.query.code || defaultQuery.code);
|
||||||
|
const level = ref(route.query.level || defaultQuery.level);
|
||||||
|
const roleList = ref([]);
|
||||||
|
const { list, pagination, searchForm, getData, resetPagination, tableRef } =
|
||||||
|
useListData(getUserList, {
|
||||||
|
params: () => ({
|
||||||
|
code: code.value,
|
||||||
|
level: level.value,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
const options = [
|
||||||
|
{ key: "roleName", label: "关键字", tip: "帐号、姓名、手机号" },
|
||||||
|
{
|
||||||
|
key: "type",
|
||||||
|
label: "部门类别",
|
||||||
|
type: "select",
|
||||||
|
options: DEPARTMENT_CATEGORY_LIST,
|
||||||
|
hidden: !(rolesId?.indexOf("1") !== -1 || userId === "1"),
|
||||||
|
},
|
||||||
|
{ key: "departmentName", label: "部门名称" },
|
||||||
|
{
|
||||||
|
key: "roleId",
|
||||||
|
label: "角色",
|
||||||
|
type: "select",
|
||||||
|
options: roleList,
|
||||||
|
valueKey: "roleId",
|
||||||
|
labelKey: "roleName",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
(async () => {
|
||||||
|
const resData = await getRoleListAll();
|
||||||
|
roleList.value = resData.roleList;
|
||||||
|
})();
|
||||||
|
const fnResetPassword = async (userId, name) => {
|
||||||
|
await ElMessageBox.confirm(
|
||||||
|
`"确定要将【${name}】的密码重置为[Aqsc@0335]吗?"`,
|
||||||
|
{ type: "warning" }
|
||||||
|
);
|
||||||
|
await setUserResetPassword({ userId });
|
||||||
|
ElMessage.success("重置成功");
|
||||||
|
resetPagination();
|
||||||
|
};
|
||||||
|
const fnDelete = async (userId, name) => {
|
||||||
|
let ids = [];
|
||||||
|
if (userId) {
|
||||||
|
await ElMessageBox.confirm(`"确定要删除【${name}】吗?"`, {
|
||||||
|
type: "warning",
|
||||||
|
});
|
||||||
|
ids.push(userId);
|
||||||
|
} else {
|
||||||
|
ids = tableRef.value.getSelectionRows();
|
||||||
|
if (ids.length === 0) {
|
||||||
|
return ElMessage.error("请选择要删除的数据");
|
||||||
|
}
|
||||||
|
await ElMessageBox.confirm(
|
||||||
|
`"确定要删除【${ids.map((item) => item.username).join("、")}】吗?"`,
|
||||||
|
{
|
||||||
|
type: "warning",
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
await setUserDelete({ ids });
|
||||||
|
ElMessage.success("删除成功");
|
||||||
|
resetPagination();
|
||||||
|
};
|
||||||
|
onBeforeRouteUpdate((to) => {
|
||||||
|
code.value = to.query.code || defaultQuery.code;
|
||||||
|
level.value = to.query.level || defaultQuery.level;
|
||||||
|
resetPagination();
|
||||||
|
});
|
||||||
|
const fnNavigation = (query) => {
|
||||||
|
router.push({
|
||||||
|
path: "/user_management/user",
|
||||||
|
query: {
|
||||||
|
...route.query,
|
||||||
|
...query,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
<style scoped></style>
|
<style scoped></style>
|
||||||
|
|
Loading…
Reference in New Issue