124
This commit is contained in:
67
src/components/Breadcrumb/index.vue
Normal file
67
src/components/Breadcrumb/index.vue
Normal file
@ -0,0 +1,67 @@
|
||||
<template>
|
||||
<el-breadcrumb class="breadcrumb-wrap" separator="/">
|
||||
<transition-group name="breadcrumb">
|
||||
<el-breadcrumb-item v-for="(item, index) in breadcrumData" :key="item.path">
|
||||
<!---不可点击-->
|
||||
<span class="no-redirect" v-if="index === breadcrumData.length - 1">{{ item.meta.title }}</span>
|
||||
<!---可点击项-->
|
||||
<span class="redirect" v-else @click="onLinkClick(item)">{{ item.meta.title }}</span>
|
||||
</el-breadcrumb-item>
|
||||
</transition-group>
|
||||
</el-breadcrumb>
|
||||
</template>
|
||||
|
||||
|
||||
<script setup>
|
||||
import { useStore } from 'vuex'
|
||||
import { watch, ref } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
const route = useRoute();
|
||||
|
||||
//生成数组数据
|
||||
const breadcrumData = ref([]);
|
||||
const getBreadcrumData = () => {
|
||||
//当前路由的标准化路由纪录
|
||||
breadcrumData.value = route.matched.filter(item => item.meta && item.meta.title)
|
||||
}
|
||||
|
||||
//watch监听路由变化
|
||||
watch(route, () => {
|
||||
getBreadcrumData();
|
||||
}, {
|
||||
immediate: true
|
||||
})
|
||||
|
||||
const store = useStore();
|
||||
const linkHoverColor = ref(store.getters.cssVar.menuBg);
|
||||
|
||||
const router = useRouter();
|
||||
const onLinkClick = (item) => {
|
||||
router.push(item.path)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.breadcrumb-wrap {
|
||||
display: inline-block;
|
||||
font-size: 14px;
|
||||
line-height: 50px;
|
||||
margin-left: 8px;
|
||||
|
||||
.no-redirect {
|
||||
color: #97a8be;
|
||||
cursor: text;
|
||||
}
|
||||
|
||||
.redirect {
|
||||
color: #666;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.redirect:hover {
|
||||
// 将来需要进行主题替换,所以这里不去写死样式
|
||||
color: v-bind(linkHoverColor);
|
||||
}
|
||||
}
|
||||
</style>
|
51
src/components/DictTag/index.vue
Normal file
51
src/components/DictTag/index.vue
Normal file
@ -0,0 +1,51 @@
|
||||
<template>
|
||||
<div>
|
||||
<template v-for="(item, index) in options">
|
||||
<template v-if="values.includes(item.value)">
|
||||
<span
|
||||
v-if="item.elTagType == 'default' || item.elTagType == '' || tag == false"
|
||||
:key="item.value"
|
||||
:index="index"
|
||||
:class="item.elTagType"
|
||||
>{{ item.label }}</span>
|
||||
<el-tag
|
||||
v-else
|
||||
:disable-transitions="true"
|
||||
:key="item.value + ''"
|
||||
:index="index"
|
||||
:type="item.elTagType === 'primary' ? '' : item.elTagType"
|
||||
:class="item.elTagType"
|
||||
>{{ item.label }}</el-tag
|
||||
>
|
||||
</template>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed } from "vue";
|
||||
|
||||
const props = defineProps({
|
||||
// 数据
|
||||
options: {
|
||||
type: Array,
|
||||
default: null
|
||||
},
|
||||
tag: false,
|
||||
value: [Number, String, Array]
|
||||
});
|
||||
|
||||
const values = computed(() => {
|
||||
if (props.value !== null && typeof props.value !== "undefined") {
|
||||
return Array.isArray(props.value) ? props.value : [String(props.value)];
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.el-tag + .el-tag {
|
||||
margin-left: 10px;
|
||||
}
|
||||
</style>
|
91
src/components/From/Email/index.vue
Normal file
91
src/components/From/Email/index.vue
Normal file
@ -0,0 +1,91 @@
|
||||
<template>
|
||||
<el-form ref="formRef" :model="groupData" :rules="rules">
|
||||
<el-form-item
|
||||
:label-width="LABEL_WIDTH"
|
||||
prop="modelValue"
|
||||
label="邮箱"
|
||||
>
|
||||
<el-input
|
||||
v-bind="$attrs"
|
||||
v-model="groupData.modelValue"
|
||||
@input="onInput()"
|
||||
@blur="validate()"
|
||||
max="11"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { LABEL_WIDTH } from '@/constant';
|
||||
import { ref, defineProps, defineEmits, defineExpose } from 'vue'
|
||||
const formRef = ref(null);
|
||||
const props = defineProps({
|
||||
isRequired: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
})
|
||||
|
||||
// import { validateIdentity } from './rules'
|
||||
const groupData = ref({
|
||||
modelValue: ''
|
||||
});
|
||||
const emits = defineEmits(['update:modelValue']);
|
||||
const onInput = (e) => {
|
||||
emits('update:modelValue', groupData.value.modelValue)
|
||||
}
|
||||
const isBX = ref(false)
|
||||
|
||||
const validateIdentity = () => {
|
||||
return (rule, value, callback) => {
|
||||
const reg = /^([a-zA-Z0-9]+[-_\.]?)+@[a-zA-Z0-9]+\.[a-z]+$/
|
||||
if (!value) {
|
||||
} else {
|
||||
if (!reg.test(value)) {
|
||||
return callback(new Error('请输入正确的邮箱地址'));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// 验证规则
|
||||
const rules = ref({
|
||||
modelValue: [
|
||||
{
|
||||
required: props.isRequired,
|
||||
message: '请输入邮箱',
|
||||
trigger: 'blur'
|
||||
},
|
||||
{
|
||||
trigger: 'blur',
|
||||
validator: validateIdentity()
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
// 校验是否 符合规则 。 把当前组件名通过 emits分发出去
|
||||
const validate = () => {
|
||||
formRef.value.validate((valid) => {
|
||||
if (valid) {
|
||||
emits('validateStatus', { 'Email': true })
|
||||
} else {
|
||||
emits('validateStatus', { 'Email': false })
|
||||
}
|
||||
})
|
||||
if (!props.isRequired && groupData.value.modelValue.length === 0) {
|
||||
emits('validateStatus', { 'Email': true })
|
||||
}
|
||||
}
|
||||
|
||||
const childMethod = () => {
|
||||
groupData.value.modelValue = ""
|
||||
}
|
||||
// 主动暴露childMethod方法
|
||||
defineExpose({ childMethod })
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
</style>
|
68
src/components/From/IdentityCard/index.vue
Normal file
68
src/components/From/IdentityCard/index.vue
Normal file
@ -0,0 +1,68 @@
|
||||
<template>
|
||||
<el-form ref="formRef" :model="groupData" :rules="rules">
|
||||
<el-form-item :label-width="LABEL_WIDTH" prop="modelValue" label="身份证号">
|
||||
<el-input
|
||||
v-bind="$attrs"
|
||||
v-model="groupData.modelValue"
|
||||
@input="onInput()"
|
||||
@blur="validate()"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { LABEL_WIDTH } from "@/constant";
|
||||
import { ref, defineProps, defineEmits, defineExpose } from "vue";
|
||||
import { validateIdentity } from "./rules";
|
||||
const props = defineProps({
|
||||
isRequired: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
});
|
||||
const groupData = ref({
|
||||
modelValue: ""
|
||||
});
|
||||
const formRef = ref(null);
|
||||
const emits = defineEmits(["videoListShowFn"]);
|
||||
const onInput = (e) => {
|
||||
emits("update:modelValue", groupData.value.modelValue);
|
||||
};
|
||||
// 验证规则
|
||||
const rules = ref({
|
||||
modelValue: [
|
||||
{
|
||||
required: props.isRequired,
|
||||
message: "请输入身份证",
|
||||
trigger: "blur"
|
||||
},
|
||||
{
|
||||
trigger: "change",
|
||||
validator: validateIdentity()
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
// 校验是否 符合规则 。 把当前组件名通过 emits分发出去
|
||||
const validate = () => {
|
||||
formRef.value.validate((valid) => {
|
||||
if (valid) {
|
||||
emits("validateStatus", { IdentityCard: true });
|
||||
} else {
|
||||
emits("validateStatus", { IdentityCard: false });
|
||||
}
|
||||
});
|
||||
if (!props.isRequired && groupData.value.modelValue.length === 0) {
|
||||
emits("validateStatus", { IdentityCard: true });
|
||||
}
|
||||
};
|
||||
|
||||
const childMethod = () => {
|
||||
groupData.value.modelValue = "";
|
||||
};
|
||||
// 主动暴露childMethod方法
|
||||
defineExpose({ childMethod });
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
79
src/components/From/IdentityCard/rules.js
Normal file
79
src/components/From/IdentityCard/rules.js
Normal file
@ -0,0 +1,79 @@
|
||||
export const validateIdentity = () => {
|
||||
return (rule, value, callback) => {
|
||||
if (!value) {
|
||||
// return callback(new Error('身份证号不能为空'));
|
||||
} else if (!/(^\d{15}$)|(^\d{17}(\d|X|x)$)/.test(value)) {
|
||||
callback(new Error('输入的身份证长度或格式错误'));
|
||||
}
|
||||
|
||||
//身份证城市
|
||||
var aCity = {
|
||||
11: '北京',
|
||||
12: '天津',
|
||||
13: '河北',
|
||||
14: '山西',
|
||||
15: '内蒙古',
|
||||
21: '辽宁',
|
||||
22: '吉林',
|
||||
23: '黑龙江',
|
||||
31: '上海',
|
||||
32: '江苏',
|
||||
33: '浙江',
|
||||
34: '安徽',
|
||||
35: '福建',
|
||||
36: '江西',
|
||||
37: '山东',
|
||||
41: '河南',
|
||||
42: '湖北',
|
||||
43: '湖南',
|
||||
44: '广东',
|
||||
45: '广西',
|
||||
46: '海南',
|
||||
50: '重庆',
|
||||
51: '四川',
|
||||
52: '贵州',
|
||||
53: '云南',
|
||||
54: '西藏',
|
||||
61: '陕西',
|
||||
62: '甘肃',
|
||||
63: '青海',
|
||||
64: '宁夏',
|
||||
65: '新疆',
|
||||
71: '台湾',
|
||||
81: '香港',
|
||||
82: '澳门',
|
||||
91: '国外'
|
||||
};
|
||||
if (!aCity[parseInt(value.substr(0, 2))]) {
|
||||
callback(new Error('身份证地区非法'));
|
||||
}
|
||||
// 出生日期验证
|
||||
var sBirthday = (
|
||||
value.substr(6, 4) +
|
||||
'-' +
|
||||
Number(value.substr(10, 2)) +
|
||||
'-' +
|
||||
Number(value.substr(12, 2))
|
||||
).replace(/-/g, '/'),
|
||||
d = new Date(sBirthday);
|
||||
if (
|
||||
sBirthday !==
|
||||
d.getFullYear() + '/' + (d.getMonth() + 1) + '/' + d.getDate()
|
||||
) {
|
||||
callback(new Error('身份证上的出生日期非法'));
|
||||
}
|
||||
|
||||
// 身份证号码校验
|
||||
var sum = 0,
|
||||
weights = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2],
|
||||
codes = '10X98765432';
|
||||
for (var i = 0; i < value.length - 1; i++) {
|
||||
sum += value[i] * weights[i];
|
||||
}
|
||||
var last = codes[sum % 11]; //计算出来的最后一位身份证号码
|
||||
if (value[value.length - 1] !== last) {
|
||||
callback(new Error('输入的身份证号非法'));
|
||||
}
|
||||
callback();
|
||||
};
|
||||
};
|
86
src/components/From/Phone/index.vue
Normal file
86
src/components/From/Phone/index.vue
Normal file
@ -0,0 +1,86 @@
|
||||
<template>
|
||||
<el-form ref="formRef" :model="groupData" :rules="rules">
|
||||
<el-form-item :label-width="LABEL_WIDTH" prop="modelValue" label="手机号">
|
||||
<el-input v-bind="$attrs" v-model="groupData.modelValue" @input="onInput()" @blur="validate()" max="11">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { LABEL_WIDTH } from '@/constant';
|
||||
import { ref, defineProps, defineEmits, defineExpose } from 'vue'
|
||||
const formRef = ref(null);
|
||||
const props = defineProps({
|
||||
isRequired: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
})
|
||||
const isOk = ref()
|
||||
const groupData = ref({
|
||||
modelValue: ''
|
||||
});
|
||||
const emits = defineEmits(['update:modelValue']);
|
||||
const onInput = (e) => {
|
||||
emits('update:modelValue', groupData.value.modelValue)
|
||||
}
|
||||
const isBX = ref(false)
|
||||
|
||||
const validateIdentity = () => {
|
||||
return (rule, value, callback) => {
|
||||
if (!value) {
|
||||
} else {
|
||||
const reg = /^1[3|4|5|7|8][0-9]\d{8}$/
|
||||
if (reg.test(value)) {
|
||||
callback();
|
||||
} else {
|
||||
return callback(new Error('请输入正确的手机号'));
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// 验证规则
|
||||
const rules = ref({
|
||||
modelValue: [
|
||||
{
|
||||
required: props.isRequired,
|
||||
message: '请输入手机号',
|
||||
trigger: 'blur'
|
||||
},
|
||||
{
|
||||
min: 11,
|
||||
message: '手机号格式不正确',
|
||||
trigger: 'blur'
|
||||
},
|
||||
{
|
||||
trigger: 'change',
|
||||
validator: validateIdentity()
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
// 校验是否 符合规则 。 把当前组件名通过 emits分发出去
|
||||
const validate = () => {
|
||||
formRef.value.validate((valid) => {
|
||||
if (valid) {
|
||||
emits('validateStatus', { Phone: true })
|
||||
isOk.value = true
|
||||
} else {
|
||||
emits('validateStatus', { Phone: false })
|
||||
isOk.value = false
|
||||
}
|
||||
})
|
||||
if (!props.isRequired && groupData.value.modelValue.length === 0) {
|
||||
emits('validateStatus', { Phone: true })
|
||||
isOk.value = true
|
||||
}
|
||||
}
|
||||
|
||||
const childMethod = () => {
|
||||
groupData.value.modelValue = ""
|
||||
}
|
||||
// 主动暴露childMethod方法
|
||||
defineExpose({ childMethod })
|
||||
</script>
|
348
src/components/GdMap/index.vue
Normal file
348
src/components/GdMap/index.vue
Normal file
@ -0,0 +1,348 @@
|
||||
<template>
|
||||
<div :id="mapid" class="map"></div>
|
||||
<div class="changeMap_box" v-if="props.isShow">
|
||||
<el-switch v-model="conditionRoute" @change="handleSwitch" active-text="打开路况" inactive-text="关闭路况" style="--el-switch-color:#13ce66;--el-switch-off-color:#ff4949;" />
|
||||
<!-- <el-carousel type="card" height="75px" :autoplay="false" indicator-position="none" :initial-index="3" @change="onMapImageChange">
|
||||
<el-carousel-item>
|
||||
<div class="mapImageItem">
|
||||
<img :src="require('@/assets/images/slt.jpg')" alt="" />
|
||||
<div>栅格浅色</div>
|
||||
</div>
|
||||
</el-carousel-item>
|
||||
<el-carousel-item>
|
||||
<div class="mapImageItem">
|
||||
<img :src="require('@/assets/images/yxt.jpg')" alt="" />
|
||||
<div>影像图</div>
|
||||
</div>
|
||||
</el-carousel-item>
|
||||
<el-carousel-item>
|
||||
<div class="mapImageItem">
|
||||
<img :src="require('@/assets/images/yst.jpg')" alt="" />
|
||||
<div>栅格深色</div>
|
||||
</div>
|
||||
</el-carousel-item>
|
||||
<el-carousel-item>
|
||||
<div class="mapImageItem">
|
||||
<img :src="require('@/assets/images/shy.png')" alt="" />
|
||||
<div>三合一</div>
|
||||
</div>
|
||||
</el-carousel-item>
|
||||
</el-carousel> -->
|
||||
<!-- 地图缩放 -->
|
||||
<div class="zoomTargetBox">
|
||||
<el-input-number :min="7" :max="18" v-model="zoomTarget" :step="1" step-strictly @change="handleZoom">
|
||||
</el-input-number>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, onUnmounted, defineProps, nextTick } from "vue";
|
||||
import { MapUtil } from "./mapUtil";
|
||||
import emitter from "@/utils/eventBus.js";
|
||||
import { getItem } from "@/utils/storage";
|
||||
const conditionRoute = ref(true); //路况
|
||||
const mMap = ref(null); //地图对象
|
||||
const mapUtil = ref(null); //地图工具对象
|
||||
const zoomTarget = ref(6);
|
||||
|
||||
const props = defineProps({
|
||||
mapid: {
|
||||
type: String,
|
||||
default: "mapDiv"
|
||||
},
|
||||
//是否显示可以切换地图底图
|
||||
isShow: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
//是否显示实时路况
|
||||
isShowMvt: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
//是否显示地图层级
|
||||
isShowZoom: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
//是否显示绘制控件
|
||||
isShowDraw: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
});
|
||||
try {
|
||||
const userInfo = getItem("deptId")[0].deptCode;
|
||||
} catch (error) {}
|
||||
let map;
|
||||
let mapLayer;
|
||||
let mapLayer1;
|
||||
onMounted(() => {
|
||||
emitter.on("followUp", (res) => {
|
||||
let box = document.getElementsByClassName("changeMap_box");
|
||||
if (!box) return;
|
||||
box[0].style.right = !res ? "4px" : "398px";
|
||||
box[0].style.transition = "0.5s";
|
||||
});
|
||||
|
||||
map = new EliMap({
|
||||
id: props.mapid,
|
||||
crs: "EPSG:3857",
|
||||
style: {
|
||||
glyphs: "./fonts/{fontstack}/{range}.pbf",
|
||||
center: [94.36,29.65],
|
||||
zoom: 10
|
||||
},
|
||||
transformRequest: (url) => {
|
||||
if (url.indexOf("TileMatrix=") != -1) {
|
||||
const arr = url.split("TileMatrix=");
|
||||
const arr1 = arr[1].split("&");
|
||||
const nurl = `${arr[0]}&TileMatrix=${Number(arr1[0])}&${arr1[1]}&${arr1[2]}`;
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
window.map = map;
|
||||
map.mapboxGLMap.on("load", () => {
|
||||
map.addGaudLayer({
|
||||
url: 'http://webrd02.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}',
|
||||
})
|
||||
zoomTarget.value = map.mapboxGLMap.getZoom();
|
||||
});
|
||||
mapUtil.value = new MapUtil(map);
|
||||
|
||||
mapUtil.value.Drawplot(); //初始化加载绘制工具
|
||||
|
||||
// 设置地图中心点及图层
|
||||
emitter.on("setMapCenter", (res) => {
|
||||
mapUtil.value.setMapCenter(res.location, res.zoomLevel);
|
||||
});
|
||||
|
||||
emitter.on("removePlot", (flag) => {
|
||||
mapUtil.value.removePlot(flag);
|
||||
});
|
||||
emitter.on("removeAll", (flag) => {
|
||||
mapUtil.value.removeAll(flag);
|
||||
});
|
||||
// 撒点
|
||||
emitter.on("addPointArea", (obj) => {
|
||||
mapUtil.value.makerSki(obj);
|
||||
});
|
||||
// 鼠标滑过提示文字的点位
|
||||
emitter.on("showPoint", (obj) => {
|
||||
mapUtil.value.showPoint(obj);
|
||||
});
|
||||
|
||||
// 清除覆盖物
|
||||
emitter.on("deletePointArea", (res) => {
|
||||
mapUtil.value.removeElement(res);
|
||||
});
|
||||
// 清除某个覆盖物的单个
|
||||
emitter.on("deletePointAreaOne", (obj) => {
|
||||
mapUtil.value.removeElementOne(obj.flag, obj.id);
|
||||
});
|
||||
|
||||
// 清除某个覆盖物的单个
|
||||
emitter.on("showSquire", (obj) => {
|
||||
mapUtil.value.zdySquire(obj);
|
||||
});
|
||||
|
||||
// 绘制图形 - 回显区域
|
||||
emitter.on("drawShape", (res) => {
|
||||
mapUtil.value.plot(res, resFun);
|
||||
});
|
||||
emitter.on("removeEara", (flag) => {
|
||||
mapUtil.value.removeEara(flag);
|
||||
});
|
||||
// 回显图形
|
||||
emitter.on("echoPlane", (res) => {
|
||||
mapUtil.value.echoPlane(res);
|
||||
});
|
||||
//移除绘制区域
|
||||
emitter.on("removeEara", (flag) => {
|
||||
mapUtil.value.removeEara(flag);
|
||||
});
|
||||
// 回显线
|
||||
emitter.on("echoLine", (res) => {
|
||||
mapUtil.value.createLine(res, res.flag);
|
||||
});
|
||||
//创建边界面(geojson)
|
||||
emitter.on("setBoundarys", (res) => {
|
||||
mapUtil.value.createBoundarys(res);
|
||||
});
|
||||
// 移除边界
|
||||
emitter.on("removeBj", (res) => {
|
||||
mapUtil.value.removeBj(res);
|
||||
});
|
||||
|
||||
// 轨迹回放
|
||||
emitter.on("drawLineAnimation", (res) => {
|
||||
mapUtil.value.displayLineAnimation(res);
|
||||
});
|
||||
|
||||
// 聚合撒点
|
||||
emitter.on("addPoint", (obj) => {
|
||||
mapUtil.value.aggregateScatteringPoint(obj);
|
||||
});
|
||||
|
||||
// 热力图显示
|
||||
emitter.on("thermodynamicChart", (res) => {
|
||||
mapUtil.value.showHeatDrawing(res);
|
||||
});
|
||||
|
||||
// 扩散圆
|
||||
emitter.on("diffusionCircle", (res) => {
|
||||
mapUtil.value.diffusionCircle(res);
|
||||
});
|
||||
|
||||
// 展示盘曲
|
||||
emitter.on("showGapText", (obj) => {
|
||||
mapUtil.value.gapText(obj);
|
||||
});
|
||||
|
||||
// 获取当前地图中心点
|
||||
emitter.on("getCurrentCenter", (res) => {
|
||||
let centerPoint = map.mapboxGLMap.getCenter();
|
||||
let coords = [centerPoint.lng, centerPoint.lat];
|
||||
emitter.emit("getcentercoord", coords);
|
||||
});
|
||||
});
|
||||
//切换地图底图
|
||||
const onMapImageChange = (val) => {
|
||||
//清除已经存在胡地图图层
|
||||
if (map.mapboxGLMap.getLayer("SGQS_ID"))
|
||||
map.mapboxGLMap.removeLayer("SGQS_ID");
|
||||
if (map.mapboxGLMap.getLayer("YX_ID")) map.mapboxGLMap.removeLayer("YX_ID");
|
||||
if (map.mapboxGLMap.getLayer("SGSG_ID"))
|
||||
map.mapboxGLMap.removeLayer("SGSG_ID");
|
||||
if (map.mapboxGLMap.getLayer("TDT_TITLE_ID"))
|
||||
map.mapboxGLMap.removeLayer("TDT_TITLE_ID");
|
||||
if (map.mapboxGLMap.getLayer("TDT_ROAD_ID"))
|
||||
map.mapboxGLMap.removeLayer("TDT_ROAD_ID");
|
||||
if (map.mapboxGLMap.getLayer("TDT_POI_ID"))
|
||||
map.mapboxGLMap.removeLayer("TDT_POI_ID");
|
||||
//设置图层
|
||||
switch (val) {
|
||||
case 0:
|
||||
mapSetLayer("SGQS_ID", "SGQS");
|
||||
break;
|
||||
case 1:
|
||||
mapSetLayer("YX_ID", "YX");
|
||||
break;
|
||||
case 2:
|
||||
mapSetLayer("SGSG_ID", "SGSG");
|
||||
break;
|
||||
case 3:
|
||||
mapSetLayer("TDT_TITLE_ID", "TDT_TITLE_SOURCES");
|
||||
mapSetLayer("TDT_ROAD_ID", "TDT_ROAD_SOURCES");
|
||||
mapSetLayer("TDT_POI_ID", "TDT_POI_SOURCES");
|
||||
break;
|
||||
}
|
||||
if (map.mapboxGLMap.getLayer("realTimeTrafficlevelOne"))
|
||||
map.mapboxGLMap.moveLayer("realTimeTrafficlevelOne");
|
||||
if (map.mapboxGLMap.getLayer("map_id")) map.mapboxGLMap.moveLayer("map_id");
|
||||
if (map.mapboxGLMap.getLayer("map_ids")) map.mapboxGLMap.moveLayer("map_ids");
|
||||
};
|
||||
|
||||
//设置图层函数
|
||||
const mapSetLayer = (id, source) => {
|
||||
map.mapboxGLMap.addLayer({ id, type: "raster", source });
|
||||
};
|
||||
|
||||
//获取地图绘制的数据
|
||||
const resFun = (coord, type, flag, data) => {
|
||||
|
||||
emitter.emit("coordString", {
|
||||
coord: coord,
|
||||
type: type,
|
||||
flag: flag,
|
||||
data: data
|
||||
});
|
||||
};
|
||||
|
||||
// 地图层级
|
||||
const handleZoom = (val) => {
|
||||
map.mapboxGLMap.setZoom(val);
|
||||
};
|
||||
|
||||
// 是否打开或者关闭路况
|
||||
const handleSwitch = (val) => {
|
||||
if (val) {
|
||||
// 打开
|
||||
} else {
|
||||
// 关闭
|
||||
}
|
||||
};
|
||||
|
||||
onUnmounted(() => {
|
||||
emitter.off("removePlot");
|
||||
emitter.off("setMapCenter");
|
||||
emitter.off("addPointArea");
|
||||
emitter.off("showPoint");
|
||||
emitter.off("deletePointArea");
|
||||
emitter.off("deletePointAreaOne");
|
||||
emitter.off("drawShape");
|
||||
emitter.off("echoPlane");
|
||||
emitter.off("removeEara");
|
||||
emitter.off("echoLine");
|
||||
emitter.off("addPoint");
|
||||
emitter.off("thermodynamicChart");
|
||||
emitter.off("drawLineAnimation");
|
||||
emitter.off("aggregateScatteringPoint");
|
||||
emitter.off("hotmap");
|
||||
emitter.off("setBoundarys");
|
||||
emitter.off("diffusionCircle");
|
||||
emitter.off("SsCircle");
|
||||
emitter.off("ClearssCircle");
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.map {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: aliceblue;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
margin: auto;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.changeMap_box {
|
||||
position: absolute;
|
||||
right: 398px;
|
||||
bottom: 4px;
|
||||
z-index: 9;
|
||||
.mapImageItem {
|
||||
border: 1px solid #08aae8;
|
||||
background: rgb(9, 26, 70);
|
||||
& > img {
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
}
|
||||
& > div {
|
||||
text-align: center;
|
||||
position: relative;
|
||||
top: -3px;
|
||||
}
|
||||
}
|
||||
.zoomTargetBox {
|
||||
margin-top: 10px;
|
||||
margin-left: 23px;
|
||||
}
|
||||
::v-deep .el-input-number__decrease,
|
||||
::v-deep .el-input-number__increase {
|
||||
background: #133362;
|
||||
color: #fff;
|
||||
border: none;
|
||||
}
|
||||
::v-deep .el-input__inner {
|
||||
background: #0c1641;
|
||||
}
|
||||
}
|
||||
</style>
|
874
src/components/GdMap/mapUtil.js
Normal file
874
src/components/GdMap/mapUtil.js
Normal file
@ -0,0 +1,874 @@
|
||||
import emitter from "@/utils/eventBus.js";
|
||||
|
||||
export function MapUtil(map) {
|
||||
let _that = this;
|
||||
_that.mMap = map; //地图对象
|
||||
_that._self = {}; //图层对象
|
||||
_that._CustomDraw = null; //自定义绘图
|
||||
_that.polygonGeo = null; //边界
|
||||
_that.idsBox = {}; //存放id的容器(需要某个标记单个删除的时候存储)
|
||||
_that.isCheck = false;
|
||||
/**
|
||||
* 设置地图中心点以
|
||||
* @param {*} location 中心坐标 [jd,wd]
|
||||
* @param {*} zoomLevel 层级 10
|
||||
*/
|
||||
MapUtil.prototype.setMapCenter = (location, zoomLevel) => {
|
||||
map.mapboxGLMap.setCenter(location);
|
||||
map.mapboxGLMap.setZoom(zoomLevel);
|
||||
};
|
||||
|
||||
/**
|
||||
* 撒点.鼠标滑动展示内容
|
||||
* @param {*} coords 坐标 geojson
|
||||
* @param {*} icon 图标
|
||||
* @param {*} flag 标识
|
||||
*/
|
||||
MapUtil.prototype.showPoint = (res) => {
|
||||
let { coords, icon, flag, iconH } = res;
|
||||
if (!coords) return;
|
||||
if (!_that._self[flag]) _that._self[flag] = [];
|
||||
let pointList = coords.map((it, index) => {
|
||||
let text = it.kfdMc || it.wzBc || it.gajgmc || it.xm || it.jczmc;
|
||||
let obj = {
|
||||
position: [it.jd, it.wd],
|
||||
userData: { deviceSn: "text" + index, area: text },
|
||||
id: it.id,
|
||||
text: text,
|
||||
data: it
|
||||
};
|
||||
if (it.jd && it.wd) return obj;
|
||||
});
|
||||
|
||||
const point = map.createdPoint(pointList, {
|
||||
image: icon, //对应上面的图片名称
|
||||
scale: 1,
|
||||
highlightImage: iconH ? iconH : icon, //高亮图标
|
||||
labelOption: {
|
||||
pixelOffset: [0, -2],
|
||||
allShow: false,
|
||||
fontSize: "18px",
|
||||
fontWeight: 600,
|
||||
fontColor: "#000000"
|
||||
}
|
||||
});
|
||||
_that._self[flag].push(point);
|
||||
|
||||
point.addEventListener("click", (val) => {
|
||||
let data = val.data ? JSON.parse(val.data) : {};
|
||||
// point.highlight(data.id) //高亮展示选中的点位
|
||||
_that.openInfoDetail(flag, [data]); //点击打开详情
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 撒点
|
||||
* @param {*} coords 坐标 geojson
|
||||
* @param {*} icon 图标
|
||||
* @param {*} flag 标识
|
||||
* @param {*} showTitle 是否展示标题
|
||||
*/
|
||||
|
||||
MapUtil.prototype.makerSki = (res) => {
|
||||
let { coords, icon, flag, showTitle } = res;
|
||||
if (!coords) return;
|
||||
if (!_that._self[flag]) _that._self[flag] = []; //存储地图标识的容器
|
||||
if (!_that.idsBox[flag]) _that.idsBox[flag] = []; //存储id的容器
|
||||
if (flag == "rx") {
|
||||
_that.handlePolice(coords, icon, flag, showTitle);
|
||||
} else {
|
||||
coords.forEach((item) => {
|
||||
let el = document.createElement("img");
|
||||
el.src = item.icon || icon;
|
||||
el.style.width = flag == "kfd" ? "32px" : "25px";
|
||||
if (flag.includes("jczMap_")) el.style.width = "45px";
|
||||
if (showTitle) _that.makerShowTitle(item, [item.jd, item.wd], flag); //展示标题
|
||||
const marker = map.Marker(el, [item.jd, item.wd], {
|
||||
anchor: "bottom",
|
||||
offset: [0, 0]
|
||||
});
|
||||
el.addEventListener("click", () => {
|
||||
_that.openInfoDetail(flag, item); //点击打开详情
|
||||
});
|
||||
_that._self[flag].push(marker);
|
||||
_that.idsBox[flag].push(item.id);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 警力处理展示
|
||||
MapUtil.prototype.handlePolice = (coords, icon, flag, showTitle) => {
|
||||
// 01-大型车辆-DXCL, 02-小型车辆=XXCL,03-摩托车-MTC,04-其他车辆-QTCL,05-重型车辆-ZXCL,06-风控车-FKC,07-巡逻车-XLC,08-装甲车-ZJC
|
||||
coords.forEach((item) => {
|
||||
let el = document.createElement("img");
|
||||
let jcIcon = require(`@/assets/point/police-car-bx.png`);
|
||||
switch (item.lx) {
|
||||
case "01": // 特警
|
||||
jcIcon = require(`@/assets/point/specialPolice.png`);
|
||||
break;
|
||||
case "02": // 交警
|
||||
jcIcon = require(`@/assets/point/trafficPolice.png`);
|
||||
break;
|
||||
case "03": // 派出所民警
|
||||
jcIcon = require(`@/assets/point/peoplePolice.png`);
|
||||
break;
|
||||
default: // 默认图标
|
||||
jcIcon = require(`@/assets/point/specialPolice.png`);
|
||||
break;
|
||||
}
|
||||
if (item.zzlx == 1) jcIcon = require(`@/assets/point/by.png`); //便衣
|
||||
let cllxList = item.cllx ? item.cllx.split(",") : [];
|
||||
|
||||
if (
|
||||
(cllxList.includes("03") || cllxList.includes("04")) &&
|
||||
item.lx == "02"
|
||||
)
|
||||
jcIcon = require(`@/assets/point/xljmtc.png`); //交警-摩托车
|
||||
if (
|
||||
(cllxList.includes("03") || cllxList.includes("04")) &&
|
||||
item.lx == "01"
|
||||
)
|
||||
jcIcon = require(`@/assets/point/tjc.png`); //特警-摩托车
|
||||
if (cllxList.includes("08") || cllxList.includes("06"))
|
||||
jcIcon = require(`@/assets/point/zjc.png`); //装甲车
|
||||
|
||||
el.src = jcIcon;
|
||||
let isShoeCar = cllxList.includes("03") || cllxList.includes("08"); //车辆类型
|
||||
// el.style.width = isShoeCar ? '38px':"25px"; //图片大小
|
||||
// if(cllxList.includes('08')) el.style.height = '40px'
|
||||
if (showTitle) _that.makerShowTitle(item, [item.jd, item.wd], flag); //展示标题
|
||||
_that.shouIcon(item, [item.jd, item.wd]); // 展示装备图标
|
||||
|
||||
let offset = isShoeCar ? [-10, 0] : [0, 0];
|
||||
if (cllxList.includes("08")) offset = [-12, -10];
|
||||
const marker = map.Marker(el, [item.jd, item.wd], {
|
||||
anchor: "bottom",
|
||||
offset: offset
|
||||
});
|
||||
el.addEventListener("click", () => {
|
||||
_that.openInfoDetail(flag, item); //点击打开详情
|
||||
});
|
||||
_that._self[flag].push(marker);
|
||||
_that.idsBox[flag].push(item.id);
|
||||
});
|
||||
};
|
||||
|
||||
// 信息框展示
|
||||
MapUtil.prototype.makerShowTitle = (item, points, flag, text) => {
|
||||
let T = flag == "rx" ? "rxTitle" : "Title";
|
||||
let flagT = flag + T;
|
||||
if (!_that._self[flagT]) _that._self[flagT] = [];
|
||||
|
||||
// 展示名字
|
||||
let textTitle = item.jzMc ? item.jzMc : item.fzrXm + "警组";
|
||||
if (flag == "sbwz_car" || flag == "sbwz_sb" || flag == "sbwz_zfjly")
|
||||
textTitle = item.sbmc;
|
||||
if (flag == "gapText") textTitle = text;
|
||||
|
||||
// 设置样式
|
||||
const el = document.createElement("div");
|
||||
el.className = "makerTitle";
|
||||
if (flag == "sbwz_car" || flag == "sbwz_sb" || flag == "sbwz_zfjly")
|
||||
el.className = "makerTitlezb";
|
||||
if (flag == "rx") {
|
||||
if (item.xfzt == "0") el.classList.add("makerTitleLine");
|
||||
else if (item.xfzt == "1") el.classList.add("makerTitlecj");
|
||||
else el.classList.add("makerTitleUnLine");
|
||||
}
|
||||
if (flag == "gapText") el.className = "makerTitleGapText";
|
||||
|
||||
// 渲染
|
||||
el.innerHTML = textTitle;
|
||||
const marker = map.Marker(el, points, {
|
||||
anchor: "bottom",
|
||||
offset: [0, -50]
|
||||
});
|
||||
_that._self[flagT].push(marker);
|
||||
};
|
||||
|
||||
/**
|
||||
* 装备图标
|
||||
* @param {点位数据} data
|
||||
* @param {点} point
|
||||
*/
|
||||
MapUtil.prototype.shouIcon = (data, point) => {
|
||||
if (!_that._self.gpsZb) _that._self.gpsZb = [];
|
||||
var qxIcon = require(`@/assets/point/qx.png`); //qixie
|
||||
var zfjlyIcon = require(`@/assets/point/interphone.png`); // 对讲机
|
||||
var clIcon = require(`@/assets/point/car.png`); // 车辆
|
||||
let jyqx =
|
||||
typeof data.jyqx == "string"
|
||||
? JSON.parse(data.jyqx)
|
||||
: data.jyqx
|
||||
? data.jyqx
|
||||
: [];
|
||||
let txzb =
|
||||
typeof data.txzb == "string"
|
||||
? JSON.parse(data.txzb)
|
||||
: data.txzb
|
||||
? data.txzb
|
||||
: [];
|
||||
let pbcl =
|
||||
typeof data.pbcl == "string"
|
||||
? JSON.parse(data.pbcl)
|
||||
: data.pbcl
|
||||
? data.pbcl
|
||||
: [];
|
||||
let list = [];
|
||||
let cl = pbcl && pbcl.length > 0 ? true : false; // 车辆
|
||||
let zb = txzb && txzb.length > 0 ? true : false; // 智能装备
|
||||
let qx = jyqx && jyqx.length > 0 ? true : false; // 警用器械
|
||||
if (zb) {
|
||||
let el = document.createElement("img");
|
||||
el.style.width = "15px";
|
||||
el.src = zfjlyIcon;
|
||||
const makerZb = map.Marker(el, point, {
|
||||
anchor: "bottom",
|
||||
offset: [20, -26]
|
||||
});
|
||||
list.push(makerZb);
|
||||
}
|
||||
if (qx) {
|
||||
let elqx = document.createElement("img");
|
||||
elqx.style.width = "15px";
|
||||
elqx.src = qxIcon;
|
||||
const makerQx = map.Marker(elqx, point, {
|
||||
anchor: "bottom",
|
||||
offset: [20, -10]
|
||||
});
|
||||
list.push(makerQx);
|
||||
}
|
||||
if (cl) {
|
||||
let elcl = document.createElement("img");
|
||||
elcl.style.width = "20px";
|
||||
elcl.src = clIcon;
|
||||
const makerCl = map.Marker(elcl, point, {
|
||||
anchor: "bottom",
|
||||
offset: [20, 2]
|
||||
});
|
||||
list.push(makerCl);
|
||||
}
|
||||
_that._self.gpsZb[data.id] = list;
|
||||
};
|
||||
|
||||
// 自定义展示
|
||||
MapUtil.prototype.zdySquire = (obj) => {
|
||||
let { points, flag, distance } = obj;
|
||||
if (!_that._self[flag]) _that._self[flag] = [];
|
||||
let textTitle = "距离:" + distance; // 展示名字
|
||||
const el = document.createElement("div");
|
||||
el.className = "makerTitle";
|
||||
if (flag == "distance") el.className = "makerTitleDistance"; // 设置样式
|
||||
el.innerHTML = textTitle;
|
||||
const marker = map.Marker(el, points, {
|
||||
anchor: "bottom",
|
||||
offset: [0, -76]
|
||||
}); // 渲染
|
||||
_that._self[flag].push(marker);
|
||||
};
|
||||
|
||||
/**扩散圆
|
||||
* @param coords:[jd,wd]
|
||||
*/
|
||||
MapUtil.prototype.diffusionCircle = (obj) => {
|
||||
let { coords, flag, isClear } = obj;
|
||||
if (!_that._self[flag]) _that._self[flag] = {};
|
||||
if (isClear) _that._self[flag].destroy(); //destroy销毁,show(false) 移除
|
||||
let data = [{ position: coords }];
|
||||
_that._self[flag] = map.DiffuseCircle(data, {
|
||||
radius: 10,
|
||||
color: "rgba(81,217,254)", //扫描扇形的颜色,必须是十六进制或者rgb
|
||||
duration: 30, //圆环与上一个圆环出现的间隔时间。配合speed参数可以调整圆圈的数量
|
||||
speed: 4 //圆环移动速度
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 聚合撒点
|
||||
* @param {*} coords 点位数据 geojson lng lat
|
||||
* @param {*} icon 点位图
|
||||
*/
|
||||
MapUtil.prototype.aggregateScatteringPoint = (obj) => {
|
||||
let { coords, icon, flag, isclear, scale, fontColor } = obj;
|
||||
let points = coords.map((item) => {
|
||||
item.lng = item.jd;
|
||||
item.lat = item.wd;
|
||||
return item;
|
||||
});
|
||||
if (!_that._self[flag]) _that._self[flag] = [];
|
||||
if (isclear) _that.removeElement(flag); //移除聚合
|
||||
let maker = map.clusterLayer(points, {
|
||||
id: flag,
|
||||
size: 18,
|
||||
pixelRange: 60,
|
||||
// gradient:{'1':'#00BFFF','10':'#008000', '100':'#FFA500', '1000':'#FF0000'},//可以自定义图片,把颜色换成图片地址
|
||||
gradient: { 1: icon, 10: icon, 100: icon, 1000: icon }, //可以自定义图片,把颜色换成图片地址
|
||||
fontSize: 14,
|
||||
fontColor: fontColor ? fontColor : "#001022",
|
||||
style: "custom", // spiral(螺旋形状),circle(圆圈),custom(自定义)
|
||||
image: icon,
|
||||
scale: scale ? scale : 1,
|
||||
// highlightImage:icon,
|
||||
fontFamily: ["Microsoft YaHei"]
|
||||
});
|
||||
|
||||
_that._self[flag].push(maker);
|
||||
|
||||
// 聚合的点击一个
|
||||
maker.addEventListener("click", (val) => {
|
||||
_that.openInfoDetail(flag, [val]); //点击打开详情
|
||||
});
|
||||
// 聚合的多个
|
||||
maker.addEventListener("clusterClick", (val) => {
|
||||
_that.openInfoDetail(flag, val); //点击打开详情
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 热力图
|
||||
* @param {*} coords 数组
|
||||
*/
|
||||
MapUtil.prototype.showHeatDrawing = (res) => {
|
||||
let { coords, flag, isclear, color } = res;
|
||||
if (!_that._self[flag]) _that._self[flag] = [];
|
||||
if (isclear) _that.removeElement(flag); //清除热力
|
||||
let data = {
|
||||
type: "FeatureCollection",
|
||||
features: []
|
||||
};
|
||||
for (let index = 0; index < coords.length; index++) {
|
||||
const item = coords[index];
|
||||
let jd = item.lng || item.jd;
|
||||
let wd = item.lat || item.wd;
|
||||
let mag =
|
||||
item.count <= 10
|
||||
? 1.4
|
||||
: item.count > 10 && item.count <= 50
|
||||
? 1.6
|
||||
: 1.9;
|
||||
let obj = {
|
||||
properties: { mag },
|
||||
type: "Feature",
|
||||
geometry: { type: "Point", coordinates: [jd, wd, 0.1] }
|
||||
};
|
||||
data.features.push(obj);
|
||||
}
|
||||
let colors = {
|
||||
0: "rgba(23,102,172,0)",
|
||||
0.5: "rgb(209,229,240)",
|
||||
1: "rgb(178,24,43)"
|
||||
};
|
||||
if (color) colors = { 0: color[0], 0.5: color[1], 1: color[2] };
|
||||
let heartmap = map.HeatMap(data, { colors });
|
||||
_that._self[flag].push(heartmap);
|
||||
};
|
||||
|
||||
// 清除所有
|
||||
MapUtil.prototype.removeAll = () => {
|
||||
for (let key in _that._self) {
|
||||
if (key != "rx" && key != "gpsZb" && !key.includes("rxTitle")) {
|
||||
let list = _that._self[key];
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
const el = list[i];
|
||||
if (el && typeof el == "object") el.destroy(); //destory()销毁 , show(false) false:隐藏 true :展示
|
||||
}
|
||||
_that._self[key] = [];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 删除图层要素
|
||||
* @param {*} layer 唯一标识
|
||||
*/
|
||||
MapUtil.prototype.removeElement = (layer) => {
|
||||
//警力装备
|
||||
if (layer == "gpsZb") {
|
||||
for (let key in _that._self.gpsZb) {
|
||||
let item = _that._self.gpsZb[key];
|
||||
if (item && item.length > 0) {
|
||||
for (let child in item) {
|
||||
item[child].destroy();
|
||||
}
|
||||
_that._self.gpsZb[key] = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (layer == "rx") _that.idsBox[layer] = [];
|
||||
// 其他图层
|
||||
if (!_that._self[layer]) return false;
|
||||
|
||||
if (layer !== "gpsZb") {
|
||||
for (let i = 0; i < _that._self[layer].length; i++) {
|
||||
const el = _that._self[layer][i];
|
||||
el.destroy(); //destory()销毁 , show(false) false:隐藏 true :展示
|
||||
}
|
||||
_that._self[layer] = [];
|
||||
|
||||
// d带标题的撒点
|
||||
let T = layer == "rx" ? "rxTitle" : "Title";
|
||||
let flagT = layer + T;
|
||||
if (!_that._self[flagT]) return false;
|
||||
for (let i = 0; i < _that._self[flagT].length; i++) {
|
||||
const el = _that._self[flagT][i];
|
||||
el.destroy(); //destory()销毁 , show(false) false:隐藏 true :展示
|
||||
}
|
||||
_that._self[flagT] = [];
|
||||
}
|
||||
};
|
||||
/**
|
||||
* 删除图层的某个要素
|
||||
* @param {*} layer 唯一标识
|
||||
*/
|
||||
MapUtil.prototype.removeElementOne = (layer, id) => {
|
||||
if (!_that.idsBox[layer]) return false;
|
||||
let list = _that.idsBox[layer];
|
||||
list.forEach((el, index) => {
|
||||
if (el == id) {
|
||||
_that.idsBox[layer].splice(index, 1);
|
||||
if (_that._self[layer][index]) _that._self[layer][index].destroy();
|
||||
_that._self[layer].splice(index, 1);
|
||||
if (layer == "rx") {
|
||||
let flagT = layer + "rxTitle";
|
||||
if (_that._self[flagT][index]) _that._self[flagT][index].destroy();
|
||||
_that._self[flagT].splice(index, 1);
|
||||
_that.removeGpsZbOverlayById(id); //删除图标
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 删除图标装备
|
||||
MapUtil.prototype.removeGpsZbOverlayById = (id) => {
|
||||
if (_that._self.gpsZb[id]) {
|
||||
try {
|
||||
let info = _that._self.gpsZb[id];
|
||||
if (info) {
|
||||
info.forEach((element) => {
|
||||
element.destroy();
|
||||
});
|
||||
delete _that._self.gpsZb[id];
|
||||
}
|
||||
} catch (err) {}
|
||||
}
|
||||
};
|
||||
|
||||
// 绘制数据的初始化
|
||||
MapUtil.prototype.Drawplot = (color) => {
|
||||
const {
|
||||
point,
|
||||
line,
|
||||
polygon,
|
||||
circle,
|
||||
rectangle,
|
||||
geoJson,
|
||||
remove,
|
||||
enableEdit
|
||||
} = map.draw({
|
||||
lineWidth: 2,
|
||||
lineColor: "rgba(233,168,32,1)",
|
||||
fillColor: "rgba(233,168,32,0.5)",
|
||||
color: "rgba(233,168,32,1)",
|
||||
pixelSzie: 0
|
||||
});
|
||||
_that._CustomDraw = {
|
||||
point,
|
||||
line,
|
||||
polygon,
|
||||
circle,
|
||||
rectangle,
|
||||
geoJson,
|
||||
remove,
|
||||
enableEdit
|
||||
};
|
||||
};
|
||||
/**
|
||||
* 绘制工具
|
||||
* @param {*} type 绘制形状
|
||||
* (point 点, line 线, circle 圆, polygon 多边形, rectangle 矩形) ,
|
||||
* geoJson:根据geojson回显图
|
||||
*/
|
||||
MapUtil.prototype.plot = (res, resFun) => {
|
||||
let { flag, color, linecolor, type, coords } = res;
|
||||
if (!_that._self[flag]) _that._self[flag] = [];
|
||||
if (res.isclear) _that.removePlot(flag); //移除绘制工具
|
||||
if (res.isclear && (res.type == "polygon" || res.type == "line"))
|
||||
_that.removeEara(flag); //移除回显的面和线条
|
||||
switch (type) {
|
||||
case "point":
|
||||
_that._CustomDraw.point((val) => {
|
||||
_that.handlePlot(val, type, flag, resFun);
|
||||
});
|
||||
break;
|
||||
case "rectangle":
|
||||
_that._CustomDraw.rectangle((val) => {
|
||||
_that.handlePlot(val, type, flag, resFun);
|
||||
});
|
||||
break;
|
||||
case "circle":
|
||||
_that._CustomDraw.circle((val) => {
|
||||
_that.handlePlot(val, type, flag, resFun);
|
||||
});
|
||||
break;
|
||||
case "polygon":
|
||||
_that._CustomDraw.polygon(
|
||||
(val) => {
|
||||
_that.handlePlot(val, type, flag, resFun);
|
||||
},
|
||||
{
|
||||
fillColor: color || "rgba(233,168,32,0.5)",
|
||||
lineColor: linecolor || "rgba(233,168,32,1)"
|
||||
}
|
||||
);
|
||||
break;
|
||||
case "line":
|
||||
_that._CustomDraw.line((val) => {
|
||||
_that.handlePlot(val, type, flag, resFun);
|
||||
});
|
||||
break;
|
||||
case "geoJson": //返回面
|
||||
let json = {
|
||||
type: "FeatureCollection",
|
||||
features: [
|
||||
{
|
||||
type: "Feature",
|
||||
geometry: {
|
||||
type: "Polygon",
|
||||
coordinates: coords // coords 是三维数组
|
||||
},
|
||||
id: flag,
|
||||
properties: {
|
||||
fillColor: color || "rgba(233,168,32,1)",
|
||||
lineColor: linecolor || "rgba(233,168,32,1)"
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
_that._CustomDraw.geoJson(json, (data) => {
|
||||
_that.handlePlot(data, type, flag, resFun);
|
||||
});
|
||||
break;
|
||||
}
|
||||
};
|
||||
/**
|
||||
* 处理自定义数据
|
||||
* @param {*} val 返回数据
|
||||
* @param {*} type 类型
|
||||
* @param {*} flag 唯一标识
|
||||
* @param {*} resFun 回调
|
||||
*/
|
||||
// 校验
|
||||
MapUtil.prototype.handlePlot = (val, type, flag, resFun) => {
|
||||
_that._self[flag].push(val.id);
|
||||
let coords = val.positionData; //绘制区域
|
||||
resFun(coords, type, flag, val);
|
||||
};
|
||||
|
||||
/**
|
||||
* 移除绘制工具
|
||||
* @param {*} flag 唯一标识
|
||||
*/
|
||||
MapUtil.prototype.removePlot = (flag) => {
|
||||
if (!_that._self[flag]) return false;
|
||||
_that._self[flag].forEach((v) => {
|
||||
_that._CustomDraw.remove(v);
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 移除绘制面
|
||||
* @param {*} flag 唯一标识
|
||||
*/
|
||||
MapUtil.prototype.removeEara = (flag) => {
|
||||
_that._CustomDraw.remove(flag);
|
||||
_that.removePlot(flag);
|
||||
};
|
||||
/**
|
||||
* 创建线
|
||||
* @param {*} type 回显形状
|
||||
* (solid 实线, dash 虚线, FlowColor 彩虹线, RoadLine 流线
|
||||
*/
|
||||
MapUtil.prototype.createLine = (res) => {
|
||||
let { type, coords, isclear, flag, color, width } = res;
|
||||
if (!coords) return false; // coords 是数组对象,可以同时撒多条数据
|
||||
if (!_that._self[flag]) _that._self[flag] = [];
|
||||
if (isclear) _that.removeElement(flag); //移除回显的线条
|
||||
let data = coords.map((item, index) => {
|
||||
return {
|
||||
position: item.coords[0], //二维数组
|
||||
text: "",
|
||||
id: index,
|
||||
userData: {
|
||||
name: item.text
|
||||
}
|
||||
};
|
||||
});
|
||||
let line = map.createLine(data, {
|
||||
color: color ? color : "rgba(20, 237, 245,1)",
|
||||
width: width ? width : 8,
|
||||
type,
|
||||
highlightColor: "red",
|
||||
labelOption: {
|
||||
pixelOffset: [0, -1],
|
||||
allShow: false,
|
||||
type: "text",
|
||||
fontColor: "rgba(20, 237, 245,1)"
|
||||
}
|
||||
});
|
||||
_that._self[flag].push(line);
|
||||
};
|
||||
|
||||
/**
|
||||
* 回显平面- 圆 - 多边形 - 矩形
|
||||
* @param {*} type 回显形状
|
||||
* type: 'polygon', 'rectangle
|
||||
coords = [{
|
||||
position:[[[jd,wd],[jd,wd] ---]], //三维数组
|
||||
text,//展示的文字
|
||||
id, //唯一标识
|
||||
FID, //渲染颜色的标识
|
||||
userData:{} //存储数据
|
||||
}]
|
||||
|
||||
* type:circle
|
||||
coords:[jd,wd] radius:半径
|
||||
|
||||
* @param {*} text 展示的文字
|
||||
*/
|
||||
MapUtil.prototype.echoPlane = (res) => {
|
||||
let {
|
||||
type,
|
||||
coords,
|
||||
fontColor,
|
||||
fontSize,
|
||||
text = "",
|
||||
radius = 0,
|
||||
isclear,
|
||||
flag,
|
||||
id = 1,
|
||||
color,
|
||||
linecolor
|
||||
} = res;
|
||||
if (!coords) return;
|
||||
if (isclear) _that.removeElement(flag);
|
||||
if (!_that._self[flag]) _that._self[flag] = [];
|
||||
let color1 = color ? color : "rgba(29,237,245,0.6)";
|
||||
let linecolor1 = linecolor ? linecolor : "rgba(29,237,245,0.6)";
|
||||
let style = {
|
||||
color: color1,
|
||||
outLineColor: linecolor1,
|
||||
outLineWidth: 2,
|
||||
highlightColor: "rgba(255,0,0,0.5)",
|
||||
labelOption: {
|
||||
pixelOffset: [0, 0],
|
||||
allShow: true,
|
||||
fontColor: fontColor ? fontColor : "#ffffff",
|
||||
fontSize: fontSize ? fontSize : "12px"
|
||||
}
|
||||
};
|
||||
let maker;
|
||||
// 圆
|
||||
if (type == "circle") {
|
||||
let params = [{ center: coords, radius, text, id }];
|
||||
maker = map.createCircle(params, style);
|
||||
}
|
||||
|
||||
// 矩形
|
||||
if (type == "rectangle") maker = map.createRectangle(coords, style);
|
||||
|
||||
// 多边形
|
||||
if (type == "polygon") maker = map.createPolygon(coords, style);
|
||||
_that._self[flag].push(maker);
|
||||
|
||||
maker.addEventListener("click", (val) => {
|
||||
if (flag == "xfq") {
|
||||
maker.highlight(val.id); //高亮展示
|
||||
emitter.emit("showXFQinfo", val);
|
||||
if (val.id == _that.lightHeight) {
|
||||
_that.isCheck = !_that.isCheck;
|
||||
if (_that.isCheck) {
|
||||
maker.highlight(0); //取消高亮展示
|
||||
emitter.emit("showXFQinfo", null);
|
||||
} else {
|
||||
emitter.emit("showXFQinfo", val);
|
||||
}
|
||||
}
|
||||
_that.lightHeight = val.id;
|
||||
}
|
||||
if (flag == "zdxl_fzyc") {
|
||||
emitter.emit("showFzycInfo", { info: val, type: true });
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 分割线展示文字
|
||||
MapUtil.prototype.gapText = (obj) => {
|
||||
let { points, text, flag } = obj;
|
||||
_that.makerShowTitle({}, points, flag, text); //展示标题
|
||||
};
|
||||
|
||||
/**
|
||||
* 轨迹回放
|
||||
* @param {*} coords 轨迹坐标.二维数组[[104.03640684556253,30.7415801286654],[103.98021233220163,30.6555411499294],[103.85766040251299,30.58094579138167]]
|
||||
* @param {*} isClear 是否清除上一次的记录
|
||||
*/
|
||||
MapUtil.prototype.displayLineAnimation = (res) => {
|
||||
let { coords, isClear, flag } = res;
|
||||
if (!coords) return;
|
||||
if (!_that._self[flag]) _that._self[flag] = [];
|
||||
if (isClear && _that._self[flag]) _that.removeElement(flag); //destroy 移除,start 播放,pause 暂停
|
||||
let lineString = getUUid().slice(3, 5);
|
||||
const data = [
|
||||
{
|
||||
position: coords,
|
||||
text: "实线",
|
||||
id: lineString,
|
||||
userData: { name: "测试1" }
|
||||
}
|
||||
];
|
||||
const track = map.trajectoryRealtime(data, {
|
||||
color: "#28F", //轨迹背景颜色
|
||||
width: 8,
|
||||
image: "images/car.png",
|
||||
speed: 80, // 单位 m/s
|
||||
imageWidth: 20,
|
||||
imageHeight: 40,
|
||||
isShowLine: false, //轨迹线是否显示
|
||||
isAgain: false, //轨迹运动是否重复,
|
||||
traveledColor: "#32b1fb" //运动轨迹颜色
|
||||
});
|
||||
track.start();
|
||||
|
||||
track.on("length", (data) => {
|
||||
let obj = { flag };
|
||||
if (data && data[0].percent == 0) {
|
||||
obj.icon = require("@/assets/point/start.png"); // 开始
|
||||
let item = data[0].position[0];
|
||||
obj.coords = [{ jd: item[0], wd: item[1] }];
|
||||
_that.makerSki(obj);
|
||||
}
|
||||
if (data && data[0].percent == 99) {
|
||||
let len = data[0].position.length;
|
||||
let val = data[0].position[len - 1];
|
||||
obj.coords = [{ jd: val[0], wd: val[1] }];
|
||||
obj.icon = require("@/assets/point/end.png"); // 结束
|
||||
_that.makerSki(obj);
|
||||
}
|
||||
});
|
||||
_that._self[flag].push(track);
|
||||
};
|
||||
|
||||
// 移除轨迹
|
||||
MapUtil.prototype.removeTrajectory = (flag) => {
|
||||
if (_that._self[flag]) {
|
||||
_that._self[flag].destroy();
|
||||
_that._self[flag] = null;
|
||||
}
|
||||
};
|
||||
|
||||
/**geojson 创建边界
|
||||
* let data = {
|
||||
* type: "FeatureCollection",
|
||||
* features: [
|
||||
* {
|
||||
geometry: {
|
||||
type: "Polygon",
|
||||
coordinates: [it.coordinates]
|
||||
},
|
||||
properties: {
|
||||
},
|
||||
type: "Feature",
|
||||
}
|
||||
* ]
|
||||
};
|
||||
*/
|
||||
MapUtil.prototype.createBoundarys = (res) => {
|
||||
let { data } = res;
|
||||
if (!data) return false;
|
||||
if (_that.polygonGeo) _that.removeBj();
|
||||
_that.polygonGeo = map.createPolygon(data, {
|
||||
color: "rgba(20,237,245,0.3)",
|
||||
outLineColor: "#cf1010",
|
||||
outLineWidth: 6,
|
||||
highlightColor: "red",
|
||||
type: "solid",
|
||||
labelOption: {
|
||||
pixelOffset: [2, 0],
|
||||
allShow: false,
|
||||
fontColor: "#ffffff"
|
||||
}
|
||||
});
|
||||
_that.polygonGeo.flyTo();
|
||||
};
|
||||
// 移除边界
|
||||
MapUtil.prototype.removeBj = (res) => {
|
||||
_that.polygonGeo.destroy();
|
||||
};
|
||||
|
||||
// 打开详情弹窗
|
||||
MapUtil.prototype.openInfoDetail = (flag, data) => {
|
||||
switch (flag) {
|
||||
case "rx":
|
||||
emitter.emit("showJzInfo", data);
|
||||
break;
|
||||
case "gaj":
|
||||
case "pcs":
|
||||
case "jwz":
|
||||
case "xfq":
|
||||
case "zdfkd":
|
||||
emitter.emit("showGazy", data);
|
||||
break;
|
||||
case "kfd":
|
||||
emitter.emit("changeGroupPoint", {
|
||||
lx: "kfd",
|
||||
xffwlx: "2",
|
||||
xffwid: data.kfdId
|
||||
});
|
||||
emitter.emit("showGazy", [data]);
|
||||
break;
|
||||
case "sp":
|
||||
emitter.emit("showGzy", data);
|
||||
emitter.emit("showGzyInfo", data);
|
||||
break;
|
||||
case "kk":
|
||||
emitter.emit("showGzy", data);
|
||||
break;
|
||||
case "aj":
|
||||
case "jqMap":
|
||||
emitter.emit("showAj", data);
|
||||
break;
|
||||
case "yj":
|
||||
case "yjMap":
|
||||
emitter.emit("showYjxq", data);
|
||||
break;
|
||||
case "dzjg":
|
||||
case "school":
|
||||
case "hospital":
|
||||
case "banck":
|
||||
case "shop":
|
||||
emitter.emit("showShzy", data);
|
||||
break;
|
||||
case "qchzc_map":
|
||||
case "jczMap_hm":
|
||||
case "jczMap_hhx":
|
||||
emitter.emit("showJcz", data);
|
||||
break;
|
||||
case "cyryMap":
|
||||
console.log(data, "从业人员");
|
||||
emitter.emit("showCyry", [data]);
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
// 获取uuid 作为边界图层ID
|
||||
function getUUid() {
|
||||
var list = [];
|
||||
var hexDigits = "0123456789abcdefghijklmnopqrstuvwxyz";
|
||||
for (var i = 0; i < 32; i++) {
|
||||
list[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
|
||||
}
|
||||
list[14] = "4";
|
||||
list[19] = hexDigits.substr((list[19] & 0x3) | 0x8, 1);
|
||||
list[8] = list[13] = list[18] = list[23];
|
||||
let uuid = list.join("");
|
||||
return uuid;
|
||||
}
|
3
src/components/GdMap/rs.json
Normal file
3
src/components/GdMap/rs.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"coords":"104.191712,30.332337,104.190379,30.321575,104.231962,30.315252,104.227763,30.283791,104.241479,30.268395,104.228153,30.257561,104.242864,30.244730,104.270769,30.240455,104.269092,30.219985,104.277914,30.224568,104.293406,30.209630,104.302729,30.213200,104.307097,30.202998,104.325129,30.207037,104.355347,30.194195,104.363096,30.183460,104.354874,30.185101,104.352787,30.178549,104.386214,30.163126,104.392108,30.139422,104.386563,30.134069,104.406584,30.128212,104.417883,30.110023,104.411449,30.102072,104.421724,30.093237,104.433945,30.091459,104.434490,30.102374,104.447575,30.103505,104.455815,30.090000,104.477106,30.090159,104.472787,30.079513,104.480840,30.075074,104.465410,30.062860,104.479359,30.049892,104.456587,30.050092,104.452813,30.040084,104.465165,30.035835,104.455327,30.027999,104.458818,30.019591,104.448027,29.999489,104.477911,29.990649,104.457530,29.956299,104.478816,29.947313,104.470366,29.937748,104.486035,29.924377,104.486081,29.908460,104.505562,29.900162,104.492675,29.891903,104.492992,29.877076,104.501067,29.874142,104.487466,29.868024,104.475572,29.839224,104.480389,29.823872,104.473848,29.813915,104.499239,29.808909,104.491448,29.794094,104.465447,29.790942,104.442186,29.735454,104.427166,29.742971,104.414194,29.733388,104.404817,29.736075,104.393217,29.753224,104.373968,29.744401,104.367685,29.731782,104.356188,29.739397,104.355446,29.733333,104.335661,29.730418,104.332333,29.717842,104.347244,29.712211,104.346778,29.702659,104.336663,29.700136,104.313561,29.713003,104.295611,29.673814,104.280138,29.671614,104.283271,29.663143,104.274707,29.653997,104.280570,29.652266,104.271474,29.639306,104.247799,29.635751,104.237983,29.645245,104.243843,29.650490,104.231474,29.654349,104.237800,29.660088,104.228079,29.663086,104.233011,29.673066,104.227693,29.678490,104.204520,29.666834,104.193826,29.684265,104.200269,29.695269,104.183408,29.688925,104.185530,29.712206,104.181102,29.708149,104.167587,29.719218,104.164097,29.712006,104.156209,29.719685,104.147994,29.708280,104.132691,29.711712,104.116456,29.735662,104.105234,29.739340,104.109314,29.745872,104.099019,29.750351,104.088669,29.742201,104.058084,29.781140,104.070105,29.785362,104.088526,29.816182,104.072903,29.815785,104.072469,29.829395,104.040234,29.833418,104.056118,29.857406,104.049233,29.871115,104.040958,29.865559,104.027382,29.876641,104.001555,29.876057,103.981529,29.851563,103.964863,29.857306,103.968616,29.869100,103.991537,29.880289,103.998148,29.894420,103.984192,29.887484,103.969852,29.890776,103.952945,29.917885,103.962461,29.927505,103.946054,29.965100,103.952523,29.969262,103.917956,29.980131,103.926683,29.990640,103.959824,29.983321,103.957729,29.994857,103.972654,30.001121,103.966893,30.009745,103.977840,30.029956,103.971729,30.047714,103.987262,30.074897,103.977687,30.093740,103.981558,30.102835,103.968602,30.112735,103.978708,30.128111,103.970273,30.143360,103.981090,30.145538,103.982377,30.158880,103.974518,30.161745,103.979487,30.172736,103.969649,30.180335,103.989892,30.197132,103.959528,30.216906,103.966730,30.233955,103.979510,30.240572,103.964281,30.252780,103.969394,30.267698,103.984404,30.277331,103.997281,30.265453,104.047086,30.274065,104.051446,30.261304,104.062409,30.268811,104.066778,30.256984,104.074634,30.261237,104.078283,30.250003,104.089862,30.253217,104.094024,30.241503,104.124537,30.228739,104.149999,30.246957,104.150805,30.269599,104.165559,30.285692,104.179104,30.327688,104.191656,30.332522,104.191712,30.332337;104.479952"
|
||||
}
|
307
src/components/MyComponents/AddressSelect/index.vue
Normal file
307
src/components/MyComponents/AddressSelect/index.vue
Normal file
@ -0,0 +1,307 @@
|
||||
<template>
|
||||
<div class="form-item-box zj-addressSelect-wrap" :style="{ width: width }">
|
||||
<el-select :placeholder="placeholder" :clearable="true" v-model="value" popper-class="adderss-select"
|
||||
@clear="handleClear">
|
||||
<el-option value="1" style="display: none"></el-option>
|
||||
<el-input v-if="filterable" v-model="filterText" style="margin-bottom: 5px; font-size: 12px"
|
||||
:prefix-icon="Search" />
|
||||
<el-tabs v-model="activeName" type="card" @tab-click="handleClick">
|
||||
<el-tab-pane name="province" :label="province ? province : '请选择'">
|
||||
<div class="citylist">
|
||||
<ul>
|
||||
<li @click="chooseProvince(item)" v-for="item in provinceList" :key="item.code"
|
||||
:class="{ selected: provinceId == item.code }">
|
||||
{{ item.name }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane name="city" v-if="cityList.length > 0" :label="city ? city : '请选择'">
|
||||
<div class="citylist">
|
||||
<ul>
|
||||
<li @click="chooseCity(item)" v-for="item in cityList" :class="{ selected: cityId == item.code }"
|
||||
:key="item.code">
|
||||
{{ item.name }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane name="area" v-if="areaList.length > 0" :label="area ? area : '请选择'">
|
||||
<div class="citylist">
|
||||
<ul>
|
||||
<li @click="chooseArea(item)" v-for="item in areaList" :key="item.code"
|
||||
:class="{ selected: areaId == item.code }">
|
||||
{{ item.name }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane name="street" v-if="streetList.length > 0" :label="street ? street : '请选择'">
|
||||
<div class="citylist">
|
||||
<ul>
|
||||
<li @click="chooseStreet(item)" v-for="item in streetList" :key="item.code"
|
||||
:class="{ selected: streetId == item.code }">
|
||||
{{ item.name }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</el-select>
|
||||
<!-- <el-icon class="errorIcon">
|
||||
<circle-close-filled />
|
||||
</el-icon>
|
||||
<el-icon class="checkIcon">
|
||||
<circle-check-filled />
|
||||
</el-icon> -->
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { COMPONENT_WIDTH } from '@/constant';
|
||||
import { nextTick, ref, watch } from "vue";
|
||||
import { Search } from "@element-plus/icons-vue";
|
||||
const emits = defineEmits(["handleChange"]); //子组件向父组件事件传递
|
||||
const props = defineProps({
|
||||
placeholder: {
|
||||
default: "选择地址",
|
||||
type: String
|
||||
},
|
||||
filterable: {
|
||||
default: false,
|
||||
type: Boolean
|
||||
},
|
||||
address: {
|
||||
default: () => [],
|
||||
type: Array
|
||||
},
|
||||
defaultConf: {
|
||||
type: Object,
|
||||
default: () => ({
|
||||
children: "",
|
||||
label: "",
|
||||
id: ""
|
||||
})
|
||||
},
|
||||
width: {
|
||||
default: COMPONENT_WIDTH,
|
||||
type: String
|
||||
}
|
||||
});
|
||||
const filterText = ref("");
|
||||
const activeName = ref("province");
|
||||
const value = ref("");
|
||||
const valueId = ref([]);
|
||||
const province = ref("");
|
||||
const provinceId = ref("");
|
||||
const provinceList = ref([]);
|
||||
provinceList.value = require("@/constant/pca-code.json");
|
||||
const city = ref("");
|
||||
const cityId = ref("");
|
||||
const cityList = ref([]);
|
||||
const area = ref("");
|
||||
const areaId = ref("");
|
||||
const areaList = ref([]);
|
||||
const street = ref("");
|
||||
const streetId = ref("");
|
||||
const streetList = ref([]);
|
||||
const provinceListFilter = ref([]);
|
||||
provinceListFilter.value = require("@/constant/pca-code.json");
|
||||
const cityListFilter = ref([]);
|
||||
const areaListFilter = ref([]);
|
||||
const streetListFilter = ref([]);
|
||||
nextTick(() => {
|
||||
if (props.address.length > 0) {
|
||||
init(props.address);
|
||||
}
|
||||
});
|
||||
watch(filterText, (val) => {
|
||||
filterNode(val);
|
||||
});
|
||||
const handleClick = () => {
|
||||
filterText.value = "";
|
||||
filterNode("");
|
||||
};
|
||||
const filterNode = (val) => {
|
||||
if (activeName.value === "province") {
|
||||
if (val !== "") {
|
||||
provinceList.value = provinceListFilter.value.filter(
|
||||
(item) => item[props.defaultConf.label].indexOf(val) !== -1
|
||||
);
|
||||
} else {
|
||||
provinceList.value = provinceListFilter.value;
|
||||
}
|
||||
} else if (activeName.value === "city") {
|
||||
if (val !== "") {
|
||||
cityList.value = cityListFilter.value.filter(
|
||||
(item) => item[props.defaultConf.label].indexOf(val) !== -1
|
||||
);
|
||||
} else {
|
||||
cityList.value = cityListFilter.value;
|
||||
}
|
||||
} else if (activeName.value === "area") {
|
||||
if (val !== "") {
|
||||
areaList.value = areaListFilter.value.filter(
|
||||
(item) => item[props.defaultConf.label].indexOf(val) !== -1
|
||||
);
|
||||
} else {
|
||||
areaList.value = areaListFilter.value;
|
||||
}
|
||||
} else if (activeName.value === "street") {
|
||||
if (val !== "") {
|
||||
streetList.value = streetListFilter.value.filter(
|
||||
(item) => item[props.defaultConf.label].indexOf(val) !== -1
|
||||
);
|
||||
} else {
|
||||
streetList.value = streetListFilter.value;
|
||||
}
|
||||
}
|
||||
};
|
||||
const chooseProvince = (e) => {
|
||||
province.value = e[props.defaultConf.label];
|
||||
provinceId.value = e[props.defaultConf.id];
|
||||
value.value = province.value;
|
||||
valueId.value = [provinceId.value];
|
||||
emits("handleChange", valueId.value);
|
||||
city.value = "";
|
||||
cityId.value = "";
|
||||
cityList.value = [];
|
||||
areaList.value = [];
|
||||
streetList.value = [];
|
||||
filterText.value = "";
|
||||
provinceList.value.forEach((el) => {
|
||||
if (el[props.defaultConf.id] === e[props.defaultConf.id]) {
|
||||
if (el[props.defaultConf.children]) {
|
||||
activeName.value = "city";
|
||||
cityList.value = el[props.defaultConf.children];
|
||||
cityListFilter.value = el[props.defaultConf.children];
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
const chooseCity = (e) => {
|
||||
city.value = e[props.defaultConf.label];
|
||||
cityId.value = e[props.defaultConf.id];
|
||||
area.value = "";
|
||||
areaId.value = "";
|
||||
areaList.value = [];
|
||||
streetList.value = [];
|
||||
filterText.value = "";
|
||||
value.value = province.value + "/" + city.value;
|
||||
valueId.value = [provinceId.value, cityId.value];
|
||||
emits("handleChange", valueId.value);
|
||||
cityList.value.forEach((el) => {
|
||||
if (el[props.defaultConf.id] === e[props.defaultConf.id]) {
|
||||
if (el[props.defaultConf.children]) {
|
||||
activeName.value = "area";
|
||||
areaList.value = el[props.defaultConf.children];
|
||||
areaListFilter.value = el[props.defaultConf.children];
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
const chooseArea = (e) => {
|
||||
area.value = e[props.defaultConf.label];
|
||||
areaId.value = e[props.defaultConf.id];
|
||||
street.value = "";
|
||||
streetId.value = "";
|
||||
streetList.value = [];
|
||||
filterText.value = "";
|
||||
value.value = province.value + "/" + city.value + "/" + area.value;
|
||||
valueId.value = [provinceId.value, cityId.value, areaId.value];
|
||||
emits("handleChange", valueId.value);
|
||||
areaList.value.forEach((el) => {
|
||||
if (el[props.defaultConf.id] === e[props.defaultConf.id]) {
|
||||
if (el[props.defaultConf.children]) {
|
||||
streetList.value = el[props.defaultConf.children];
|
||||
activeName.value = "street";
|
||||
streetListFilter.value = el[props.defaultConf.children];
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
const chooseStreet = (e) => {
|
||||
street.value = e[props.defaultConf.label];
|
||||
streetId.value = e[props.defaultConf.id];
|
||||
value.value =
|
||||
province.value + "/" + city.value + "/" + area.value + "/" + street.value;
|
||||
valueId.value = [
|
||||
provinceId.value,
|
||||
cityId.value,
|
||||
areaId.value,
|
||||
streetId.value
|
||||
];
|
||||
emits("handleChange", valueId.value);
|
||||
};
|
||||
const handleClear = () => {
|
||||
activeName.value = "province";
|
||||
value.value = "";
|
||||
valueId.value = [];
|
||||
province.value = "";
|
||||
provinceId.value = "";
|
||||
city.value = "";
|
||||
cityId.value = "";
|
||||
cityList.value = [];
|
||||
area.value = "";
|
||||
areaId.value = "";
|
||||
areaList.value = [];
|
||||
street.value = "";
|
||||
streetId.value = "";
|
||||
streetList.value = [];
|
||||
cityListFilter.value = [];
|
||||
areaListFilter.value = [];
|
||||
streetListFilter.value = [];
|
||||
filterText.value = "";
|
||||
filterNode("");
|
||||
emits("handleChange", []);
|
||||
};
|
||||
const treeValueFind = (tree, arr, newArr = []) => {
|
||||
tree.forEach((el) => {
|
||||
if (el[props.defaultConf.id] === arr) {
|
||||
newArr.push(el);
|
||||
}
|
||||
if (el[props.defaultConf.children]) {
|
||||
treeValueFind(el[props.defaultConf.children], arr, newArr);
|
||||
}
|
||||
});
|
||||
return newArr;
|
||||
};
|
||||
const init = (data) => {
|
||||
let obj1 = treeValueFind(provinceList.value, data[0])[0];
|
||||
province.value = obj1[props.defaultConf.label];
|
||||
provinceId.value = obj1[props.defaultConf.id];
|
||||
cityList.value = obj1[props.defaultConf.children];
|
||||
cityListFilter.value = obj1[props.defaultConf.children];
|
||||
value.value = province.value;
|
||||
if (data[1]) {
|
||||
let obj2 = treeValueFind(provinceList.value, data[1])[0];
|
||||
city.value = obj2[props.defaultConf.label];
|
||||
cityId.value = obj2[props.defaultConf.id];
|
||||
areaList.value = obj2[props.defaultConf.children];
|
||||
areaListFilter.value = obj2[props.defaultConf.children];
|
||||
value.value = province.value + "/" + city.value;
|
||||
}
|
||||
if (data[2]) {
|
||||
let obj3 = treeValueFind(provinceList.value, data[2])[0];
|
||||
area.value = obj3[props.defaultConf.label];
|
||||
areaId.value = obj3[props.defaultConf.id];
|
||||
streetList.value = obj3[props.defaultConf.children];
|
||||
streetListFilter.value = obj3[props.defaultConf.children];
|
||||
value.value = province.value + "/" + city.value + "/" + area.value;
|
||||
}
|
||||
if (data[3]) {
|
||||
let obj4 = treeValueFind(provinceList.value, data[3])[0];
|
||||
street.value = obj4[props.defaultConf.label];
|
||||
streetId.value = obj4[props.defaultConf.id];
|
||||
value.value =
|
||||
province.value + "/" + city.value + "/" + area.value + "/" + street.value;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.zj-addressSelect-wrap {
|
||||
::v-deep .el-select {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
88
src/components/MyComponents/ChooseIcon/index.vue
Normal file
88
src/components/MyComponents/ChooseIcon/index.vue
Normal file
@ -0,0 +1,88 @@
|
||||
<template>
|
||||
<!--选择图标-->
|
||||
<div class="form-item-box choose-icon-zj" :style="{ width: width }">
|
||||
<el-autocomplete v-bind="$attrs" v-model="modelValue" :fetch-suggestions="querySearch"
|
||||
popper-class="choose-icon-zj-autocomplete" :placeholder="placeholder" @change="onInput" @select="handleSelect">
|
||||
<template #prefix>
|
||||
<SvgIcon :icon="modelValue"></SvgIcon>
|
||||
</template>
|
||||
<template #default="{ item }">
|
||||
<SvgIcon :icon="item.link"></SvgIcon>
|
||||
<div class="value">{{ item.value }}</div>
|
||||
</template>
|
||||
</el-autocomplete>
|
||||
<!-- <el-icon class="errorIcon">
|
||||
<circle-close-filled />
|
||||
</el-icon>
|
||||
<el-icon class="checkIcon">
|
||||
<circle-check-filled />
|
||||
</el-icon> -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { COMPONENT_WIDTH } from "@/constant";
|
||||
import { ref, defineProps, defineEmits, defineExpose, onMounted } from "vue";
|
||||
const props = defineProps({
|
||||
placeholder: {
|
||||
default: "请输入图标名称",
|
||||
type: String
|
||||
},
|
||||
modelValue: {
|
||||
default: "",
|
||||
type: String
|
||||
},
|
||||
width: {
|
||||
default: COMPONENT_WIDTH,
|
||||
type: String
|
||||
}
|
||||
});
|
||||
const links = ref([]);
|
||||
|
||||
const querySearch = (queryString, cb) => {
|
||||
const results = queryString
|
||||
? links.value.filter(createFilter(queryString))
|
||||
: links.value;
|
||||
cb(results);
|
||||
};
|
||||
const createFilter = (queryString) => {
|
||||
return (restaurant) => {
|
||||
return (
|
||||
restaurant.value.toLowerCase().indexOf(queryString.toLowerCase()) === 0
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
const handleSelect = (item) => {
|
||||
emits("update:modelValue", item.value);
|
||||
};
|
||||
|
||||
const handleIconClick = (ev) => {
|
||||
};
|
||||
|
||||
const loadAll = () => {
|
||||
const svgRequire = require.context("@/icons/svg", false, /\.svg$/);
|
||||
const re = svgRequire.keys().map((svgIcon) => {
|
||||
const iconName = svgIcon.split("/")[1];
|
||||
const prefixIconName = iconName.split(".")[0];
|
||||
return { value: prefixIconName, link: prefixIconName };
|
||||
});
|
||||
return re;
|
||||
};
|
||||
const iconListShow = ref(false);
|
||||
const showIconList = () => {
|
||||
iconListShow.value = true;
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
links.value = loadAll();
|
||||
});
|
||||
|
||||
const emits = defineEmits(["update:modelValue"]);
|
||||
const onInput = (e) => {
|
||||
emits("update:modelValue", e);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
</style>
|
253
src/components/MyComponents/ChooseUser/index.vue
Normal file
253
src/components/MyComponents/ChooseUser/index.vue
Normal file
@ -0,0 +1,253 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
:title="titleValue"
|
||||
width="1400px"
|
||||
:model-value="modelValue"
|
||||
append-to-body
|
||||
@close="closed"
|
||||
>
|
||||
<div>
|
||||
<el-form :model="listQuery" class="mosty-from-wrap" :inline="true">
|
||||
<el-form-item label="所属部门">
|
||||
<MOSTY.Department width="100%" clearable v-model="listQuery.ssbmdm" />
|
||||
</el-form-item>
|
||||
<el-form-item label="用户名">
|
||||
<el-input
|
||||
placeholder="请输入用户名"
|
||||
v-model="listQuery.loginName"
|
||||
clearable
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="电话号码">
|
||||
<el-input
|
||||
placeholder="请输入电话号码"
|
||||
v-model="listQuery.phone"
|
||||
clearable
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="success" @click="handleFilter">查询</el-button>
|
||||
<el-button type="info" @click="reset()"> 重置 </el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div
|
||||
class="tabBox"
|
||||
:class="props.Single ? 'tabBoxRadio' : ''"
|
||||
style="margin-top: 0px"
|
||||
>
|
||||
<el-table
|
||||
ref="multipleUserRef"
|
||||
@selection-change="handleSelectionChange"
|
||||
:data="tableData"
|
||||
border
|
||||
:row-key="keyid"
|
||||
style="width: 100%"
|
||||
height="450"
|
||||
>
|
||||
<el-table-column
|
||||
type="selection"
|
||||
width="55"
|
||||
:reserve-selection="true"
|
||||
/>
|
||||
<el-table-column
|
||||
prop="loginName"
|
||||
align="center"
|
||||
label="用户名"
|
||||
width="150"
|
||||
></el-table-column>
|
||||
<el-table-column
|
||||
prop="idEntityCard"
|
||||
align="center"
|
||||
label="身份证号"
|
||||
></el-table-column>
|
||||
<el-table-column
|
||||
prop="deptName"
|
||||
align="center"
|
||||
label="部门"
|
||||
></el-table-column>
|
||||
<el-table-column
|
||||
prop="inDustRialId"
|
||||
align="center"
|
||||
width="150"
|
||||
label="警号"
|
||||
></el-table-column>
|
||||
|
||||
<el-table-column
|
||||
prop="mobile"
|
||||
width="150"
|
||||
align="center"
|
||||
label="电话"
|
||||
></el-table-column>
|
||||
|
||||
<el-table-column prop="sex" align="center" label="性别">
|
||||
<template #default="{ row }">
|
||||
<span> {{ row.sex == 1 ? "男" : "女" }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<div class="fenye" :style="{ top: tableHeight + 'px' }">
|
||||
<el-pagination
|
||||
class="pagination"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
:current-page="listQuery.current"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
:page-size="listQuery.size"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="total"
|
||||
></el-pagination>
|
||||
</div>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="closed">取消</el-button>
|
||||
<el-button type="primary" @click="onComfirm">确认</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import * as rule from "@/utils/rules.js";
|
||||
import * as MOSTY from "@/components/MyComponents/index";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { defineProps, watch, ref, onMounted, nextTick } from "vue";
|
||||
import { selectUnAccreditPage, selectUserDeptPage } from "@/api/user-manage";
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
},
|
||||
titleValue: {
|
||||
type: String,
|
||||
default: "选择用户"
|
||||
},
|
||||
LeaderType: {
|
||||
type: String,
|
||||
default: ""
|
||||
},
|
||||
//是否单选
|
||||
Single: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
roleIds: {
|
||||
type: Array,
|
||||
default: []
|
||||
}
|
||||
});
|
||||
const total = ref(0);
|
||||
const listQuery = ref({
|
||||
current: 1,
|
||||
size: 20
|
||||
});
|
||||
const form = ref({});
|
||||
const tableData = ref([]);
|
||||
const emits = defineEmits(["update:modelValue", "choosedUsers"]);
|
||||
onMounted(() => {
|
||||
handleFilter();
|
||||
});
|
||||
const closed = () => {
|
||||
emits("update:modelValue", false);
|
||||
};
|
||||
const reset = () => {
|
||||
listQuery.value = {
|
||||
current: 1,
|
||||
size: 20,
|
||||
loginName: "",
|
||||
phone: ""
|
||||
};
|
||||
getListData();
|
||||
};
|
||||
|
||||
const keyid = (row) => {
|
||||
return row.id;
|
||||
};
|
||||
// 为用户分配角色
|
||||
const onComfirm = () => {
|
||||
const userList = multipleSelectionUser.value;
|
||||
let list = [];
|
||||
let listId = [];
|
||||
userList.forEach((val) => {
|
||||
if (listId.indexOf(val.id) == -1) {
|
||||
list.push(val);
|
||||
listId.push(val.id);
|
||||
}
|
||||
});
|
||||
emits("choosedUsers", list);
|
||||
let data = { type: props.LeaderType, userList: userList };
|
||||
emits("choosedUsersLeader", data);
|
||||
closed();
|
||||
};
|
||||
/**
|
||||
* pageSize 改变触发
|
||||
*/
|
||||
const handleSizeChange = (currentSize) => {
|
||||
listQuery.value.size = currentSize;
|
||||
getListData();
|
||||
};
|
||||
|
||||
/**
|
||||
* 页码改变触发
|
||||
*/
|
||||
const handleCurrentChange = (currentPage) => {
|
||||
listQuery.value.current = currentPage;
|
||||
getListData();
|
||||
};
|
||||
const getListData = () => {
|
||||
const params = listQuery.value;
|
||||
selectUserDeptPage(params).then((res) => {
|
||||
tableData.value = res?.records;
|
||||
total.value = Number(res.total);
|
||||
multipleUser();
|
||||
});
|
||||
};
|
||||
|
||||
//列表回显
|
||||
function multipleUser() {
|
||||
tableData.value.forEach((item) => {
|
||||
if (props.roleIds.some((id) => id == item.id)) {
|
||||
multipleUserRef.value.toggleRowSelection(item, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const handleFilter = () => {
|
||||
listQuery.value.current = 1;
|
||||
getListData();
|
||||
};
|
||||
|
||||
const multipleUserRef = ref(null);
|
||||
const multipleSelectionUser = ref([]);
|
||||
const handleSelectionChange = (val) => {
|
||||
if (props.Single) {
|
||||
if (val.length > 1) {
|
||||
let del_row = val.shift();
|
||||
multipleUserRef.value.toggleRowSelection(del_row, false);
|
||||
}
|
||||
multipleSelectionUser.value = val;
|
||||
} else {
|
||||
multipleSelectionUser.value = val;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "@/assets/css/layout.scss";
|
||||
@import "@/assets/css/element-plus.scss";
|
||||
</style>
|
||||
<style>
|
||||
.tabBoxRadio .el-checkbox__inner {
|
||||
border-radius: 50% !important;
|
||||
}
|
||||
.tabBoxRadio .el-table__header-wrapper .el-checkbox {
|
||||
display: none;
|
||||
}
|
||||
.el-dialog {
|
||||
/* background: #050e33; */
|
||||
}
|
||||
.el-dialog__title {
|
||||
/* color: #fff; */
|
||||
}
|
||||
</style>
|
32
src/components/MyComponents/Date/index.vue
Normal file
32
src/components/MyComponents/Date/index.vue
Normal file
@ -0,0 +1,32 @@
|
||||
<template>
|
||||
<div class="form-item-box" :style="{ width: width }">
|
||||
<el-date-picker style="width:100%" v-model="modelValue" type="date" v-bind="$attrs" @change="onInput" :placeholder="placeholder" value-format="YYYY-MM-DD"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { COMPONENT_WIDTH } from "@/constant";
|
||||
import { ref, defineProps, defineEmits, defineExpose } from "vue";
|
||||
const props = defineProps({
|
||||
//获取组件传值
|
||||
placeholder: {
|
||||
default: "请填写",
|
||||
type: String
|
||||
},
|
||||
modelValue: {
|
||||
default: "",
|
||||
type: String
|
||||
},
|
||||
width: {
|
||||
default: COMPONENT_WIDTH,
|
||||
type: String
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
const emits = defineEmits(["update:modelValue"]);
|
||||
const onInput = (e) => {
|
||||
emits("update:modelValue", e);
|
||||
};
|
||||
</script>
|
||||
|
119
src/components/MyComponents/Department/index.vue
Normal file
119
src/components/MyComponents/Department/index.vue
Normal file
@ -0,0 +1,119 @@
|
||||
<template>
|
||||
<div class="form-item-box" :style="{ width: width }">
|
||||
<el-cascader
|
||||
style="width: 100%"
|
||||
class="el-cascader-zj"
|
||||
:show-all-levels="false"
|
||||
clearable
|
||||
filterable
|
||||
:placeholder="modelValue ? placeholder : '请选择部门'"
|
||||
:options="tableData"
|
||||
v-model="oldmodelValue"
|
||||
@change="handleChange"
|
||||
:props="endProps"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { COMPONENT_WIDTH } from "@/constant";
|
||||
import { qcckPost, qcckGet, qcckFlvGet } from "@/api/qcckApi.js";
|
||||
import {
|
||||
ref,
|
||||
defineProps,
|
||||
defineEmits,
|
||||
defineExpose,
|
||||
computed,
|
||||
onMounted,
|
||||
watch
|
||||
} from "vue";
|
||||
import { selectDeptPage } from "@/api/user-manage";
|
||||
const props = defineProps({
|
||||
//获取组件传值
|
||||
placeholder: {
|
||||
default: "请选择",
|
||||
type: String
|
||||
},
|
||||
multiple: {
|
||||
default: false,
|
||||
type: Boolean
|
||||
},
|
||||
isAll: {
|
||||
default: 100,
|
||||
type: Number
|
||||
},
|
||||
modelValue: {
|
||||
type: Array || String,
|
||||
default: []
|
||||
},
|
||||
width: {
|
||||
default: COMPONENT_WIDTH,
|
||||
type: String
|
||||
}
|
||||
});
|
||||
const modelShow = ref(false);
|
||||
const oldmodelValue = ref([]);
|
||||
const listQuery = ref({
|
||||
deptname: "",
|
||||
deptcode: "",
|
||||
parentid: ""
|
||||
});
|
||||
const depList = ref([])
|
||||
//配置项
|
||||
const endProps = {
|
||||
children: "childDeptList",
|
||||
value: "orgCode",
|
||||
label: "orgName",
|
||||
checkStrictly: true,
|
||||
multiple: props.multiple,
|
||||
lazy: true,
|
||||
lazyLoad(node, resolve) {
|
||||
listQuery.value.parentid = node.data.id;
|
||||
selectDeptPage(listQuery.value).then((res) => {
|
||||
depList.value = depList.value.concat(res)
|
||||
//处理部门是否包含下级
|
||||
for (let i = 0; i < res.length; i++) {
|
||||
res[i].leaf = !res[i].hasChildren;
|
||||
}
|
||||
resolve(res);
|
||||
});
|
||||
}
|
||||
};
|
||||
const tableData = ref([]);
|
||||
const getSysMenuTree = async () => {
|
||||
const res = await selectDeptPage(listQuery.value);
|
||||
tableData.value = res;
|
||||
depList.value = res
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
getSysMenuTree();
|
||||
});
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(val) => {
|
||||
console.log(val,'val');
|
||||
oldmodelValue.value = val;
|
||||
},
|
||||
{ deep: true, immediate: true }
|
||||
);
|
||||
const emits = defineEmits(["update:modelValue",'getDepValue']);
|
||||
const handleChange = (e) => {
|
||||
console.log(e,'e');
|
||||
if (props.multiple === true) {
|
||||
const data = e.map((item) => {return item[item.length - 1];});
|
||||
emits("update:modelValue", data);
|
||||
} else {
|
||||
const data = e ? e[e.length - 1] : "";
|
||||
emits("update:modelValue", data);
|
||||
let obj = depList.value.find(item=>{ return item.orgCode == data})
|
||||
emits("getDepValue", obj);
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.el-cascader-zj {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
158
src/components/MyComponents/DepartmentTree/index.vue
Normal file
158
src/components/MyComponents/DepartmentTree/index.vue
Normal file
@ -0,0 +1,158 @@
|
||||
<template>
|
||||
<div class="departmentTree-box" :style="{ width: width, height: '100%' }">
|
||||
<div class="depar_hear">
|
||||
<el-input
|
||||
v-model="listQuery.deptname"
|
||||
v-if="filterable"
|
||||
clearable
|
||||
:debounce="500"
|
||||
@input="filterTextChange"
|
||||
placeholder="请输入筛选条件"
|
||||
/>
|
||||
</div>
|
||||
<div class="depar_foot">
|
||||
<el-tree
|
||||
ref="treeRef"
|
||||
class="filter-tree"
|
||||
:props="endProps"
|
||||
lazy
|
||||
:load="loadNode"
|
||||
@node-click="nodeClick"
|
||||
:filter-node-method="filterNode"
|
||||
:data="treeData"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { debounce } from "lodash";
|
||||
import { getItem } from "@/utils/storage";
|
||||
import { COMPONENT_WIDTH } from "@/constant";
|
||||
import { ref, defineProps, defineEmits, watch, computed, onMounted } from "vue";
|
||||
import { selectDeptPage, getAllChildDeptList } from "@/api/user-manage";
|
||||
const props = defineProps({
|
||||
//获取组件传值
|
||||
placeholder: {
|
||||
default: "请选择",
|
||||
type: String
|
||||
},
|
||||
multiple: {
|
||||
default: false,
|
||||
type: Boolean
|
||||
},
|
||||
filterable: {
|
||||
default: false,
|
||||
type: Boolean
|
||||
},
|
||||
modelValue: {
|
||||
type: Number
|
||||
},
|
||||
width: {
|
||||
default: COMPONENT_WIDTH,
|
||||
type: String
|
||||
},
|
||||
isBmId:{
|
||||
type:Boolean,
|
||||
default:false
|
||||
}
|
||||
});
|
||||
const listQuery = ref({
|
||||
deptname: "",
|
||||
deptcode: "",
|
||||
parentid: ""
|
||||
});
|
||||
const treeRef = ref(null);
|
||||
const node_had = ref([]);
|
||||
const resolve_had = ref([]);
|
||||
//防抖处理
|
||||
const filterTextChange = debounce(inputChange, 500);
|
||||
onMounted(() => {});
|
||||
//获取部门数据
|
||||
function getTreeData() {
|
||||
selectDeptPage(listQuery.value).then((res) => {
|
||||
for (let i = 0; i < res.length; i++) {
|
||||
res[i].leaf = !res[i].hasChildren;
|
||||
}
|
||||
treeData.value = res;
|
||||
});
|
||||
}
|
||||
//搜索查询
|
||||
function inputChange(e) {
|
||||
selectDeptPage(listQuery.value).then((res) => {
|
||||
treeData.value = res;
|
||||
});
|
||||
}
|
||||
|
||||
watch(
|
||||
() => listQuery.value.deptname,
|
||||
(val) => {
|
||||
treeRef.value.filter("tree", val);
|
||||
}
|
||||
);
|
||||
const endProps = {
|
||||
children: "childDeptList",
|
||||
value: "id",
|
||||
label: "orgName",
|
||||
isLeaf: "leaf"
|
||||
};
|
||||
const treeData = ref([]);
|
||||
//懒加载方法
|
||||
async function loadNode(node, resolve) {
|
||||
listQuery.value.parentid = node.data.id;
|
||||
if (node.level === 0) {
|
||||
node_had.value = node;
|
||||
resolve_had.value = resolve;
|
||||
getTreeData();
|
||||
}
|
||||
if (node.level >= 1) {
|
||||
selectDeptPage(listQuery.value).then((res) => {
|
||||
for (let i = 0; i < res.length; i++) {
|
||||
res[i].leaf = !res[i].hasChildren;
|
||||
}
|
||||
resolve(res);
|
||||
});
|
||||
}
|
||||
}
|
||||
const filterNode = (value, data) => {
|
||||
if (!value) return true;
|
||||
return data.orgName.includes(value);
|
||||
};
|
||||
|
||||
const nodeClick = (node) => {
|
||||
if(props.isBmId){
|
||||
emits("update:modelValue", node.id);
|
||||
}else{
|
||||
emits("update:modelValue", node.orgCode);
|
||||
}
|
||||
};
|
||||
|
||||
const emits = defineEmits(["update:modelValue"]);
|
||||
const handleChange = (e) => {
|
||||
if (props.multiple === true) {
|
||||
const data = e.map((item) => {
|
||||
return item[item.length - 1];
|
||||
});
|
||||
emits("update:modelValue", data);
|
||||
} else {
|
||||
const data = e[0];
|
||||
emits("update:modelValue", data);
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.depar_hear {
|
||||
height: 32px;
|
||||
}
|
||||
.depar_foot {
|
||||
height: calc(100% - 32px);
|
||||
overflow: auto;
|
||||
width: 280px;
|
||||
width: 100%;
|
||||
min-width: 300px;
|
||||
}
|
||||
.departmentTree-box {
|
||||
overflow: auto;
|
||||
}
|
||||
</style>
|
88
src/components/MyComponents/DownLoad/index.vue
Normal file
88
src/components/MyComponents/DownLoad/index.vue
Normal file
@ -0,0 +1,88 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
title="导出预览"
|
||||
width="1400px"
|
||||
:model-value="modelValue"
|
||||
@close="closed"
|
||||
>
|
||||
<el-table :data="data" :id="myId" style="width: 100%" border>
|
||||
<el-table-column label="序号" type="index" align="center" width="80" />
|
||||
<el-table-column
|
||||
v-for="(item, index) in tabOption"
|
||||
:key="index + 'tab'"
|
||||
:prop="item.prop"
|
||||
:label="item.label"
|
||||
align="center"
|
||||
>
|
||||
<template v-if="item.dict" #default="{ row }">
|
||||
<dict-tag :options="item.dict" :value="row[item.prop]" :tag="false" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="closed">取消</el-button>
|
||||
<el-button type="primary" @click="exportExcel">确定</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { defineProps, ref, onMounted, getCurrentInstance } from "vue";
|
||||
import FileSaver from "file-saver";
|
||||
import * as XLSX from "xlsx";
|
||||
const tabRef = ref(null);
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
},
|
||||
tabOption: {
|
||||
type: Array,
|
||||
require: []
|
||||
},
|
||||
data: {
|
||||
type: Array,
|
||||
required: []
|
||||
},
|
||||
myId: {
|
||||
type: String,
|
||||
require: ""
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
require: ""
|
||||
}
|
||||
});
|
||||
const emits = defineEmits(["update:modelValue"]);
|
||||
const closed = () => {
|
||||
emits("update:modelValue", false);
|
||||
};
|
||||
const { proxy } = getCurrentInstance();
|
||||
function exportExcel() {
|
||||
let xlsxParam = { raw: true };
|
||||
let wb = XLSX.utils.table_to_book(
|
||||
document.querySelector("#" + props.myId),
|
||||
xlsxParam
|
||||
);
|
||||
let wbout = XLSX.write(wb, {
|
||||
bookType: "xlsx",
|
||||
bookSST: true,
|
||||
type: "array"
|
||||
});
|
||||
closed();
|
||||
try {
|
||||
FileSaver.saveAs(
|
||||
new Blob([wbout], { type: "application/octet-stream" }),
|
||||
`${props.title}.xlsx`
|
||||
);
|
||||
} catch (e) {
|
||||
if (typeof console !== "undefined") console.log(e, wbout);
|
||||
}
|
||||
return wbout;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
</style>
|
80
src/components/MyComponents/Email/index.vue
Normal file
80
src/components/MyComponents/Email/index.vue
Normal file
@ -0,0 +1,80 @@
|
||||
<template>
|
||||
<div class="form-item-box zj-email-wrap" :style="{ width: width }">
|
||||
<el-autocomplete v-model="email" v-bind="$attrs" :placeholder="placeholder" :fetch-suggestions="querySearch"
|
||||
:trigger-on-focus="false" class="inline-input" @select="handleSelect" @input="onInput" />
|
||||
<!-- <el-icon class="errorIcon">
|
||||
<circle-close-filled />
|
||||
</el-icon>
|
||||
<el-icon class="checkIcon">
|
||||
<circle-check-filled />
|
||||
</el-icon> -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { COMPONENT_WIDTH } from '@/constant';
|
||||
import { ref, defineProps, defineEmits, defineExpose, onMounted } from "vue";
|
||||
const props = defineProps({
|
||||
//获取组件传值
|
||||
placeholder: {
|
||||
default: "请填写邮箱",
|
||||
type: String
|
||||
},
|
||||
email: {
|
||||
default: "",
|
||||
type: String
|
||||
},
|
||||
width: {
|
||||
default: COMPONENT_WIDTH,
|
||||
type: String
|
||||
}
|
||||
});
|
||||
|
||||
const emits = defineEmits(["update:email"]);
|
||||
const onInput = (e) => {
|
||||
emits("update:email", e);
|
||||
};
|
||||
const restaurants = ref([]);
|
||||
const createFilter = (queryString) => {
|
||||
return (item) => {
|
||||
return item.value.toLowerCase().indexOf(queryString.toLowerCase()) === 0;
|
||||
};
|
||||
};
|
||||
const querySearch = (queryString, callback) => {
|
||||
let results = JSON.parse(JSON.stringify(restaurants.value)); //把数组的浅复制换成深复制
|
||||
if (queryString.indexOf("@") > -1) {
|
||||
results.length = 0;
|
||||
callback(results);
|
||||
return false;
|
||||
}
|
||||
for (let item in results) {
|
||||
results[item].value = queryString + "" + restaurants.value[item].value;
|
||||
}
|
||||
callback(results);
|
||||
};
|
||||
|
||||
const loadAll = () => {
|
||||
return [
|
||||
{ value: "@qq.com" },
|
||||
{ value: "@mosty.com" },
|
||||
{ value: "@163.com" },
|
||||
{ value: "@outlook.com" },
|
||||
{ value: "@sohu.com" }
|
||||
];
|
||||
};
|
||||
const handleSelect = (item) => {
|
||||
emits("update:email", item.value);
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
restaurants.value = loadAll();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.zj-email-wrap {
|
||||
::v-deep .el-autocomplete {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
29
src/components/MyComponents/Empty/index.vue
Normal file
29
src/components/MyComponents/Empty/index.vue
Normal file
@ -0,0 +1,29 @@
|
||||
<template>
|
||||
<el-empty
|
||||
:image-size="imgSize"
|
||||
:image="require('@/assets/images/icon_043.png')"
|
||||
:description="description"
|
||||
v-if="show"
|
||||
/>
|
||||
</template>
|
||||
<script setup>
|
||||
const props = defineProps({
|
||||
show: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
imgSize: {
|
||||
type: Number,
|
||||
default: 200
|
||||
},
|
||||
description: {
|
||||
type: String,
|
||||
default: "暂无数据"
|
||||
}
|
||||
// img: {
|
||||
// type: String,
|
||||
// default: "@/assets/images/icon_043.png"
|
||||
// }
|
||||
});
|
||||
</script>
|
||||
<style lang="css" scoped></style>
|
247
src/components/MyComponents/FileUpload/index.vue
Normal file
247
src/components/MyComponents/FileUpload/index.vue
Normal file
@ -0,0 +1,247 @@
|
||||
<template>
|
||||
<div class="main-box">
|
||||
<div class="file_box" v-for="(item, index) in fileList" :key="index">
|
||||
<div class="show_file" :style="{ width: width, height: width }">
|
||||
<div class="icon_box_y" :style="{ width: width, height: width }">
|
||||
<svg-icon :icon="getSuffix(item.url)" />
|
||||
<span class="file_name_box">{{ item.name }}</span>
|
||||
</div>
|
||||
<div class="load_and_del" :style="{ width: width, height: width }">
|
||||
<el-icon class="load_and_del_icon" :size="18" color="#aaaaaa">
|
||||
<DeleteFilled v-if="props.isEdit" @click="delFile(index)" />
|
||||
</el-icon>
|
||||
<el-icon class="load_and_del_icon" :size="18" color="#aaaaaa">
|
||||
<Download @click="downloadFile(item.url)" />
|
||||
</el-icon>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="file_box" v-if="fileList.length != props.limit && props.isEdit">
|
||||
<div class="upload_img" :style="{ width: width, height: width }">
|
||||
<div class="icon_box" :style="{ width: width, height: width }">
|
||||
<el-icon :size="30" color="#aaaaaa">
|
||||
<Plus />
|
||||
</el-icon>
|
||||
</div>
|
||||
<div class="file_box_item" :style="{ width: width, height: width }">
|
||||
<input
|
||||
type="file"
|
||||
:style="{ width: width, height: width }"
|
||||
class="file_input"
|
||||
id="file"
|
||||
@change="fileChange"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {
|
||||
ref,
|
||||
defineProps,
|
||||
defineEmits,
|
||||
defineExpose,
|
||||
computed,
|
||||
onMounted
|
||||
} from "vue";
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
import request from "@/utils/request";
|
||||
import axios from "axios";
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: String,
|
||||
default: ""
|
||||
},
|
||||
width: {
|
||||
type: String,
|
||||
default: "150px"
|
||||
},
|
||||
limit: {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
isEdit: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
});
|
||||
const fileList = ref([]);
|
||||
const count = ref(0); // 上传的数量
|
||||
|
||||
const emits = defineEmits(["update:modelValue", "handleChange"]);
|
||||
//获取后缀
|
||||
const getSuffix = (fileName) => {
|
||||
let suffix = "";
|
||||
try {
|
||||
suffix = fileName.substr(fileName.lastIndexOf(".") + 1, 4);
|
||||
if (suffix.indexOf("?") !== -1) suffix = suffix.replaceAll("?", "");
|
||||
} catch (err) {
|
||||
suffix = "";
|
||||
return "OTHER";
|
||||
}
|
||||
// fileName无后缀返回 false
|
||||
if (!suffix) return "";
|
||||
// 图片格式
|
||||
var imglist = ["png", "jpg", "jpeg", "bmp", "gif"];
|
||||
if (imglist.includes(suffix)) return "IMG";
|
||||
//txt
|
||||
if (suffix === "txt") return "TXT";
|
||||
//excel XLS
|
||||
const excelist = ["xls", "xlsx"];
|
||||
if (excelist.includes(suffix)) return "XLS";
|
||||
// 匹配 word
|
||||
var wordlist = ["doc", "docx"];
|
||||
if (wordlist.includes(suffix)) return "DOC";
|
||||
//pdf
|
||||
if (suffix === "pdf") return "PDF";
|
||||
//视频 音频
|
||||
var videolist = [
|
||||
"mp4",
|
||||
"m2v",
|
||||
"mkv",
|
||||
"rmvb",
|
||||
"wmv",
|
||||
"avi",
|
||||
"flv",
|
||||
"mov",
|
||||
"m4v"
|
||||
];
|
||||
if (videolist.includes(suffix)) return "VIDEO";
|
||||
var musiclist = ["mp3", "wav", "wmv"];
|
||||
if (musiclist.includes(suffix)) return "MUSIC";
|
||||
var pptlist = ["ppt", "pptx"];
|
||||
if (pptlist.includes(suffix)) return "PPT";
|
||||
//压缩包
|
||||
var yslist = ["7z", "rar", "zip", "apz", "ar", "hpk", "hyp", "hbc2"];
|
||||
if (yslist.includes(suffix)) return "YS";
|
||||
//否则返回other
|
||||
return "OTHER";
|
||||
};
|
||||
// 删除
|
||||
function delFile(index) {
|
||||
fileList.value = fileList.value.filter((item, i) => {
|
||||
return i !== index;
|
||||
});
|
||||
}
|
||||
// 文件下载
|
||||
function downloadFile(url) {
|
||||
window.open('/mosty-api/mosty-base/minio/image/download/'+url, "_blank");
|
||||
}
|
||||
// 选择文件
|
||||
function fileChange(e) {
|
||||
let file = document.getElementById("file").files[0];
|
||||
let name = file.name;
|
||||
let formData = new FormData();
|
||||
formData.append("file", file);
|
||||
axios
|
||||
.post("/mosty-api/mosty-base/minio/image/upload/id", formData, {
|
||||
"Content-type": "multipart/form-data"
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.status == 200 && res.data && res.data.code === 10000) {
|
||||
let url = res.data.data;
|
||||
let f = {
|
||||
url: url,
|
||||
name: name
|
||||
};
|
||||
fileList.value.push(f);
|
||||
count.value = count.value + 1;
|
||||
let list = fileList.value.map((item) => {
|
||||
return item.url;
|
||||
});
|
||||
emits("handleChange", JSON.stringify(list));
|
||||
} else {
|
||||
ElMessage.warning("文件上传失败");
|
||||
}
|
||||
});
|
||||
}
|
||||
onMounted(() => {
|
||||
if (props.modelValue) {
|
||||
let list = JSON.parse(props.modelValue);
|
||||
list.forEach((item, index) => {
|
||||
let temp = {
|
||||
url: item,
|
||||
name: "文件" + (index + 1)
|
||||
};
|
||||
fileList.value.push(temp);
|
||||
});
|
||||
count.value = list.length;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.main-box {
|
||||
width: 100%;
|
||||
.file_box {
|
||||
background-color: #112b63;
|
||||
border: 1px dashed #4579b5;
|
||||
margin: 10px 0 0 10px;
|
||||
border-radius: 5px;
|
||||
position: relative;
|
||||
.show_file {
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
&:hover > .load_and_del {
|
||||
display: block;
|
||||
}
|
||||
.load_and_del {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
.load_and_del_icon {
|
||||
cursor: pointer;
|
||||
margin-left:5px;
|
||||
margin-top: 5px;
|
||||
}
|
||||
}
|
||||
.icon_box_y {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
.file_name_box {
|
||||
margin-top: 10px;
|
||||
width: 80%;
|
||||
line-height: 30px;
|
||||
height: 30px;
|
||||
overflow: hidden;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
::v-deep .svg-icon {
|
||||
font-size: 48px;
|
||||
}
|
||||
}
|
||||
.upload_img {
|
||||
position: relative;
|
||||
.icon_box {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
.file_box_item {
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
z-index: 2;
|
||||
top: 0;
|
||||
left: 0;
|
||||
.file_input {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
.file_box_item_show {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
198
src/components/MyComponents/FrameWork/index.vue
Normal file
198
src/components/MyComponents/FrameWork/index.vue
Normal file
@ -0,0 +1,198 @@
|
||||
<template>
|
||||
<div class="form-item-box zk-frameWork-wrap" :style="{ width: width }">
|
||||
<el-select
|
||||
:model-value="frameWork"
|
||||
:placeholder="placeholder"
|
||||
@clear="handleClear"
|
||||
@change="selectChange"
|
||||
:clearable="clearable"
|
||||
v-bind="$attrs"
|
||||
:multiple="multiple"
|
||||
popper-class="frameWork-select"
|
||||
>
|
||||
<el-option value="1" style="display: none"></el-option>
|
||||
<el-input
|
||||
v-if="filterable"
|
||||
v-model="filterText"
|
||||
style="width: 96% !important; margin: 0 2%; font-size: 12px"
|
||||
:prefix-icon="Search"
|
||||
/>
|
||||
<div class="alllist">
|
||||
<el-tree
|
||||
ref="tree"
|
||||
:data="treeData"
|
||||
:props="defaultConf"
|
||||
default-expand-all
|
||||
:filter-node-method="filterNode"
|
||||
:show-checkbox="multiple"
|
||||
:node-key="nodeKey"
|
||||
@check-change="handleCheckChange"
|
||||
@node-click="clickNode"
|
||||
/>
|
||||
</div>
|
||||
</el-select>
|
||||
<!-- <el-icon class="errorIcon"><circle-close-filled /></el-icon>
|
||||
<el-icon class="checkIcon"><circle-check-filled /></el-icon> -->
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { COMPONENT_WIDTH } from '@/constant';
|
||||
import { nextTick, ref, watch } from "vue";
|
||||
import { Search } from "@element-plus/icons-vue";
|
||||
const emits = defineEmits(["handleChange"]); //子组件向父组件事件传递
|
||||
const props = defineProps({
|
||||
clearable: {
|
||||
default: false,
|
||||
type: Boolean
|
||||
},
|
||||
multiple: {
|
||||
default: false,
|
||||
type: Boolean
|
||||
},
|
||||
filterable: {
|
||||
default: false,
|
||||
type: Boolean
|
||||
},
|
||||
treeData: {
|
||||
default: () => [],
|
||||
type: Array
|
||||
},
|
||||
placeholder: {
|
||||
default: "选择组织机构",
|
||||
type: String
|
||||
},
|
||||
defaultConf: {
|
||||
type: Object,
|
||||
default: () => ({
|
||||
children: "children",
|
||||
label: "label"
|
||||
})
|
||||
},
|
||||
frameWork: {
|
||||
type: [String, Array],
|
||||
default: ""
|
||||
},
|
||||
width: {
|
||||
default: COMPONENT_WIDTH,
|
||||
type: String
|
||||
}
|
||||
});
|
||||
const nodeKey = "id";
|
||||
const filterText = ref("");
|
||||
const mineStatusValue = ref([]); //选中状态存贮
|
||||
nextTick(() => {
|
||||
if (props.frameWork) {
|
||||
if (typeof props.frameWork === "string") {
|
||||
//传过来的默认值类型
|
||||
if (props.frameWork) {
|
||||
tree.value.setCheckedKeys([props.frameWork], false);
|
||||
}
|
||||
} else {
|
||||
if (props.frameWork.length > 0) {
|
||||
tree.value.setCheckedKeys(props.frameWork, false);
|
||||
}
|
||||
}
|
||||
mineStatusValue.value = treeValueFind(props.treeData, props.frameWork);
|
||||
}
|
||||
});
|
||||
const tree = ref(null);
|
||||
let deferTimer;
|
||||
watch(filterText, (val) => {
|
||||
tree.value.filter(val);
|
||||
});
|
||||
const filterNode = (value, data) => {
|
||||
if (!value) return true;
|
||||
return data[props.defaultConf.label].indexOf(value) !== -1;
|
||||
};
|
||||
|
||||
//多选选中
|
||||
const handleCheckChange = () => {
|
||||
const res = tree.value.getCheckedNodes(true, true); // 这里两个true,1. 是否只是叶子节点 2. 是否包含半选节点
|
||||
mineStatusValue.value = res;
|
||||
clearTimeout(deferTimer);
|
||||
deferTimer = setTimeout(() => {
|
||||
emits("handleChange", res);
|
||||
}, 200);
|
||||
};
|
||||
//节点选择
|
||||
const clickNode = (data, node, obj) => {
|
||||
if (props.multiple) {
|
||||
// 多选不执行
|
||||
const index = mineStatusValue.value.findIndex((d) => d.id === data.id);
|
||||
if (index > -1) {
|
||||
tree.value.setChecked(data, false);
|
||||
} else {
|
||||
tree.value.setChecked(data, true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!data.children) {
|
||||
mineStatusValue.value.push(data.id);
|
||||
tree.value.setCheckedKeys([data.id], false);
|
||||
}
|
||||
};
|
||||
//select值变化
|
||||
const selectChange = (e) => {
|
||||
if (!props.multiple || !props.treeData.length) {
|
||||
return false;
|
||||
}
|
||||
const arrNew = [];
|
||||
const dataLength = mineStatusValue.value.length;
|
||||
const eleng = e.length;
|
||||
for (let i = 0; i < dataLength; i++) {
|
||||
for (let j = 0; j < eleng; j++) {
|
||||
if (e[j] === mineStatusValue.value[i][props.defaultConf.label]) {
|
||||
arrNew.push(mineStatusValue.value[i][nodeKey]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
setTimeout(() => {
|
||||
tree.value.setCheckedKeys(arrNew, false);
|
||||
}, 200);
|
||||
};
|
||||
//select clear
|
||||
const handleClear = (e) => {
|
||||
mineStatusValue.value = [];
|
||||
tree.value.setCheckedKeys([], false);
|
||||
};
|
||||
const treeValueFind = (tree, arr, newArr = []) => {
|
||||
if (typeof arr === "string") {
|
||||
tree.forEach((el) => {
|
||||
if (el[nodeKey] === arr) {
|
||||
newArr.push(el);
|
||||
}
|
||||
if (el[props.defaultConf.children]) {
|
||||
treeValueFind(el[props.defaultConf.children], arr, newArr);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
for (let i = arr.length; i >= 0; i--) {
|
||||
tree.forEach((el) => {
|
||||
if (el[nodeKey] === arr[i]) {
|
||||
newArr.push(el);
|
||||
arr.splice(i, 1);
|
||||
}
|
||||
if (el[props.defaultConf.children] && arr.length > 0) {
|
||||
treeValueFind(el[props.defaultConf.children], arr, newArr);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
return newArr;
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.optionclass {
|
||||
height: auto;
|
||||
padding: 0;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
overflow-y: overflow;
|
||||
}
|
||||
.zk-frameWork-wrap {
|
||||
.el-select {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
83
src/components/MyComponents/FrameWork2/index.vue
Normal file
83
src/components/MyComponents/FrameWork2/index.vue
Normal file
@ -0,0 +1,83 @@
|
||||
<template>
|
||||
<div class="form-item-box" :style="{ width: width }">
|
||||
<el-cascader
|
||||
class="el-cascader-zj"
|
||||
:placeholder="placeholder"
|
||||
:options="tableData"
|
||||
v-bind="$attrs"
|
||||
v-model="modelValue"
|
||||
@change="handleChange"
|
||||
:props="endProps"
|
||||
:filterable="filterable"
|
||||
/>
|
||||
<!-- <el-icon class="errorIcon"><circle-close-filled /></el-icon>
|
||||
<el-icon class="checkIcon"><circle-check-filled /></el-icon> -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { COMPONENT_WIDTH } from '@/constant';
|
||||
import { ref, defineProps, defineEmits, defineExpose,computed } from "vue";
|
||||
import { getSystemMeny } from "@/api/user-manage";
|
||||
const props = defineProps({
|
||||
//获取组件传值
|
||||
placeholder: {
|
||||
default: "请选择",
|
||||
type: String
|
||||
},
|
||||
multiple: {
|
||||
default: false,
|
||||
type: Boolean
|
||||
},
|
||||
filterable: {
|
||||
default: false,
|
||||
type: Boolean
|
||||
},
|
||||
modelValue: {
|
||||
default: [],
|
||||
type: Array
|
||||
},
|
||||
width: {
|
||||
default: COMPONENT_WIDTH,
|
||||
type: String
|
||||
}
|
||||
});
|
||||
const endProps = computed(() => {
|
||||
let re = { children: 'sysMenuList', value: 'id', label: 'menuName' }
|
||||
if (props.multiple === true) {
|
||||
re.multiple = true;
|
||||
}
|
||||
return re;
|
||||
})
|
||||
const tableData = ref([]);
|
||||
const getSysMenuTree = async () => {
|
||||
const params = {
|
||||
menuName: "",
|
||||
current: 1,
|
||||
size: 999
|
||||
}
|
||||
const res = await getSystemMeny(params);
|
||||
tableData.value = res?.records;
|
||||
};
|
||||
getSysMenuTree();
|
||||
|
||||
const emits = defineEmits(["update:modelValue"]);
|
||||
const handleChange = (e) => {
|
||||
if (props.multiple === true) {
|
||||
const data = e.map((item) => {
|
||||
return item[item.length - 1];
|
||||
});
|
||||
emits("update:modelValue", data);
|
||||
} else {
|
||||
const data = e ? e[e.length - 1] : ''
|
||||
emits("update:modelValue", data);
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.el-cascader-zj{
|
||||
width: 100%;
|
||||
|
||||
}
|
||||
</style>
|
38
src/components/MyComponents/IdentityCard/index.vue
Normal file
38
src/components/MyComponents/IdentityCard/index.vue
Normal file
@ -0,0 +1,38 @@
|
||||
<template>
|
||||
<div
|
||||
class="form-item-box"
|
||||
:style="{ width: width}"
|
||||
>
|
||||
<el-input
|
||||
:placeholder="placeholder"
|
||||
v-bind="$attrs"
|
||||
v-model="modelValue"
|
||||
@input="onInput"
|
||||
></el-input>
|
||||
<!-- <el-icon class="errorIcon"><circle-close-filled /></el-icon>
|
||||
<el-icon class="checkIcon"><circle-check-filled /></el-icon> -->
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { COMPONENT_WIDTH } from '@/constant';
|
||||
import { defineProps, defineEmits } from "vue";
|
||||
const props = defineProps({
|
||||
placeholder: {
|
||||
default: "请输入身份证号",
|
||||
type: String
|
||||
},
|
||||
modelValue: {
|
||||
default: "",
|
||||
type: String
|
||||
},
|
||||
width: {
|
||||
default: COMPONENT_WIDTH,
|
||||
type: String
|
||||
}
|
||||
});
|
||||
|
||||
const emits = defineEmits(["update:modelValue"]);
|
||||
const onInput = (e) => {
|
||||
emits("update:modelValue", e);
|
||||
};
|
||||
</script>
|
71
src/components/MyComponents/MarkdownEdit/index.vue
Normal file
71
src/components/MyComponents/MarkdownEdit/index.vue
Normal file
@ -0,0 +1,71 @@
|
||||
<template>
|
||||
<div class="markdown-wrap">
|
||||
<!---->
|
||||
<div id="markdown-box">
|
||||
<strong v-html="modelValue"></strong>
|
||||
</div>
|
||||
<div style="margin-top: 1vw">
|
||||
<el-link type="primary" @click="saveEdit('detail', row)">确定详情信息</el-link>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import MKEditor from "@toast-ui/editor";
|
||||
import "@toast-ui/editor/dist/toastui-editor.css";
|
||||
import "@toast-ui/editor/dist/i18n/zh-cn.js";
|
||||
|
||||
import { COMPONENT_WIDTH } from "@/constant";
|
||||
import {
|
||||
ref,
|
||||
defineProps,
|
||||
defineEmits,
|
||||
defineExpose,
|
||||
onMounted,
|
||||
watch
|
||||
} from "vue";
|
||||
const props = defineProps({
|
||||
//获取组件传值
|
||||
placeholder: {
|
||||
default: "请填写手机号",
|
||||
type: String
|
||||
},
|
||||
modelValue: {
|
||||
default: "",
|
||||
type: String
|
||||
},
|
||||
width: {
|
||||
default: "800px",
|
||||
type: String
|
||||
}
|
||||
});
|
||||
let mkEditor;
|
||||
let el;
|
||||
onMounted(() => {
|
||||
el = document.querySelector("#markdown-box");
|
||||
initEditor();
|
||||
});
|
||||
const emits = defineEmits(["update:modelValue"]);
|
||||
const initEditor = () => {
|
||||
mkEditor = new MKEditor({
|
||||
el,
|
||||
height: "700px",
|
||||
previewStyle: "vertical",
|
||||
language: "zh-CN",
|
||||
initiaValue:props.modelValue
|
||||
});
|
||||
mkEditor.getMarkdown();
|
||||
};
|
||||
const saveEdit = () => {
|
||||
emits("update:modelValue", mkEditor.getHTML());
|
||||
};
|
||||
const onInput = (e) => {
|
||||
emits("update:modelValue", e);
|
||||
};
|
||||
//回显
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.markdown-wrap {
|
||||
}
|
||||
</style>
|
31
src/components/MyComponents/Other/index.vue
Normal file
31
src/components/MyComponents/Other/index.vue
Normal file
@ -0,0 +1,31 @@
|
||||
<template>
|
||||
<div class="form-item-box" :style="{ width: width }">
|
||||
<el-input :placeholder="placeholder" v-bind="$attrs" v-model="modelValue" @input="onInput" ></el-input>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { COMPONENT_WIDTH } from "@/constant";
|
||||
import { ref, defineProps, defineEmits, defineExpose } from "vue";
|
||||
const props = defineProps({
|
||||
//获取组件传值
|
||||
placeholder: {
|
||||
default: "请填写手机号",
|
||||
type: String
|
||||
},
|
||||
modelValue: {
|
||||
default: "",
|
||||
type: String
|
||||
},
|
||||
width: {
|
||||
default: COMPONENT_WIDTH,
|
||||
type: String
|
||||
}
|
||||
});
|
||||
|
||||
const emits = defineEmits(["update:modelValue"]);
|
||||
const onInput = (e) => {
|
||||
emits("update:modelValue", e);
|
||||
};
|
||||
</script>
|
||||
|
32
src/components/MyComponents/Phone/index.vue
Normal file
32
src/components/MyComponents/Phone/index.vue
Normal file
@ -0,0 +1,32 @@
|
||||
<template>
|
||||
<div class="form-item-box" :style="{ width: width }">
|
||||
<el-input :placeholder="placeholder" v-bind="$attrs" v-model="modelValue" @input="onInput" ></el-input>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { COMPONENT_WIDTH } from '@/constant';
|
||||
import { ref, defineProps, defineEmits, defineExpose } from "vue";
|
||||
const props = defineProps({
|
||||
//获取组件传值
|
||||
placeholder: {
|
||||
default: "请填写手机号",
|
||||
type: String
|
||||
},
|
||||
modelValue: {
|
||||
default: "",
|
||||
type: String
|
||||
},
|
||||
width: {
|
||||
default: COMPONENT_WIDTH,
|
||||
type: String
|
||||
}
|
||||
});
|
||||
|
||||
const emits = defineEmits(["update:modelValue"]);
|
||||
const onInput = (e) => {
|
||||
emits("update:modelValue", e);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
109
src/components/MyComponents/Provinces/index.vue
Normal file
109
src/components/MyComponents/Provinces/index.vue
Normal file
@ -0,0 +1,109 @@
|
||||
<template>
|
||||
<div class="form-item-box">
|
||||
<el-select v-model="province" clearable placeholder="请选择省份">
|
||||
<el-option v-for="item in areas" :value="item.code" :label="item.name" :key="item.code">{{ item.name }}
|
||||
</el-option>
|
||||
</el-select>
|
||||
<el-select clearable :disabled="!province" style="margin: 0 10px" v-model="city" placeholder="请选择城市">
|
||||
<el-option v-for="item in selectCity" :value="item.code" :label="item.name" :key="item.code">{{ item.name }}
|
||||
</el-option>
|
||||
</el-select>
|
||||
<el-select clearable :disabled="!province || !city" v-model="area" placeholder="请选择区域">
|
||||
<el-option v-for="item in selectArea" :value="item.code" :label="item.name" :key="item.code">{{ item.name }}
|
||||
</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import allAreas from "@/constant/pca-code.json";
|
||||
import {
|
||||
ref,
|
||||
defineProps,
|
||||
defineEmits,
|
||||
defineExpose,
|
||||
computed,
|
||||
watch
|
||||
} from "vue";
|
||||
const props = defineProps({
|
||||
//获取组件传值
|
||||
placeholder: {
|
||||
default: "请选择省市区",
|
||||
type: String
|
||||
},
|
||||
modelValue: {
|
||||
default: "",
|
||||
type: String
|
||||
}
|
||||
});
|
||||
|
||||
let province = ref("");
|
||||
let city = ref("");
|
||||
let area = ref("");
|
||||
let areas = ref(allAreas);
|
||||
|
||||
let selectCity = ref([]);
|
||||
let selectArea = ref([]);
|
||||
//分发事件给父组件
|
||||
//分发事件给父组件
|
||||
const emits = defineEmits(["update:modelValue"]);
|
||||
//监听省份变化
|
||||
watch(
|
||||
() => province.value,
|
||||
(val) => {
|
||||
if (val) {
|
||||
let cities = areas.value.find(
|
||||
(item) => item.code === province.value
|
||||
)?.children;
|
||||
selectCity.value = cities;
|
||||
}
|
||||
city.value = "";
|
||||
area.value = "";
|
||||
}
|
||||
);
|
||||
|
||||
//监听城市变化
|
||||
watch(
|
||||
() => city.value,
|
||||
(val) => {
|
||||
if (val) {
|
||||
let area = selectCity.value.find(
|
||||
(item) => item.code === city.value
|
||||
)?.children;
|
||||
selectArea.value = area;
|
||||
}
|
||||
area.value = "";
|
||||
}
|
||||
);
|
||||
|
||||
//监听区域变化
|
||||
watch(
|
||||
() => area.value,
|
||||
(val) => {
|
||||
let provinceData = {
|
||||
code: province.value,
|
||||
name:
|
||||
province.value &&
|
||||
allAreas.find((item) => item.code === province.value).name
|
||||
};
|
||||
let cityData = {
|
||||
code: city.value,
|
||||
name:
|
||||
city.value &&
|
||||
selectCity.value &&
|
||||
selectCity.value.find((item) => item.code === city.value).name
|
||||
};
|
||||
let areaData = {
|
||||
code: val,
|
||||
name:
|
||||
val &&
|
||||
selectArea.value &&
|
||||
selectArea.value.find((item) => item.code === val).name
|
||||
};
|
||||
emits("update:modelValue", `${provinceData},${cityData},${areaData}`);
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
</style>
|
62
src/components/MyComponents/Provinces2/index.vue
Normal file
62
src/components/MyComponents/Provinces2/index.vue
Normal file
@ -0,0 +1,62 @@
|
||||
<template>
|
||||
<div class="form-item-box" :style="{ width: width }">
|
||||
<el-cascader class="el-cascader-zj" :props="{ value: 'label', label: 'label', children: 'children' }"
|
||||
:options="arercity" expand-trigger="hover" change-on-select @change="onInChange" :placeholder="placeholder"
|
||||
v-bind="$attrs" v-model="value"></el-cascader>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { COMPONENT_WIDTH } from '@/constant';
|
||||
import allAreas from "./provicesData";
|
||||
import {
|
||||
ref,
|
||||
defineProps,
|
||||
defineEmits,
|
||||
defineExpose,
|
||||
computed,
|
||||
nextTick,
|
||||
watch
|
||||
} from "vue";
|
||||
const props = defineProps({
|
||||
//获取组件传值
|
||||
placeholder: {
|
||||
default: "请选择地区位置",
|
||||
type: String
|
||||
},
|
||||
|
||||
provinces2: {
|
||||
default: () => [],
|
||||
type: Array
|
||||
},
|
||||
width: {
|
||||
default: COMPONENT_WIDTH,
|
||||
type: String
|
||||
}
|
||||
});
|
||||
const value = ref([]);
|
||||
|
||||
nextTick(() => {
|
||||
if (props.provinces2.length > 0) {
|
||||
init(props.provinces2);
|
||||
}
|
||||
});
|
||||
|
||||
const init = (data) => { };
|
||||
const registerAddress = ref([]);
|
||||
|
||||
const arercity = ref(allAreas);
|
||||
const emits = defineEmits(["update:provinces2"]);
|
||||
const onInChange = (e) => {
|
||||
emits("update:provinces2", e);
|
||||
};
|
||||
// const onInput = (e) => {
|
||||
// emits("update:provinces2", e);
|
||||
// };
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.el-cascader-zj {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
6138
src/components/MyComponents/Provinces2/provicesData.js
Normal file
6138
src/components/MyComponents/Provinces2/provicesData.js
Normal file
File diff suppressed because it is too large
Load Diff
287
src/components/MyComponents/RichOnly/index.vue
Normal file
287
src/components/MyComponents/RichOnly/index.vue
Normal file
@ -0,0 +1,287 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-dialog
|
||||
:title="titleValue"
|
||||
width="1400px"
|
||||
:model-value="modelValue"
|
||||
@close="closed"
|
||||
>
|
||||
<el-form :model="listQuery" :inline="true">
|
||||
<el-form-item label="所属部门">
|
||||
<MOSTY.Department width="100%" clearable v-model="listQuery.ssbmdm" />
|
||||
</el-form-item>
|
||||
<el-form-item label="圈层名称">
|
||||
<el-input
|
||||
v-model="listQuery.qcmc"
|
||||
placeholder="请输入圈层名称"
|
||||
clearable
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-button type="success" @click="handleFilter">查询</el-button>
|
||||
<el-button type="info" @click="reset()"> 重置 </el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div class="tabBox" style="margin-top: 0px" v-if="modelValue">
|
||||
<el-table
|
||||
ref="multipleUserRef"
|
||||
@selection-change="handleSelectionChange"
|
||||
:data="tableData"
|
||||
border
|
||||
style="width: 100%"
|
||||
:row-key="keyid"
|
||||
height="450"
|
||||
>
|
||||
<el-table-column
|
||||
type="selection"
|
||||
width="55"
|
||||
:reserve-selection="true"
|
||||
v-if="props.multiple"
|
||||
/>
|
||||
<el-table-column width="55" #default="{ row }" v-else>
|
||||
<el-radio v-model="ridioIndex" :label="row.id"></el-radio>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
label="序号"
|
||||
type="index"
|
||||
align="center"
|
||||
sortable
|
||||
width="80"
|
||||
/>
|
||||
<el-table-column
|
||||
sortable
|
||||
prop="ssbm"
|
||||
label="所属部门"
|
||||
show-overflow-tooltip
|
||||
align="center"
|
||||
></el-table-column>
|
||||
<el-table-column
|
||||
sortable
|
||||
prop="qcmc"
|
||||
show-overflow-tooltip
|
||||
label="圈层名称"
|
||||
align="center"
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
sortable
|
||||
prop="qclx"
|
||||
show-overflow-tooltip
|
||||
label="圈层类型"
|
||||
align="center"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<dict-tag :options="D_BZ_QCLX" :value="row.qclx" :tag="false" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
sortable
|
||||
prop="qcjb"
|
||||
show-overflow-tooltip
|
||||
label="圈层等级"
|
||||
align="center"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<dict-tag :options="D_BZ_QCDJ" :value="row.qcjb" :tag="false" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<div class="fenye" :style="{ top: tableHeight + 'px' }">
|
||||
<el-pagination
|
||||
class="pagination"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
:current-page="listQuery.pageCurrent"
|
||||
:page-sizes="[2, 5, 10, 20]"
|
||||
:page-size="listQuery.pageSize"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="total"
|
||||
></el-pagination>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="closed">取消</el-button>
|
||||
<el-button type="primary" @click="onComfirm">确认</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import * as rule from "@/utils/rules.js";
|
||||
import * as MOSTY from "@/components/MyComponents/index";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { qcckGet, qcckPost } from "@/api/qcckApi.js";
|
||||
import {
|
||||
defineProps,
|
||||
watch,
|
||||
ref,
|
||||
onMounted,
|
||||
nextTick,
|
||||
getCurrentInstance
|
||||
} from "vue";
|
||||
const { proxy } = getCurrentInstance();
|
||||
const { D_BZ_QCLX, D_BZ_QCDJ } = proxy.$dict("D_BZ_QCLX", "D_BZ_QCDJ");
|
||||
const props = defineProps({
|
||||
//是否显示
|
||||
modelValue: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
},
|
||||
//标题
|
||||
titleValue: {
|
||||
type: String,
|
||||
default: "选择圈层"
|
||||
},
|
||||
//是否多选
|
||||
multiple: {
|
||||
default: true,
|
||||
type: Boolean
|
||||
},
|
||||
//已经选中得数据回显
|
||||
data: {
|
||||
type: Array,
|
||||
default: []
|
||||
}
|
||||
});
|
||||
const keyid = (row) => {
|
||||
return row.id;
|
||||
};
|
||||
const total = ref(0);
|
||||
const ridioIndex = ref(null);
|
||||
const listQuery = ref({
|
||||
pageCurrent: 1,
|
||||
pageSize: 20,
|
||||
qcmc: "",
|
||||
ssbmdm: ""
|
||||
});
|
||||
const form = ref({});
|
||||
const tableData = ref([]);
|
||||
const emits = defineEmits(["close", "choosedQc"]);
|
||||
const closed = () => {
|
||||
emits("close", false);
|
||||
};
|
||||
const reset = () => {
|
||||
listQuery.value = {
|
||||
pageCurrent: 1,
|
||||
pageSize: 20,
|
||||
qcmc: "",
|
||||
ssbmdm: ""
|
||||
};
|
||||
getListData();
|
||||
};
|
||||
//确认选中
|
||||
const onComfirm = () => {
|
||||
if (props.multiple) {
|
||||
//多选
|
||||
const List = JSON.parse(JSON.stringify(multipleSelectionUser.value));
|
||||
if (List.length === 0) {
|
||||
proxy.$message.warning("请选择圈层");
|
||||
return;
|
||||
}
|
||||
emits("choosedQc", List);
|
||||
} else {
|
||||
//单选
|
||||
if (![ridioIndex.value][0]) {
|
||||
proxy.$message.warning("请选择圈层");
|
||||
return;
|
||||
}
|
||||
const info = tableData.value.find((item) => {
|
||||
return item.id === ridioIndex.value;
|
||||
});
|
||||
emits("choosedQc", [info]);
|
||||
}
|
||||
closed();
|
||||
};
|
||||
onMounted(() => {
|
||||
getListData();
|
||||
});
|
||||
/**
|
||||
* pageSize 改变触发
|
||||
*/
|
||||
const handleSizeChange = (currentSize) => {
|
||||
listQuery.value.pageSize = currentSize;
|
||||
getListData();
|
||||
};
|
||||
|
||||
/**
|
||||
* 页码改变触发
|
||||
*/
|
||||
const handleCurrentChange = (currentPage) => {
|
||||
listQuery.value.pageSize = currentPage;
|
||||
getListData();
|
||||
};
|
||||
//圈层数据
|
||||
const getListData = async () => {
|
||||
qcckGet(listQuery.value, "/mosty-jcgl/qc/selectQcList").then((res) => {
|
||||
tableData.value = res?.records;
|
||||
multipleUser(props.data, tableData.value);
|
||||
total.value = Number(res.total);
|
||||
});
|
||||
};
|
||||
const handleFilter = () => {
|
||||
listQuery.value.pageCurrent = 1;
|
||||
getListData();
|
||||
};
|
||||
|
||||
const multipleUserRef = ref(null); //表单
|
||||
//多选选中的数据
|
||||
const multipleSelectionUser = ref([]);
|
||||
const handleSelectionChange = (val) => {
|
||||
multipleSelectionUser.value = val;
|
||||
};
|
||||
//回显
|
||||
function multipleUser(row, list) {
|
||||
if (row) {
|
||||
if (props.multiple) {
|
||||
row.forEach((item) => {
|
||||
list.forEach((select) => {
|
||||
if (item.id == select.id) {
|
||||
if (multipleUserRef.value) {
|
||||
multipleUserRef.value.toggleRowSelection(select, true);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(val) => {
|
||||
if (val === true) {
|
||||
handleFilter();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.data,
|
||||
(val) => {
|
||||
if (multipleUserRef.value) multipleUser(val, tableData.value);
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "@/assets/css/layout.scss";
|
||||
@import "@/assets/css/element-plus.scss";
|
||||
::v-deep .el-form--inline {
|
||||
padding-left: 0 !important;
|
||||
}
|
||||
::v-deep .el-radio__label {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
<style lang="scss">
|
||||
.el-dialog {
|
||||
// --el-dialog-bg-color: #001238 !important;
|
||||
}
|
||||
.el-dialog__title {
|
||||
color: #fff !important;
|
||||
}
|
||||
</style>
|
49
src/components/MyComponents/Select/index.vue
Normal file
49
src/components/MyComponents/Select/index.vue
Normal file
@ -0,0 +1,49 @@
|
||||
|
||||
<template>
|
||||
<div class="Select-wrap" :style="{ width: width }">
|
||||
<el-select :disabled="props.disabled" v-bind="$attrs" v-model="modelValue" @change="hanlderSelect" :popper-class="selectOption.length > 20 ? 'nation-select' : ''" :placeholder="placeholder">
|
||||
<el-option v-for="item in dictEnum" :key="item.value" :label="item.zdmc || item.label" :value="item.dm || item.value">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { nextTick, onBeforeMount, ref } from "vue";
|
||||
const emits = defineEmits(["change"]); //子组件向父组件事件传递
|
||||
const props = defineProps({
|
||||
//获取组件传值
|
||||
placeholder: {
|
||||
default: "请选择",
|
||||
type: String
|
||||
},
|
||||
disabled:{
|
||||
default: false,
|
||||
type: Boolean
|
||||
},
|
||||
modelValue: {
|
||||
default: "",
|
||||
type: String
|
||||
},
|
||||
dictEnum: {
|
||||
default: Array,
|
||||
type: String
|
||||
},
|
||||
width: {
|
||||
default: '100%',
|
||||
type: String
|
||||
}
|
||||
});
|
||||
const selectOption = ref([]);
|
||||
|
||||
const hanlderSelect = (data) => {
|
||||
emits("change", data);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.Select-wrap {
|
||||
::v-deep .el-select {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
52
src/components/MyComponents/Sex/index.vue
Normal file
52
src/components/MyComponents/Sex/index.vue
Normal file
@ -0,0 +1,52 @@
|
||||
<template>
|
||||
<div class="form-item-box" :style="{ width: width }">
|
||||
<el-select :disabled="disabled" v-model="sex" placeholder="请选择性别" @change="onChange">
|
||||
<el-option
|
||||
v-for="item in D_BZ_XB"
|
||||
:key="item"
|
||||
:label="item.zdmc"
|
||||
:value="item.dm"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { COMPONENT_WIDTH } from "@/constant";
|
||||
import {
|
||||
ref,
|
||||
defineProps,
|
||||
defineEmits,
|
||||
defineExpose,
|
||||
getCurrentInstance,
|
||||
onBeforeMount
|
||||
} from "vue";
|
||||
const { proxy } = getCurrentInstance();
|
||||
const { D_BZ_XB } = proxy.$dict("D_BZ_XB");
|
||||
const props = defineProps({
|
||||
//获取组件传值
|
||||
sex: {
|
||||
type: String
|
||||
},
|
||||
disabled:{
|
||||
type:Boolean,
|
||||
default:false
|
||||
},
|
||||
width: {
|
||||
default: COMPONENT_WIDTH,
|
||||
type: String
|
||||
}
|
||||
});
|
||||
|
||||
const emits = defineEmits(["update:sex"]);
|
||||
const onChange = (e) => {
|
||||
emits("update:sex", e);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.manIcon,
|
||||
.womanIcon {
|
||||
font-size: 30px;
|
||||
}
|
||||
</style>
|
49
src/components/MyComponents/StationSelect/index.vue
Normal file
49
src/components/MyComponents/StationSelect/index.vue
Normal file
@ -0,0 +1,49 @@
|
||||
<template>
|
||||
<div class="form-item-box zj-packageSelect-wrap" :style="{ width: width }">
|
||||
<el-select v-bind="$attrs" :model-value="modelValue" @change="hanlderSelect" :popper-class="selectOption.length > 20 ? 'nation-select' : ''">
|
||||
<el-option v-for="item in selectOption" :key="item.id" :label="item.postName" :value="item.id">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { COMPONENT_WIDTH } from '@/constant';
|
||||
import { onBeforeMount, ref } from "vue";
|
||||
import { selectJobPage } from "@/api/user-manage";
|
||||
const emits = defineEmits(["handleChange"]); //子组件向父组件事件传递
|
||||
const props = defineProps({
|
||||
//获取组件传值
|
||||
placeholder: {
|
||||
default: "请选择",
|
||||
type: String
|
||||
},
|
||||
modelValue: {
|
||||
default: "",
|
||||
type: String
|
||||
},
|
||||
dictEnum: {
|
||||
default: "",
|
||||
type: String
|
||||
},
|
||||
width: {
|
||||
default: COMPONENT_WIDTH,
|
||||
type: String
|
||||
}
|
||||
});
|
||||
const selectOption = ref([]);
|
||||
onBeforeMount(async () => {
|
||||
const res = await selectJobPage({ page: 1, size: 9999 });
|
||||
selectOption.value = [...res.records];
|
||||
});
|
||||
const hanlderSelect = (data) => {
|
||||
emits("handleChange", data);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.zj-packageSelect-wrap {
|
||||
::v-deep .el-select {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
300
src/components/MyComponents/Upload/index.vue
Normal file
300
src/components/MyComponents/Upload/index.vue
Normal file
@ -0,0 +1,300 @@
|
||||
<template>
|
||||
<div class="form-item-box" :style="{ width: width }">
|
||||
<el-upload
|
||||
v-bind="$attrs"
|
||||
:headers="headers"
|
||||
:multiple="false"
|
||||
class="avatar-uploader"
|
||||
:limit="props.limit"
|
||||
:action="actionUrl"
|
||||
list-type="picture-card"
|
||||
:file-list="fileList"
|
||||
show-file-list
|
||||
:on-exceed="handleExceed"
|
||||
:on-success="handlerSuccess"
|
||||
:before-upload="beforeImgUpload"
|
||||
>
|
||||
<template #default>
|
||||
<el-icon> <Plus /> </el-icon>
|
||||
</template>
|
||||
<template #file="{ file }">
|
||||
<div v-if="props.isImg">
|
||||
<img class="el-upload-list__item-thumbnail" :src="file.url" alt="" />
|
||||
<span class="el-upload-list__item-actions">
|
||||
<span
|
||||
class="el-upload-list__item-preview"
|
||||
@click="handlePictureCardPreview(file)"
|
||||
>
|
||||
<el-icon> <zoom-in /> </el-icon>
|
||||
</span>
|
||||
<span
|
||||
v-if="!disabled"
|
||||
class="el-upload-list__item-delete"
|
||||
@click="handleRemove(file, fileList)"
|
||||
>
|
||||
<el-icon><Delete /></el-icon>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div v-else>
|
||||
<div class="file-wrap">
|
||||
<span><svg-icon :icon="getSuffix(file.name)" /></span>
|
||||
<span class="file-name">{{ file.name }}</span>
|
||||
</div>
|
||||
<span class="el-upload-list__item-actions">
|
||||
<span
|
||||
v-if="!disabled"
|
||||
class="el-upload-list__item-delete"
|
||||
@click="handleDownload(file)"
|
||||
>
|
||||
<el-icon> <Download /> </el-icon>
|
||||
</span>
|
||||
<span
|
||||
v-if="!disabled"
|
||||
class="el-upload-list__item-delete"
|
||||
@click="handleRemove(file, fileList)"
|
||||
>
|
||||
<el-icon> <Delete /> </el-icon>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-upload>
|
||||
<el-dialog v-model="dialogVisible">
|
||||
<img style="width: 100%" :src="dialogImageUrl" alt="" />
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { COMPONENT_WIDTH } from "@/constant";
|
||||
import {
|
||||
ref,
|
||||
defineProps,
|
||||
defineEmits,
|
||||
defineExpose,
|
||||
computed,
|
||||
watch,
|
||||
onMounted,
|
||||
onUnmounted
|
||||
} from "vue";
|
||||
import { ElMessage, ElMessageBox } from "element-plus";
|
||||
import type from "element-plus/es/components/upload/src/upload.type";
|
||||
import { useStore } from "vuex";
|
||||
const props = defineProps({
|
||||
//获取组件传值
|
||||
modelValue: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
limit: {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
isImg: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
width: {
|
||||
default: COMPONENT_WIDTH,
|
||||
type: String
|
||||
}
|
||||
});
|
||||
const actionUrl = computed(() =>
|
||||
props.isImg
|
||||
? "/mosty-api/mosty-base/minio/image/upload/id"
|
||||
: "/mosty-api/mosty-base/minio/file/upload"
|
||||
);
|
||||
|
||||
const emits = defineEmits(["update:modelValue", "handleChange"]);
|
||||
|
||||
//获取后缀
|
||||
const getSuffix = (fileName) => {
|
||||
let suffix = "";
|
||||
try {
|
||||
suffix = fileName.substr(fileName.lastIndexOf(".") + 1, 4); //截取最后一个点号后4个字符
|
||||
} catch (err) {
|
||||
suffix = "";
|
||||
return "OTHER";
|
||||
}
|
||||
// fileName无后缀返回 false
|
||||
if (!suffix) return "";
|
||||
|
||||
// 图片格式
|
||||
var imglist = ["png", "jpg", "jpeg", "bmp", "gif"];
|
||||
if (imglist.includes(suffix)) return "IMG";
|
||||
|
||||
//txt
|
||||
if (suffix === "txt") return "TXT";
|
||||
|
||||
//excel XLS
|
||||
const excelist = ["xls", "xlsx"];
|
||||
if (excelist.includes(suffix)) return "XLS";
|
||||
|
||||
// 匹配 word
|
||||
var wordlist = ["doc", "docx"];
|
||||
if (wordlist.includes(suffix)) return "DOC";
|
||||
|
||||
//pdf
|
||||
if (suffix === "pdf") return "PDF";
|
||||
|
||||
//视频 音频
|
||||
var videolist = [
|
||||
"mp4",
|
||||
"m2v",
|
||||
"mkv",
|
||||
"rmvb",
|
||||
"wmv",
|
||||
"avi",
|
||||
"flv",
|
||||
"mov",
|
||||
"m4v"
|
||||
];
|
||||
if (videolist.includes(suffix)) return "VIDEO";
|
||||
|
||||
var musiclist = ["mp3", "wav", "wmv"];
|
||||
if (musiclist.includes(suffix)) return "MUSIC";
|
||||
|
||||
var pptlist = ["ppt", "pptx"];
|
||||
if (pptlist.includes(suffix)) return "PPT";
|
||||
|
||||
//压缩包
|
||||
var yslist = ["7z", "rar", "zip", "apz", "ar", "hpk", "hyp", "hbc2"];
|
||||
if (yslist.includes(suffix)) return "YS";
|
||||
|
||||
//否则返回other
|
||||
return "OTHER";
|
||||
};
|
||||
|
||||
const imageUrl = ref("");
|
||||
const store = useStore();
|
||||
const dialogImageUrl = ref("");
|
||||
const dialogVisible = ref(false);
|
||||
const disabled = ref(false);
|
||||
const headers = ref({
|
||||
Authorization: store.getters.token
|
||||
});
|
||||
const listImg = ref([]);
|
||||
onMounted(() => {
|
||||
console.log(props.modelValue);
|
||||
|
||||
if (props.modelValue) {
|
||||
listImg.value = props.modelValue;
|
||||
fileList.value = props.modelValue.map((el) => {
|
||||
return { url: `/mosty-api/mosty-base/minio/image/download/` + el };
|
||||
});
|
||||
} else {
|
||||
listImg.value = [];
|
||||
fileList.value = [];
|
||||
}
|
||||
});
|
||||
const fileList = ref([]);
|
||||
|
||||
const handlerSuccess = (res, file) => {
|
||||
file.url = `/mosty-api/mosty-base/minio/image/download/` + res.data;
|
||||
fileList.value.push(file);
|
||||
listImg.value.push(res.data);
|
||||
emits("handleChange", listImg.value);
|
||||
emits("update:modelValue", listImg.value);
|
||||
};
|
||||
const handlePreview = (file) => {};
|
||||
const handleExceed = (files, fileList) => {
|
||||
ElMessage.warning(`限制,只能上传${props.limit}个文件或图片`);
|
||||
};
|
||||
|
||||
const beforeImgUpload = (file) => {
|
||||
if (props.isImg) {
|
||||
let isIMG = false;
|
||||
if (getSuffix(file.name) === "IMG") {
|
||||
isIMG = true;
|
||||
}
|
||||
const isLt5M = file.size / 1024 / 1024 < 5;
|
||||
if (!isIMG) {
|
||||
ElMessage.error("上传图片只能是jpg/png/jpeg/bmp/gif格式!");
|
||||
}
|
||||
if (!isLt5M) {
|
||||
ElMessage.error("上传图片大小不能超过 5MB!");
|
||||
}
|
||||
return isIMG && isLt5M;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
const handleAvatarSuccess = (res, file) => {
|
||||
imageUrl.value = URL.createObjectURL(file.raw);
|
||||
};
|
||||
//查询图片
|
||||
const handlePictureCardPreview = (file) => {
|
||||
dialogImageUrl.value = file.url;
|
||||
dialogVisible.value = true;
|
||||
};
|
||||
const handleDownload = (file) => {
|
||||
window.open(file.response.data);
|
||||
};
|
||||
const handleRemove = (file) => {
|
||||
let index = fileList.value.findIndex(function (item) {
|
||||
return item.url === file.url;
|
||||
});
|
||||
fileList.value.splice(index, 1);
|
||||
listImg.value.splice(index, 1);
|
||||
emits("handleChange", listImg.value);
|
||||
emits("update:modelValue", listImg.value);
|
||||
};
|
||||
onUnmounted(() => {
|
||||
listImg.value = [];
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.avatar-uploader .el-upload {
|
||||
border: 1px dashed #d9d9d9;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.avatar-uploader .el-upload:hover {
|
||||
border-color: #409eff;
|
||||
}
|
||||
|
||||
.el-icon.avatar-uploader-icon {
|
||||
font-size: 28px;
|
||||
color: #8c939d;
|
||||
width: 178px;
|
||||
height: 178px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
width: 178px;
|
||||
height: 178px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.file-wrap {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
::v-deep .svg-icon {
|
||||
font-size: 48px;
|
||||
margin: 28px 0 2px 0;
|
||||
}
|
||||
|
||||
.file-name {
|
||||
width: 88%;
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
/*将对象作为弹性伸缩盒子模型显示*/
|
||||
display: -webkit-box;
|
||||
/*设置子元素排列方式*/
|
||||
-webkit-box-orient: vertical;
|
||||
/*设置显示的行数,多出的部分会显示为...*/
|
||||
-webkit-line-clamp: 2;
|
||||
}
|
||||
}
|
||||
</style>
|
40
src/components/MyComponents/index.js
Normal file
40
src/components/MyComponents/index.js
Normal file
@ -0,0 +1,40 @@
|
||||
import AddressSelect from "./AddressSelect/index.vue";
|
||||
import FrameWork from "./FrameWork/index.vue";
|
||||
import FrameWork2 from "./FrameWork2/index.vue";
|
||||
import Phone from "./Phone/index.vue";
|
||||
import IdentityCard from "./IdentityCard/index.vue";
|
||||
import Email from "./Email/index.vue";
|
||||
import Other from "./Other/index.vue";
|
||||
import Sex from "./Sex/index.vue";
|
||||
import Select from "./Select/index.vue";
|
||||
import Upload from "./Upload/index.vue";
|
||||
import Department from "./Department/index.vue";
|
||||
import DepartmentTree from "./DepartmentTree/index.vue";
|
||||
import ChooseIcon from "./ChooseIcon/index.vue";
|
||||
import StationSelect from "./StationSelect/index.vue";
|
||||
import Provinces from "./Provinces2/index.vue";
|
||||
import MarkdownEdit from "./MarkdownEdit/index.vue";
|
||||
import FileUpload from "./FileUpload/index.vue";
|
||||
import RichOnly from "./RichOnly/index.vue";
|
||||
import Date from "./Date/index.vue";
|
||||
export {
|
||||
AddressSelect,
|
||||
FrameWork,
|
||||
Phone,
|
||||
IdentityCard,
|
||||
Email,
|
||||
Other,
|
||||
Sex,
|
||||
Select,
|
||||
Upload,
|
||||
FrameWork2,
|
||||
Department,
|
||||
DepartmentTree,
|
||||
ChooseIcon,
|
||||
StationSelect,
|
||||
Provinces,
|
||||
MarkdownEdit,
|
||||
FileUpload,
|
||||
RichOnly,
|
||||
Date
|
||||
};
|
63
src/components/SvgIcon/index.vue
Normal file
63
src/components/SvgIcon/index.vue
Normal file
@ -0,0 +1,63 @@
|
||||
<template >
|
||||
<!---外部图标-->
|
||||
<div
|
||||
v-bind="$attrs"
|
||||
v-if="isExternal"
|
||||
:style="styleExternalIcon"
|
||||
class="svg-external-icon svg-icon"
|
||||
:class="className"
|
||||
/>
|
||||
<!--内部图标-->
|
||||
<svg v-else class="svg-icon" :class="className" aria-hidden="true" v-bind="$attrs">
|
||||
<use :xlink:href="iconName" />
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { isExternal as external } from '@/utils/validate'
|
||||
import { defineProps, computed } from 'vue'
|
||||
const props = defineProps({
|
||||
// icon 图标
|
||||
icon: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
// 图标类名
|
||||
className: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* 判断是否为外部图标
|
||||
*/
|
||||
const isExternal = computed(() => external(props.icon))
|
||||
/**
|
||||
* 外部图标样式
|
||||
*/
|
||||
const styleExternalIcon = computed(() => ({
|
||||
mask: `url(${props.icon}) no-repeat 50% 50%`,
|
||||
'-webkit-mask': `url(${props.icon}) no-repeat 50% 50%`
|
||||
}))
|
||||
/**
|
||||
* 项目内图标
|
||||
*/
|
||||
const iconName = computed(() => `#icon-${props.icon}`)
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.svg-icon {
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
vertical-align: -0.15em;
|
||||
fill: currentColor;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.svg-external-icon {
|
||||
background-color: currentColor;
|
||||
mask-size: cover !important;
|
||||
display: inline-block;
|
||||
}
|
||||
</style>
|
198
src/components/Watermark.vue
Normal file
198
src/components/Watermark.vue
Normal file
@ -0,0 +1,198 @@
|
||||
<template>
|
||||
<div ref="watermarkContainerRef" class="watermark-container">
|
||||
<!-- 插槽-->
|
||||
<slot></slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, watchEffect, onUnmounted, computed } from "vue";
|
||||
// 使用 defineProps 定义一个组件的 props,这些 props 描述了组件从父组件接收的属性
|
||||
const props = defineProps({
|
||||
// 文本内容,类型为字符串,必须提供,默认值为'张苹果博客'
|
||||
text: {
|
||||
type: Array,
|
||||
required: true,
|
||||
default: []
|
||||
},
|
||||
// 字体大小,类型为数字,默认值为10
|
||||
fontSize: {
|
||||
type: Number,
|
||||
default: 15
|
||||
},
|
||||
// 间距,类型为数字,默认值为2
|
||||
gap: {
|
||||
type: Number,
|
||||
default: 2
|
||||
},
|
||||
// 颜色,类型为字符串,默认值为' rgba(136, 135, 135, 0.58)'
|
||||
color: {
|
||||
type: String,
|
||||
default: "rgba(136, 135, 135, 0.58)"
|
||||
},
|
||||
//角度 类型为数字 默认值 -45
|
||||
angle: {
|
||||
type: Number,
|
||||
default: -45
|
||||
}
|
||||
});
|
||||
/**
|
||||
* 绘制多行文本
|
||||
* @param ctx canvas对象
|
||||
* @param words 文本数组
|
||||
* @param x 坐标
|
||||
* @param y 坐标(行高)
|
||||
* @param maxWidth 最大宽度
|
||||
*/
|
||||
function drawTextWithWrap(ctx, words, x, y, maxWidth) {
|
||||
let line = "";
|
||||
const row = JSON.parse(JSON.stringify(y)); //拷贝一份Y的 行间距
|
||||
for (let n = 0; n < words.length; n++) {
|
||||
const testLine = line + words[n];
|
||||
const metrics = ctx.measureText(testLine);
|
||||
const testWidth = metrics.width;
|
||||
if (testWidth > maxWidth) {
|
||||
ctx.fillText(line, x, y);
|
||||
line = words[n];
|
||||
y = row * (n + 1);
|
||||
} else {
|
||||
line = testLine;
|
||||
}
|
||||
}
|
||||
ctx.fillText(line, x, y);
|
||||
}
|
||||
// 定义一个用于绘制水印的函数,这里可以封装一下单独引入。
|
||||
// 它是一个计算属性,意味着它的值会根据其依赖的 props 的变化而自动重新计算
|
||||
const waterMarkBg = (props) => {
|
||||
return computed(() => {
|
||||
// 创建一个新的 canvas 元素
|
||||
const canvas = document.createElement("canvas");
|
||||
// 获取设备的像素比,如果未定义则默认为1
|
||||
const devicePixelRatio = window.devicePixelRatio || 1;
|
||||
// 根据像素比计算字体大小
|
||||
const fontSize = props.fontSize * devicePixelRatio;
|
||||
// 设置字体样式
|
||||
const font = fontSize + "px serif";
|
||||
// 获取 canvas 的 2D 渲染上下文
|
||||
const ctx = canvas.getContext("2d");
|
||||
// 设置字体
|
||||
ctx.font = font;
|
||||
// 测量文本的宽度
|
||||
// const { width } = ctx.measureText(props.text);
|
||||
// 计算 canvas 的大小,至少为 60,并根据文本宽度和间距因子进行调整
|
||||
const canvasSize = Math.max(60, 180) * props.gap + devicePixelRatio;
|
||||
// 设置 canvas 的宽高
|
||||
canvas.width = canvasSize;
|
||||
canvas.height = canvasSize;
|
||||
// 将 canvas 的原点移动到中心
|
||||
ctx.translate(canvas.width / 5, canvas.height / 5);
|
||||
// 旋转 canvas 45 度
|
||||
ctx.rotate((Math.PI / 180) * props.angle);
|
||||
// 设置填充颜色
|
||||
ctx.fillStyle = props.color;
|
||||
// 设置文本对齐方式和基线
|
||||
ctx.textAlign = "center";
|
||||
ctx.textBaseline = "middle";
|
||||
// 再次设置字体
|
||||
ctx.font = font;
|
||||
drawTextWithWrap(ctx, props.text, 0, 25, 100);
|
||||
// 在 canvas 上填充文本
|
||||
// ctx.fillText(props.text, 0, 0);
|
||||
|
||||
// 返回一个对象,包含 base64 编码的图片数据、canvas 的大小和样式尺寸
|
||||
return {
|
||||
base64: canvas.toDataURL(),
|
||||
size: canvasSize,
|
||||
styleSize: canvasSize / devicePixelRatio
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
// 用于存储 MutationObserver 的变量
|
||||
let ob;
|
||||
// 用于存储水印 div 的变量
|
||||
let div;
|
||||
// 调用 waterMarkBg 函数获取水印相关的计算属性
|
||||
const bg = waterMarkBg(props);
|
||||
// 创建一个 ref 用于存储水印容器的 DOM 引用
|
||||
const watermarkContainerRef = ref("");
|
||||
// 创建一个 ref 用于标记水印是否需要重新生成
|
||||
const flag = ref(0);
|
||||
|
||||
// 在组件挂载后执行
|
||||
onMounted(() => {
|
||||
// 创建一个新的 MutationObserver,用于监听水印容器的变化
|
||||
ob = new MutationObserver((records) => {
|
||||
// 遍历所有的变化记录
|
||||
for (const record of records) {
|
||||
// 遍历所有被移除的节点
|
||||
for (const dom of record.removedNodes) {
|
||||
// 如果被移除的节点是水印 div,则更新 flag 的值并返回
|
||||
if (dom === div) {
|
||||
flag.value++;
|
||||
return;
|
||||
}
|
||||
}
|
||||
// 如果变化的节点就是水印 div,则更新 flag 的值并返回
|
||||
if (record.target === div) {
|
||||
flag.value++;
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
// 包括子节点的变化、属性的变化以及子树的变化
|
||||
ob.observe(watermarkContainerRef.value, {
|
||||
childList: true,
|
||||
attributes: true,
|
||||
subtree: true
|
||||
});
|
||||
});
|
||||
|
||||
//卸载
|
||||
onUnmounted(() => {
|
||||
ob && ob.disconnect();
|
||||
div = null;
|
||||
});
|
||||
|
||||
// 生成水印
|
||||
watchEffect(() => {
|
||||
// 触发 watchEffect 的重新执行
|
||||
flag.value;
|
||||
// 如果水印容器没有值,则直接返回,不执行后续操作
|
||||
if (!watermarkContainerRef.value) {
|
||||
return;
|
||||
}
|
||||
// 如果之前已经存在水印 div,则先移除它
|
||||
if (div) {
|
||||
div.remove();
|
||||
}
|
||||
// 创建一个新的 div 元素用于作为水印的容器
|
||||
div = document.createElement("div");
|
||||
// 从计算属性 bg 中获取 base64 编码的图片数据和样式尺寸
|
||||
const { base64, styleSize } = bg.value;
|
||||
// 设置 div 的背景图片为水印图片的 base64 编码
|
||||
div.style.backgroundImage = `url(${base64})`;
|
||||
// 设置背景图片的尺寸
|
||||
div.style.backgroundSize = `${styleSize}px ${styleSize}px`;
|
||||
// 设置背景图片重复显示
|
||||
div.style.backgroundRepeat = "repeat";
|
||||
// 设置水印 div 的 z-index 为 9999,以确保它显示在大多数其他元素之上
|
||||
div.style.zIndex = 9999;
|
||||
// 设置水印 div 不响应鼠标事件,如点击、悬停等
|
||||
div.style.pointerEvents = "none";
|
||||
// 设置水印 div 的位置为绝对定位
|
||||
div.style.position = "absolute";
|
||||
// 使用 inset 属性设置 div 占据整个父容器的空间
|
||||
div.style.inset = "0";
|
||||
// 将水印 div 添加到水印容器中
|
||||
watermarkContainerRef.value.appendChild(div);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.watermark-container {
|
||||
position: relative;
|
||||
height: 100vh;
|
||||
color: rgba(136, 135, 135, 0.58);
|
||||
}
|
||||
</style>
|
216
src/components/aboutTable/MyTable.vue
Normal file
216
src/components/aboutTable/MyTable.vue
Normal file
@ -0,0 +1,216 @@
|
||||
<template>
|
||||
<div style="width: 100%">
|
||||
<!-- hasChildren要在tableData中定义表示当前行有没有下一级 children要在tableData中定义表示下一级的数据-->
|
||||
<el-table
|
||||
ref="multipleTableRef"
|
||||
:data="tableData"
|
||||
@selection-change="handleSelectionChange"
|
||||
@row-click="singleElection"
|
||||
:row-key="getConfiger.rowKey"
|
||||
:border="getConfiger.border"
|
||||
:default-expand-all="getConfiger.defaultExpandAll"
|
||||
:stripe="getConfiger.stripe"
|
||||
:height="tableHeight"
|
||||
v-loading="tableConfiger.loading"
|
||||
:lazy="getConfiger.lazy"
|
||||
:load="load"
|
||||
:tree-props="treePros"
|
||||
style="width: 100%"
|
||||
:header-cell-class-name="() => '街面警情统计HeadBgColor'"
|
||||
:highlight-current-row="getConfiger.showSelectType === 'radio'"
|
||||
:row-style="{
|
||||
height:
|
||||
getConfiger.rowHeight === 'auto'
|
||||
? getConfiger.rowHeight
|
||||
: getConfiger.rowHeight + 'px'
|
||||
}"
|
||||
>
|
||||
<el-table-column
|
||||
type="selection"
|
||||
width="55"
|
||||
v-if="getConfiger.showSelectType === 'checkBox'"
|
||||
/>
|
||||
<el-table-column
|
||||
width="55"
|
||||
v-else-if="getConfiger.showSelectType === 'radio'"
|
||||
#default="{ row }"
|
||||
>
|
||||
<el-radio
|
||||
class="radio"
|
||||
v-model="radioChoose"
|
||||
:label="row[getConfiger.rowKey]"
|
||||
> </el-radio
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
type="index"
|
||||
label="序号"
|
||||
v-if="getConfiger.showIndex"
|
||||
width="60"
|
||||
:align="getConfiger?.align"
|
||||
/>
|
||||
|
||||
<el-table-column
|
||||
v-for="(item, index) in tableColumn"
|
||||
:align="getConfiger?.align"
|
||||
:prop="item.prop"
|
||||
:key="index"
|
||||
:label="item.label"
|
||||
:width="item.width"
|
||||
style="width: 100%; font-size: 14px"
|
||||
:show-overflow-tooltip="item.showOverflowTooltip || false"
|
||||
:sortable="item.sortable || false"
|
||||
>
|
||||
<!-- 使用自定义 -->
|
||||
<template v-if="item.showSolt" #default="scope">
|
||||
<slot :name="item.prop" v-bind="scope"></slot>
|
||||
</template>
|
||||
<!-- 默认 -->
|
||||
<template v-else #default="{ row }">
|
||||
{{ row[item.prop] }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<!-- 操作 -->
|
||||
<el-table-column
|
||||
v-if="getConfiger.haveControls"
|
||||
:fixed="fixed"
|
||||
:label="getConfiger.controls"
|
||||
:width="controlsWidth"
|
||||
:align="getConfiger?.align"
|
||||
>
|
||||
<template #default="scope">
|
||||
<slot name="controls" v-bind="scope"></slot>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { nextTick, onMounted, reactive, ref, watch, watchEffect } from "vue";
|
||||
const props = defineProps({
|
||||
tableConfiger: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
},
|
||||
tableData: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
tableColumn: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
controlsWidth: {
|
||||
type: Number,
|
||||
default: 180
|
||||
},
|
||||
tableHeight: {
|
||||
type: Number
|
||||
},
|
||||
treePros: {
|
||||
type: Object,
|
||||
default: {
|
||||
children: "children",
|
||||
hasChildren: "hasChildren"
|
||||
}
|
||||
},
|
||||
fixed: {
|
||||
type: String,
|
||||
default: "right"
|
||||
}
|
||||
});
|
||||
// 可选的时候选择的数据
|
||||
const emit = defineEmits(["chooseData"]);
|
||||
const multipleTableRef = ref();
|
||||
let getConfiger = reactive({
|
||||
showSelectType: null, // 显示多选还是单选还是没有选择 checkBox/radio/null
|
||||
showIndex: true, // 是否显示索引
|
||||
rowKey: "id", // 如果是树形表格必须设置rowKey
|
||||
border: true, // 是否显示边框
|
||||
defaultExpandAll: false, // 是否展开全部
|
||||
loading: false,
|
||||
align: "center", // 列的对齐方式 left / center / right
|
||||
haveControls: true, // 是否有操作列
|
||||
controls: "操作", // 操作列的表头
|
||||
stripe: false, // 是否有斑马线
|
||||
lazy: true, // 树形表格的懒加载必须在tableDatez中给有children的项设置 hasChildren: true,才会显示展开icon
|
||||
portUrl: "", // 当树形表格使用懒加载的时候传入的请求路径/接口用于懒加载数据
|
||||
defaultSelectKeys: [], // 默认选中的key集合
|
||||
radioChoose: null, // 单选时选中的值------------- 待完成
|
||||
rowHeight: "41" // 每行的高度
|
||||
});
|
||||
|
||||
const radioChoose = ref("");
|
||||
|
||||
watchEffect(() => {
|
||||
getConfiger = { ...getConfiger, ...props.tableConfiger };
|
||||
setDefaultChoose();
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
setDefaultChoose();
|
||||
});
|
||||
// 可选的时候选择的数据
|
||||
const handleSelectionChange = (val) => {
|
||||
emit("chooseData", val);
|
||||
};
|
||||
// 单选的时候选择的数据
|
||||
const singleElection = (val) => {
|
||||
if (getConfiger.showSelectType === "radio") {
|
||||
radioChoose.value = val[getConfiger.rowKey];
|
||||
emit("chooseData", [val]);
|
||||
}
|
||||
};
|
||||
// 懒加载数据的方法
|
||||
const load = (date, treeNode, resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve([
|
||||
{
|
||||
id: 31,
|
||||
date: "2016-05-01",
|
||||
name: "wangxiaohu",
|
||||
address: "No. 189, Grove St, Los Angeles"
|
||||
},
|
||||
{
|
||||
id: 32,
|
||||
date: "2016-05-01",
|
||||
name: "wangxiaohu",
|
||||
address: "No. 189, Grove St, Los Angeles"
|
||||
}
|
||||
]);
|
||||
}, 1000);
|
||||
};
|
||||
// 设置默认选中(在调用的父页面要确保 tableData传出来了如果延迟传过来默认选中不会生效)
|
||||
function setDefaultChoose() {
|
||||
nextTick(() => {
|
||||
// 多选的默认选中
|
||||
if (
|
||||
getConfiger.defaultSelectKeys?.length > 0 &&
|
||||
getConfiger.showSelectType === "checkBox"
|
||||
) {
|
||||
props.tableData.forEach((item) => {
|
||||
if (
|
||||
getConfiger.defaultSelectKeys.findIndex(
|
||||
(v) => v === item[getConfiger.rowKey]
|
||||
) > -1
|
||||
) {
|
||||
if (multipleTableRef.value)
|
||||
multipleTableRef.value.toggleRowSelection(item, true);
|
||||
}
|
||||
});
|
||||
// 单选的默认选中
|
||||
} else if (
|
||||
getConfiger.defaultSelectKeys &&
|
||||
getConfiger.defaultSelectKeys?.length > 0 &&
|
||||
getConfiger.showSelectType === "radio"
|
||||
) {
|
||||
radioChoose.value = getConfiger.defaultSelectKeys[0];
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss"></style>
|
71
src/components/aboutTable/PageTitle.vue
Normal file
71
src/components/aboutTable/PageTitle.vue
Normal file
@ -0,0 +1,71 @@
|
||||
<template>
|
||||
<div class="pageTitle" :style="`margin-bottom: ${marginBottom}px;background-color: ${backgroundColor}`">
|
||||
<div class="title">
|
||||
<ul class="flex" v-if="Array.isArray(title)">
|
||||
<li :class=" idx == active ? 'hedBtn':''" @click="handleBtn(it,idx)" class="pointer ml10 mr10" v-for="(it,idx) in title" :key="it">{{ it }}</li>
|
||||
</ul>
|
||||
<div class="font" v-else>{{ title }}</div>
|
||||
</div>
|
||||
<div class="cnetr">
|
||||
<slot name="center"></slot>
|
||||
</div>
|
||||
<div class="right">
|
||||
<slot> </slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { defineProps, defineEmits } from "vue";
|
||||
defineProps({
|
||||
title: {
|
||||
type: String,
|
||||
default: ""
|
||||
},
|
||||
marginBottom: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
active: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
backgroundColor: {
|
||||
type: String,
|
||||
default: "rgb(255, 255, 255, 0)"
|
||||
}
|
||||
});
|
||||
|
||||
const emit = defineEmits(["update:active","change"]);
|
||||
|
||||
const handleBtn = (it, idx) => {
|
||||
emit("update:active", idx);
|
||||
emit("change", idx);
|
||||
};
|
||||
|
||||
</script>
|
||||
|
||||
<style lang = "scss" scoped>
|
||||
.pageTitle {
|
||||
width: 100%;
|
||||
border-radius: 6px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
min-height: 52px;
|
||||
.title {
|
||||
display: flex;
|
||||
margin: auto 0;
|
||||
.icon {
|
||||
margin: auto 0;
|
||||
}
|
||||
.font {
|
||||
vertical-align: middle;
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
.hedBtn{
|
||||
color: #0072ff;
|
||||
}
|
||||
}
|
||||
</style>
|
88
src/components/aboutTable/Pages.vue
Normal file
88
src/components/aboutTable/Pages.vue
Normal file
@ -0,0 +1,88 @@
|
||||
<!--
|
||||
* @Author: 表格分页
|
||||
* @Date: 2023-10-20 09:34:38
|
||||
* @LastEditTime: 2023-11-13 18:34:05
|
||||
* @LastEditors: your name
|
||||
* @Description: In User Settings Edit
|
||||
* @FilePath: \project\src\components\aboutTable\Pages\index.vue
|
||||
-->
|
||||
<template>
|
||||
<div class="fenye" :style="{ top: tableHeight+10 + 'px' }">
|
||||
<el-pagination
|
||||
:current-page="
|
||||
pageData.configer.currentPage ||
|
||||
pageData.configer.pageNo ||
|
||||
pageData.configer.current ||
|
||||
pageData.configer.pageCurrent ||
|
||||
pageData.configer.pageNum"
|
||||
:page-size="pageData.configer.pageSize || pageData.configer.size"
|
||||
:page-sizes="pageSizeArr"
|
||||
:small="small"
|
||||
:disabled="disabled"
|
||||
:background="background"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="pageData.configer.total"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { reactive, ref, watchEffect } from "vue";
|
||||
|
||||
const props = defineProps({
|
||||
pageSizeArr: {
|
||||
type: Array,
|
||||
default: () => [10, 20, 50, 100]
|
||||
},
|
||||
background: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
small: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
marginTop: {
|
||||
type: Number,
|
||||
default: 10
|
||||
},
|
||||
tableHeight: {
|
||||
type: Number
|
||||
},
|
||||
pageConfiger: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {
|
||||
pageSize: 10,
|
||||
currentPage: 1,
|
||||
total: 0
|
||||
};
|
||||
}
|
||||
}
|
||||
});
|
||||
const pageData = reactive({
|
||||
configer: {}
|
||||
});
|
||||
const emit = defineEmits(["changeSize", "changeNo"]);
|
||||
// 改变每页条数
|
||||
const handleSizeChange = (val) => {
|
||||
emit("changeSize", val);
|
||||
};
|
||||
// 翻页
|
||||
const handleCurrentChange = (val) => {
|
||||
emit("changeNo", val);
|
||||
};
|
||||
watchEffect(() => {
|
||||
pageData.configer = props.pageConfiger;
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
</style>
|
654
src/components/aboutTable/Search.vue
Normal file
654
src/components/aboutTable/Search.vue
Normal file
@ -0,0 +1,654 @@
|
||||
<template>
|
||||
<div
|
||||
v-loading="loadingPage"
|
||||
class="pageSearch searchBox"
|
||||
:style="`margin-bottom: ${marginBottom}px;background-color: ${backgroundColor}`"
|
||||
>
|
||||
<div class="box">
|
||||
<div v-for="(item, index) in getArr" :key="index" class="item">
|
||||
<div class="label" v-if="item.label">{{ item.label }}</div>
|
||||
<!-- select -->
|
||||
<el-select
|
||||
v-if="item.showType === 'select'"
|
||||
v-model="searchObj[item.prop]"
|
||||
:multiple="item.multiple"
|
||||
:clearable="item.clearable"
|
||||
:filterable="item.filterable"
|
||||
:placeholder="item.placeholder"
|
||||
collapse-tags
|
||||
collapse-tags-tooltip
|
||||
>
|
||||
<el-option
|
||||
v-for="obj in getOptions[item.prop]"
|
||||
:key="obj.value"
|
||||
:label="obj.label || obj.lable"
|
||||
:value="obj.value"
|
||||
/>
|
||||
</el-select>
|
||||
<!-- input -->
|
||||
<el-input
|
||||
v-else-if="item.showType === 'input'"
|
||||
class="input"
|
||||
v-model="searchObj[item.prop]"
|
||||
:clearable="item.clearable"
|
||||
:placeholder="item.placeholder"
|
||||
/>
|
||||
<!-- 日期段选择器 -->
|
||||
<el-date-picker
|
||||
v-else-if="item.showType === 'daterange'"
|
||||
v-model="searchObj[item.prop]"
|
||||
type="daterange"
|
||||
unlink-panels
|
||||
:range-separator="item.rangeSeparator"
|
||||
:start-placeholder="item.startPlaceholder"
|
||||
:end-placeholder="item.endPlaceholder"
|
||||
:shortcuts="item.shortcuts"
|
||||
:disabledDate="disabledDate"
|
||||
value-format="YYYY-MM-DD"
|
||||
/>
|
||||
<!-- 日期段选择器 -->
|
||||
<el-date-picker
|
||||
v-else-if="item.showType === 'datetimerange'"
|
||||
v-model="searchObj[item.prop]"
|
||||
type="datetimerange"
|
||||
unlink-panels
|
||||
:range-separator="item.rangeSeparator"
|
||||
:start-placeholder="item.startPlaceholder"
|
||||
:end-placeholder="item.endPlaceholder"
|
||||
:shortcuts="item.shortcuts"
|
||||
:disabledDate="disabledDate"
|
||||
value-format="YYYY-MM-DD HH:mm:ss"
|
||||
/>
|
||||
<el-date-picker
|
||||
v-else-if="item.showType === 'date'"
|
||||
v-model="searchObj[item.prop]"
|
||||
type="date"
|
||||
:placeholder="item.placeholder"
|
||||
:disabled-date="disabledDate"
|
||||
:shortcuts="item.shortcuts"
|
||||
value-format="YYYY-MM-DD"
|
||||
>
|
||||
</el-date-picker>
|
||||
|
||||
<template v-else-if="item.showType === 'department'">
|
||||
<MOSTY.Department clearable v-model="searchObj[item.prop]" />
|
||||
</template>
|
||||
<!-- checkbox -->
|
||||
<template v-else-if="item.showType === 'checkbox'">
|
||||
<el-checkbox
|
||||
v-if="item.showSelectAll"
|
||||
v-model="item.checkAll"
|
||||
:indeterminate="item.isIndeterminate"
|
||||
@change="
|
||||
(val) => {
|
||||
handleCheckAllChange(val, item);
|
||||
}
|
||||
"
|
||||
>全选</el-checkbox
|
||||
>
|
||||
<el-checkbox-group
|
||||
v-model="searchObj[item.prop]"
|
||||
@change="
|
||||
(val) => {
|
||||
handleCheckedCitiesChange(val, item);
|
||||
}
|
||||
"
|
||||
>
|
||||
<el-checkbox
|
||||
v-for="obj in item.options"
|
||||
:key="obj.value"
|
||||
:label="obj.value"
|
||||
>{{ obj.label }}</el-checkbox
|
||||
>
|
||||
</el-checkbox-group>
|
||||
</template>
|
||||
<!-- radio -->
|
||||
<el-radio-group
|
||||
v-else-if="item.showType === 'radio'"
|
||||
v-model="searchObj[item.prop]"
|
||||
@change="
|
||||
(val) => {
|
||||
handleRadioChange(val, item);
|
||||
}
|
||||
"
|
||||
>
|
||||
<el-radio
|
||||
v-for="obj in item.options"
|
||||
:key="obj.value"
|
||||
:label="obj.value"
|
||||
>{{ obj.label }}</el-radio
|
||||
>
|
||||
</el-radio-group>
|
||||
<!-- 级联选择 -->
|
||||
<el-cascader
|
||||
v-else-if="item.showType === 'cascader'"
|
||||
@change="changeca"
|
||||
v-model="searchObj[item.prop]"
|
||||
:props="item.props"
|
||||
:show-all-levels="item.showAllLevels"
|
||||
:clearable="item.clearable"
|
||||
:options="getOptions[item.prop]"
|
||||
:placeholder="item.placeholder"
|
||||
/>
|
||||
<div v-else-if="item.showType === 'defaultSlot'">
|
||||
<slot name="defaultSlot"></slot>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="butBox">
|
||||
<el-button type="primary" @click="submit">确定</el-button>
|
||||
<el-button type="" @click="reset">重置</el-button>
|
||||
<slot> </slot>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {
|
||||
ref,
|
||||
reactive,
|
||||
watch,
|
||||
watchEffect,
|
||||
nextTick,
|
||||
getCurrentInstance,
|
||||
toRefs
|
||||
} from "vue";
|
||||
import * as MOSTY from "@/components/MyComponents/index";
|
||||
const { proxy } = getCurrentInstance();
|
||||
const props = defineProps({
|
||||
searchArr: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return [
|
||||
{
|
||||
showType: "select",
|
||||
prop: "selectKey",
|
||||
options: [
|
||||
{
|
||||
value: 1,
|
||||
label: "选择1"
|
||||
}
|
||||
],
|
||||
defaultVal: "",
|
||||
label: "选择",
|
||||
dict: "" // 字典编码
|
||||
},
|
||||
{
|
||||
showType: "input",
|
||||
prop: "inputKey",
|
||||
defaultVal: "",
|
||||
label: "输入"
|
||||
},
|
||||
{
|
||||
showType: "daterange",
|
||||
prop: "daterangeKey",
|
||||
defaultVal: "",
|
||||
label: "输入"
|
||||
},
|
||||
{
|
||||
showType: "datetimerange",
|
||||
prop: "datetimerangeKey",
|
||||
defaultVal: "",
|
||||
label: "输入"
|
||||
},
|
||||
{
|
||||
showType: "date",
|
||||
prop: "date",
|
||||
defaultVal: ""
|
||||
},
|
||||
{
|
||||
showType: "checkbox",
|
||||
prop: "checkboxKey1",
|
||||
options: [
|
||||
{
|
||||
value: 1,
|
||||
label: "选择1"
|
||||
}
|
||||
],
|
||||
defaultVal: ""
|
||||
},
|
||||
{
|
||||
showType: "cascader",
|
||||
prop: "cascaderKey",
|
||||
label: "级联选择",
|
||||
checkStrictly: false, //点击任意选中
|
||||
defaultVal: ""
|
||||
},
|
||||
{
|
||||
showType: "radio",
|
||||
defaultVal: ""
|
||||
// prop: "cascaderKey",
|
||||
// label: "级联选择",
|
||||
// checkStrictly: false //点击任意选中
|
||||
},
|
||||
{
|
||||
showType: "defaultTime",
|
||||
prop: "timeField",
|
||||
options: []
|
||||
}
|
||||
];
|
||||
}
|
||||
},
|
||||
marginBottom: {
|
||||
type: Number,
|
||||
default: 15
|
||||
},
|
||||
backgroundColor: {
|
||||
type: String,
|
||||
default: "rgb(255, 255, 255)"
|
||||
}
|
||||
});
|
||||
let loadingPage = ref(false);
|
||||
const isShowDate = ref(false);
|
||||
const emit = defineEmits(["submit", "reset"]);
|
||||
let searchObj = reactive({});
|
||||
const timeConfig = reactive({
|
||||
//时间字典筛选和自定义日期组件相关数据
|
||||
typeValue: "01", //时间字典类型默认
|
||||
timeArry: [] //时间筛选自定义默认值
|
||||
});
|
||||
//全所或自定义选择按钮
|
||||
const slectType = ref("qs");
|
||||
// select 的一些默认配置
|
||||
const selectDefault = {
|
||||
clearable: true, // 是否可以清空
|
||||
filterable: true, // 是否可以筛选
|
||||
multiple: false, // 是否多选
|
||||
placeholder: "请选择"
|
||||
};
|
||||
// 重新定义下拉框的选项
|
||||
let getOptions = reactive({});
|
||||
// input 的一些默认配置
|
||||
const inputDefault = {
|
||||
clearable: true, // 是否可以清空
|
||||
placeholder: "请输入"
|
||||
};
|
||||
const shortcuts = [
|
||||
{
|
||||
text: "今天",
|
||||
value: () => {
|
||||
const end = new Date();
|
||||
const start = new Date();
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 0);
|
||||
return [start, end];
|
||||
}
|
||||
},
|
||||
{
|
||||
text: "昨天",
|
||||
value: () => {
|
||||
const end = new Date();
|
||||
const start = new Date();
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 1);
|
||||
end.setTime(end.getTime() - 3600 * 1000 * 24 * 1);
|
||||
return [start, end];
|
||||
}
|
||||
},
|
||||
{
|
||||
text: "最近7天",
|
||||
value: () => {
|
||||
const end = new Date();
|
||||
const start = new Date();
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
|
||||
return [start, end];
|
||||
}
|
||||
},
|
||||
{
|
||||
text: "最近30天",
|
||||
value: () => {
|
||||
const end = new Date();
|
||||
const start = new Date();
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
|
||||
return [start, end];
|
||||
}
|
||||
},
|
||||
{
|
||||
text: "最近90天",
|
||||
value: () => {
|
||||
const end = new Date();
|
||||
const start = new Date();
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 90);
|
||||
return [start, end];
|
||||
}
|
||||
}
|
||||
];
|
||||
// daterange 的一些默认配置
|
||||
const daterangeDefault = {
|
||||
rangeSeparator: "至",
|
||||
startPlaceholder: "开始日期",
|
||||
endPlaceholder: "结束日期",
|
||||
shortcuts: [], // 快捷选择
|
||||
defaultShortcuts: true // 是否显示快捷选择 如果要自定义快捷选择传入一个shortcuts就可以了
|
||||
};
|
||||
// date 的一些默认配置
|
||||
const defaultDate = {
|
||||
clearable: true, // 是否可以清空
|
||||
placeholder: "请输入",
|
||||
shortcuts: [], // 快捷选择
|
||||
defaultShortcuts: true // 是否显示快捷选择 如果要自定义快捷选择传入一个shortcuts就可以了
|
||||
};
|
||||
const dateShortcuts = [
|
||||
{
|
||||
text: "今天",
|
||||
value: new Date()
|
||||
},
|
||||
{
|
||||
text: "昨天",
|
||||
value: () => {
|
||||
const date = new Date();
|
||||
date.setTime(date.getTime() - 3600 * 1000 * 24);
|
||||
return date;
|
||||
}
|
||||
},
|
||||
{
|
||||
text: "7天前",
|
||||
value: () => {
|
||||
const date = new Date();
|
||||
date.setTime(date.getTime() - 3600 * 1000 * 24 * 7);
|
||||
return date;
|
||||
}
|
||||
},
|
||||
{
|
||||
text: "30天前",
|
||||
value: () => {
|
||||
const date = new Date();
|
||||
date.setTime(date.getTime() - 3600 * 1000 * 24 * 30);
|
||||
return date;
|
||||
}
|
||||
},
|
||||
{
|
||||
text: "90天前",
|
||||
value: () => {
|
||||
const date = new Date();
|
||||
date.setTime(date.getTime() - 3600 * 1000 * 24 * 90);
|
||||
return date;
|
||||
}
|
||||
}
|
||||
];
|
||||
//自定义时间选择 item 配置项 value 选中的值
|
||||
const screenSelect = (item, value) => {
|
||||
if (value == "08") {
|
||||
searchObj[item.prop] = value;
|
||||
isShowDate.value = true;
|
||||
} else {
|
||||
timeConfig.typeValue = value;
|
||||
searchObj[item.prop] = value;
|
||||
submit();
|
||||
}
|
||||
};
|
||||
//自定义时间确定时间
|
||||
const chooseDateOk = (item) => {
|
||||
timeConfig.typeValue = "08";
|
||||
if (timeConfig.timeArry && timeConfig.timeArry.length) {
|
||||
//选择了时间
|
||||
searchObj[item.propStart] = timeConfig.timeArry[0];
|
||||
searchObj[item.propEnd] = timeConfig.timeArry[1];
|
||||
} else {
|
||||
//清空了时间
|
||||
searchObj[item.prop] = "01";
|
||||
timeConfig.typeValue = "01";
|
||||
}
|
||||
isShowDate.value = false;
|
||||
submit();
|
||||
};
|
||||
//全所-部门选择回调
|
||||
const organizatioHland = (val) => {
|
||||
let item = getArr.find((item) => item.showType == "qsOrZdy");
|
||||
searchObj[item.propBm] = val?.data?.orgCode || "";
|
||||
if (!val || val == "") {
|
||||
//清空了部门选择后清空责任区ID
|
||||
slectType.value = "qs";
|
||||
delete searchObj[item.propZrq];
|
||||
}
|
||||
submit();
|
||||
};
|
||||
//全所-责任区回调
|
||||
const zrqHland = (val) => {
|
||||
let item = getArr.find((item) => item.showType == "qsOrZdy");
|
||||
searchObj[item.propZrq] = val || ""; //责任区选择
|
||||
submit();
|
||||
};
|
||||
//自定义时间取消事件
|
||||
const popoverCancel = (item) => {
|
||||
isShowDate.value = false;
|
||||
};
|
||||
// 设置不可选的日期
|
||||
const disabledDate = (time) => {
|
||||
return time.getTime() > Date.now();
|
||||
};
|
||||
// checkbox 的一些默认配置
|
||||
const defaultCheckbox = reactive({
|
||||
defaultVal: [],
|
||||
checkAll: false, // 全选的值
|
||||
isIndeterminate: false, // 控制全选按钮样式
|
||||
showSelectAll: true // 是否显示全选
|
||||
});
|
||||
// 全选复选框的选中与不选中
|
||||
const handleCheckAllChange = (val, obj) => {
|
||||
searchObj[obj.prop] = val ? obj.checkboxValueArr : [];
|
||||
obj.isIndeterminate = false;
|
||||
};
|
||||
// 单个复选框的选中与不选中
|
||||
const handleCheckedCitiesChange = (value, obj) => {
|
||||
const checkedCount = value.length;
|
||||
obj.checkAll = checkedCount === obj.checkboxValueArr.length;
|
||||
obj.isIndeterminate =
|
||||
checkedCount > 0 && checkedCount < obj.checkboxValueArr.length;
|
||||
};
|
||||
//单选
|
||||
const handleRadioChange = (val, obj) => {
|
||||
console.log(val, obj);
|
||||
};
|
||||
// cascader 的一些默认配置
|
||||
let defaultCascader = {
|
||||
filterable: true, // 是否可以搜索
|
||||
clearable: true, // 是否可以清空
|
||||
placeholder: "请选择",
|
||||
checkStrictly: true, // 控制是否父子联动(是否可以选择任意节点)
|
||||
showAllLevels: false, // 是否显示完整路径
|
||||
lazy: true, // 是否懒加载 当设置为false时就要传入options
|
||||
portUrl: "", // 这里必须写 接口地址
|
||||
props: {
|
||||
label: "label",
|
||||
value: "value",
|
||||
children: "children"
|
||||
},
|
||||
options: []
|
||||
};
|
||||
// 在懒加载状态下cascader 的props的一些配置
|
||||
const cascaderLazyProps = reactive({
|
||||
value: "value",
|
||||
label: "label",
|
||||
lazy: true,
|
||||
lazyLoad(node, resolve) {
|
||||
// 这里要根据实际情况修改
|
||||
const { level } = node;
|
||||
let options = [];
|
||||
switch (level) {
|
||||
case 0:
|
||||
options = [
|
||||
{
|
||||
value: 1,
|
||||
label: "选择1",
|
||||
leaf: false // 表示有下一级 必须有这个表示 不然获取不到值
|
||||
},
|
||||
{
|
||||
value: 2,
|
||||
label: "选择2",
|
||||
leaf: false // 表示有下一级
|
||||
},
|
||||
{
|
||||
value: 3,
|
||||
label: "选择3",
|
||||
leaf: false // 表示有下一级
|
||||
},
|
||||
{
|
||||
value: 4,
|
||||
label: "选择4",
|
||||
leaf: true // 表示没有下一级了
|
||||
}
|
||||
];
|
||||
break;
|
||||
case 1:
|
||||
options = [
|
||||
{
|
||||
value: 11,
|
||||
label: "选择1_1",
|
||||
leaf: true // 表示没有下一级了
|
||||
},
|
||||
{
|
||||
value: 21,
|
||||
label: "选择2_1",
|
||||
leaf: true // 表示没有下一级了
|
||||
},
|
||||
{
|
||||
value: 31,
|
||||
label: "选择3_1",
|
||||
leaf: true // 表示没有下一级了
|
||||
},
|
||||
{
|
||||
value: 41,
|
||||
label: "选择4_1",
|
||||
leaf: true // 表示没有下一级了
|
||||
}
|
||||
];
|
||||
}
|
||||
resolve(options);
|
||||
}
|
||||
});
|
||||
// 级联框选择
|
||||
function changeca(v) {
|
||||
console.log("vvvv", v);
|
||||
}
|
||||
// 获取到传过来的参数
|
||||
let getArr = reactive([]);
|
||||
const submit = () => {
|
||||
emit("submit", searchObj);
|
||||
};
|
||||
const reset = () => {
|
||||
getArr.forEach((item) => {
|
||||
searchObj[item.prop] = item.defaultVal;
|
||||
});
|
||||
emit("submit", searchObj);
|
||||
emit("reset", false);
|
||||
};
|
||||
let dataOptions = reactive([]); //时间字典筛选
|
||||
watchEffect(() => {
|
||||
loadingPage.value = true;
|
||||
getArr = JSON.parse(JSON.stringify(props.searchArr));
|
||||
getArr = getArr.map((item) => {
|
||||
switch (item.showType) {
|
||||
case "select":
|
||||
item = { ...selectDefault, ...item };
|
||||
item.options = reactive(item.options);
|
||||
getOptions[item.prop] = item.options;
|
||||
break;
|
||||
case "input":
|
||||
item = { ...inputDefault, ...item };
|
||||
break;
|
||||
case "daterange":
|
||||
item = { ...daterangeDefault, ...item };
|
||||
if (item.defaultShortcuts) {
|
||||
item.shortcuts = shortcuts;
|
||||
}
|
||||
break;
|
||||
case "datetimerange":
|
||||
item = { ...daterangeDefault, ...item };
|
||||
if (item.defaultShortcuts) {
|
||||
item.shortcuts = shortcuts;
|
||||
}
|
||||
break;
|
||||
case "date":
|
||||
item = { ...defaultDate, ...item };
|
||||
if (item.defaultShortcuts) {
|
||||
item.shortcuts = dateShortcuts;
|
||||
}
|
||||
break;
|
||||
case "checkbox":
|
||||
item = reactive({ ...defaultCheckbox, ...item });
|
||||
item.checkboxValueArr = item.options.map((obj) => {
|
||||
return obj.value;
|
||||
});
|
||||
break;
|
||||
case "cascader":
|
||||
item = { ...defaultCascader, ...item };
|
||||
if (item.lazy) {
|
||||
cascaderLazyProps.checkStrictly = item.checkStrictly;
|
||||
item.props = { ...cascaderLazyProps, ...(item.props || {}) };
|
||||
delete item.options;
|
||||
} else {
|
||||
item.props = {
|
||||
...defaultCascader.props,
|
||||
...(item.props || {}),
|
||||
...{ checkStrictly: item.checkStrictly }
|
||||
};
|
||||
getOptions[item.prop] = reactive(item.options);
|
||||
}
|
||||
break;
|
||||
}
|
||||
loadingPage.value = false;
|
||||
searchObj[item.prop] = item.defaultVal;
|
||||
return item;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.pageSearch {
|
||||
.box {
|
||||
display: flex;
|
||||
/* justify-content: space-between; */
|
||||
flex-wrap: wrap;
|
||||
.item {
|
||||
display: flex;
|
||||
margin-right: 20px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
.label {
|
||||
margin: auto;
|
||||
color: #000;
|
||||
margin-right: 5px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
.butBox {
|
||||
display: flex;
|
||||
}
|
||||
.department_box {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: rgb(0, 0, 0);
|
||||
.checkbox-box {
|
||||
margin-left: 10px;
|
||||
}
|
||||
::v-deep .el-radio {
|
||||
margin-right: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.default_time {
|
||||
display: flex;
|
||||
}
|
||||
.but_type {
|
||||
background-color: #002961;
|
||||
border: 1px solid #23adf3;
|
||||
border-radius: 50px;
|
||||
color: #93a1ca;
|
||||
height: 34px;
|
||||
line-height: 34px;
|
||||
min-width: 90px;
|
||||
text-align: center;
|
||||
margin-right: 15px;
|
||||
cursor: pointer;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.acavte_but {
|
||||
border: none;
|
||||
color: rgb(0, 0, 0);
|
||||
background: linear-gradient(#0d66dc 0%, #2dbbfa 100%);
|
||||
}
|
||||
.picker-btn {
|
||||
margin-top: 10px;
|
||||
text-align: right;
|
||||
}
|
||||
</style>
|
75
src/components/allocation/staff.vue
Normal file
75
src/components/allocation/staff.vue
Normal file
@ -0,0 +1,75 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
v-model="modelValue"
|
||||
title="Shipping address"
|
||||
@close="close"
|
||||
class="box"
|
||||
>
|
||||
<!-- <Search />-->
|
||||
<!-- <MyTable
|
||||
@chooseData="chooseDataL"
|
||||
:tableData="pageDataL.tableData"
|
||||
:tableColumn="pageDataL.tableColumn"
|
||||
:tableHeight="common.tableHeight"
|
||||
:key="common.keyCount"
|
||||
:tableConfiger="common.tableConfiger"
|
||||
>
|
||||
</MyTable> -->
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script setup>
|
||||
import { reactive } from "vue";
|
||||
import MyTable from "@/components/aboutTable/MyTable.vue";
|
||||
import Search from "@/components/aboutTable/Search.vue";
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
});
|
||||
|
||||
const common = reactive({
|
||||
tableHeight: 360,
|
||||
keyCount: 0,
|
||||
total: 0,
|
||||
pageConfiger: {
|
||||
pageSize: 20,
|
||||
pageCurrent: 1
|
||||
}, //分页
|
||||
tableConfiger: {
|
||||
loading: false,
|
||||
rowHieght: 61,
|
||||
showSelectType: "checkBox",
|
||||
haveControls: false,
|
||||
showIndex: false,
|
||||
defaultSelectKeys: [] // 默认选中的key集合
|
||||
},
|
||||
searchConfiger: [
|
||||
{
|
||||
showType: "input",
|
||||
prop: "key",
|
||||
placeholder: "请输入关键字",
|
||||
label: "关键字"
|
||||
}
|
||||
],
|
||||
tableColumn: [
|
||||
{ label: "报备", prop: "sfbb", showSolt: true },
|
||||
{ label: "姓名", prop: "xm" },
|
||||
{ label: "警号", prop: "jh" },
|
||||
{ label: "所属部门", prop: "ssbm", showOverflowTooltip: true },
|
||||
{ label: "警种", prop: "lx", showSolt: true },
|
||||
{ label: "人员类型", prop: "fl", showSolt: true }
|
||||
] //搜索
|
||||
});
|
||||
|
||||
const emit = defineEmits(["update:modelValue"]);
|
||||
|
||||
const close = () => {
|
||||
emit("update:modelValue", false);
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.box {
|
||||
height: 500px;
|
||||
}
|
||||
</style>
|
71
src/components/checkBox/index.vue
Normal file
71
src/components/checkBox/index.vue
Normal file
@ -0,0 +1,71 @@
|
||||
<template>
|
||||
<div class="checkBox">
|
||||
<el-checkbox class="checkall" :class="customClass" v-model="checkAll" :indeterminate="isIndeterminate" @change="handleCheckAll">全部</el-checkbox>
|
||||
<el-checkbox-group v-model="hasChecked" @change="handleCheckedChange">
|
||||
<span class="zwModel" :class="customClass"></span>
|
||||
<el-checkbox :class="customClass" v-for="item in checkedList" :key="item" :label="item" :style="{width:props.width || 'auto'}">{{item}}</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, defineProps, watch, defineEmits } from "vue";
|
||||
const emits = defineEmits(["changeData"]);
|
||||
const props = defineProps({
|
||||
data: {
|
||||
type: Object,
|
||||
default: {
|
||||
list: [],
|
||||
hasChoose: []
|
||||
}
|
||||
},
|
||||
width:String,
|
||||
customClass:String //自定义样式
|
||||
});
|
||||
const checkAll = ref(false);
|
||||
const isIndeterminate = ref(true);
|
||||
const hasChecked = ref([]); //已经全选的数据
|
||||
const checkedList = ref([]);
|
||||
watch(
|
||||
() => props.data,
|
||||
(val) => {
|
||||
hasChecked.value = val.hasChoose;
|
||||
checkedList.value = val.list;
|
||||
handleChange(val.hasChoose); //判断是否全选
|
||||
},
|
||||
{
|
||||
deep: true,
|
||||
immediate: true
|
||||
}
|
||||
);
|
||||
// 全选
|
||||
function handleCheckAll(val) {
|
||||
hasChecked.value = val ? checkedList.value : [];
|
||||
isIndeterminate.value = false;
|
||||
emits("changeData", hasChecked.value);
|
||||
}
|
||||
// 处理多选框改变
|
||||
function handleCheckedChange(val) {
|
||||
handleChange(val);////判断是否全选
|
||||
emits("changeData", hasChecked.value);
|
||||
}
|
||||
//判断是否全选
|
||||
function handleChange(val) {
|
||||
let checkCount = val.length;
|
||||
let len = checkedList.value.length;
|
||||
checkAll.value = checkCount == len ? true : false;
|
||||
isIndeterminate.value = checkCount > 0 && checkCount < len ? true : false;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.checkBox {
|
||||
display: flex;
|
||||
flex-wrap:nowrap;
|
||||
width:100%;
|
||||
height:100%;
|
||||
.checkall {
|
||||
margin: 0 20px 0 4px;
|
||||
}
|
||||
}
|
||||
</style>
|
922
src/components/chooseList/chooseTable.vue
Normal file
922
src/components/chooseList/chooseTable.vue
Normal file
@ -0,0 +1,922 @@
|
||||
<template>
|
||||
<el-popover
|
||||
popper-class="dinw"
|
||||
:visible="visible"
|
||||
:width="getConfiger.width"
|
||||
:trigger="getConfiger.trigger"
|
||||
>
|
||||
<template #reference
|
||||
><span class="deBtn" @click="handleClick">{{
|
||||
getConfiger.selectName
|
||||
}}</span></template
|
||||
>
|
||||
<div class="flex just-between align-center">
|
||||
<span>{{ title }}</span>
|
||||
<span @click="visible = false">
|
||||
<el-icon>
|
||||
<Close />
|
||||
</el-icon>
|
||||
</span>
|
||||
</div>
|
||||
<Search :searchArr="common.searchConfiger" @submit="onSearch" />
|
||||
<div class="tableBox flex" v-if="visible">
|
||||
<!-- 左边 -->
|
||||
<div class="table">
|
||||
<MyTable
|
||||
@chooseData="chooseDataL"
|
||||
:tableData="pageDataL.tableData"
|
||||
:tableColumn="pageDataL.tableColumn"
|
||||
:tableHeight="common.tableHeight"
|
||||
:key="common.keyCount"
|
||||
:tableConfiger="common.tableConfiger"
|
||||
>
|
||||
<!-- 是否报备 -->
|
||||
<template #sfbb="{ row }">
|
||||
<dict-tag
|
||||
:options="props.dic.D_BZ_SF"
|
||||
:value="row.sfbb"
|
||||
:tag="false"
|
||||
/>
|
||||
</template>
|
||||
<!-- 警种类型 -->
|
||||
<template #lx="{ row }">
|
||||
<dict-tag
|
||||
:options="props.dic.D_BZ_RYJZLB"
|
||||
:value="row.lx"
|
||||
:tag="false"
|
||||
/>
|
||||
</template>
|
||||
<!-- 人员类型 -->
|
||||
<template #fl="{ row }">
|
||||
<dict-tag
|
||||
:options="props.dic.D_BZ_RYMFJLB"
|
||||
:value="row.fl"
|
||||
:tag="false"
|
||||
/>
|
||||
</template>
|
||||
<!-- 设备类型 -->
|
||||
<template #pddtlx="{ row }">
|
||||
<dict-tag
|
||||
:options="props.dic.D_BZ_PDDTLX"
|
||||
:value="row.pddtlx"
|
||||
:tag="false"
|
||||
/>
|
||||
</template>
|
||||
<!-- 班次类型 -->
|
||||
<template #bcQwBbzl="{ row }">
|
||||
<dict-tag
|
||||
:options="props.dic.D_QW_BBZL"
|
||||
:value="row.bcQwBbzl"
|
||||
:tag="false"
|
||||
></dict-tag>
|
||||
</template>
|
||||
<!-- 跨越天数 -->
|
||||
<template #bcKtsDict="{ row }">
|
||||
<dict-tag
|
||||
:options="props.dic.D_QW_BC_KTS"
|
||||
:value="row.bcKtsDict"
|
||||
:tag="false"
|
||||
></dict-tag>
|
||||
</template>
|
||||
<!-- 请选择大类别 -->
|
||||
<template #jyjtfwlb="{ row }">
|
||||
<dict-tag
|
||||
:options="props.dic.D_JCGL_JYCL_JYJTFWLB"
|
||||
:value="row.jyjtfwlb"
|
||||
:tag="false"
|
||||
></dict-tag>
|
||||
</template>
|
||||
<!-- 请选择小类别 -->
|
||||
<template #jyjtgjlb="{ row }">
|
||||
<dict-tag
|
||||
:options="props.dic.D_JCGL_JYCL_JYJTGJLB"
|
||||
:value="row.jyjtgjlb"
|
||||
:tag="false"
|
||||
></dict-tag>
|
||||
</template>
|
||||
<!-- 设备类型 -->
|
||||
<template #sblx="{ row }">
|
||||
<dict-tag
|
||||
:options="props.dic.D_JCGL_ZDSB_SBLX"
|
||||
:value="row.sblx"
|
||||
:tag="false"
|
||||
></dict-tag>
|
||||
</template>
|
||||
<!-- 终端类别 -->
|
||||
<template #sblb="{ row }">
|
||||
<dict-tag
|
||||
:options="props.dic.D_JCGL_ZDSB_SBLB"
|
||||
:value="row.sblb"
|
||||
:tag="false"
|
||||
></dict-tag>
|
||||
</template>
|
||||
<!-- 器械类型 -->
|
||||
<template #qxlx="{ row }">
|
||||
<dict-tag
|
||||
:options="props.dic.D_JCGL_JYQX_QXLX"
|
||||
:value="row.qxlx"
|
||||
:tag="false"
|
||||
></dict-tag>
|
||||
</template>
|
||||
<!-- 报备种类 -->
|
||||
<template #jzQwBbzl="{ row }">
|
||||
<dict-tag
|
||||
:options="props.dic.D_QW_BBZL"
|
||||
:value="row.jzQwBbzl"
|
||||
:tag="false"
|
||||
></dict-tag>
|
||||
</template>
|
||||
<!-- 巡防区域类别 -->
|
||||
<template #xqlb="{ row }">
|
||||
<dict-tag
|
||||
:options="props.dic.D_QW_XQLB"
|
||||
:value="row.xqlb"
|
||||
:tag="false"
|
||||
></dict-tag>
|
||||
</template>
|
||||
<!-- 巡防区域类型 -->
|
||||
<template #xqlx="{ row }">
|
||||
<dict-tag
|
||||
:options="props.dic.D_QW_XQLX"
|
||||
:value="row.xqlx"
|
||||
:tag="false"
|
||||
></dict-tag>
|
||||
</template>
|
||||
<!-- 警务站类型: -->
|
||||
<template #jwzLx="{ row }">
|
||||
<dict-tag
|
||||
:options="props.dic.D_BZ_JWZLX"
|
||||
:value="row.jwzLx"
|
||||
:tag="false"
|
||||
></dict-tag>
|
||||
</template>
|
||||
<!-- 时间段 -->
|
||||
<template #sdList="{ row }">
|
||||
<div v-for="(it, idxx) in row.sdList" :key="idxx">
|
||||
{{ it.kssj }} - {{ it.jssj }}
|
||||
</div>
|
||||
</template>
|
||||
<!-- 检查站 -->
|
||||
<template #jczlx="{ row }">
|
||||
<span v-if="row.jczlx == '1'">固定检查站</span>
|
||||
<span v-if="row.jczlx == '2'">临时检查站</span>
|
||||
<span v-if="row.jczlx == '3'">动态检查站</span>
|
||||
</template>
|
||||
</MyTable>
|
||||
</div>
|
||||
<!-- 切换按钮 -->
|
||||
<div
|
||||
class="cnt flex just-center align-center"
|
||||
v-if="!getConfiger.isRadio"
|
||||
>
|
||||
<el-button :icon="Back" circle @click="upLeft" />
|
||||
<el-button :icon="Right" circle @click="upRight" />
|
||||
</div>
|
||||
<!-- 右边 -->
|
||||
<div class="table" v-if="!getConfiger.isRadio">
|
||||
<MyTable
|
||||
@chooseData="chooseDataR"
|
||||
:tableData="pageDataR.tableData"
|
||||
:tableColumn="pageDataR.tableColumn"
|
||||
:tableHeight="common.tableHeight"
|
||||
:key="common.keyCount"
|
||||
:tableConfiger="common.tableConfiger"
|
||||
>
|
||||
<!-- 是否报备 -->
|
||||
<template #sfbb="{ row }">
|
||||
<dict-tag
|
||||
:options="props.dic.D_BZ_SF"
|
||||
:value="row.sfbb"
|
||||
:tag="false"
|
||||
/>
|
||||
</template>
|
||||
<!-- 警种类型 -->
|
||||
<template #lx="{ row }">
|
||||
<dict-tag
|
||||
:options="props.dic.D_BZ_RYJZLB"
|
||||
:value="row.lx"
|
||||
:tag="false"
|
||||
/>
|
||||
</template>
|
||||
<!-- 人员类型 -->
|
||||
<template #fl="{ row }">
|
||||
<dict-tag
|
||||
:options="props.dic.D_BZ_RYMFJLB"
|
||||
:value="row.fl"
|
||||
:tag="false"
|
||||
/>
|
||||
</template>
|
||||
<!-- 设备类型 -->
|
||||
<template #pddtlx="{ row }">
|
||||
<dict-tag
|
||||
:options="props.dic.D_BZ_PDDTLX"
|
||||
:value="row.pddtlx"
|
||||
:tag="false"
|
||||
/>
|
||||
</template>
|
||||
<!-- 班次类型 -->
|
||||
<template #bcQwBbzl="{ row }">
|
||||
<dict-tag
|
||||
:options="props.dic.D_QW_BBZL"
|
||||
:value="row.bcQwBbzl"
|
||||
:tag="false"
|
||||
></dict-tag>
|
||||
</template>
|
||||
<!-- 跨越天数 -->
|
||||
<template #bcKtsDict="{ row }">
|
||||
<dict-tag
|
||||
:options="props.dic.D_QW_BC_KTS"
|
||||
:value="row.bcKtsDict"
|
||||
:tag="false"
|
||||
></dict-tag>
|
||||
</template>
|
||||
<!-- 请选择大类别 -->
|
||||
<template #jyjtfwlb="{ row }">
|
||||
<dict-tag
|
||||
:options="props.dic.D_JCGL_JYCL_JYJTFWLB"
|
||||
:value="row.jyjtfwlb"
|
||||
:tag="false"
|
||||
></dict-tag>
|
||||
</template>
|
||||
<!-- 请选择小类别 -->
|
||||
<template #jyjtgjlb="{ row }">
|
||||
<dict-tag
|
||||
:options="props.dic.D_JCGL_JYCL_JYJTGJLB"
|
||||
:value="row.jyjtgjlb"
|
||||
:tag="false"
|
||||
></dict-tag>
|
||||
</template>
|
||||
<!-- 设备类型 -->
|
||||
<template #sblx="{ row }">
|
||||
<dict-tag
|
||||
:options="props.dic.D_JCGL_ZDSB_SBLX"
|
||||
:value="row.sblx"
|
||||
:tag="false"
|
||||
></dict-tag>
|
||||
</template>
|
||||
<!-- 终端类别 -->
|
||||
<template #sblb="{ row }">
|
||||
<dict-tag
|
||||
:options="props.dic.D_JCGL_ZDSB_SBLB"
|
||||
:value="row.sblb"
|
||||
:tag="false"
|
||||
></dict-tag>
|
||||
</template>
|
||||
<!-- 器械类型 -->
|
||||
<template #qxlx="{ row }">
|
||||
<dict-tag
|
||||
:options="props.dic.D_JCGL_JYQX_QXLX"
|
||||
:value="row.qxlx"
|
||||
:tag="false"
|
||||
></dict-tag>
|
||||
</template>
|
||||
<!-- 报备种类 -->
|
||||
<template #jzQwBbzl="{ row }">
|
||||
<dict-tag
|
||||
:options="props.dic.D_QW_BBZL"
|
||||
:value="row.jzQwBbzl"
|
||||
:tag="false"
|
||||
></dict-tag>
|
||||
</template>
|
||||
<!-- 巡防区域类别 -->
|
||||
<template #xqlb="{ row }">
|
||||
<dict-tag
|
||||
:options="props.dic.D_QW_XQLB"
|
||||
:value="row.xqlb"
|
||||
:tag="false"
|
||||
></dict-tag>
|
||||
</template>
|
||||
<!-- 巡防区域类型 -->
|
||||
<template #xqlx="{ row }">
|
||||
<dict-tag
|
||||
:options="props.dic.D_QW_XQLX"
|
||||
:value="row.xqlx"
|
||||
:tag="false"
|
||||
></dict-tag>
|
||||
</template>
|
||||
<!-- 时间段 -->
|
||||
<template #sdList="{ row }">
|
||||
<div v-for="(it, idxx) in row.sdList" :key="idxx">
|
||||
{{ it.kssj }} - {{ it.jssj }}
|
||||
</div>
|
||||
</template>
|
||||
<!-- 检查站 -->
|
||||
<template #jczlx="{ row }">
|
||||
<span v-if="row.jczlx == '01'">固定检查站</span>
|
||||
<span v-if="row.jczlx == '02'">临时检查站</span>
|
||||
<span v-if="row.jczlx == '03'">动态检查站</span>
|
||||
</template>
|
||||
</MyTable>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footInfoBtn flex just-between align-center">
|
||||
<Pages
|
||||
@changeNo="changeNo"
|
||||
@changeSize="changeSize"
|
||||
:tableHeight="common.tableHeight"
|
||||
:pageConfiger="{ ...listQuery }"
|
||||
/>
|
||||
<el-button type="primary" @click="submitDate">确定选择</el-button>
|
||||
</div>
|
||||
</el-popover>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { Right, Back } from "@element-plus/icons-vue";
|
||||
import { qcckGet, qcckPost } from "@/api/qcckApi.js";
|
||||
import MyTable from "@/components/aboutTable/MyTable.vue";
|
||||
import emitter from "@/utils/eventBus.js";
|
||||
import Pages from "@/components/aboutTable/Pages.vue";
|
||||
import Search from "@/components/aboutTable/Search.vue";
|
||||
import {
|
||||
reactive,
|
||||
defineProps,
|
||||
ref,
|
||||
watch,
|
||||
getCurrentInstance,
|
||||
watchEffect,
|
||||
onMounted,
|
||||
onUnmounted,
|
||||
nextTick
|
||||
} from "vue";
|
||||
const { proxy } = getCurrentInstance();
|
||||
const props = defineProps({
|
||||
configer: {
|
||||
type: Object,
|
||||
default: {}
|
||||
},
|
||||
dic: Object,
|
||||
modelValue: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
rightData: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
deptment: {
|
||||
type: Object,
|
||||
default: {
|
||||
bmdm: JSON.parse(localStorage.getItem("deptId"))[0].deptCode,
|
||||
bmmc: JSON.parse(localStorage.getItem("deptId"))[0].deptName
|
||||
}
|
||||
}
|
||||
});
|
||||
const emits = defineEmits(["update:modelValue", "change"]);
|
||||
|
||||
const common = reactive({
|
||||
tableHeight: 360,
|
||||
keyCount: 0,
|
||||
total: 0,
|
||||
pageConfiger: {
|
||||
pageSize: 20,
|
||||
pageCurrent: 1
|
||||
}, //分页
|
||||
tableConfiger: {
|
||||
loading: false,
|
||||
rowHieght: 61,
|
||||
showSelectType: "checkBox",
|
||||
haveControls: false,
|
||||
showIndex: false,
|
||||
defaultSelectKeys: [] // 默认选中的key集合
|
||||
},
|
||||
searchConfiger: [
|
||||
{
|
||||
showType: "input",
|
||||
prop: "key",
|
||||
placeholder: "请输入关键字",
|
||||
label: "关键字"
|
||||
}
|
||||
] //搜索
|
||||
});
|
||||
const pageDataL = reactive({
|
||||
tableData: [],
|
||||
tableColumn: [{ label: "班次名称", prop: "bcmc" }]
|
||||
});
|
||||
const pageDataR = reactive({
|
||||
tableData: [],
|
||||
tableColumn: [{ label: "班次名称", prop: "bcmc" }]
|
||||
});
|
||||
let getConfiger = reactive({
|
||||
placement: "right", //方向 right/left/bottom/top/top-start/top-end .....
|
||||
trigger: "click", //气泡框类型 = click (点击),hover(鼠标滑过),
|
||||
isRadio: false, //是否单选
|
||||
width: 1000, //宽度
|
||||
selectName: "选择",
|
||||
lx: null, //查询的类型 - 民警(mj)
|
||||
rowKey: "id"
|
||||
});
|
||||
const visible = ref(false);
|
||||
const title = ref("");
|
||||
|
||||
const listQuery = ref({
|
||||
total: 0,
|
||||
pageSize: 20,
|
||||
pageCurrent: 1
|
||||
});
|
||||
const url = ref("");
|
||||
const hasChoosedL = ref([]); //左边选择的数据
|
||||
const hasChoosedR = ref([]); //右边选择的数据
|
||||
|
||||
const handleClick = () => {
|
||||
const deptId = localStorage.getItem("deptId")
|
||||
? JSON.parse(localStorage.getItem("deptId"))
|
||||
: [];
|
||||
(listQuery.value.ssbmdm = deptId[0].deptCode),
|
||||
(visible.value = !visible.value);
|
||||
if (visible.value) handleData(getConfiger.lx);
|
||||
};
|
||||
// 接收数据类型
|
||||
const handleData = (val, type) => {
|
||||
let arr = [];
|
||||
switch (val) {
|
||||
case "mj":
|
||||
case "fj":
|
||||
title.value = "选择人员";
|
||||
url.value = "/mosty-jcz/tbQwXfll/getXfllList";
|
||||
arr = [
|
||||
{ label: "报备", prop: "sfbb", showSolt: true },
|
||||
{ label: "姓名", prop: "xm" },
|
||||
{ label: "警号", prop: "jh" },
|
||||
{ label: "所属部门", prop: "ssbm", showOverflowTooltip: true },
|
||||
|
||||
{ label: "人员类型", prop: "fl", showSolt: true },
|
||||
{ label: "警种", prop: "lx", showSolt: true }
|
||||
];
|
||||
pageDataL.tableColumn = arr;
|
||||
pageDataR.tableColumn = arr.filter((v) => {
|
||||
return v.label != "报备";
|
||||
});
|
||||
if (!type) {
|
||||
common.searchConfiger = [
|
||||
{
|
||||
showType: "department",
|
||||
prop: "ssbmdm",
|
||||
label: "所属部门",
|
||||
lazy: false
|
||||
},
|
||||
{
|
||||
showType: "input",
|
||||
prop: "xm",
|
||||
placeholder: "请输入姓名",
|
||||
label: "姓名"
|
||||
},
|
||||
{
|
||||
showType: "input",
|
||||
prop: "jh",
|
||||
placeholder: "请输入警号",
|
||||
label: "警号"
|
||||
}
|
||||
];
|
||||
}
|
||||
break;
|
||||
case "pdh":
|
||||
title.value = "频道号选择";
|
||||
url.value = "/mosty-base/sysDeptExtendPdh/selectPage";
|
||||
pageDataL.tableColumn = [
|
||||
{ label: "频道名称", prop: "pdmc" },
|
||||
{ label: "频道号", prop: "pdh" },
|
||||
{ label: "频道电台类型", prop: "pddtlx", showSolt: true }
|
||||
];
|
||||
if (!type) {
|
||||
common.searchConfiger = [
|
||||
{
|
||||
showType: "input",
|
||||
prop: "pdmc",
|
||||
placeholder: "请输入频道名称",
|
||||
label: "频道名称"
|
||||
},
|
||||
{
|
||||
showType: "input",
|
||||
prop: "pdh",
|
||||
placeholder: "请输入频道号",
|
||||
label: "频道号"
|
||||
},
|
||||
{
|
||||
showType: "select",
|
||||
prop: "pddtlx",
|
||||
placeholder: "请输入频道电台类型",
|
||||
label: "频道电台类型",
|
||||
options: props.dic.D_BZ_PDDTLX
|
||||
}
|
||||
];
|
||||
}
|
||||
break;
|
||||
case "zbbc":
|
||||
title.value = "班次选择";
|
||||
url.value = "/mosty-qwzx/tbQwglQwbc/selectPage";
|
||||
pageDataL.tableColumn = [
|
||||
{ label: "班次名称", prop: "bcMc" },
|
||||
{ label: "班次类型", prop: "bcQwBbzl", showSolt: true },
|
||||
{ label: "开始时间", prop: "bcKssj" },
|
||||
{ label: "结束时间", prop: "bcJssj" },
|
||||
{ label: "跨越天数", prop: "bcKtsDict", showSolt: true }
|
||||
];
|
||||
if (!type) {
|
||||
common.searchConfiger = [
|
||||
{
|
||||
showType: "input",
|
||||
prop: "bcMc",
|
||||
placeholder: "请输入班次名称",
|
||||
label: "班次名称"
|
||||
}
|
||||
];
|
||||
}
|
||||
break;
|
||||
case "xfq":
|
||||
case "bxd":
|
||||
case "bxx":
|
||||
title.value =
|
||||
val == "xfq" ? "巡防区名称" : val == "bxd" ? "必巡点" : "必巡线";
|
||||
url.value = "/mosty-qwzx/tbQwglXfqy/selectPage";
|
||||
pageDataL.tableColumn = [
|
||||
{ label: "名称", prop: "xqmc" },
|
||||
{ label: "类别", prop: "xqlb", showSolt: true },
|
||||
{ label: "类型", prop: "xqlx", showSolt: true }
|
||||
];
|
||||
pageDataR.tableColumn = [
|
||||
{ label: "名称", prop: "xqmc" },
|
||||
{ label: "类别", prop: "xqlb", showSolt: true },
|
||||
{ label: "类型", prop: "xqlx", showSolt: true }
|
||||
];
|
||||
if (!type) {
|
||||
common.searchConfiger = [
|
||||
{
|
||||
showType: "input",
|
||||
prop: "xqmc",
|
||||
placeholder: "请输入名称",
|
||||
label: "名称"
|
||||
}
|
||||
];
|
||||
}
|
||||
break;
|
||||
case "cl":
|
||||
title.value = "车辆选择";
|
||||
url.value = "/mosty-jcz/tpJczXfcl/getXfclList";
|
||||
arr = [
|
||||
{ label: "号牌号码", prop: "cph" },
|
||||
{ label: "车辆名称", prop: "clmc" },
|
||||
{ label: "大类别", prop: "jyjtfwlb", showSolt: true },
|
||||
{ label: "小类别", prop: "jyjtgjlb", showSolt: true }
|
||||
];
|
||||
pageDataL.tableColumn = arr;
|
||||
pageDataR.tableColumn = arr;
|
||||
if (!type) {
|
||||
common.searchConfiger = [
|
||||
{
|
||||
showType: "input",
|
||||
prop: "cph",
|
||||
placeholder: "请输入车辆名称",
|
||||
label: "车辆名称"
|
||||
}
|
||||
];
|
||||
}
|
||||
break;
|
||||
case "zdsb":
|
||||
title.value = "终端选择";
|
||||
url.value = "/mosty-jcgl/tbJcglZdsb/selectPage";
|
||||
arr = [
|
||||
{ label: "设备编号", prop: "sbbh" },
|
||||
{ label: "设备名称", prop: "sbmc" },
|
||||
{ label: "终端类别", prop: "sblb", showSolt: true },
|
||||
{ label: "设备类型", prop: "sblx", showSolt: true }
|
||||
];
|
||||
pageDataL.tableColumn = arr;
|
||||
pageDataR.tableColumn = arr;
|
||||
if (!type) {
|
||||
common.searchConfiger = [
|
||||
{
|
||||
showType: "input",
|
||||
prop: "sbmc",
|
||||
placeholder: "请输入设备名称",
|
||||
label: "设备名称"
|
||||
},
|
||||
{
|
||||
showType: "select",
|
||||
prop: "sblb",
|
||||
placeholder: "请选择设备类型",
|
||||
label: "设备类型",
|
||||
options: props.dic.D_JCGL_ZDSB_SBLX
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
break;
|
||||
case "jyqx":
|
||||
title.value = "装备选择";
|
||||
url.value = "/mosty-jcz/tpJczJyqx/selectJyqx";
|
||||
arr = [
|
||||
{ label: "器械名称", prop: "qxMc" },
|
||||
{ label: "器械编号", prop: "qxbh" },
|
||||
{ label: "器械类型", prop: "qxlx", showSolt: true },
|
||||
{ label: "数量", prop: "sl" }
|
||||
];
|
||||
pageDataL.tableColumn = arr;
|
||||
pageDataR.tableColumn = arr;
|
||||
if (!type) {
|
||||
common.searchConfiger = [
|
||||
{
|
||||
showType: "input",
|
||||
prop: "qxMc",
|
||||
placeholder: "请输入器械名称",
|
||||
label: "器械名称"
|
||||
}
|
||||
];
|
||||
}
|
||||
break;
|
||||
case "jz":
|
||||
title.value = "警组";
|
||||
url.value = "/mosty-qwzx/tbQwglJz/selectPage";
|
||||
pageDataL.tableColumn = [
|
||||
{ label: "警组名称", prop: "jzMc" },
|
||||
{ label: "报备类型", prop: "jzQwBbzl", showSolt: true }
|
||||
];
|
||||
if (!type) {
|
||||
common.searchConfiger = [
|
||||
{
|
||||
showType: "input",
|
||||
prop: "jzMc",
|
||||
placeholder: "警组名称",
|
||||
label: "警组名称"
|
||||
}
|
||||
];
|
||||
}
|
||||
break;
|
||||
case "kfd":
|
||||
title.value = "快反点";
|
||||
url.value = "/mosty-jcgl/tpJcglKfd/selectKfdList";
|
||||
pageDataL.tableColumn = [
|
||||
{ label: "快反点名称", prop: "kfdMc" },
|
||||
{ label: "快反点地址", prop: "kfdDz" }
|
||||
];
|
||||
if (!type) {
|
||||
common.searchConfiger = [
|
||||
{
|
||||
showType: "input",
|
||||
prop: "kfdMc",
|
||||
placeholder: "请输入名称",
|
||||
label: "快反点名称"
|
||||
}
|
||||
];
|
||||
}
|
||||
break;
|
||||
case "jcz":
|
||||
title.value = "检查站";
|
||||
url.value = "/mosty-jcz/jcz/selectJczList";
|
||||
pageDataL.tableColumn = [
|
||||
{ label: "检查站名称", prop: "jczmc" },
|
||||
{ label: "检查站类型", prop: "jczlx", showSolt: true }
|
||||
];
|
||||
if (!type) {
|
||||
common.searchConfiger = [
|
||||
{
|
||||
showType: "input",
|
||||
prop: "jczmc",
|
||||
placeholder: "检查站名称",
|
||||
label: "检查站名称"
|
||||
}
|
||||
];
|
||||
}
|
||||
break;
|
||||
case "znzb":
|
||||
title.value = "智能装备";
|
||||
url.value = "/mosty-jcz/tbJczTcsb/selectPage";
|
||||
let crr = [
|
||||
{ label: "设备名称", prop: "sbmc" },
|
||||
{ label: "设备编号", prop: "sbbh" },
|
||||
{ label: "所属部门", prop: "gldwmc" }
|
||||
];
|
||||
pageDataL.tableColumn = crr;
|
||||
pageDataR.tableColumn = crr;
|
||||
if (!type) {
|
||||
common.searchConfiger = [
|
||||
{
|
||||
showType: "input",
|
||||
prop: "sbmc",
|
||||
placeholder: "请输入设备名称",
|
||||
label: "设备名称"
|
||||
}
|
||||
];
|
||||
}
|
||||
break;
|
||||
case "hxg":
|
||||
title.value = "选择护学岗";
|
||||
url.value = "/mosty-jcgl/tbNbhyXxjbxx/selectPage";
|
||||
let zrr = [
|
||||
{ label: "学校名称", prop: "xxMc" },
|
||||
{ label: "学校地址", prop: "xxDz" },
|
||||
{ label: "时间段", prop: "sdList", showSolt: true }
|
||||
];
|
||||
pageDataL.tableColumn = zrr;
|
||||
pageDataR.tableColumn = zrr;
|
||||
if (!type) {
|
||||
common.searchConfiger = [
|
||||
{
|
||||
showType: "input",
|
||||
prop: "xxMc",
|
||||
placeholder: "请输入学校名称",
|
||||
label: "学校名称"
|
||||
}
|
||||
];
|
||||
}
|
||||
break;
|
||||
case "jwz":
|
||||
title.value = "选择警务站";
|
||||
url.value = "/mosty-jcgl/tbJcglJwz/selectJwzList";
|
||||
pageDataL.tableColumn = [
|
||||
{ label: "警务站名称", prop: "jwzMc" },
|
||||
{ label: "负责人姓名", prop: "fzrXm" },
|
||||
{ label: "警务站类型", prop: "jwzLx", showSolt: true }
|
||||
];
|
||||
if (!type) {
|
||||
common.searchConfiger = [
|
||||
{
|
||||
showType: "input",
|
||||
prop: "jwzMc",
|
||||
placeholder: "请输入警务站名称",
|
||||
label: "警务站名称"
|
||||
}
|
||||
];
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (val && visible.value) getData();
|
||||
};
|
||||
|
||||
// 搜索
|
||||
const onSearch = (val) => {
|
||||
common.pageConfiger.pageCurrent = 1;
|
||||
listQuery.value = { ...listQuery.value, ...val };
|
||||
handleData(getConfiger.lx, "look");
|
||||
};
|
||||
// 获取数据
|
||||
const getData = () => {
|
||||
if (getConfiger.lx == "jyqx")
|
||||
listQuery.value.pageNo = listQuery.value.pageCurrent;
|
||||
if (getConfiger.lx == "mj") listQuery.value.jllx = "01";
|
||||
if (getConfiger.lx == "fj") listQuery.value.jllx = "02";
|
||||
if (getConfiger.lx == "zbbc") listQuery.value.bcQwBbzl = getConfiger.bclx;
|
||||
if (getConfiger.lx == "jz") listQuery.value.jzQwBbzl = getConfiger.jzlx;
|
||||
if (getConfiger.lx == "kfd") listQuery.value.dwlxs = "01";
|
||||
if (getConfiger.lx == "zfjly") listQuery.value.sblx = "06";
|
||||
if (getConfiger.lx == "bxd") listQuery.value.xqlx = "01";
|
||||
if (getConfiger.lx == "xfq") listQuery.value.xqlx = "03";
|
||||
if (getConfiger.lx == "bxx") listQuery.value.xqlx = "02";
|
||||
common.tableConfiger.loading = true;
|
||||
|
||||
let params = { ...listQuery.value };
|
||||
// params.ssbmdm = props.deptment.bmdm;
|
||||
params.pageNo = params.pageCurrent;
|
||||
qcckGet(params, url.value)
|
||||
.then((res) => {
|
||||
if (getConfiger.lx == "cl") {
|
||||
pageDataL.tableData =
|
||||
res.records.map((item) => {
|
||||
return { id: item.cid, ...item };
|
||||
}) || [];
|
||||
} else {
|
||||
pageDataL.tableData = res.records || [];
|
||||
}
|
||||
listQuery.value.total = res.total;
|
||||
common.tableConfiger.loading = false;
|
||||
})
|
||||
.catch(() => {
|
||||
common.tableConfiger.loading = false;
|
||||
});
|
||||
};
|
||||
// 左边选择z
|
||||
const chooseDataL = (val) => {
|
||||
if (getConfiger.isRadio) {
|
||||
hasChoosedL.value = val[0];
|
||||
} else {
|
||||
hasChoosedL.value = val;
|
||||
}
|
||||
};
|
||||
// 右边选择的数据
|
||||
const chooseDataR = (val) => {
|
||||
console.log(val);
|
||||
hasChoosedR.value = val;
|
||||
};
|
||||
// 添加数据
|
||||
const upRight = () => {
|
||||
const data = [...pageDataR.tableData, ...hasChoosedL.value];
|
||||
pageDataR.tableData = data.reduce((acc, curr) => {
|
||||
const x = acc.find((item) => item.id == curr.id);
|
||||
if (!x) {
|
||||
return acc.concat([curr]);
|
||||
} else {
|
||||
return acc;
|
||||
}
|
||||
}, []);
|
||||
// pageDataR.tableData = [...map.values]
|
||||
};
|
||||
// 移除数据
|
||||
const upLeft = () => {
|
||||
pageDataR.tableData = pageDataR.tableData.filter((item) => {
|
||||
return !hasChoosedR.value.includes(item);
|
||||
});
|
||||
};
|
||||
|
||||
// 提交数据
|
||||
const submitDate = () => {
|
||||
if (getConfiger.isRadio) {
|
||||
console.log(hasChoosedL.value);
|
||||
|
||||
emits("update:modelValue", hasChoosedL.value); //单选
|
||||
emits("change", hasChoosedL.value);
|
||||
} else {
|
||||
if (pageDataR.tableData.length == 0)
|
||||
return proxy.$message.warning("请选择数据");
|
||||
emits("update:modelValue", pageDataR.tableData); //多选
|
||||
emits("change", pageDataR.tableData);
|
||||
}
|
||||
visible.value = false;
|
||||
};
|
||||
|
||||
// 改变分页
|
||||
const changeNo = (val) => {
|
||||
listQuery.value.pageCurrent = val;
|
||||
handleData(getConfiger.lx);
|
||||
};
|
||||
// 页数
|
||||
const changeSize = (val) => {
|
||||
listQuery.value.pageSize = val;
|
||||
handleData(getConfiger.lx);
|
||||
};
|
||||
|
||||
watch(
|
||||
() => props.configer,
|
||||
(val) => {
|
||||
getConfiger = { ...getConfiger, ...val };
|
||||
|
||||
if (getConfiger.lx) handleData(getConfiger.lx);
|
||||
if (getConfiger.isRadio) common.tableConfiger.showSelectType = "radio";
|
||||
if (getConfiger.rowKey) common.tableConfiger.rowKey = getConfiger.rowKey;
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(val) => {
|
||||
if (val && val.length > 0) {
|
||||
common.tableConfiger.defaultSelectKeys = props.modelValue.map((it) => {
|
||||
return it.id || it.cid;
|
||||
});
|
||||
pageDataR.tableData = props.modelValue;
|
||||
} else {
|
||||
common.tableConfiger.defaultSelectKeys = [];
|
||||
pageDataR.tableData = [];
|
||||
}
|
||||
},
|
||||
{ immediate: true, deep: true }
|
||||
);
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.tableBox .cnt {
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.tableBox .table {
|
||||
flex: 1 0 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.deBtn {
|
||||
display: inline-block;
|
||||
border-radius: 40px;
|
||||
width: 70px;
|
||||
height: 28px;
|
||||
line-height: 28px;
|
||||
text-align: center;
|
||||
color: #fff;
|
||||
background-color: #3e85c3;
|
||||
border-color: #2b669a;
|
||||
box-shadow: 0 1px 1px rgb(90 90 90 / 30%);
|
||||
margin: 0 10px;
|
||||
}
|
||||
|
||||
::v-deep .el-table tr {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
::v-deep .el-table td.el-table__cell {
|
||||
color: #505152;
|
||||
}
|
||||
|
||||
// ::v-deep .el-popper{
|
||||
// position: fixed !important;
|
||||
// top: 50% !important;
|
||||
// left: 50% !important;
|
||||
// transform: translate(-50%, -50%) !important;
|
||||
// }
|
||||
.dinw {
|
||||
position: absolute !important;
|
||||
left: 50% !important;
|
||||
transform: translate(-50%, -50%) !important;
|
||||
top: 50% !important;
|
||||
// width: 1000px;
|
||||
margin: 0px !important;
|
||||
}
|
||||
</style>
|
117
src/components/contextmenu/index.vue
Normal file
117
src/components/contextmenu/index.vue
Normal file
@ -0,0 +1,117 @@
|
||||
<template>
|
||||
<transition name="el-zoom-in-center">
|
||||
<div
|
||||
class="el-popper is-pure is-light el-dropdown__popper ba-contextmenu"
|
||||
:style="`top: ${state.axis.y + 18}px;left: ${ state.axis.x - 14 }px;width:150px`"
|
||||
:key="Math.random()"
|
||||
v-show="state.show"
|
||||
aria-hidden="false"
|
||||
data-popper-placement="bottom"
|
||||
>
|
||||
<ul class="el-dropdown-menu">
|
||||
<template v-for="(item, idx) in props.items" :key="idx">
|
||||
<li
|
||||
class="el-dropdown-menu__item"
|
||||
:class="item.disabled ? 'is-disabled' : ''"
|
||||
tabindex="-1"
|
||||
@click="onContextmenuItem(item)"
|
||||
>
|
||||
<Icon size="12" :name="item.icon" />
|
||||
<span>{{ item.label }}</span>
|
||||
</li>
|
||||
</template>
|
||||
</ul>
|
||||
<span
|
||||
class="el-popper__arrow"
|
||||
:style="{ left: `${state.arrowAxis}px` }"
|
||||
></span>
|
||||
</div>
|
||||
</transition>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {
|
||||
onMounted,
|
||||
onUnmounted,
|
||||
reactive,
|
||||
toRaw,
|
||||
defineProps,
|
||||
defineEmits
|
||||
} from "vue";
|
||||
import { useRoute, useRouter } from "vue-router";
|
||||
import { useStore } from "vuex";
|
||||
const route = useRoute();
|
||||
|
||||
const props = defineProps({
|
||||
items: {
|
||||
type: Array,
|
||||
default: []
|
||||
}
|
||||
});
|
||||
const emits = defineEmits(["contextmenuItemClick"]);
|
||||
const state = reactive({
|
||||
show: false,
|
||||
axis: {
|
||||
x: 0,
|
||||
y: 0
|
||||
},
|
||||
menu: {},
|
||||
arrowAxis: 10
|
||||
});
|
||||
|
||||
const onShowContextmenu = (menu, axis) => {
|
||||
state.menu = menu;
|
||||
state.axis = axis;
|
||||
state.show = true;
|
||||
};
|
||||
|
||||
const onContextmenuItem = (item) => {
|
||||
if (item.disabled) return;
|
||||
item.menu = toRaw(state.menu);
|
||||
emits("contextmenuItemClick", item);
|
||||
};
|
||||
|
||||
const onHideContextmenu = () => {
|
||||
state.show = false;
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
onShowContextmenu,
|
||||
onHideContextmenu
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
document.body.addEventListener("click", onHideContextmenu);
|
||||
});
|
||||
onUnmounted(() => {
|
||||
document.body.removeEventListener("click", onHideContextmenu);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.ba-contextmenu {
|
||||
z-index: 9999;
|
||||
position: fixed;
|
||||
}
|
||||
.el-popper,
|
||||
.el-popper.is-light .el-popper__arrow::before {
|
||||
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
||||
border: none;
|
||||
}
|
||||
.el-dropdown-menu__item {
|
||||
padding: 8px 20px;
|
||||
user-select: none;
|
||||
}
|
||||
.el-dropdown-menu__item .icon {
|
||||
margin-right: 5px;
|
||||
}
|
||||
.el-dropdown-menu__item:not(.is-disabled) {
|
||||
&:hover {
|
||||
background-color: var(--el-dropdown-menuItem-hover-fill);
|
||||
color: var(--el-dropdown-menuItem-hover-color);
|
||||
.fa {
|
||||
color: var(--el-dropdown-menuItem-hover-color) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
174
src/components/echarts/3DbarEcharts.vue
Normal file
174
src/components/echarts/3DbarEcharts.vue
Normal file
@ -0,0 +1,174 @@
|
||||
<template>
|
||||
<div style="height:100%;width:100%" :id="echartsId"></div>
|
||||
</template>
|
||||
<script setup>
|
||||
import * as echarts from "echarts";
|
||||
import { fa } from "element-plus/es/locale.mjs";
|
||||
import { onMounted, ref, reactive, defineProps, onUnmounted, watch, nextTick } from "vue";
|
||||
const props = defineProps({
|
||||
echartsId:{
|
||||
type:String,
|
||||
default:'lineId'
|
||||
},
|
||||
data:{
|
||||
type:Object,
|
||||
default:{
|
||||
list:[],
|
||||
colors:[]
|
||||
}
|
||||
}
|
||||
});
|
||||
watch(()=>props.data,val=>{
|
||||
nextTick(()=>{ haandleData(val) })
|
||||
},{immediate:true,deep:true})
|
||||
|
||||
const haandleData = (data)=>{
|
||||
let val = [],x_value=[]
|
||||
let color = data.colors;
|
||||
let topColor = data.topColor;
|
||||
data.list.forEach(item=>{
|
||||
val.push(item.val);
|
||||
x_value.push(item.label);
|
||||
})
|
||||
chartFn(val,x_value,color,topColor)
|
||||
}
|
||||
|
||||
function chartFn(val,x_value,color,topColor) {
|
||||
var myChart = echarts.init(document.getElementById(props.echartsId));
|
||||
const sideData1 = val//[100, 110, 120, 134, 190, 230];
|
||||
const name = ''; //"销量";
|
||||
var x_value = x_value;//['周一', '周二', '周三', '周四', '周五', '周六', '周日']
|
||||
var option = {
|
||||
tooltip: { trigger: 'axis' },
|
||||
legend: {
|
||||
show: false,
|
||||
},
|
||||
grid: {
|
||||
top:"30px",
|
||||
left:"5px",
|
||||
right:"0px",
|
||||
bottom:"10%",
|
||||
containLabel: true
|
||||
},
|
||||
toolbox: {
|
||||
show: true,
|
||||
},
|
||||
calculable: true,
|
||||
xAxis: [
|
||||
{
|
||||
type: 'category',
|
||||
splitLine: {
|
||||
show: false
|
||||
},
|
||||
data: x_value,
|
||||
axisLabel: {
|
||||
show: true,
|
||||
textStyle: {
|
||||
color: "#333" //X轴文字颜色
|
||||
},
|
||||
},
|
||||
}
|
||||
],
|
||||
yAxis: [
|
||||
{
|
||||
name:'单位:元/吨',
|
||||
nameTextStyle: { color: "#fff" },
|
||||
type: 'value',
|
||||
splitLine: { show: false },
|
||||
axisLabel: {
|
||||
show: true,
|
||||
textStyle: {
|
||||
color: "#333" //X轴文字颜色
|
||||
},
|
||||
},
|
||||
}
|
||||
],
|
||||
series: [
|
||||
{
|
||||
name: name,
|
||||
tooltip: { show: false },
|
||||
type: 'bar',
|
||||
barWidth: 12,
|
||||
itemStyle: {
|
||||
normal: {
|
||||
color: new echarts.graphic.LinearGradient(0, 1, 0, 0, [{
|
||||
offset: 0,
|
||||
color: color ? color[0] : '#28EEBF'// 0% 处的颜色
|
||||
}, {
|
||||
offset: 1,
|
||||
color: color ? color[1] : '#0DBAC5', // 100% 处的颜色
|
||||
}], false)
|
||||
}
|
||||
},
|
||||
data: sideData1,
|
||||
barGap: 0,
|
||||
label: {
|
||||
show: true,
|
||||
position: 'top',
|
||||
distance: 10,
|
||||
textStyle: {
|
||||
color: '#0EBBC5',
|
||||
fontSize: 14,
|
||||
fontWeight: 'bold'
|
||||
},
|
||||
formatter: '{c}'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: name,
|
||||
type: 'bar',
|
||||
barWidth: 12,
|
||||
itemStyle: {
|
||||
normal: {
|
||||
color: new echarts.graphic.LinearGradient(0, 1, 0, 0, [{
|
||||
offset: 0,
|
||||
color: color ? color[0] : '#28EEBF'// 0% 处的颜色
|
||||
}, {
|
||||
offset: 1,
|
||||
color: color ? color[1] : '#0DBAC5', // 100% 处的颜色
|
||||
}], false)
|
||||
}
|
||||
},
|
||||
barGap: 0,
|
||||
data: sideData1,
|
||||
label: {
|
||||
show: true,
|
||||
position: 'top',
|
||||
textStyle: {
|
||||
color: 'white',
|
||||
fontSize: 10
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: name,
|
||||
tooltip: {
|
||||
show: false
|
||||
},
|
||||
type: 'pictorialBar',
|
||||
itemStyle: {
|
||||
borderWidth: 1,
|
||||
borderColor: '#fff',
|
||||
color: topColor || '#1bd6c2' // 顶部方块的颜色
|
||||
},
|
||||
symbol: 'path://M 0,0 l 90,0 l -60,60 l -90,0 z',
|
||||
symbolSize: ['22', '12'], // 第一个值控制顶部方形大小
|
||||
symbolOffset: ['-0', '-6'], // 控制顶部放行 左右和上下
|
||||
symbolRotate: -30,
|
||||
symbolPosition: 'end',
|
||||
barGap: 0,
|
||||
data: sideData1,
|
||||
z: 3,
|
||||
}
|
||||
]
|
||||
};
|
||||
option && myChart.setOption(option);
|
||||
window.addEventListener('resize',function(){
|
||||
myChart.resize();
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
</style>
|
291
src/components/echarts/3DpieEcharts.vue
Normal file
291
src/components/echarts/3DpieEcharts.vue
Normal file
@ -0,0 +1,291 @@
|
||||
<template>
|
||||
<div style="height:100%;width:100%" :id="echartsId"></div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import * as echarts from "echarts";
|
||||
import "echarts-gl";
|
||||
import { fa } from "element-plus/es/locale.mjs";
|
||||
import { onMounted, toRefs,nextTick, defineProps,ref, reactive } from "vue";
|
||||
const props = defineProps({
|
||||
echartsId:{
|
||||
type:String,
|
||||
default:'lineId'
|
||||
},
|
||||
// 传入数据生成 option
|
||||
data:{
|
||||
type:Array,
|
||||
default:[
|
||||
{
|
||||
name: "待办",
|
||||
value: 2056,
|
||||
itemStyle: {
|
||||
// color: "#2A71FF"
|
||||
echarts: "rgba(44,44,44,0.8)"
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "已办",
|
||||
value: 4356,
|
||||
itemStyle: {
|
||||
color: "#00EDFE"
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
watch(()=>props.data,val=>{
|
||||
nextTick(()=>{
|
||||
echartInit()
|
||||
})
|
||||
},{immediate:true,deep:true})
|
||||
|
||||
|
||||
const echartInit = () => {
|
||||
var myChart = echarts.init(document.getElementById(props.echartsId));
|
||||
const series = getPie3D(props.data, 0.8, 240, 28, 26, 0.5);
|
||||
series.push({
|
||||
name: "pie2d",
|
||||
type: "pie",
|
||||
label: {
|
||||
// show: false,
|
||||
opacity: 1,
|
||||
fontSize: 14,
|
||||
lineHeight: 20,
|
||||
textStyle: {
|
||||
fontSize: 14,
|
||||
color: "#fff"
|
||||
}
|
||||
},
|
||||
labelLine: {
|
||||
// show: false,
|
||||
length: 20,
|
||||
length2: 25
|
||||
},
|
||||
startAngle: -30, //起始角度,支持范围[0, 360]。
|
||||
clockwise: false, //饼图的扇区是否是顺时针排布。上述这两项配置主要是为了对齐3d的样式
|
||||
// radius: ["40%", "60%"],
|
||||
center: ["40%", "50%"],
|
||||
data: props.data,
|
||||
itemStyle: {
|
||||
opacity: 0
|
||||
}
|
||||
});
|
||||
// 准备待返回的配置项,把准备好的 legendData、series 传入。
|
||||
let option = {
|
||||
legend: {
|
||||
show: true,
|
||||
tooltip: {
|
||||
show: true
|
||||
},
|
||||
orient: "vertical",
|
||||
data: props.data.map((item) => item.name),
|
||||
// data: ["待办", "已办", "未处理", "忽略"],
|
||||
top: "center",
|
||||
itemGap: 14,
|
||||
itemHeight: 8,
|
||||
itemWidth: 17,
|
||||
right: "2%",
|
||||
textStyle: {
|
||||
color: "#fff",
|
||||
fontSize: 12
|
||||
}
|
||||
},
|
||||
animation: true,
|
||||
tooltip: {
|
||||
formatter: (params) => {
|
||||
if ( params.seriesName !== "mouseoutSeries" && params.seriesName !== "pie2d" ) {
|
||||
return `${ params.seriesName }<br/><span style="display:inline-block;margin-right:5px;border-radius:10px;width:10px;height:10px;background-color:${params.color };"></span>${option.series[params.seriesIndex].pieData.value + "人"}`;
|
||||
}
|
||||
},
|
||||
textStyle: {
|
||||
fontSize: 14
|
||||
}
|
||||
},
|
||||
title: {
|
||||
x: "center",
|
||||
top: "20",
|
||||
textStyle: {
|
||||
color: "#fff",
|
||||
fontSize: 22
|
||||
}
|
||||
},
|
||||
backgroundColor: "rgba(0, 29, 75, 0.65)",
|
||||
labelLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
color: "#7BC0CB"
|
||||
},
|
||||
normal: {
|
||||
show: false,
|
||||
length: 20,
|
||||
length2: 20
|
||||
}
|
||||
},
|
||||
label: {
|
||||
show: true,
|
||||
position: "outside",
|
||||
formatter: "{b} \n{d}%",
|
||||
textStyle: {
|
||||
color: "#fff",
|
||||
fontSize: "14px"
|
||||
}
|
||||
},
|
||||
xAxis3D: {
|
||||
min: -1,
|
||||
max: 1
|
||||
},
|
||||
yAxis3D: {
|
||||
min: -1,
|
||||
max: 1
|
||||
},
|
||||
zAxis3D: {
|
||||
min: -1,
|
||||
max: 1
|
||||
},
|
||||
grid3D: {
|
||||
show: false,
|
||||
boxHeight: 0.01,
|
||||
bottom: "50%",
|
||||
left: "-12%",
|
||||
// environment: "rgba(255,255,255,0)",// 环境颜色
|
||||
viewControl: {
|
||||
distance: 180, //圆环的大小 ,值越大换越小
|
||||
alpha: 25, //倾斜的角度
|
||||
beta: 0, //旋转的角度
|
||||
autoRotate: false // 取消自动旋转
|
||||
}
|
||||
},
|
||||
series: series
|
||||
};
|
||||
// 使用刚指定的配置项和数据显示图表。
|
||||
myChart.setOption(option);
|
||||
};
|
||||
|
||||
function getParametricEquation( startRatio, endRatio, isSelected, isHovered, k, height ) {
|
||||
// 计算
|
||||
let midRatio = (startRatio + endRatio) / 2;
|
||||
let startRadian = startRatio * Math.PI * 2;
|
||||
let endRadian = endRatio * Math.PI * 2;
|
||||
let midRadian = midRatio * Math.PI * 2;
|
||||
// 如果只有一个扇形,则不实现选中效果。
|
||||
if (startRatio === 0 && endRatio === 1) {
|
||||
isSelected = false;
|
||||
}
|
||||
|
||||
// 通过扇形内径/外径的值,换算出辅助参数 k(默认值 1/3)
|
||||
k = typeof k !== "undefined" ? k : 1 / 3;
|
||||
|
||||
// 计算选中效果分别在 x 轴、y 轴方向上的位移(未选中,则位移均为 0)
|
||||
let offsetX = isSelected ? Math.cos(midRadian) * 0.1 : 0;
|
||||
let offsetY = isSelected ? Math.sin(midRadian) * 0.1 : 0;
|
||||
|
||||
// 计算高亮效果的放大比例(未高亮,则比例为 1)
|
||||
let hoverRate = isHovered ? 1.05 : 1;
|
||||
|
||||
// 返回曲面参数方程
|
||||
return {
|
||||
u: {
|
||||
min: -Math.PI,
|
||||
max: Math.PI * 3,
|
||||
step: Math.PI / 32
|
||||
},
|
||||
|
||||
v: {
|
||||
min: 0,
|
||||
max: Math.PI * 2,
|
||||
step: Math.PI / 20
|
||||
},
|
||||
|
||||
x: function (u, v) {
|
||||
if (u < startRadian) {
|
||||
return (offsetX + Math.cos(startRadian) * (1 + Math.cos(v) * k) * hoverRate);
|
||||
}
|
||||
if (u > endRadian) {
|
||||
return (offsetX + Math.cos(endRadian) * (1 + Math.cos(v) * k) * hoverRate);
|
||||
}
|
||||
return offsetX + Math.cos(u) * (1 + Math.cos(v) * k) * hoverRate;
|
||||
},
|
||||
|
||||
y: function (u, v) {
|
||||
if (u < startRadian) {
|
||||
return (offsetY + Math.sin(startRadian) * (1 + Math.cos(v) * k) * hoverRate);
|
||||
}
|
||||
if (u > endRadian) {
|
||||
return ( offsetY + Math.sin(endRadian) * (1 + Math.cos(v) * k) * hoverRate);
|
||||
}
|
||||
return offsetY + Math.sin(u) * (1 + Math.cos(v) * k) * hoverRate;
|
||||
},
|
||||
|
||||
z: function (u, v) {
|
||||
if (u < -Math.PI * 0.5) {
|
||||
return Math.sin(u);
|
||||
}
|
||||
if (u > Math.PI * 2.5) {
|
||||
return Math.sin(u);
|
||||
}
|
||||
return Math.sin(v) > 0 ? 1 * height : -1;
|
||||
}
|
||||
};
|
||||
}
|
||||
// 生成模拟 3D 饼图的配置项
|
||||
function getPie3D(pieData, internalDiameterRatio) {
|
||||
let series = [];
|
||||
let sumValue = 0;
|
||||
let startValue = 0;
|
||||
let endValue = 0;
|
||||
let legendData = [];
|
||||
let k = typeof internalDiameterRatio !== "undefined" ? (1 - internalDiameterRatio) / (1 + internalDiameterRatio) : 1 / 3;
|
||||
|
||||
// 为每一个饼图数据,生成一个 series-surface 配置
|
||||
for (let i = 0; i < pieData.length; i++) {
|
||||
sumValue += pieData[i].value;
|
||||
|
||||
let seriesItem = {
|
||||
name: typeof pieData[i].name === "undefined" ? `series${i}` : pieData[i].name, type: "surface",
|
||||
parametric: true,
|
||||
wireframe: { show: false },
|
||||
pieData: pieData[i],
|
||||
pieStatus: {
|
||||
selected: false,
|
||||
hovered: false,
|
||||
k: k
|
||||
}
|
||||
};
|
||||
|
||||
if (typeof pieData[i].itemStyle != "undefined") {
|
||||
let itemStyle = {};
|
||||
typeof pieData[i].itemStyle.color != "undefined" ? (itemStyle.color = pieData[i].itemStyle.color) : null;
|
||||
typeof pieData[i].itemStyle.opacity != "undefined" ? (itemStyle.opacity = pieData[i].itemStyle.opacity) : null;
|
||||
seriesItem.itemStyle = itemStyle;
|
||||
}
|
||||
series.push(seriesItem);
|
||||
}
|
||||
|
||||
// 使用上一次遍历时,计算出的数据和 sumValue,调用 getParametricEquation 函数,
|
||||
// 向每个 series-surface 传入不同的参数方程 series-surface.parametricEquation,也就是实现每一个扇形。
|
||||
for (let i = 0; i < series.length; i++) {
|
||||
endValue = startValue + series[i].pieData.value;
|
||||
console.log(series[i]);
|
||||
series[i].pieData.startRatio = startValue / sumValue;
|
||||
series[i].pieData.endRatio = endValue / sumValue;
|
||||
series[i].parametricEquation = getParametricEquation(
|
||||
series[i].pieData.startRatio,
|
||||
series[i].pieData.endRatio,
|
||||
false,
|
||||
false,
|
||||
k,
|
||||
series[i].pieData.value
|
||||
);
|
||||
startValue = endValue;
|
||||
legendData.push(series[i].name);
|
||||
}
|
||||
return series;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang='scss' scoped>
|
||||
|
||||
</style>
|
||||
|
106
src/components/echarts/barEcharts.vue
Normal file
106
src/components/echarts/barEcharts.vue
Normal file
@ -0,0 +1,106 @@
|
||||
<template>
|
||||
<div style="height:100%;width:100%" :id="echartsId"></div>
|
||||
</template>
|
||||
<script setup>
|
||||
import * as echarts from "echarts";
|
||||
import { onMounted, ref, reactive, defineProps, onUnmounted, watch, nextTick } from "vue";
|
||||
const props = defineProps({
|
||||
echartsId:{
|
||||
type:String,
|
||||
default:'lineId'
|
||||
},
|
||||
data:{
|
||||
type:Object,
|
||||
default:{
|
||||
list:[],
|
||||
colors:[]
|
||||
}
|
||||
}
|
||||
});
|
||||
watch(()=>props.data,val=>{
|
||||
nextTick(()=>{
|
||||
chartFn()
|
||||
})
|
||||
},{immediate:true,deep:true})
|
||||
|
||||
function chartFn() {
|
||||
var myChart = echarts.init(document.getElementById(props.echartsId));
|
||||
var option = {
|
||||
grid: {
|
||||
top: "16%",
|
||||
right: "2%",
|
||||
left: "2%",
|
||||
bottom: "4%",
|
||||
containLabel:true
|
||||
},
|
||||
tooltip: {
|
||||
trigger: "axis",
|
||||
axisPointer: {
|
||||
lineStyle: {
|
||||
color: "#ddd"
|
||||
}
|
||||
},
|
||||
backgroundColor: "rgba(255,255,255,1)",
|
||||
padding: [5, 10],
|
||||
textStyle: {
|
||||
color: "#7588E4"
|
||||
},
|
||||
},
|
||||
xAxis: {
|
||||
type: "category",
|
||||
data:props.data.list.map(v=>{return v.label}),
|
||||
axisTick: { show: false },
|
||||
axisLine: { show: false },
|
||||
axisLabel: { color: "#fff",magin:20 },
|
||||
},
|
||||
yAxis: {
|
||||
type: "value",
|
||||
splitLine: {
|
||||
show:true ,
|
||||
lineStyle: {
|
||||
type:'dashed',
|
||||
color: "rgba(14,95,255,0.5)"
|
||||
}
|
||||
},
|
||||
axisTick: { show: false },
|
||||
axisLine: { show: false },
|
||||
axisLabel: { color: "#fff" },
|
||||
},
|
||||
series: [
|
||||
{
|
||||
type: "bar",
|
||||
barGap:'80%',
|
||||
barWidth: "20px",
|
||||
data: props.data.list.map(v=>{return v.val}),
|
||||
label:{
|
||||
normal:{show:true,position:'top',color:'#EB00FF'}
|
||||
},
|
||||
itemStyle: {
|
||||
normal: {
|
||||
color:function name(params) {
|
||||
let colorList = []
|
||||
if(props.data.colors && props.data.colors.length>0){
|
||||
props.data.colors.forEach(item => {
|
||||
colorList.push(new echarts.graphic.LinearGradient( 0,0,0, 1,[{offset:0,color:item[0]},{offset:1,color:item[1]}]))
|
||||
});
|
||||
}
|
||||
if(colorList.length > 0) return colorList[params.dataIndex]
|
||||
else return new echarts.graphic.LinearGradient( 0,0,0, 1,[{ offset: 0,color: "rgba(0,244,255,1)"},{ offset: 1, color: "rgba(0,77,167,1)" }])
|
||||
},
|
||||
shadowColor: "rgba(0,160,221,1)",
|
||||
shadowBlur: 2
|
||||
}
|
||||
},
|
||||
}
|
||||
]
|
||||
};
|
||||
option && myChart.setOption(option);
|
||||
window.addEventListener('resize',function(){
|
||||
myChart.resize();
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
</style>
|
147
src/components/echarts/barHatEcharts.vue
Normal file
147
src/components/echarts/barHatEcharts.vue
Normal file
@ -0,0 +1,147 @@
|
||||
<template>
|
||||
<div style="height:100%;width:100%" :id="echartsId"></div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import * as echarts from "echarts";
|
||||
import { nextTick , onMounted, watch, defineProps } from "vue";
|
||||
const props = defineProps({
|
||||
echartsId:{
|
||||
type:String,
|
||||
default:'barHatId'
|
||||
},
|
||||
textcolor:{
|
||||
type:String,
|
||||
default:'#333'
|
||||
},
|
||||
barWidth:{
|
||||
type:String,
|
||||
default:'20px'
|
||||
},
|
||||
data:{
|
||||
type:Object,
|
||||
default:{
|
||||
xDate: ['巴宜区', '工布江达县', '波密县', '朗县', '墨脱县', '察隅县', '米林县'],
|
||||
list:[
|
||||
{ name: "总数", value: [10,20,30,40,50,60,70] ,color:['rgba(0,244,255,1)','rgba(0,77,167,1)'] ,hatColor:'#087df9'},
|
||||
{ name: "已处置", value: [10,20,30,40,50,60,70],color:['rgba(24, 232, 229, 1)','rgba(3, 110, 83, 1)'],hatColor:'#00FFFF' },
|
||||
],
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
watch(()=>props.data,val=>{
|
||||
nextTick(()=>{ handleDate() })
|
||||
},{immediate:true,deep:true})
|
||||
|
||||
// 处理数据
|
||||
function handleDate() {
|
||||
let xDate = props.data.xDate;
|
||||
let legend = props.data.list.map(v=>{return {name:v.name}})
|
||||
let series = props.data.list.map((item,i)=>{
|
||||
let obj = {
|
||||
name: item.name,
|
||||
type: "bar",
|
||||
data: item.value,
|
||||
barWidth: props.barWidth || "20px",
|
||||
itemStyle: {
|
||||
normal: {
|
||||
color: new echarts.graphic.LinearGradient(0,0,0,1,[
|
||||
{ offset: 0, color: item.color ? item.color[0] : "rgba(0,244,255,1)" },
|
||||
{ offset: 1, color: item.color ? item.color[1] : "rgba(0,77,167,1)" }],false),
|
||||
}
|
||||
},
|
||||
markPoint: {
|
||||
symbol: 'path://M62 62h900v900h-900v-900z', // 使用 SVG path 绘制扁圆形状
|
||||
symbolSize: [21, 4], // 设置扁圆的宽和高
|
||||
itemStyle: { color: item.hatColor || '#087df9' },// 圆盘颜色
|
||||
data: item.value.map((obj, index) => ({
|
||||
xAxis: index, // 对应柱子的横坐标
|
||||
yAxis: obj + 0 // 柱子的值加上一些偏移量
|
||||
}))
|
||||
},
|
||||
}
|
||||
return obj
|
||||
})
|
||||
lineChartFn(xDate,legend,series)
|
||||
}
|
||||
|
||||
function lineChartFn(xDate,legend,series) {
|
||||
var myChart = echarts.init(document.getElementById(props.echartsId));
|
||||
var option = {
|
||||
legend: {
|
||||
type: "plain",
|
||||
show: true,
|
||||
right: 0,
|
||||
textStyle: { color: "#333" },
|
||||
data: legend
|
||||
},
|
||||
tooltip: {
|
||||
trigger: "axis",
|
||||
axisPointer: {
|
||||
type: "shadow"
|
||||
}
|
||||
},
|
||||
grid: {
|
||||
top: "25%",
|
||||
right: "5%",
|
||||
left: "10%",
|
||||
bottom: "10%"
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
type: "category",
|
||||
data: xDate,
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: "rgba(255,255,255,0.12)"
|
||||
}
|
||||
},
|
||||
axisLabel: {
|
||||
margin: 10,
|
||||
color: props.textcolor || '#333',
|
||||
textStyle: {
|
||||
fontSize: 14
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
yAxis: [
|
||||
{
|
||||
// name: '单位:万元',
|
||||
axisLabel: {
|
||||
formatter: "{value}",
|
||||
color: props.textcolor || '#333',
|
||||
|
||||
},
|
||||
axisLine: {
|
||||
show: false,
|
||||
lineStyle: {
|
||||
color: "rgba(255,255,255,1)"
|
||||
}
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
color: "rgba(255,255,255,0.12)"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
series: series
|
||||
};
|
||||
option && myChart.setOption(option);
|
||||
window.onresize = function () { myChart.resize(); };
|
||||
document.getElementById(props.echartsId).setAttribute("_echarts_instance_", "");
|
||||
}
|
||||
onMounted(() => {
|
||||
lineChartFn();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.circlecz {
|
||||
height: 100%;
|
||||
background: rgba(0,29,75,0.6);
|
||||
border-radius: 0 0 4px 4px;
|
||||
}
|
||||
</style>
|
115
src/components/echarts/lineEcharts.vue
Normal file
115
src/components/echarts/lineEcharts.vue
Normal file
@ -0,0 +1,115 @@
|
||||
<template>
|
||||
<div style="height:100%;width:100%" :id="echartsId"></div>
|
||||
</template>
|
||||
<script setup>
|
||||
import * as echarts from "echarts";
|
||||
import { onMounted, ref, reactive, defineProps, onUnmounted, watch, nextTick } from "vue";
|
||||
const props = defineProps({
|
||||
echartsId:{
|
||||
type:String,
|
||||
default:'lineId'
|
||||
},
|
||||
color:{
|
||||
type:String,
|
||||
default:'#fff'
|
||||
},
|
||||
data:{
|
||||
type:Array,
|
||||
default:[]
|
||||
}
|
||||
});
|
||||
watch(()=>props.data,val=>{
|
||||
nextTick(()=>{ chartFn() })
|
||||
},{immediate:true,deep:true})
|
||||
|
||||
function chartFn() {
|
||||
var myChart = echarts.init(document.getElementById(props.echartsId));
|
||||
var option = {
|
||||
grid: {
|
||||
top: "8%",
|
||||
right: "2%",
|
||||
left: "10%",
|
||||
bottom: "12%",
|
||||
containLabel:true
|
||||
},
|
||||
tooltip: {
|
||||
trigger: "axis",
|
||||
axisPointer: {
|
||||
lineStyle: {
|
||||
color: "#ddd"
|
||||
}
|
||||
},
|
||||
backgroundColor: "rgba(255,255,255,1)",
|
||||
padding: [5, 10],
|
||||
textStyle: {
|
||||
color: "#7588E4"
|
||||
},
|
||||
extraCssText: "box-shadow: 0 0 5px rgba(0,0,0,0.3)"
|
||||
},
|
||||
xAxis: {
|
||||
type: "category",
|
||||
data:props.data.map(v=>{return v.label}),
|
||||
axisTick: { show: false },
|
||||
axisLine: { show: false },
|
||||
axisLabel: { color: "#fff" },
|
||||
axisLabel: {
|
||||
show: true,
|
||||
color: props.color,
|
||||
interval: 0, // 强制显示所有标签
|
||||
// rotate: 15, // 标签旋转角度
|
||||
}
|
||||
},
|
||||
yAxis: {
|
||||
type: "value",
|
||||
splitLine: {
|
||||
show:true ,
|
||||
lineStyle: {
|
||||
type:'dashed',
|
||||
color: "rgba(14,95,255,0.5)"
|
||||
}
|
||||
},
|
||||
axisTick: { show: false },
|
||||
axisLine: { show: false },
|
||||
axisLabel: { color: props.color },
|
||||
},
|
||||
series: [
|
||||
{
|
||||
type: "line",
|
||||
smooth:true,
|
||||
showSymbol:false,
|
||||
data: props.data.map(v=>{return v.value}),
|
||||
areaStyle: {
|
||||
normal: {
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
|
||||
offset: 0,
|
||||
color: 'rgba(199, 237, 250,0.5)'
|
||||
}, {
|
||||
offset: 1,
|
||||
color: 'rgba(199, 237, 250,0.2)'
|
||||
}], false)
|
||||
}
|
||||
},
|
||||
itemStyle: {
|
||||
normal: {
|
||||
color: "rgb(4, 145, 216)"
|
||||
}
|
||||
},
|
||||
lineStyle: {
|
||||
normal: {
|
||||
width: 1,
|
||||
color:'#00FFFF'
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
option && myChart.setOption(option);
|
||||
window.addEventListener('resize',function(){
|
||||
myChart.resize();
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
</style>
|
113
src/components/echarts/moreBarEcharts.vue
Normal file
113
src/components/echarts/moreBarEcharts.vue
Normal file
@ -0,0 +1,113 @@
|
||||
<template>
|
||||
<div style="height:100%;width:100%" :id="echartsId"></div>
|
||||
</template>
|
||||
<script setup>
|
||||
import * as echarts from "echarts";
|
||||
import { on } from "element-plus/lib/utils";
|
||||
import { onMounted, ref, reactive, defineProps, onUnmounted, watch, nextTick } from "vue";
|
||||
|
||||
const props = defineProps({
|
||||
echartsId:{
|
||||
type:String,
|
||||
default:'moreBarId'
|
||||
},
|
||||
data:{
|
||||
type:Object,
|
||||
default:{
|
||||
xData:[], //['巴宜区', '工布江达县', '波密县', '朗县', '墨脱县', '察隅县', '米林县'],
|
||||
color:[],//['rgba(0,244,255,1)','rgba(0,77,167,1)'],
|
||||
list:[],//[{label:'总数',val:[]},{label:'已处置',val:[]}
|
||||
}
|
||||
}
|
||||
});
|
||||
watch(()=>props.data,val=>{
|
||||
nextTick(()=>{ init(val) })
|
||||
},{immediate:true,deep:true})
|
||||
|
||||
|
||||
// 初始化
|
||||
function init (val) {
|
||||
let color = val.color ? val.color : [];
|
||||
let list = val.list
|
||||
let total = 0
|
||||
let series = list.map((item ,idx)=>{
|
||||
let obj = {
|
||||
type: "bar",
|
||||
stack:'total',
|
||||
name:item.label,
|
||||
data:item.val,
|
||||
barGap:'80%',
|
||||
barWidth: "30px",
|
||||
}
|
||||
if(color.length > 0) obj.itemStyle = {normal: { color: color[idx] }}
|
||||
if(item.label == '总数'){
|
||||
obj.stack = ''
|
||||
obj.z = -1
|
||||
obj.barGap = '-100%'
|
||||
obj.label = { normal:{show:true,position:'top',color:'#EB00FF'} }
|
||||
}
|
||||
return obj;
|
||||
})
|
||||
chartFn(series)
|
||||
}
|
||||
|
||||
function chartFn(series) {
|
||||
var myChart = echarts.init(document.getElementById(props.echartsId));
|
||||
var option = {
|
||||
grid: {
|
||||
top: "30%",
|
||||
right: "2%",
|
||||
left: "2%",
|
||||
bottom: "3%",
|
||||
containLabel:true
|
||||
},
|
||||
legend:{
|
||||
data:props.data.list.map(v=>{return v.label}),
|
||||
textStyle: { color: "#fff"},
|
||||
icon:'diamond', //arrow,diamond,roundRect,rect,none,circle
|
||||
itemWidth:16,
|
||||
itemHeight:8,
|
||||
itemGap:10
|
||||
},
|
||||
tooltip: {
|
||||
trigger: "axis",
|
||||
axisPointer: {
|
||||
lineStyle: { color: "#ddd" }
|
||||
},
|
||||
backgroundColor: "rgba(255,255,255,1)",
|
||||
padding: [5, 10],
|
||||
textStyle: { color: "#7588E4" },
|
||||
extraCssText: "box-shadow: 0 0 5px rgba(0,0,0,0.3)"
|
||||
},
|
||||
xAxis: {
|
||||
type: "category",
|
||||
data:props.data.xData,
|
||||
axisTick: { show: false },
|
||||
axisLine: { show: false },
|
||||
axisLabel: { color: "#fff",magin:20 },
|
||||
},
|
||||
yAxis: {
|
||||
type: "value",
|
||||
splitLine: {
|
||||
show:true ,
|
||||
lineStyle: {
|
||||
type:'dashed',
|
||||
color: "rgba(14,95,255,0.5)"
|
||||
}
|
||||
},
|
||||
axisTick: { show: false },
|
||||
axisLine: { show: false },
|
||||
axisLabel: { color: "#fff" },
|
||||
},
|
||||
series:series
|
||||
};
|
||||
option && myChart.setOption(option);
|
||||
window.addEventListener('resize',function(){
|
||||
myChart.resize();
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
</style>
|
127
src/components/echarts/moreLineEcharts.vue
Normal file
127
src/components/echarts/moreLineEcharts.vue
Normal file
@ -0,0 +1,127 @@
|
||||
<template>
|
||||
<div style="height:100%;width:100%" :id="echartsId"></div>
|
||||
</template>
|
||||
<script setup>
|
||||
import * as echarts from "echarts";
|
||||
import { onMounted, ref, reactive, defineProps, onUnmounted, watch, nextTick } from "vue";
|
||||
|
||||
const props = defineProps({
|
||||
echartsId:{
|
||||
type:String,
|
||||
default:'morelineId'
|
||||
},
|
||||
smooth:{
|
||||
type:Boolean,
|
||||
default:false
|
||||
},
|
||||
data:{
|
||||
type:Object,
|
||||
default:{
|
||||
color:[], //['#EB00FF','#F57100']
|
||||
list:[], //[{label:'总数',val:[80,70,60,50]}, {label:'已处置',val:[70,40,30,80]}, ]
|
||||
xData:[] ,//['09-01','09-02','09-03','09-04']
|
||||
}
|
||||
}
|
||||
});
|
||||
watch(()=>props.data,val=>{
|
||||
nextTick(()=>{
|
||||
init(val)
|
||||
})
|
||||
},{immediate:true,deep:true})
|
||||
|
||||
|
||||
// 初始化
|
||||
function init (val) {
|
||||
let color = val.color;
|
||||
let list = val.list
|
||||
let series = list.map((item ,idx)=>{
|
||||
return {
|
||||
type: "line",
|
||||
name:item.label,
|
||||
data:item.val,
|
||||
itemStyle:{normal: { color: color[idx] }},
|
||||
smooth:props.smooth,
|
||||
showSymbol:false,
|
||||
areaStyle: {
|
||||
normal: {
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
|
||||
offset: 0,
|
||||
color: 'rgba(199, 237, 250,0.5)'
|
||||
}, {
|
||||
offset: 1,
|
||||
color: 'rgba(199, 237, 250,0.2)'
|
||||
}], false)
|
||||
}
|
||||
},
|
||||
}
|
||||
})
|
||||
chartFn(series)
|
||||
}
|
||||
|
||||
function chartFn(series) {
|
||||
var myChart = echarts.init(document.getElementById(props.echartsId));
|
||||
var option = {
|
||||
grid: {
|
||||
top: "20%",
|
||||
right: "6%",
|
||||
left: "2%",
|
||||
bottom: "3%",
|
||||
containLabel:true
|
||||
},
|
||||
legend:{
|
||||
data:props.data.list.map(v=>{return v.label}),
|
||||
textStyle: { color: "#333"},
|
||||
icon:'diamond', //arrow,diamond,roundRect,rect,none,circle
|
||||
itemWidth:16,
|
||||
itemHeight:8,
|
||||
itemGap:5
|
||||
},
|
||||
tooltip: {
|
||||
trigger: "axis",
|
||||
axisPointer: {
|
||||
lineStyle: { color: "#ddd" }
|
||||
},
|
||||
backgroundColor: "rgba(255,255,255,1)",
|
||||
padding: [5, 10],
|
||||
textStyle: { color: "#7588E4" },
|
||||
extraCssText: "box-shadow: 0 0 5px rgba(0,0,0,0.3)"
|
||||
},
|
||||
xAxis: {
|
||||
type: "category",
|
||||
data:props.data.xData,
|
||||
axisTick: { show: false },
|
||||
axisLine: { show: false },
|
||||
axisLabel: { color: "#fff" },
|
||||
axisLabel: {
|
||||
show: true,
|
||||
color: "#333",
|
||||
interval: 0, // 强制显示所有标签
|
||||
// rotate: 15, // 标签旋转角度
|
||||
// formatter: function(value) { return value.split("").join("\n");}
|
||||
}
|
||||
},
|
||||
yAxis: {
|
||||
type: "value",
|
||||
splitLine: {
|
||||
show:true ,
|
||||
lineStyle: {
|
||||
type:'dashed',
|
||||
color: "rgba(14,95,255,0.5)"
|
||||
}
|
||||
},
|
||||
axisTick: { show: false },
|
||||
axisLine: { show: false },
|
||||
axisLabel: { color: "#333" },
|
||||
},
|
||||
series:series
|
||||
};
|
||||
option && myChart.setOption(option);
|
||||
window.addEventListener('resize',function(){
|
||||
myChart.resize();
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
</style>
|
119
src/components/echarts/pieEcharts.vue
Normal file
119
src/components/echarts/pieEcharts.vue
Normal file
@ -0,0 +1,119 @@
|
||||
<template>
|
||||
<div style="height:100%;width:100%" :id="echartsId"></div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import * as echarts from "echarts";
|
||||
import "echarts-gl";
|
||||
import { ref, watch ,defineProps,nextTick } from "vue";
|
||||
const props = defineProps({
|
||||
echartsId:{
|
||||
type:String,
|
||||
default:'lineId'
|
||||
},
|
||||
color:{
|
||||
type:String,
|
||||
default:'lineId'
|
||||
},
|
||||
data:{
|
||||
type:Array,
|
||||
default:[]
|
||||
}
|
||||
});
|
||||
watch(()=>props.data,val=>{
|
||||
nextTick(()=>{ handleDate(val) })
|
||||
},{immediate:true,deep:true})
|
||||
|
||||
const handleDate = (val)=>{
|
||||
let newArray = val.map(v=>{
|
||||
let obj = {
|
||||
value: v.value,
|
||||
name: v.label,
|
||||
}
|
||||
if(v.color) obj.itemStyle = { color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ { offset: 0, color: v.color[0] }, { offset: 1, color: v.color[1] } ])}
|
||||
return obj
|
||||
})
|
||||
initChart(newArray)
|
||||
}
|
||||
|
||||
const initChart = (data) => {
|
||||
var myChart = echarts.init(document.getElementById(props.echartsId));
|
||||
const option = {
|
||||
backgroundColor: "transparent",
|
||||
tooltip: {
|
||||
trigger: "item",
|
||||
formatter: "{a} <br/>{b}: {c} ({d}%)",
|
||||
backgroundColor: "rgba(0,0,0,0.7)",
|
||||
borderColor: "#0C2E5A",
|
||||
textStyle: {
|
||||
color: "#fff"
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
top: "middle",
|
||||
right: "5%",
|
||||
orient: "vertical",
|
||||
itemGap: 20,
|
||||
textStyle: {
|
||||
color: props.color,
|
||||
fontSize: 14
|
||||
},
|
||||
itemWidth: 15,
|
||||
itemHeight: 15,
|
||||
icon: "roundRect",
|
||||
formatter: function (name) {
|
||||
const data = option.series[0].data;
|
||||
const target = data.find((item) => item.label === name);
|
||||
if (target) {
|
||||
return `${name} ${target.value} ${( (target.value / 50) * 100 ).toFixed(0)}%`;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: "情报反馈统计",
|
||||
type: "pie",
|
||||
radius: ["40%", "75%"],
|
||||
center: ["30%", "50%"],
|
||||
startAngle: 90,
|
||||
zlevel: 10,
|
||||
itemStyle: {},
|
||||
selectedMode: "single",
|
||||
selectedOffset: 30,
|
||||
animation: true,
|
||||
animationType: "scale",
|
||||
animationEasing: "elasticOut",
|
||||
label: { show: false },
|
||||
labelLine: { show: false },
|
||||
|
||||
data: data,
|
||||
zlevel: 10,
|
||||
emphasis: {
|
||||
scale: true,
|
||||
scaleSize: 10,
|
||||
itemStyle: {
|
||||
shadowBlur: 30,
|
||||
shadowColor: "rgba(0,0,0,0.6)"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
option && myChart.setOption(option);
|
||||
|
||||
// 监听窗口大小变化
|
||||
window.addEventListener("resize", () => {
|
||||
myChart.resize();
|
||||
});
|
||||
};
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.echartsBox {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
179
src/components/export/index.vue
Normal file
179
src/components/export/index.vue
Normal file
@ -0,0 +1,179 @@
|
||||
<template>
|
||||
<div class="exportBox">
|
||||
<el-dialog
|
||||
v-model="show"
|
||||
title="导入文件"
|
||||
width="400px"
|
||||
:show-close="true"
|
||||
:center="true"
|
||||
:before-close="handleClose"
|
||||
>
|
||||
<div class="uplodBox">
|
||||
<el-upload
|
||||
action="#"
|
||||
drag
|
||||
:on-success="handleSuccess"
|
||||
:on-change="handleChange"
|
||||
:show-file-list="true"
|
||||
:file-list="fileDate"
|
||||
accept=".xls,.xlsx"
|
||||
:auto-upload="false"
|
||||
>
|
||||
<el-icon class="el-icon-upload" size="100"><upload-filled /></el-icon>
|
||||
<div class="el-upload-text">
|
||||
拖动或者点击上传或者<span @click.stop="downloadModel" class="model">下载模板</span>
|
||||
</div>
|
||||
<div>仅支持扩展名:.xls , xlsx</div>
|
||||
</el-upload>
|
||||
</div>
|
||||
<div class="check">
|
||||
<el-checkbox true-label="true" false-label="false" v-model="isSelect"
|
||||
>是否替换已存在的数据</el-checkbox
|
||||
>
|
||||
</div>
|
||||
<div class="foot">
|
||||
<el-button @click="handleClose">取消</el-button>
|
||||
<el-button type="primary" @click="onComfirm">确认</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import axios from "axios";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { qcckPost, qcckGet } from "@/api/qcckApi.js";
|
||||
import { useStore } from "vuex";
|
||||
import { ref, defineProps, defineEmits, watch } from "vue";
|
||||
const store = useStore();
|
||||
const props = defineProps({
|
||||
show: { type: Boolean, default: false },
|
||||
lx:{ type: String, default:'policeF'}
|
||||
});
|
||||
const headers = ref({
|
||||
Authorization: "Bearer " + store.getters.token
|
||||
});
|
||||
const isSelect = ref(false);
|
||||
const emits = defineEmits(["closeImport", "handleImport"]);
|
||||
const fileDate = ref([]);
|
||||
const filesList = ref({});
|
||||
const baseUrl = ref('')//上传地址
|
||||
const modelUrl = ref('')//下载模板地址
|
||||
watch(()=>props.lx,(val)=>{
|
||||
let url = ''
|
||||
let moyRL = ''
|
||||
switch (val) {
|
||||
case 'policeF':
|
||||
baseUrl.value = '/mosty-api/mosty-jcgl/tbJcglXfll/importData'
|
||||
modelUrl.value = '/mosty-api/mosty-jcgl/tbJcglXfll/importTemplate'
|
||||
break;
|
||||
case 'car':
|
||||
baseUrl.value = '/mosty-api/mosty-jcgl/tpJcglXfcl/importData'
|
||||
modelUrl.value = '/mosty-api/mosty-jcgl/tpJcglXfcl/importTemplate'
|
||||
break;
|
||||
case 'jyqx':
|
||||
baseUrl.value = '/mosty-api/mosty-jcgl/tpJcglJyqx/importData'
|
||||
modelUrl.value = '/mosty-api/mosty-jcgl/tpJcglJyqx/importTemplate'
|
||||
break;
|
||||
case 'znzb':
|
||||
baseUrl.value = '/mosty-api/mosty-jcgl/tpjcglZnzb/importData'
|
||||
modelUrl.value = '/mosty-api/mosty-jcgl/tpjcglZnzb/importTemplate'
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
},{
|
||||
immediate:true
|
||||
})
|
||||
|
||||
// 关闭
|
||||
function handleClose() {
|
||||
fileDate.value = [];
|
||||
filesList.value = {};
|
||||
emits("closeImport");
|
||||
}
|
||||
|
||||
// 覆盖前一个文件
|
||||
function handleChange(file, fileList) {
|
||||
const fileSuffix = file.name.substring(file.name.lastIndexOf(".") + 1);
|
||||
let whiteList = ["xls", "xlsx"];
|
||||
if (!whiteList.includes(fileSuffix)) {
|
||||
fileList.splice(0, 1);
|
||||
filesList.value = {};
|
||||
ElMessage.warning("上传只能是.xls、.xlsx 格式,请重新上传");
|
||||
return false;
|
||||
} else {
|
||||
if (fileList.length > 1) {
|
||||
fileList.splice(0, 1);
|
||||
}
|
||||
filesList.value = file;
|
||||
}
|
||||
}
|
||||
// 上传成功
|
||||
function handleSuccess(row) {}
|
||||
// 下载模板
|
||||
function downloadModel() {
|
||||
window.open(modelUrl.value, "_self");
|
||||
}
|
||||
|
||||
// 确定上传
|
||||
function onComfirm() {
|
||||
if (filesList.value.length <= 0) {
|
||||
ElMessage.warning("请上传文件");
|
||||
} else {
|
||||
let file = filesList.value.raw;
|
||||
let formData = new FormData();
|
||||
formData.append("file", file);
|
||||
formData.append("updateSupport", isSelect.value);
|
||||
axios.post(baseUrl.value, formData, {"Content-type": "multipart/form-data"})
|
||||
.then((res) => {
|
||||
if (res.status == 200) {
|
||||
let { data, message, code } = res.data;
|
||||
if (code == -1) ElMessage({ type:'warning', message:message, dangerouslyUseHTMLString:true });
|
||||
if(code == 10000) ElMessage({ type:'success', message:data, dangerouslyUseHTMLString:true });
|
||||
emits("handleImport");
|
||||
handleClose();
|
||||
} else {
|
||||
ElMessage.warning("文件上传失败");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.exportBox {
|
||||
.uplodBox {
|
||||
width: 100%;
|
||||
.el-icon {
|
||||
font-size: 64px;
|
||||
color: #505050;
|
||||
}
|
||||
.el-icon-upload {
|
||||
top: 33px;
|
||||
}
|
||||
::v-deep .el-upload-dragger {
|
||||
line-height: 50px;
|
||||
}
|
||||
.el-upload-text {
|
||||
color: #505050;
|
||||
> .model {
|
||||
color: #409eff;
|
||||
}
|
||||
}
|
||||
}
|
||||
.foot {
|
||||
text-align: center;
|
||||
margin: 10px 0;
|
||||
}
|
||||
.check {
|
||||
height: 20px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
.el-upload-list__item-name {
|
||||
color: #fff;
|
||||
}
|
||||
</style>
|
340
src/components/loder/Jczloder.vue
Normal file
340
src/components/loder/Jczloder.vue
Normal file
@ -0,0 +1,340 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-dialog
|
||||
:title="titleValue"
|
||||
width="1400px"
|
||||
v-model="modelValue"
|
||||
@close="closed"
|
||||
>
|
||||
<div v-if="modelValue">
|
||||
<el-form :model="listQuery" class="mosty-from-wrap" :inline="true">
|
||||
<el-form-item label="所属部门">
|
||||
<MOSTY.Department
|
||||
width="100%"
|
||||
clearable
|
||||
v-model="listQuery.ssbmdm"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="检查站名称">
|
||||
<el-input
|
||||
v-model="listQuery.jczmc"
|
||||
placeholder="请输入检查站名称"
|
||||
clearable
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-button type="success" @click="handleFilter">查询</el-button>
|
||||
<el-button type="info" @click="reset()"> 重置 </el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div class="tabBox" style="margin-top: 0px" v-if="modelValue">
|
||||
<el-table
|
||||
ref="multipleUserRef"
|
||||
@selection-change="handleSelectionChange"
|
||||
:data="tableData"
|
||||
:highlight-current-row="props.Single"
|
||||
border
|
||||
v-loading="loading"
|
||||
style="width: 100%"
|
||||
:row-key="keyid"
|
||||
height="450"
|
||||
>
|
||||
<el-table-column
|
||||
type="selection"
|
||||
width="55"
|
||||
:reserve-selection="true"
|
||||
v-if="!props.Single"
|
||||
/>
|
||||
<el-table-column width="55" #default="{ row }" v-else>
|
||||
<el-radio v-model="ridioIndex" :label="row.id"></el-radio>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
label="序号"
|
||||
type="index"
|
||||
align="center"
|
||||
sortable
|
||||
width="80"
|
||||
/>
|
||||
<el-table-column
|
||||
sortable
|
||||
prop="ssbm"
|
||||
label="所属部门"
|
||||
show-overflow-tooltip
|
||||
align="center"
|
||||
></el-table-column>
|
||||
<el-table-column
|
||||
sortable
|
||||
prop="jczmc"
|
||||
show-overflow-tooltip
|
||||
align="center"
|
||||
label="检查站名称"
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
show-overflow-tooltip
|
||||
align="center"
|
||||
label="检查站类型"
|
||||
prop="jczlx"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<dict-tag
|
||||
:options="D_BZ_JCZLX"
|
||||
:value="row.jczlx"
|
||||
:tag="false"
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="xxdz"
|
||||
show-overflow-tooltip
|
||||
align="center"
|
||||
label="检查站地址"
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
sortable
|
||||
prop="jd"
|
||||
show-overflow-tooltip
|
||||
label="经度"
|
||||
align="center"
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
sortable
|
||||
prop="wd"
|
||||
show-overflow-tooltip
|
||||
label="纬度"
|
||||
align="center"
|
||||
>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<div class="fenye">
|
||||
<el-pagination
|
||||
class="pagination"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
:current-page="listQuery.pageCurrent"
|
||||
:page-sizes="[2, 5, 10, 20]"
|
||||
:page-size="listQuery.pageSize"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="total"
|
||||
></el-pagination>
|
||||
</div>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="closed">取消</el-button>
|
||||
<el-button type="primary" @click="onComfirm">确认</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import * as rule from "@/utils/rules.js";
|
||||
import * as MOSTY from "@/components/MyComponents/index";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { qcckGet, qcckPost } from "@/api/qcckApi.js";
|
||||
import {
|
||||
defineProps,
|
||||
watch,
|
||||
ref,
|
||||
onMounted,
|
||||
nextTick,
|
||||
getCurrentInstance
|
||||
} from "vue";
|
||||
const { proxy } = getCurrentInstance();
|
||||
const { D_BZ_JCZLX } = proxy.$dict("D_BZ_JCZLX");
|
||||
const props = defineProps({
|
||||
//是否显示
|
||||
modelValue: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
},
|
||||
//标题
|
||||
titleValue: {
|
||||
type: String,
|
||||
default: "选择检查站"
|
||||
},
|
||||
//是否单选
|
||||
Single: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
//已经选中得数据回显
|
||||
data: {
|
||||
type: Array,
|
||||
default: []
|
||||
}
|
||||
});
|
||||
const keyid = (row) => {
|
||||
return row.id;
|
||||
};
|
||||
const ridioIndex = ref(null);
|
||||
const total = ref(0);
|
||||
const listQuery = ref({
|
||||
pageCurrent: 1,
|
||||
pageSize: 20,
|
||||
jczmc: "",
|
||||
ssbmdm: ""
|
||||
});
|
||||
const tableData = ref([]);
|
||||
const loading = ref(false);
|
||||
const emits = defineEmits(["update:modelValue", "choosedJcz"]);
|
||||
const closed = () => {
|
||||
listQuery.value.jczmc = "";
|
||||
emits("update:modelValue", false);
|
||||
};
|
||||
const reset = () => {
|
||||
listQuery.value = {
|
||||
pageCurrent: 1,
|
||||
pageSize: 20,
|
||||
jczmc: "",
|
||||
ssbmdm: ""
|
||||
};
|
||||
getListData();
|
||||
};
|
||||
// 判断传进来的选中数据和加载的选中数据不满足的数据
|
||||
const checkopenList = ref([]);
|
||||
|
||||
// 确定选中
|
||||
const onComfirm = () => {
|
||||
//单选
|
||||
if (props.Single) {
|
||||
if (![ridioIndex.value][0]) {
|
||||
proxy.$message.warning("请选择检查站");
|
||||
return;
|
||||
}
|
||||
const info = tableData.value.find((item) => {
|
||||
return item.id === ridioIndex.value;
|
||||
});
|
||||
emits("choosedJcz", JSON.parse(JSON.stringify(info)));
|
||||
} else {
|
||||
//多选
|
||||
const jczList = JSON.parse(JSON.stringify(multipleSelectionUser.value));
|
||||
if (jczList.length === 0) {
|
||||
proxy.$message.warning("请选择检查站");
|
||||
return;
|
||||
}
|
||||
emits("choosedJcz", [...jczList, ...checkopenList.value]);
|
||||
}
|
||||
closed();
|
||||
};
|
||||
onMounted(() => {
|
||||
getListData();
|
||||
});
|
||||
/**
|
||||
* pageSize 改变触发
|
||||
*/
|
||||
const handleSizeChange = (currentSize) => {
|
||||
listQuery.value.pageSize = currentSize;
|
||||
getListData();
|
||||
};
|
||||
|
||||
/**
|
||||
* 页码改变触发
|
||||
*/
|
||||
const handleCurrentChange = (currentPage) => {
|
||||
listQuery.value.pageCurrent = currentPage;
|
||||
getListData();
|
||||
};
|
||||
//检查站数据
|
||||
const getListData = async () => {
|
||||
loading.value = true;
|
||||
qcckGet(listQuery.value, "/mosty-jcz/jcz/selectJczList")
|
||||
.then((res) => {
|
||||
tableData.value = res?.records;
|
||||
loading.value = false;
|
||||
multipleUser(props.data, tableData.value);
|
||||
total.value = Number(res.total);
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
const handleFilter = () => {
|
||||
listQuery.value.pageCurrent = 1;
|
||||
getListData();
|
||||
};
|
||||
|
||||
const multipleUserRef = ref(null);
|
||||
const multipleSelectionUser = ref([]);
|
||||
const handleSelectionChange = (val) => {
|
||||
multipleSelectionUser.value = val;
|
||||
if (checkopenList.value) {
|
||||
for (let i = 0; i < multipleSelectionUser.value.length; i++) {
|
||||
const l = multipleSelectionUser.value[i];
|
||||
for (let j = 0; j < checkopenList.value.length; j++) {
|
||||
const z = checkopenList.value[j];
|
||||
if (l.id == z.id) {
|
||||
checkopenList.value.splice(j, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
//回显--用于多选表格
|
||||
function multipleUser(row, list) {
|
||||
if (row) {
|
||||
if (props.Single) {
|
||||
row.forEach((item) => {
|
||||
list.forEach((select) => {
|
||||
if (typeof item == "object") {
|
||||
if (item.id == select.id) {
|
||||
ridioIndex.value = item.id;
|
||||
}
|
||||
} else {
|
||||
if (item == select.id) {
|
||||
ridioIndex.value = item;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
} else {
|
||||
row.forEach((item) => {
|
||||
list.forEach((select) => {
|
||||
if (item.id == select.id) {
|
||||
if (multipleUserRef.value) {
|
||||
multipleUserRef.value.toggleRowSelection(select, true);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(val) => {
|
||||
if (val === true) {
|
||||
ridioIndex.value = "";
|
||||
handleFilter();
|
||||
}
|
||||
}
|
||||
);
|
||||
watch(
|
||||
() => props.data,
|
||||
(val) => {
|
||||
if (multipleUserRef.value) multipleUser(val, tableData.value);
|
||||
checkopenList.value = JSON.parse(JSON.stringify(val));
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "@/assets/css/layout.scss";
|
||||
@import "@/assets/css/element-plus.scss";
|
||||
::v-deep .el-form--inline {
|
||||
padding-left: 0 !important;
|
||||
}
|
||||
::v-deep .el-radio__label {
|
||||
display: none;
|
||||
}
|
||||
|
||||
::v-deep .el-table__body tr.current-row > td.el-table__cell {
|
||||
// background: #106fdc;
|
||||
}
|
||||
</style>
|
Reference in New Issue
Block a user