lcw
This commit is contained in:
@ -7,9 +7,17 @@
|
|||||||
@close="closed"
|
@close="closed"
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<div class="flex" style="margin-bottom: 10px;">
|
<div class="mark-tabs">
|
||||||
<el-button :type="bqLb === '01' ? 'success' : 'info'" @click="qihuan('01')">标签大类</el-button>
|
<span class="label">标签类型:</span>
|
||||||
<el-button :type="bqLb === '02' ? 'success' : 'info'" @click="qihuan('02')"> 标签小类 </el-button>
|
<el-radio-group v-model="bqLx" @change="changeBqLx">
|
||||||
|
<el-radio-button label="02">行为标签</el-radio-button>
|
||||||
|
<el-radio-button label="01">身份标签</el-radio-button>
|
||||||
|
</el-radio-group>
|
||||||
|
<span class="label" style="margin-left: 20px;">类别:</span>
|
||||||
|
<el-radio-group v-model="bqLb" @change="qihuan">
|
||||||
|
<el-radio-button label="01">大类</el-radio-button>
|
||||||
|
<el-radio-button label="02">小类</el-radio-button>
|
||||||
|
</el-radio-group>
|
||||||
</div>
|
</div>
|
||||||
<el-form :model="listQuery" class="mosty-from-wrap" :inline="true">
|
<el-form :model="listQuery" class="mosty-from-wrap" :inline="true">
|
||||||
<el-form-item label="标签名称">
|
<el-form-item label="标签名称">
|
||||||
@ -83,7 +91,7 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { qcckGet } from "@/api/qcckApi.js";
|
import { qcckGet } from "@/api/qcckApi.js";
|
||||||
import { defineProps, ref, getCurrentInstance, watch } from "vue";
|
import { defineProps, ref, getCurrentInstance, watch, nextTick } from "vue";
|
||||||
const { proxy } = getCurrentInstance();
|
const { proxy } = getCurrentInstance();
|
||||||
const { D_GS_BQ_DJ, D_GS_SSYJ } = proxy.$dict("D_GS_BQ_DJ", "D_GS_SSYJ"); //获取字典数据
|
const { D_GS_BQ_DJ, D_GS_SSYJ } = proxy.$dict("D_GS_BQ_DJ", "D_GS_SSYJ"); //获取字典数据
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@ -107,6 +115,11 @@ const props = defineProps({
|
|||||||
roleIds: {
|
roleIds: {
|
||||||
type: Array,
|
type: Array,
|
||||||
default: []
|
default: []
|
||||||
|
},
|
||||||
|
// 标签类型:02-行为标签,01-身份标签
|
||||||
|
bqLx: {
|
||||||
|
type: String,
|
||||||
|
default: "02"
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
@ -120,6 +133,8 @@ const keyVal = ref();
|
|||||||
const multipleUserRef = ref(null);
|
const multipleUserRef = ref(null);
|
||||||
const multipleSelectionUser = ref([]);
|
const multipleSelectionUser = ref([]);
|
||||||
const tableData = ref([]);
|
const tableData = ref([]);
|
||||||
|
const bqLx = ref(props.bqLx);
|
||||||
|
const bqLb = ref("01");
|
||||||
const emits = defineEmits(["update:modelValue", "choosed"]);
|
const emits = defineEmits(["update:modelValue", "choosed"]);
|
||||||
const keyid = (row) => {
|
const keyid = (row) => {
|
||||||
return row.id;
|
return row.id;
|
||||||
@ -148,9 +163,9 @@ const onComfirm = () => {
|
|||||||
closed();
|
closed();
|
||||||
};
|
};
|
||||||
const qihuan = (val) => {
|
const qihuan = (val) => {
|
||||||
bqLb.value = val
|
listQuery.value.pageCurrent = 1;
|
||||||
getListData()
|
getListData();
|
||||||
}
|
};
|
||||||
/**
|
/**
|
||||||
* pageSize 改变触发
|
* pageSize 改变触发
|
||||||
*/
|
*/
|
||||||
@ -168,7 +183,7 @@ const handleCurrentChange = (currentPage) => {
|
|||||||
const getListData = () => {
|
const getListData = () => {
|
||||||
keyVal.value++;
|
keyVal.value++;
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
const params = { ...listQuery.value, bqLx: "02",bqLb:bqLb.value };
|
const params = { ...listQuery.value, bqLx: bqLx.value, bqLb: bqLb.value };
|
||||||
qcckGet(params, "/mosty-gsxt/tbGsxtBqgl/selectPage")
|
qcckGet(params, "/mosty-gsxt/tbGsxtBqgl/selectPage")
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
@ -183,23 +198,25 @@ const getListData = () => {
|
|||||||
|
|
||||||
//列表回显 - 优化版,确保已选择数据正确回显
|
//列表回显 - 优化版,确保已选择数据正确回显
|
||||||
function multipleUser() {
|
function multipleUser() {
|
||||||
if (!multipleUserRef.value || !tableData.value || tableData.value.length === 0) {
|
nextTick(() => {
|
||||||
return;
|
if (!multipleUserRef.value || !tableData.value || tableData.value.length === 0) {
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// 先清除所有选中状态
|
// 先清除所有选中状态
|
||||||
tableData.value.forEach((item) => {
|
|
||||||
multipleUserRef.value.toggleRowSelection(item, false);
|
|
||||||
});
|
|
||||||
|
|
||||||
// 再根据roleIds重新设置选中状态
|
|
||||||
if (props.roleIds && Array.isArray(props.roleIds) && props.roleIds.length > 0) {
|
|
||||||
tableData.value.forEach((item) => {
|
tableData.value.forEach((item) => {
|
||||||
if (props.roleIds.some((id) => id == item.id)) {
|
multipleUserRef.value.toggleRowSelection(item, false);
|
||||||
multipleUserRef.value.toggleRowSelection(item, true);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
// 再根据roleIds重新设置选中状态
|
||||||
|
if (props.roleIds && Array.isArray(props.roleIds) && props.roleIds.length > 0) {
|
||||||
|
tableData.value.forEach((item) => {
|
||||||
|
if (props.roleIds.some((id) => id == item.id)) {
|
||||||
|
multipleUserRef.value.toggleRowSelection(item, true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleFilter = () => {
|
const handleFilter = () => {
|
||||||
@ -218,7 +235,11 @@ const handleSelectionChange = (val) => {
|
|||||||
multipleSelectionUser.value = val;
|
multipleSelectionUser.value = val;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const bqLb=ref('01')
|
const changeBqLx = (val) => {
|
||||||
|
listQuery.value.pageCurrent = 1;
|
||||||
|
multipleUserRef.value?.clearSelection();
|
||||||
|
getListData();
|
||||||
|
};
|
||||||
// 监听弹窗打开状态,打开时重新加载数据
|
// 监听弹窗打开状态,打开时重新加载数据
|
||||||
watch(
|
watch(
|
||||||
() => props.modelValue,
|
() => props.modelValue,
|
||||||
@ -233,19 +254,40 @@ watch(
|
|||||||
// 监听roleIds变化,确保数据回显正确
|
// 监听roleIds变化,确保数据回显正确
|
||||||
watch(
|
watch(
|
||||||
() => props.roleIds,
|
() => props.roleIds,
|
||||||
(newRoleIds) => {
|
() => {
|
||||||
// 使用setTimeout确保在表格数据加载完成后再进行选择
|
nextTick(() => {
|
||||||
setTimeout(() => {
|
|
||||||
multipleUser();
|
multipleUser();
|
||||||
}, 100);
|
});
|
||||||
},
|
},
|
||||||
{ deep: true }
|
{ deep: true }
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// 监听外部传入的 bqLx 变化
|
||||||
|
watch(
|
||||||
|
() => props.bqLx,
|
||||||
|
(newVal) => {
|
||||||
|
bqLx.value = newVal;
|
||||||
|
}
|
||||||
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import "@/assets/css/layout.scss";
|
@import "@/assets/css/layout.scss";
|
||||||
@import "@/assets/css/element-plus.scss";
|
@import "@/assets/css/element-plus.scss";
|
||||||
|
|
||||||
|
.mark-tabs {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
padding: 10px 15px;
|
||||||
|
background: #f5f7fa;
|
||||||
|
border-radius: 6px;
|
||||||
|
|
||||||
|
.label {
|
||||||
|
font-weight: 500;
|
||||||
|
color: #606266;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
<style>
|
<style>
|
||||||
.tabBoxRadio .el-checkbox__inner {
|
.tabBoxRadio .el-checkbox__inner {
|
||||||
|
|||||||
@ -1,5 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="form-item-box" :class="props.showBtn ? 'showBtn-upload' : ''" :style="{ width: width }">
|
<div
|
||||||
|
class="form-item-box"
|
||||||
|
:class="props.showBtn ? 'showBtn-upload' : ''"
|
||||||
|
:style="{ width: width }"
|
||||||
|
>
|
||||||
<el-upload
|
<el-upload
|
||||||
v-bind="$attrs"
|
v-bind="$attrs"
|
||||||
:headers="headers"
|
:headers="headers"
|
||||||
@ -13,19 +17,33 @@
|
|||||||
:before-remove="beforeRemove"
|
:before-remove="beforeRemove"
|
||||||
:on-exceed="handleExceed"
|
:on-exceed="handleExceed"
|
||||||
:on-success="handlerSuccess"
|
:on-success="handlerSuccess"
|
||||||
:before-upload="beforeImgUpload">
|
:before-upload="beforeImgUpload"
|
||||||
|
>
|
||||||
<template #default>
|
<template #default>
|
||||||
<el-button v-if="props.showBtn" size="small" type="primary">上传文件</el-button>
|
<el-button v-if="props.showBtn" size="small" type="primary"
|
||||||
|
>上传文件</el-button
|
||||||
|
>
|
||||||
<el-icon v-else><Plus /></el-icon>
|
<el-icon v-else><Plus /></el-icon>
|
||||||
</template>
|
</template>
|
||||||
<template #file="{ file }" v-if="!props.showBtn">
|
<template #file="{ file }" v-if="!props.showBtn">
|
||||||
<div v-if="props.isImg">
|
<div v-if="props.isImg">
|
||||||
<img class="el-upload-list__item-thumbnail" :src="file.url || ''" alt="" />
|
<img
|
||||||
|
class="el-upload-list__item-thumbnail"
|
||||||
|
:src="file.url || ''"
|
||||||
|
alt=""
|
||||||
|
/>
|
||||||
<span class="el-upload-list__item-actions">
|
<span class="el-upload-list__item-actions">
|
||||||
<span class="el-upload-list__item-preview" @click="handlePictureCardPreview(file)">
|
<span
|
||||||
|
class="el-upload-list__item-preview"
|
||||||
|
@click="handlePictureCardPreview(file)"
|
||||||
|
>
|
||||||
<el-icon> <zoom-in /></el-icon>
|
<el-icon> <zoom-in /></el-icon>
|
||||||
</span>
|
</span>
|
||||||
<span v-if="!disabled" class="el-upload-list__item-delete" @click="handleRemove(file, fileList)">
|
<span
|
||||||
|
v-if="!disabled"
|
||||||
|
class="el-upload-list__item-delete"
|
||||||
|
@click="handleRemove(file, fileList)"
|
||||||
|
>
|
||||||
<el-icon><Delete /></el-icon>
|
<el-icon><Delete /></el-icon>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
@ -36,10 +54,18 @@
|
|||||||
<span class="file-name">{{ file.name }}</span>
|
<span class="file-name">{{ file.name }}</span>
|
||||||
</div>
|
</div>
|
||||||
<span class="el-upload-list__item-actions">
|
<span class="el-upload-list__item-actions">
|
||||||
<span v-if="!disabled" class="el-upload-list__item-delete" @click="handleDownload(file)">
|
<span
|
||||||
|
v-if="!disabled"
|
||||||
|
class="el-upload-list__item-delete"
|
||||||
|
@click="handleDownload(file)"
|
||||||
|
>
|
||||||
<el-icon><Download /></el-icon>
|
<el-icon><Download /></el-icon>
|
||||||
</span>
|
</span>
|
||||||
<span v-if="!disabled" class="el-upload-list__item-delete" @click="handleRemove(file, fileList)">
|
<span
|
||||||
|
v-if="!disabled"
|
||||||
|
class="el-upload-list__item-delete"
|
||||||
|
@click="handleRemove(file, fileList)"
|
||||||
|
>
|
||||||
<el-icon><Delete /></el-icon>
|
<el-icon><Delete /></el-icon>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
@ -54,7 +80,15 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { COMPONENT_WIDTH } from "@/constant";
|
import { COMPONENT_WIDTH } from "@/constant";
|
||||||
import { ref, defineProps, defineEmits, computed, watch, onMounted, onUnmounted } from "vue";
|
import {
|
||||||
|
ref,
|
||||||
|
defineProps,
|
||||||
|
defineEmits,
|
||||||
|
computed,
|
||||||
|
watch,
|
||||||
|
onMounted,
|
||||||
|
onUnmounted
|
||||||
|
} from "vue";
|
||||||
import { ElMessage } from "element-plus";
|
import { ElMessage } from "element-plus";
|
||||||
import { useStore } from "vuex";
|
import { useStore } from "vuex";
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@ -98,35 +132,41 @@ const headers = ref({
|
|||||||
});
|
});
|
||||||
const fileList = ref([]);
|
const fileList = ref([]);
|
||||||
|
|
||||||
watch(() => props.modelValue,(val) => {
|
watch(
|
||||||
let arr = val ? (Array.isArray(val) ? val :[val]): [];
|
() => props.modelValue,
|
||||||
if(arr.length == 0 ) return fileList.value = [];
|
(val) => {
|
||||||
fileList.value = arr.map((el) => {
|
let arr = val ? (Array.isArray(val) ? val : [val]) : [];
|
||||||
if (Object.prototype.toString.call(el) === "[object Object]") {
|
if (arr.length == 0) return (fileList.value = []);
|
||||||
// 确保file.url始终是字符串URL
|
fileList.value = arr.map((el) => {
|
||||||
const fileUrl = props.isAll ? `/mosty-api/mosty-base/minio/image/download/` + el.id : el.url;
|
if (Object.prototype.toString.call(el) === "[object Object]") {
|
||||||
return {
|
// 确保file.url始终是字符串URL
|
||||||
...el,
|
const fileUrl = props.isAll
|
||||||
url: String(fileUrl || ''),
|
? `/mosty-api/mosty-base/minio/image/download/` + el.id
|
||||||
name: el.name || '',
|
: el.url;
|
||||||
|
return {
|
||||||
};
|
...el,
|
||||||
} else {
|
url: String(fileUrl || ""),
|
||||||
return {
|
name: el.name || ""
|
||||||
url: String(`/mosty-api/mosty-base/minio/image/download/` + el || ''),
|
};
|
||||||
id: el
|
} else {
|
||||||
};
|
return {
|
||||||
}
|
url: String(`/mosty-api/mosty-base/minio/image/download/` + el || ""),
|
||||||
});
|
id: el
|
||||||
console.log(fileList.value, "fileList.value");
|
};
|
||||||
|
}
|
||||||
},{ immediate: true,deep:true });
|
});
|
||||||
|
console.log(fileList.value, "fileList.value");
|
||||||
|
},
|
||||||
|
{ immediate: true, deep: true }
|
||||||
|
);
|
||||||
|
|
||||||
const actionUrl = computed(() => {
|
const actionUrl = computed(() => {
|
||||||
if (props.isAll) {
|
if (props.isAll) {
|
||||||
return "/mosty-api/mosty-base/minio/image/upload/id";
|
return "/mosty-api/mosty-base/minio/image/upload/id";
|
||||||
} else {
|
} else {
|
||||||
return props.isImg ? "/mosty-api/mosty-base/minio/image/upload/id": "/mosty-api/mosty-base/minio/file/uploadObj";
|
return props.isImg
|
||||||
|
? "/mosty-api/mosty-base/minio/image/upload/id"
|
||||||
|
: "/mosty-api/mosty-base/minio/file/uploadObj";
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -158,7 +198,17 @@ const getSuffix = (fileName) => {
|
|||||||
//pdf
|
//pdf
|
||||||
if (suffix === "pdf") return "PDF";
|
if (suffix === "pdf") return "PDF";
|
||||||
//视频 音频
|
//视频 音频
|
||||||
var videolist = ["mp4","m2v","mkv","rmvb","wmv","avi","flv","mov","m4v"];
|
var videolist = [
|
||||||
|
"mp4",
|
||||||
|
"m2v",
|
||||||
|
"mkv",
|
||||||
|
"rmvb",
|
||||||
|
"wmv",
|
||||||
|
"avi",
|
||||||
|
"flv",
|
||||||
|
"mov",
|
||||||
|
"m4v"
|
||||||
|
];
|
||||||
if (videolist.includes(suffix)) return "VIDEO";
|
if (videolist.includes(suffix)) return "VIDEO";
|
||||||
var musiclist = ["mp3", "wav", "wmv"];
|
var musiclist = ["mp3", "wav", "wmv"];
|
||||||
if (musiclist.includes(suffix)) return "MUSIC";
|
if (musiclist.includes(suffix)) return "MUSIC";
|
||||||
@ -177,19 +227,19 @@ const handlerSuccess = (res, file) => {
|
|||||||
file.url = `/mosty-api/mosty-base/minio/image/download/` + res.data;
|
file.url = `/mosty-api/mosty-base/minio/image/download/` + res.data;
|
||||||
file.id = res.data;
|
file.id = res.data;
|
||||||
fileList.value.push(file);
|
fileList.value.push(file);
|
||||||
let arr = []
|
let arr = [];
|
||||||
if(props.isImg){
|
if (props.isImg) {
|
||||||
arr = fileList.value.map((el) => el.id)
|
arr = fileList.value.map((el) => el.id);
|
||||||
} else {
|
} else {
|
||||||
console.log(fileList,"测试");
|
console.log(fileList, "测试");
|
||||||
arr = fileList.value.map((el) => {
|
arr = fileList.value.map((el) => {
|
||||||
console.log(el,'xunhuan');
|
console.log(el, "xunhuan");
|
||||||
return {
|
return {
|
||||||
id: el.id, name: el.name
|
id: el.id,
|
||||||
}
|
name: el.name
|
||||||
})
|
};
|
||||||
console.log(arr,"测试2222");
|
});
|
||||||
|
console.log(arr, "测试2222");
|
||||||
}
|
}
|
||||||
emits("update:modelValue", arr);
|
emits("update:modelValue", arr);
|
||||||
};
|
};
|
||||||
@ -201,7 +251,7 @@ const handleExceed = (files, fileList) => {
|
|||||||
const beforeImgUpload = (file) => {
|
const beforeImgUpload = (file) => {
|
||||||
if (props.isImg) {
|
if (props.isImg) {
|
||||||
let isIMG = false;
|
let isIMG = false;
|
||||||
if (getSuffix(file.name) === "IMG") isIMG = true;
|
if (getSuffix(file.name) === "IMG") isIMG = true;
|
||||||
const isLt5M = file.size / 1024 / 1024 < 5;
|
const isLt5M = file.size / 1024 / 1024 < 5;
|
||||||
if (!isIMG) ElMessage.error("上传图片只能是jpg/png/jpeg/bmp/gif格式!");
|
if (!isIMG) ElMessage.error("上传图片只能是jpg/png/jpeg/bmp/gif格式!");
|
||||||
if (!isLt5M) ElMessage.error("上传图片大小不能超过 5MB!");
|
if (!isLt5M) ElMessage.error("上传图片大小不能超过 5MB!");
|
||||||
@ -212,7 +262,7 @@ const beforeImgUpload = (file) => {
|
|||||||
};
|
};
|
||||||
//查询图片
|
//查询图片
|
||||||
const handlePictureCardPreview = (file) => {
|
const handlePictureCardPreview = (file) => {
|
||||||
dialogImageUrl.value = file.url || '';
|
dialogImageUrl.value = file.url || "";
|
||||||
dialogVisible.value = true;
|
dialogVisible.value = true;
|
||||||
};
|
};
|
||||||
function downloadFile(url, filename) {
|
function downloadFile(url, filename) {
|
||||||
@ -247,7 +297,7 @@ const beforeRemove = (file) => {
|
|||||||
});
|
});
|
||||||
props.modelValue.splice(index, 1);
|
props.modelValue.splice(index, 1);
|
||||||
emits("update:modelValue", props.modelValue);
|
emits("update:modelValue", props.modelValue);
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleRemove = (file) => {
|
const handleRemove = (file) => {
|
||||||
let index = fileList.value.findIndex(function (item) {
|
let index = fileList.value.findIndex(function (item) {
|
||||||
@ -257,7 +307,6 @@ const handleRemove = (file) => {
|
|||||||
props.modelValue.splice(index, 1);
|
props.modelValue.splice(index, 1);
|
||||||
emits("update:modelValue", props.modelValue);
|
emits("update:modelValue", props.modelValue);
|
||||||
};
|
};
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
import { ref, toRefs, isRef } from 'vue';
|
import { ref, toRefs, isRef } from "vue";
|
||||||
import { getSysDictByCode, fzdict } from '@/api/sysDict' //引入封装数字字典接口
|
import { getSysDictByCode, fzdict } from "@/api/sysDict"; //引入封装数字字典接口
|
||||||
|
|
||||||
import { getLocalDic } from "@/utils/localDic/index.js"
|
import { getLocalDic } from "@/utils/localDic/index.js";
|
||||||
/**
|
/**
|
||||||
* 获取字典数据
|
* 获取字典数据
|
||||||
*/
|
*/
|
||||||
let list = []
|
let list = [];
|
||||||
/** 是否取本地字典 (需要本地加载就加这里,不需要就删除) */
|
/** 是否取本地字典 (需要本地加载就加这里,不需要就删除) */
|
||||||
export function isLocalDict(dictCode) {
|
export function isLocalDict(dictCode) {
|
||||||
let localDicObj = {
|
let localDicObj = {
|
||||||
@ -15,9 +15,9 @@ export function isLocalDict(dictCode) {
|
|||||||
D_GS_SSYJ: true, // "岗哨系统四色预警"
|
D_GS_SSYJ: true, // "岗哨系统四色预警"
|
||||||
D_BZ_SF: true, // "是否"
|
D_BZ_SF: true, // "是否"
|
||||||
BD_BK_CLYJBQ: true, // "车辆预警标签"
|
BD_BK_CLYJBQ: true, // "车辆预警标签"
|
||||||
D_YJXX_CZCSLX: true, //常控处置措施类型
|
D_YJXX_CZCSLX: true //常控处置措施类型
|
||||||
}
|
};
|
||||||
return localDicObj[dictCode]
|
return localDicObj[dictCode];
|
||||||
}
|
}
|
||||||
export function getDict(...args) {
|
export function getDict(...args) {
|
||||||
const res = ref({});
|
const res = ref({});
|
||||||
@ -26,32 +26,32 @@ export function getDict(...args) {
|
|||||||
res.value[d] = [];
|
res.value[d] = [];
|
||||||
// 本地字典拦截,如果本地字典存在,则使用本地字典,否则使用远程字典
|
// 本地字典拦截,如果本地字典存在,则使用本地字典,否则使用远程字典
|
||||||
if (isLocalDict(d) && getLocalDic(d)) {
|
if (isLocalDict(d) && getLocalDic(d)) {
|
||||||
res.value[d] = getLocalDic(d)
|
res.value[d] = getLocalDic(d);
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
getSysDictByCode({
|
getSysDictByCode({
|
||||||
dictCode: d
|
dictCode: d
|
||||||
}).then(result => {
|
}).then((result) => {
|
||||||
result = result || {}
|
result = result || {};
|
||||||
result.itemList = Array.isArray(result.itemList) ? result.itemList : []
|
result.itemList = Array.isArray(result.itemList)
|
||||||
result.itemList.forEach(p => {
|
? result.itemList
|
||||||
p.label = p.zdmc
|
: [];
|
||||||
p.value = p.dm
|
result.itemList.forEach((p) => {
|
||||||
p.id = p.dm
|
p.label = p.zdmc;
|
||||||
p.elTagType = p.dictType
|
p.value = p.dm;
|
||||||
|
p.id = p.dm;
|
||||||
|
p.elTagType = p.dictType;
|
||||||
if (p?.itemList && p.itemList?.length > 0) {
|
if (p?.itemList && p.itemList?.length > 0) {
|
||||||
getChildren(p)
|
getChildren(p);
|
||||||
}
|
}
|
||||||
p.children = p.itemList
|
p.children = p.itemList;
|
||||||
})
|
});
|
||||||
res.value[d] = result.itemList
|
res.value[d] = result.itemList;
|
||||||
//
|
//
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
});
|
||||||
})
|
|
||||||
return toRefs(res.value);
|
return toRefs(res.value);
|
||||||
})()
|
})();
|
||||||
}
|
}
|
||||||
export function getFzDict(...args) {
|
export function getFzDict(...args) {
|
||||||
const res = ref({});
|
const res = ref({});
|
||||||
@ -64,7 +64,7 @@ export function getFzDict(...args) {
|
|||||||
} else {
|
} else {
|
||||||
fzdict({
|
fzdict({
|
||||||
dictLabel: d
|
dictLabel: d
|
||||||
}).then(result => {
|
}).then((result) => {
|
||||||
result = result || {};
|
result = result || {};
|
||||||
// result.itemList = Array.isArray(result.itemList) ? result.itemList : [];
|
// result.itemList = Array.isArray(result.itemList) ? result.itemList : [];
|
||||||
// result.itemList.forEach(p => {
|
// result.itemList.forEach(p => {
|
||||||
@ -79,26 +79,25 @@ export function getFzDict(...args) {
|
|||||||
// });
|
// });
|
||||||
// console.log(res.value);
|
// console.log(res.value);
|
||||||
|
|
||||||
res.value[d] = result
|
res.value[d] = result;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 使用toRefs确保返回的是响应式对象
|
// 使用toRefs确保返回的是响应式对象
|
||||||
return toRefs(res.value);
|
return toRefs(res.value);
|
||||||
})()
|
})();
|
||||||
|
|
||||||
}
|
}
|
||||||
export function getChildren(item) {
|
export function getChildren(item) {
|
||||||
item.label = item.zdmc
|
item.label = item.zdmc;
|
||||||
item.value = item.dm
|
item.value = item.dm;
|
||||||
item.id = item.dm
|
item.id = item.dm;
|
||||||
if (item.itemList && item.itemList.length > 0) {
|
if (item.itemList && item.itemList.length > 0) {
|
||||||
item.itemList.forEach(v => {
|
item.itemList.forEach((v) => {
|
||||||
getChildren(v)
|
getChildren(v);
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
item.children = item.itemList
|
item.children = item.itemList;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* 设置级联选择器回显
|
* 设置级联选择器回显
|
||||||
@ -106,17 +105,17 @@ export function getChildren(item) {
|
|||||||
* @param {*} array 级联数据树
|
* @param {*} array 级联数据树
|
||||||
* @param {*} childDeptList 子集变量
|
* @param {*} childDeptList 子集变量
|
||||||
*/
|
*/
|
||||||
export function setCascader(id, array, childDeptList = 'childDeptList', fun) {
|
export function setCascader(id, array, childDeptList = "childDeptList", fun) {
|
||||||
if (array) {
|
if (array) {
|
||||||
array.forEach(item => {
|
array.forEach((item) => {
|
||||||
if (item.childDeptList && item.id != id) {
|
if (item.childDeptList && item.id != id) {
|
||||||
setCascader(id, item.childDeptList, childDeptList, fun)
|
setCascader(id, item.childDeptList, childDeptList, fun);
|
||||||
} else if (item.childDeptList && item.id == id) {
|
} else if (item.childDeptList && item.id == id) {
|
||||||
fun(item)
|
fun(item);
|
||||||
} else if (!item.childDeptList && item.id == id) {
|
} else if (!item.childDeptList && item.id == id) {
|
||||||
fun(item)
|
fun(item);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@ -127,58 +126,64 @@ export function setCascader(id, array, childDeptList = 'childDeptList', fun) {
|
|||||||
*/
|
*/
|
||||||
export function IdCard(IdCard, type) {
|
export function IdCard(IdCard, type) {
|
||||||
let user = {
|
let user = {
|
||||||
birthday: '',
|
birthday: "",
|
||||||
sex: '',
|
sex: "",
|
||||||
age: ''
|
age: ""
|
||||||
}
|
};
|
||||||
if (type === 1 || type == 'all') {
|
if (type === 1 || type == "all") {
|
||||||
//获取出生日期
|
//获取出生日期
|
||||||
let birthday = IdCard.substring(6, 10) + "-" + IdCard.substring(10, 12) + "-" + IdCard.substring(12, 14)
|
let birthday =
|
||||||
if (type == 'all') {
|
IdCard.substring(6, 10) +
|
||||||
user.birthday = birthday
|
"-" +
|
||||||
|
IdCard.substring(10, 12) +
|
||||||
|
"-" +
|
||||||
|
IdCard.substring(12, 14);
|
||||||
|
if (type == "all") {
|
||||||
|
user.birthday = birthday;
|
||||||
} else {
|
} else {
|
||||||
return birthday
|
return birthday;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (type === 2 || type == 'all') {
|
if (type === 2 || type == "all") {
|
||||||
//获取性别
|
//获取性别
|
||||||
if (parseInt(IdCard.substr(16, 1)) % 2 === 1) {
|
if (parseInt(IdCard.substr(16, 1)) % 2 === 1) {
|
||||||
if (type == 'all') {
|
if (type == "all") {
|
||||||
user.sex = '男'
|
user.sex = "男";
|
||||||
} else {
|
} else {
|
||||||
return "男女"
|
return "男";
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (type == 'all') {
|
if (type == "all") {
|
||||||
user.sex = '女'
|
user.sex = "女";
|
||||||
} else {
|
} else {
|
||||||
return "女"
|
return "女";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (type === 3 || type == 'all') {
|
if (type === 3 || type == "all") {
|
||||||
//获取年龄
|
//获取年龄
|
||||||
var ageDate = new Date()
|
var ageDate = new Date();
|
||||||
var month = ageDate.getMonth() + 1
|
var month = ageDate.getMonth() + 1;
|
||||||
var day = ageDate.getDate()
|
var day = ageDate.getDate();
|
||||||
var age = ageDate.getFullYear() - IdCard.substring(6, 10) - 1
|
var age = ageDate.getFullYear() - IdCard.substring(6, 10) - 1;
|
||||||
if (IdCard.substring(10, 12) < month || IdCard.substring(10, 12) === month && IdCard.substring(12, 14) <= day) {
|
if (
|
||||||
age++
|
IdCard.substring(10, 12) < month ||
|
||||||
|
(IdCard.substring(10, 12) === month && IdCard.substring(12, 14) <= day)
|
||||||
|
) {
|
||||||
|
age++;
|
||||||
}
|
}
|
||||||
if (age <= 0) {
|
if (age <= 0) {
|
||||||
age = 1
|
age = 1;
|
||||||
}
|
}
|
||||||
if (type == 'all') {
|
if (type == "all") {
|
||||||
user.age = age
|
user.age = age;
|
||||||
} else {
|
} else {
|
||||||
return age
|
return age;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return user
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*翻译字典数据
|
*翻译字典数据
|
||||||
* @export
|
* @export
|
||||||
@ -186,14 +191,14 @@ export function IdCard(IdCard, type) {
|
|||||||
* @param {*} array
|
* @param {*} array
|
||||||
*/
|
*/
|
||||||
export function getDictValue(dm, array) {
|
export function getDictValue(dm, array) {
|
||||||
let item = array.value.find(item => {
|
let item = array.value.find((item) => {
|
||||||
if (item.value) {
|
if (item.value) {
|
||||||
return item.value == dm;
|
return item.value == dm;
|
||||||
} else if (item.dm) {
|
} else if (item.dm) {
|
||||||
return item.dm == dm;
|
return item.dm == dm;
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
return item ? item.label : ""
|
return item ? item.label : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 获取多个字典值(一个值也可以) 字典内容 value-label
|
/** 获取多个字典值(一个值也可以) 字典内容 value-label
|
||||||
@ -201,15 +206,15 @@ export function getDictValue(dm, array) {
|
|||||||
* @param {Array} dict 字典内容
|
* @param {Array} dict 字典内容
|
||||||
*/
|
*/
|
||||||
export function getMultiDictVal(values, dict) {
|
export function getMultiDictVal(values, dict) {
|
||||||
if (typeof values === 'string' && values?.length) values = values.split(',')
|
if (typeof values === "string" && values?.length) values = values.split(",");
|
||||||
if (!Array.isArray(values)) return ''
|
if (!Array.isArray(values)) return "";
|
||||||
if (isRef(dict)) dict = dict.value
|
if (isRef(dict)) dict = dict.value;
|
||||||
if (!Array.isArray(dict)) return ''
|
if (!Array.isArray(dict)) return "";
|
||||||
|
|
||||||
return values.map(v => {
|
return values
|
||||||
const item = dict.find(item => item.value === v);
|
.map((v) => {
|
||||||
return item ? item.label : v;
|
const item = dict.find((item) => item.value === v);
|
||||||
}).join(',');
|
return item ? item.label : v;
|
||||||
|
})
|
||||||
|
.join(",");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -13,13 +13,24 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 表格 -->
|
<!-- 表格 -->
|
||||||
<div class="margTop" style="padding: 0;">
|
<div class="margTop" style="padding: 0">
|
||||||
<WarnDataTable :data="pageData.tableData" :columns="pageData.tableColumn" :tableHeight="pageData.tableHeight"
|
<WarnDataTable
|
||||||
:loading="pageData.tableConfiger.loading" @selection-change="chooseData">
|
:data="pageData.tableData"
|
||||||
|
:columns="pageData.tableColumn"
|
||||||
|
:tableHeight="pageData.tableHeight"
|
||||||
|
:loading="pageData.tableConfiger.loading"
|
||||||
|
@selection-change="chooseData"
|
||||||
|
>
|
||||||
<template #bqList="{ row }">
|
<template #bqList="{ row }">
|
||||||
<ul>
|
<ul>
|
||||||
<li class="one_text_detail marks mb4" :key="index" v-for="(item, index) in row.bqList">{{ item.bqMc }}({{
|
<li
|
||||||
item.bqFz || 0 }} 分) </li>
|
:style="{ background: Bqys(item.bqYs) }"
|
||||||
|
class="one_text_detail marks mb4"
|
||||||
|
:key="index"
|
||||||
|
v-for="(item, index) in row.bqList"
|
||||||
|
>
|
||||||
|
{{ item.bqMc }}({{ item.bqFz || 0 }} 分)
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</template>
|
</template>
|
||||||
<template #ryXb="{ row }">
|
<template #ryXb="{ row }">
|
||||||
@ -48,35 +59,93 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #xtSjzt="{ row }">
|
<template #xtSjzt="{ row }">
|
||||||
<div> {{ row.xtSjzt == 0 ? "注销" : row.xtSjzt == 1 ? "正常" : "封存" }}</div>
|
<div>
|
||||||
|
{{ row.xtSjzt == 0 ? "注销" : row.xtSjzt == 1 ? "正常" : "封存" }}
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- 操作 -->
|
<!-- 操作 -->
|
||||||
<template #controls="{ row }">
|
<template #controls="{ row }">
|
||||||
<!-- <el-link size="small" type="success" @click="handleremove(row.id)">移至关注库</el-link> -->
|
<!-- <el-link size="small" type="success" @click="handleremove(row.id)">移至关注库</el-link> -->
|
||||||
<el-link size="small" type="success" @click="handleMoveToFocus(row.id)">移入关注库</el-link>
|
<el-link
|
||||||
<el-link size="small" type="success" @click="handleremove(row.id)">移入基础库</el-link>
|
size="small"
|
||||||
<el-link size="small" type="success" v-if="row.zdrZt == '01' || row.zdrZt == '03'"
|
type="success"
|
||||||
@click="handleSend(row.id)">送审</el-link>
|
@click="handleMoveToFocus(row.id)"
|
||||||
<el-link size="small" type="primary" v-if="row.zdrZt == '01' || row.zdrZt == '03'"
|
>移入关注库</el-link
|
||||||
@click="addEdit('edit', row)">编辑</el-link>
|
>
|
||||||
<el-link size="small" type="primary" @click="addEdit('detail', row)">详情</el-link>
|
<el-link size="small" type="success" @click="handleremove(row.id)"
|
||||||
<el-link size="small" type="danger" @click="deleteRow(row.id)">删除</el-link>
|
>移入基础库</el-link
|
||||||
|
>
|
||||||
|
<el-link
|
||||||
|
size="small"
|
||||||
|
type="success"
|
||||||
|
v-if="row.zdrZt == '01' || row.zdrZt == '03'"
|
||||||
|
@click="handleSend(row.id)"
|
||||||
|
>送审</el-link
|
||||||
|
>
|
||||||
|
<el-link
|
||||||
|
size="small"
|
||||||
|
type="primary"
|
||||||
|
v-if="row.zdrZt == '01' || row.zdrZt == '03'"
|
||||||
|
@click="addEdit('edit', row)"
|
||||||
|
>编辑</el-link
|
||||||
|
>
|
||||||
|
<el-link size="small" type="primary" @click="addEdit('detail', row)"
|
||||||
|
>详情</el-link
|
||||||
|
>
|
||||||
|
<el-link size="small" type="danger" @click="deleteRow(row.id)"
|
||||||
|
>删除</el-link
|
||||||
|
>
|
||||||
</template>
|
</template>
|
||||||
</WarnDataTable>
|
</WarnDataTable>
|
||||||
<Pages @changeNo="changeNo" @changeSize="changeSize" :tableHeight="pageData.tableHeight" :pageConfiger="{
|
<Pages
|
||||||
...pageData.pageConfiger,
|
@changeNo="changeNo"
|
||||||
total: pageData.total
|
@changeSize="changeSize"
|
||||||
}"></Pages>
|
:tableHeight="pageData.tableHeight"
|
||||||
|
:pageConfiger="{
|
||||||
|
...pageData.pageConfiger,
|
||||||
|
total: pageData.total
|
||||||
|
}"
|
||||||
|
></Pages>
|
||||||
</div>
|
</div>
|
||||||
<!-- 详情 -->
|
<!-- 详情 -->
|
||||||
<AddForm ref="addFormDiloag" @updateDate="getList"
|
<AddForm
|
||||||
:dic="{ D_GS_ZDR_RYJB, D_BZ_XB, D_BZ_MZ, D_BZ_XZQHDM, D_ZDRGK_GKZT, D_GS_ZDR_CZZT, D_GS_BQ_ZL, D_GS_BQ_LB, D_GS_BQ_LX, D_GS_ZDR_YJDJ, D_GS_BK_SSJZ }" />
|
ref="addFormDiloag"
|
||||||
|
@updateDate="getList"
|
||||||
|
:dic="{
|
||||||
|
D_GS_ZDR_RYJB,
|
||||||
|
D_BZ_XB,
|
||||||
|
D_BZ_MZ,
|
||||||
|
D_BZ_XZQHDM,
|
||||||
|
D_ZDRGK_GKZT,
|
||||||
|
D_GS_ZDR_CZZT,
|
||||||
|
D_GS_BQ_ZL,
|
||||||
|
D_GS_BQ_LB,
|
||||||
|
D_GS_BQ_LX,
|
||||||
|
D_GS_ZDR_YJDJ,
|
||||||
|
D_GS_BK_SSJZ
|
||||||
|
}"
|
||||||
|
/>
|
||||||
<!-- 选择用户 -->
|
<!-- 选择用户 -->
|
||||||
<ChooseUser v-model="chooseUserVisible" @choosedUsers="handleUserSelected" :roleIds="roleIds" />
|
<ChooseUser
|
||||||
|
v-model="chooseUserVisible"
|
||||||
|
@choosedUsers="handleUserSelected"
|
||||||
|
:roleIds="roleIds"
|
||||||
|
/>
|
||||||
<!-- 转线索 -->
|
<!-- 转线索 -->
|
||||||
<ZxsForm v-if="showzxs" ref="zxsDilof" @change="getList"
|
<ZxsForm
|
||||||
:dic="{ D_BZ_SF, D_BZ_XB, D_GS_XS_LY, D_BZ_SSZT, D_GS_XS_LX, D_GS_XS_QTLX }"></ZxsForm>
|
v-if="showzxs"
|
||||||
|
ref="zxsDilof"
|
||||||
|
@change="getList"
|
||||||
|
:dic="{
|
||||||
|
D_BZ_SF,
|
||||||
|
D_BZ_XB,
|
||||||
|
D_GS_XS_LY,
|
||||||
|
D_BZ_SSZT,
|
||||||
|
D_GS_XS_LX,
|
||||||
|
D_GS_XS_QTLX
|
||||||
|
}"
|
||||||
|
></ZxsForm>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -91,13 +160,52 @@ import Search from "@/components/aboutTable/Search.vue";
|
|||||||
import AddForm from "./components/addForm.vue";
|
import AddForm from "./components/addForm.vue";
|
||||||
import { qcckGet, qcckPost, qcckDelete } from "@/api/qcckApi.js";
|
import { qcckGet, qcckPost, qcckDelete } from "@/api/qcckApi.js";
|
||||||
import { reactive, ref, onMounted, getCurrentInstance, nextTick } from "vue";
|
import { reactive, ref, onMounted, getCurrentInstance, nextTick } from "vue";
|
||||||
import { useRouter, useRoute } from 'vue-router'
|
import { useRouter, useRoute } from "vue-router";
|
||||||
import { getItem } from "@/utils/storage.js";
|
import { getItem } from "@/utils/storage.js";
|
||||||
const router = useRouter()
|
const router = useRouter();
|
||||||
const route = useRoute()
|
const route = useRoute();
|
||||||
const { proxy } = getCurrentInstance();
|
const { proxy } = getCurrentInstance();
|
||||||
const { D_GS_ZDQT_ZT, D_GS_ZDR_RYJB, D_BZ_XB, D_BZ_MZ, D_BZ_RCBKZT, D_BZ_XZQHDM, D_ZDRGK_GKZT, D_GS_ZDR_CZZT, D_GS_BQ_ZL, D_GS_BQ_LB, D_GS_BQ_LX, D_GS_ZDR_YJDJ, D_GS_BK_SSJZ, D_GS_BK_SQLX, D_BZ_SF, D_GS_XS_LY, D_BZ_SSZT, D_GS_XS_LX, D_GS_XS_QTLX } =
|
const {
|
||||||
proxy.$dict("D_GS_ZDQT_ZT", "D_BZ_RCBKZT", "D_GS_ZDR_RYJB", "D_BZ_XB", "D_BZ_MZ", "D_BZ_XZQHDM", "D_ZDRGK_GKZT", "D_GS_ZDR_CZZT", "D_GS_BQ_ZL", "D_GS_BQ_LB", "D_GS_BQ_LX", "D_GS_ZDR_YJDJ", "D_GS_BK_SSJZ", "D_GS_BK_SQLX", "D_BZ_SF", "D_GS_XS_LY", "D_BZ_SSZT", "D_GS_XS_LX", "D_GS_XS_QTLX");
|
D_GS_ZDQT_ZT,
|
||||||
|
D_GS_ZDR_RYJB,
|
||||||
|
D_BZ_XB,
|
||||||
|
D_BZ_MZ,
|
||||||
|
D_BZ_RCBKZT,
|
||||||
|
D_BZ_XZQHDM,
|
||||||
|
D_ZDRGK_GKZT,
|
||||||
|
D_GS_ZDR_CZZT,
|
||||||
|
D_GS_BQ_ZL,
|
||||||
|
D_GS_BQ_LB,
|
||||||
|
D_GS_BQ_LX,
|
||||||
|
D_GS_ZDR_YJDJ,
|
||||||
|
D_GS_BK_SSJZ,
|
||||||
|
D_GS_BK_SQLX,
|
||||||
|
D_BZ_SF,
|
||||||
|
D_GS_XS_LY,
|
||||||
|
D_BZ_SSZT,
|
||||||
|
D_GS_XS_LX,
|
||||||
|
D_GS_XS_QTLX
|
||||||
|
} = proxy.$dict(
|
||||||
|
"D_GS_ZDQT_ZT",
|
||||||
|
"D_BZ_RCBKZT",
|
||||||
|
"D_GS_ZDR_RYJB",
|
||||||
|
"D_BZ_XB",
|
||||||
|
"D_BZ_MZ",
|
||||||
|
"D_BZ_XZQHDM",
|
||||||
|
"D_ZDRGK_GKZT",
|
||||||
|
"D_GS_ZDR_CZZT",
|
||||||
|
"D_GS_BQ_ZL",
|
||||||
|
"D_GS_BQ_LB",
|
||||||
|
"D_GS_BQ_LX",
|
||||||
|
"D_GS_ZDR_YJDJ",
|
||||||
|
"D_GS_BK_SSJZ",
|
||||||
|
"D_GS_BK_SQLX",
|
||||||
|
"D_BZ_SF",
|
||||||
|
"D_GS_XS_LY",
|
||||||
|
"D_BZ_SSZT",
|
||||||
|
"D_GS_XS_LX",
|
||||||
|
"D_GS_XS_QTLX"
|
||||||
|
);
|
||||||
const obj = ref({});
|
const obj = ref({});
|
||||||
const showzxs = ref(false);
|
const showzxs = ref(false);
|
||||||
const zxsDilof = ref();
|
const zxsDilof = ref();
|
||||||
@ -134,7 +242,7 @@ const searchConfiger = ref([
|
|||||||
placeholder: "请输入人员级别",
|
placeholder: "请输入人员级别",
|
||||||
showType: "select",
|
showType: "select",
|
||||||
options: D_GS_ZDR_RYJB
|
options: D_GS_ZDR_RYJB
|
||||||
},
|
}
|
||||||
]);
|
]);
|
||||||
const queryFrom = ref({});
|
const queryFrom = ref({});
|
||||||
const pageData = reactive({
|
const pageData = reactive({
|
||||||
@ -150,30 +258,48 @@ const pageData = reactive({
|
|||||||
pageSize: 20,
|
pageSize: 20,
|
||||||
pageCurrent: 1
|
pageCurrent: 1
|
||||||
},
|
},
|
||||||
controlsWidth: 250,
|
|
||||||
tableColumn: [
|
tableColumn: [
|
||||||
{ label: "姓名", prop: "ryXm", width: 100 },
|
{ label: "姓名", prop: "ryXm", width: 100 },
|
||||||
{ label: "性别", prop: "ryXb", slotName: "ryXb", width: 80 },
|
{ label: "性别", prop: "ryXb", slotName: "ryXb", width: 80 },
|
||||||
{ label: "身份证", prop: "rySfzh", width: 170 },
|
{ label: "身份证", prop: "rySfzh", width: 170 },
|
||||||
{ label: "民族", prop: "ryMz", slotName: "ryMz", width: 80 },
|
{ label: "民族", prop: "ryMz", slotName: "ryMz", width: 80 },
|
||||||
{ label: "户籍派出所", prop: "hjdPcsmc" },
|
{ label: "户籍派出所", prop: "hjdPcsmc" },
|
||||||
{ label: "标签", prop: "bqList", slotName: "bqList", showOverflowTooltip: true },
|
{
|
||||||
|
label: "标签",
|
||||||
|
prop: "bqList",
|
||||||
|
slotName: "bqList",
|
||||||
|
showOverflowTooltip: true
|
||||||
|
},
|
||||||
{ label: "协管单位", prop: "gxSsbmmc" },
|
{ label: "协管单位", prop: "gxSsbmmc" },
|
||||||
{ label: "管控状态", prop: "zdrBkZt", showOverflowTooltip: true, slotName: "zdrBkZt", width: 100 },
|
{
|
||||||
|
label: "管控状态",
|
||||||
|
prop: "zdrBkZt",
|
||||||
|
showOverflowTooltip: true,
|
||||||
|
slotName: "zdrBkZt",
|
||||||
|
width: 100
|
||||||
|
},
|
||||||
{ label: "审核状态", prop: "zdrZt", slotName: "zdrZt", width: 100 },
|
{ label: "审核状态", prop: "zdrZt", slotName: "zdrZt", width: 100 },
|
||||||
{ label: "入库时间", prop: "zdrRkkssj", },
|
{ label: "入库时间", prop: "zdrRkkssj" },
|
||||||
{ label: "操作", prop: "controls", slotName: "controls", width: 250 },
|
{
|
||||||
|
label: "操作",
|
||||||
|
prop: "controls",
|
||||||
|
slotName: "controls",
|
||||||
|
align: "center",
|
||||||
|
width: 350
|
||||||
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
const isShiQzDelet = ref(false)
|
const isShiQzDelet = ref(false);
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
tabHeightFn();
|
tabHeightFn();
|
||||||
const isShiQz = getItem('roleList').find(item => item.roleCode == 'JS_777777') != undefined
|
const isShiQz =
|
||||||
if (isShiQz) isShiQzDelet.value = true
|
getItem("roleList").find((item) => item.roleCode == "JS_777777") !=
|
||||||
|
undefined;
|
||||||
|
if (isShiQz) isShiQzDelet.value = true;
|
||||||
if (route.query.id) {
|
if (route.query.id) {
|
||||||
addEdit('x', {
|
addEdit("x", {
|
||||||
id: route.query.id
|
id: route.query.id
|
||||||
})
|
});
|
||||||
} else {
|
} else {
|
||||||
getList();
|
getList();
|
||||||
}
|
}
|
||||||
@ -200,14 +326,16 @@ const getList = () => {
|
|||||||
pageData.tableConfiger.loading = true;
|
pageData.tableConfiger.loading = true;
|
||||||
// 人员类型D_ZDRY_RYLX(01 重点 02 普通〉
|
// 人员类型D_ZDRY_RYLX(01 重点 02 普通〉
|
||||||
// rylx: '01',
|
// rylx: '01',
|
||||||
let data = { ...pageData.pageConfiger, ...queryFrom.value, rylx: '01' };
|
let data = { ...pageData.pageConfiger, ...queryFrom.value, rylx: "01" };
|
||||||
qcckGet(data, "/mosty-gsxt/tbGsxtZdry/selectPage").then((res) => {
|
qcckGet(data, "/mosty-gsxt/tbGsxtZdry/selectPage")
|
||||||
pageData.tableData = res.records || [];
|
.then((res) => {
|
||||||
pageData.total = res.total;
|
pageData.tableData = res.records || [];
|
||||||
pageData.tableConfiger.loading = false;
|
pageData.total = res.total;
|
||||||
}).catch(() => {
|
pageData.tableConfiger.loading = false;
|
||||||
pageData.tableConfiger.loading = false;
|
})
|
||||||
});
|
.catch(() => {
|
||||||
|
pageData.tableConfiger.loading = false;
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
//送审
|
//送审
|
||||||
@ -217,25 +345,27 @@ const handleSend = (id) => {
|
|||||||
proxy.$message({ type: "success", message: "送审成功" });
|
proxy.$message({ type: "success", message: "送审成功" });
|
||||||
getList();
|
getList();
|
||||||
});
|
});
|
||||||
})
|
});
|
||||||
};
|
};
|
||||||
// 移除
|
// 移除
|
||||||
const handleremove = (id) => {
|
const handleremove = (id) => {
|
||||||
proxy.$confirm("确定要移除此重点人员?", "警告", { type: "warning" }).then(() => {
|
proxy
|
||||||
qcckPost({ id, rylx: '02' }, "/mosty-gsxt/tbGsxtZdry/update").then(() => {
|
.$confirm("确定要移除此重点人员?", "警告", { type: "warning" })
|
||||||
proxy.$message({ type: "success", message: "移除成功" });
|
.then(() => {
|
||||||
getList();
|
qcckPost({ id, rylx: "02" }, "/mosty-gsxt/tbGsxtZdry/update").then(() => {
|
||||||
|
proxy.$message({ type: "success", message: "移除成功" });
|
||||||
|
getList();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
})
|
};
|
||||||
}
|
|
||||||
const handleMoveToFocus = (id) => {
|
const handleMoveToFocus = (id) => {
|
||||||
proxy.$confirm("确定要移至关注库?", "警告", { type: "warning" }).then(() => {
|
proxy.$confirm("确定要移至关注库?", "警告", { type: "warning" }).then(() => {
|
||||||
qcckPost({ id, rylx: '03' }, "/mosty-gsxt/tbGsxtZdry/rylxyd").then(() => {
|
qcckPost({ id, rylx: "03" }, "/mosty-gsxt/tbGsxtZdry/rylxyd").then(() => {
|
||||||
proxy.$message({ type: "success", message: "移除成功" });
|
proxy.$message({ type: "success", message: "移除成功" });
|
||||||
getList();
|
getList();
|
||||||
});
|
});
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
const chooseData = (data) => {
|
const chooseData = (data) => {
|
||||||
ids.value = Array.isArray(data) ? data.map((item) => item.id) : [];
|
ids.value = Array.isArray(data) ? data.map((item) => item.id) : [];
|
||||||
@ -243,14 +373,17 @@ const chooseData = (data) => {
|
|||||||
};
|
};
|
||||||
// 选择申请数据数据
|
// 选择申请数据数据
|
||||||
const handleApplication = () => {
|
const handleApplication = () => {
|
||||||
if (ids.value.length === 0) return ElMessage.error("请先选择需要布控的重点人");
|
if (ids.value.length === 0)
|
||||||
qcckPost({ ids: ids.value }, "/mosty-gsxt/tbGsxtZdry/addBksq").then(() => {
|
return ElMessage.error("请先选择需要布控的重点人");
|
||||||
ElMessage.success("申请成功");
|
qcckPost({ ids: ids.value }, "/mosty-gsxt/tbGsxtZdry/addBksq")
|
||||||
visible.value = false;
|
.then(() => {
|
||||||
getList();
|
ElMessage.success("申请成功");
|
||||||
}).catch(() => {
|
visible.value = false;
|
||||||
ElMessage.error("布控申请失败");
|
getList();
|
||||||
});
|
})
|
||||||
|
.catch(() => {
|
||||||
|
ElMessage.error("布控申请失败");
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleUserSelected = (val) => {
|
const handleUserSelected = (val) => {
|
||||||
@ -260,33 +393,43 @@ const handleUserSelected = (val) => {
|
|||||||
|
|
||||||
// 处理分配
|
// 处理分配
|
||||||
const handlefp = () => {
|
const handlefp = () => {
|
||||||
if (ids.value.length === 0) return ElMessage.error("请先选择需要布控的重点人");
|
if (ids.value.length === 0)
|
||||||
qcckPost({ ids: ids.value, uid: obj.value.fpid }, "/mosty-gsxt/tbGsxtZdry/addGkmj").then(() => {
|
return ElMessage.error("请先选择需要布控的重点人");
|
||||||
ElMessage.success("分配成功");
|
qcckPost(
|
||||||
visible.value = false;
|
{ ids: ids.value, uid: obj.value.fpid },
|
||||||
visiblefp.value = false;
|
"/mosty-gsxt/tbGsxtZdry/addGkmj"
|
||||||
getList();
|
)
|
||||||
}).catch(() => {
|
.then(() => {
|
||||||
ElMessage.error("分配失败");
|
ElMessage.success("分配成功");
|
||||||
});
|
visible.value = false;
|
||||||
|
visiblefp.value = false;
|
||||||
|
getList();
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
ElMessage.error("分配失败");
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// 移交管控
|
// 移交管控
|
||||||
const handleMove = () => {
|
const handleMove = () => {
|
||||||
if (ids.value.length === 0) return ElMessage.error("请先选择需要移交管控的重点群体");
|
if (ids.value.length === 0)
|
||||||
|
return ElMessage.error("请先选择需要移交管控的重点群体");
|
||||||
proxy.$confirm("是否确定移交?", "警告", { type: "warning" }).then(() => {
|
proxy.$confirm("是否确定移交?", "警告", { type: "warning" }).then(() => {
|
||||||
qcckPost({ ids: ids.value }, "/mosty-gsxt/tbGsxtZdry/addSfyj").then(() => {
|
qcckPost({ ids: ids.value }, "/mosty-gsxt/tbGsxtZdry/addSfyj")
|
||||||
ElMessage.success("移交管控成功");
|
.then(() => {
|
||||||
getList();
|
ElMessage.success("移交管控成功");
|
||||||
}).catch(() => {
|
getList();
|
||||||
ElMessage.error("移交管控失败");
|
})
|
||||||
});
|
.catch(() => {
|
||||||
|
ElMessage.error("移交管控失败");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// 转线索
|
// 转线索
|
||||||
const handleZxs = () => {
|
const handleZxs = () => {
|
||||||
if (ids.value.length === 0) return ElMessage.error("请先选择需要转线索的重点群体");
|
if (ids.value.length === 0)
|
||||||
|
return ElMessage.error("请先选择需要转线索的重点群体");
|
||||||
showzxs.value = true;
|
showzxs.value = true;
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
zxsDilof.value.init(choosList.value);
|
zxsDilof.value.init(choosList.value);
|
||||||
@ -303,22 +446,38 @@ const deleteRow = (id) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
//新增编辑
|
//新增编辑
|
||||||
const addEdit = (type, row) => {
|
const addEdit = (type, row) => {
|
||||||
show.value = true;
|
show.value = true;
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
addFormDiloag.value.init(type, row);
|
addFormDiloag.value.init(type, row);
|
||||||
})
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// 表格高度计算
|
// 表格高度计算
|
||||||
const tabHeightFn = () => {
|
const tabHeightFn = () => {
|
||||||
pageData.tableHeight = window.innerHeight - searchBox.value.offsetHeight - 220;
|
pageData.tableHeight =
|
||||||
|
window.innerHeight - searchBox.value.offsetHeight - 220;
|
||||||
window.onresize = function () {
|
window.onresize = function () {
|
||||||
tabHeightFn();
|
tabHeightFn();
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 标签颜色
|
||||||
|
const Bqys = (ys) => {
|
||||||
|
switch (ys) {
|
||||||
|
case "01":
|
||||||
|
return "#fd4343";
|
||||||
|
case "02":
|
||||||
|
return "#c26e09";
|
||||||
|
case "03":
|
||||||
|
return "#ffd208ff";
|
||||||
|
case "04":
|
||||||
|
return "#01abee";
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|||||||
@ -3,35 +3,60 @@
|
|||||||
<div class="headClass">
|
<div class="headClass">
|
||||||
<h3>人员信息</h3>
|
<h3>人员信息</h3>
|
||||||
<!-- @click="gettbGsxtZdqtUpdate" -->
|
<!-- @click="gettbGsxtZdqtUpdate" -->
|
||||||
<el-button type="primary" v-if="showBut" :disabled="disabled" @click="submit">保存</el-button>
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
v-if="showBut"
|
||||||
|
:disabled="disabled"
|
||||||
|
@click="submit"
|
||||||
|
>保存</el-button
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<FormMessage :disabled="disabled" v-model="listQuery" :formList="formData" labelWidth="130px" ref="elform"
|
<FormMessage
|
||||||
:rules="rules">
|
:disabled="disabled"
|
||||||
|
v-model="listQuery"
|
||||||
|
:formList="formData"
|
||||||
|
labelWidth="130px"
|
||||||
|
ref="elform"
|
||||||
|
:rules="rules"
|
||||||
|
>
|
||||||
<template #ryzp>
|
<template #ryzp>
|
||||||
<div style="width: 100%; padding-left: 50px">
|
<div style="width: 100%; padding-left: 50px">
|
||||||
<MOSTY.Upload :showBtn="false" :limit="1" v-model="listQuery.ryzp" />
|
<MOSTY.Upload
|
||||||
|
:showBtn="false"
|
||||||
|
:limit="1"
|
||||||
|
v-model="listQuery.ryzp"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #gkMjXm>
|
<template #gkMjXm>
|
||||||
<div>
|
<div>
|
||||||
<el-input v-model="listQuery.gkMjXm" class="group" placeholder="请输入管控民警姓名" readonly
|
<el-input
|
||||||
@click="chooseMarksVisible = true" />
|
v-model="listQuery.gkMjXm"
|
||||||
|
class="group"
|
||||||
|
placeholder="请输入管控民警姓名"
|
||||||
|
readonly
|
||||||
|
@click="chooseMarksVisible = true"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<!-- <template #gkmjsfzh>
|
<!-- <template #gkMjSfzh>
|
||||||
<div>
|
<div>
|
||||||
<el-input v-model="listQuery.gkmjsfzh" class="group" placeholder="请输入管控民警身份证号" readonly
|
<el-input v-model="listQuery.gkMjSfzh" class="group" placeholder="请输入管控民警身份证号" readonly
|
||||||
@click="chooseMarksVisible = true" />
|
@click="chooseMarksVisible = true" />
|
||||||
</div>
|
</div>
|
||||||
</template> -->
|
</template> -->
|
||||||
<!-- { label: "管控民警", prop: "gkMjXm", type: "slot" }, -->
|
<!-- { label: "管控民警", prop: "gkMjXm", type: "slot" }, -->
|
||||||
<!-- { label: "管控民警身份证号", prop: "gkmjsfzh", type: "slot" }, -->
|
<!-- { label: "管控民警身份证号", prop: "gkMjSfzh", type: "slot" }, -->
|
||||||
</FormMessage>
|
</FormMessage>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- <ChooseMarks v-model="chooseMarksVisible" @choosed="choosed" :roleIds="roleIds" /> -->
|
<!-- <ChooseMarks v-model="chooseMarksVisible" @choosed="choosed" :roleIds="roleIds" /> -->
|
||||||
<ChooseUser v-model="chooseMarksVisible" @choosedUsers="choosed" :roleIds="roleIds" />
|
<ChooseUser
|
||||||
|
v-model="chooseMarksVisible"
|
||||||
|
@choosedUsers="choosed"
|
||||||
|
:roleIds="roleIds"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
@ -43,24 +68,52 @@ import ChooseUser from "@/components/ChooseList/ChooseUser/index.vue";
|
|||||||
import { ref, reactive, onMounted, getCurrentInstance, watch } from "vue";
|
import { ref, reactive, onMounted, getCurrentInstance, watch } from "vue";
|
||||||
import { tbGsxtZdryUpdate } from "@/api/zdr.js";
|
import { tbGsxtZdryUpdate } from "@/api/zdr.js";
|
||||||
const { proxy } = getCurrentInstance();
|
const { proxy } = getCurrentInstance();
|
||||||
const { D_BZ_XB, D_BZ_ZZMM, D_BZ_HYZK, D_BZ_MZ, D_BZ_XZQHDM, D_ZDRY_RYLX, D_BZ_RCBKZT, D_GS_ZDR_RYJB, D_GS_ZDR_YJDJ, D_GS_BK_SSJZ, D_GS_ZDR_CZZT, D_BZ_WHCD, D_ZDRY_ZYLB } =
|
const {
|
||||||
proxy.$dict('D_BZ_XB', 'D_BZ_ZZMM', 'D_BZ_HYZK', 'D_BZ_MZ', "D_ZDRY_RYLX", 'D_BZ_XZQHDM', 'D_BZ_RCBKZT', 'D_GS_ZDR_RYJB', 'D_GS_ZDR_YJDJ', 'D_GS_BK_SSJZ', 'D_GS_ZDR_CZZT', 'D_BZ_WHCD', 'D_ZDRY_ZYLB')
|
D_BZ_XB,
|
||||||
|
D_BZ_ZZMM,
|
||||||
|
D_BZ_HYZK,
|
||||||
|
D_BZ_MZ,
|
||||||
|
D_BZ_XZQHDM,
|
||||||
|
D_ZDRY_RYLX,
|
||||||
|
D_BZ_RCBKZT,
|
||||||
|
D_GS_ZDR_RYJB,
|
||||||
|
D_GS_ZDR_YJDJ,
|
||||||
|
D_GS_BK_SSJZ,
|
||||||
|
D_GS_ZDR_CZZT,
|
||||||
|
D_BZ_WHCD,
|
||||||
|
D_ZDRY_ZYLB
|
||||||
|
} = proxy.$dict(
|
||||||
|
"D_BZ_XB",
|
||||||
|
"D_BZ_ZZMM",
|
||||||
|
"D_BZ_HYZK",
|
||||||
|
"D_BZ_MZ",
|
||||||
|
"D_ZDRY_RYLX",
|
||||||
|
"D_BZ_XZQHDM",
|
||||||
|
"D_BZ_RCBKZT",
|
||||||
|
"D_GS_ZDR_RYJB",
|
||||||
|
"D_GS_ZDR_YJDJ",
|
||||||
|
"D_GS_BK_SSJZ",
|
||||||
|
"D_GS_ZDR_CZZT",
|
||||||
|
"D_BZ_WHCD",
|
||||||
|
"D_ZDRY_ZYLB"
|
||||||
|
);
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
dataList: {
|
dataList: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: () => { },
|
default: () => {}
|
||||||
}, disabled: {
|
},
|
||||||
|
disabled: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
},
|
},
|
||||||
showBut: {
|
showBut: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
},
|
}
|
||||||
})
|
});
|
||||||
const rules = reactive({
|
const rules = reactive({
|
||||||
ryXm: [{ required: true, message: "请输入姓名", trigger: "blur" }],
|
ryXm: [{ required: true, message: "请输入姓名", trigger: "blur" }],
|
||||||
...rule.identityCardRule({ validator: true }, 'rySfzh'), //身份证校验
|
...rule.identityCardRule({ validator: true }, "rySfzh"), //身份证校验
|
||||||
...rule.phoneRule({ validator: true }, "gkMjLxfs"), // 是否必填 是否进行校验,
|
...rule.phoneRule({ validator: true }, "gkMjLxfs"), // 是否必填 是否进行校验,
|
||||||
rySfzh: [{ required: true, message: "请输入身份证号", trigger: "blur" }],
|
rySfzh: [{ required: true, message: "请输入身份证号", trigger: "blur" }],
|
||||||
ryXb: [{ required: true, message: "请选择性别", trigger: "change" }],
|
ryXb: [{ required: true, message: "请选择性别", trigger: "change" }],
|
||||||
@ -68,11 +121,15 @@ const rules = reactive({
|
|||||||
ryCsrq: [{ required: true, message: "请选择出生日期", trigger: "change" }],
|
ryCsrq: [{ required: true, message: "请选择出生日期", trigger: "change" }],
|
||||||
zdrYjdj: [{ required: true, message: "请选择预警等级", trigger: "change" }],
|
zdrYjdj: [{ required: true, message: "请选择预警等级", trigger: "change" }],
|
||||||
gxSsbmdm: [{ required: true, message: "请选择协管单位", trigger: "change" }],
|
gxSsbmdm: [{ required: true, message: "请选择协管单位", trigger: "change" }],
|
||||||
zdrRkkssj: [{ required: true, message: "请选择入库开始时间", trigger: "change" }],
|
zdrRkkssj: [
|
||||||
zdrRkjssj: [{ required: true, message: "请选择入库结束时间", trigger: "change" }],
|
{ required: true, message: "请选择入库开始时间", trigger: "change" }
|
||||||
gkMjLxfs: [{ required: true, message: "请输入民警联系方式", trigger: "blur" }],
|
],
|
||||||
|
zdrRkjssj: [
|
||||||
|
{ required: true, message: "请选择入库结束时间", trigger: "change" }
|
||||||
|
],
|
||||||
|
gkMjLxfs: [{ required: true, message: "请输入民警联系方式", trigger: "blur" }]
|
||||||
// gkMjXm: [{ required: true, message: "请选择管控民警", trigger: "change" }],
|
// gkMjXm: [{ required: true, message: "请选择管控民警", trigger: "change" }],
|
||||||
// gkmjsfzh: [{ required: true, message: "请选择管控民警身份证号", trigger: "change" }],
|
// gkMjSfzh: [{ required: true, message: "请选择管控民警身份证号", trigger: "change" }],
|
||||||
// rylx: [{ required: true, message: "请选择人员类型", trigger: "change" }]
|
// rylx: [{ required: true, message: "请选择人员类型", trigger: "change" }]
|
||||||
});
|
});
|
||||||
const listQuery = ref({}); //表单
|
const listQuery = ref({}); //表单
|
||||||
@ -82,11 +139,35 @@ const formData = ref([
|
|||||||
{ label: "人员照片", prop: "ryzp", type: "slot", width: "100%" },
|
{ label: "人员照片", prop: "ryzp", type: "slot", width: "100%" },
|
||||||
{ label: "姓名", prop: "ryXm", type: "input", width: "30%" },
|
{ label: "姓名", prop: "ryXm", type: "input", width: "30%" },
|
||||||
{ label: "身份证号", prop: "rySfzh", type: "input", width: "30%" },
|
{ label: "身份证号", prop: "rySfzh", type: "input", width: "30%" },
|
||||||
{ label: "性别", prop: "ryXb", type: "select", options: D_BZ_XB, width: "30%" },
|
{
|
||||||
|
label: "性别",
|
||||||
|
prop: "ryXb",
|
||||||
|
type: "select",
|
||||||
|
options: D_BZ_XB,
|
||||||
|
width: "30%"
|
||||||
|
},
|
||||||
{ label: "出生日期", prop: "ryCsrq", type: "date", width: "30%" },
|
{ label: "出生日期", prop: "ryCsrq", type: "date", width: "30%" },
|
||||||
{ label: "民族", prop: "ryMz", type: "select", options: D_BZ_MZ, width: "30%" },
|
{
|
||||||
{ label: "协管单位", prop: "gxSsbmdm", depMc: 'gxSsbmmc', type: "department", width: "30%" },
|
label: "民族",
|
||||||
{ label: "预警等级", prop: "zdrYjdj", type: "select", options: D_GS_ZDR_YJDJ, width: "30%" },
|
prop: "ryMz",
|
||||||
|
type: "select",
|
||||||
|
options: D_BZ_MZ,
|
||||||
|
width: "30%"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "协管单位",
|
||||||
|
prop: "gxSsbmdm",
|
||||||
|
depMc: "gxSsbmmc",
|
||||||
|
type: "department",
|
||||||
|
width: "30%"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "预警等级",
|
||||||
|
prop: "zdrYjdj",
|
||||||
|
type: "select",
|
||||||
|
options: D_GS_ZDR_YJDJ,
|
||||||
|
width: "30%"
|
||||||
|
},
|
||||||
{ label: "管控民警", prop: "gkMjXm", type: "slot", width: "30%" },
|
{ label: "管控民警", prop: "gkMjXm", type: "slot", width: "30%" },
|
||||||
{ label: "民警联系方式", prop: "gkMjLxfs", type: "input", width: "30%" },
|
{ label: "民警联系方式", prop: "gkMjLxfs", type: "input", width: "30%" },
|
||||||
{ label: "入库开始时间", prop: "zdrRkkssj", type: "datetime", width: "30%" },
|
{ label: "入库开始时间", prop: "zdrRkkssj", type: "datetime", width: "30%" },
|
||||||
@ -94,30 +175,85 @@ const formData = ref([
|
|||||||
{ label: "重点人联系电话", prop: "ryLxdh", type: "input", width: "30%" },
|
{ label: "重点人联系电话", prop: "ryLxdh", type: "input", width: "30%" },
|
||||||
{ label: "籍贯", prop: "ryJg", type: "input", width: "30%" },
|
{ label: "籍贯", prop: "ryJg", type: "input", width: "30%" },
|
||||||
{ label: "曾用名", prop: "cym", type: "input", width: "30%" },
|
{ label: "曾用名", prop: "cym", type: "input", width: "30%" },
|
||||||
{ label: "文化程度", prop: "whcdBm", type: "select", options: D_BZ_WHCD, width: "30%" },
|
{
|
||||||
{ label: "政治面貌", prop: "zzmm", type: "select", options: D_BZ_ZZMM, width: "30%" },
|
label: "文化程度",
|
||||||
|
prop: "whcdBm",
|
||||||
|
type: "select",
|
||||||
|
options: D_BZ_WHCD,
|
||||||
|
width: "30%"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "政治面貌",
|
||||||
|
prop: "zzmm",
|
||||||
|
type: "select",
|
||||||
|
options: D_BZ_ZZMM,
|
||||||
|
width: "30%"
|
||||||
|
},
|
||||||
{ label: "职业", prop: "zyBm", type: "input", width: "30%" },
|
{ label: "职业", prop: "zyBm", type: "input", width: "30%" },
|
||||||
{ label: "人员级别", prop: "zdrRyjb", type: "select", options: D_GS_ZDR_RYJB, width: "30%" },
|
{
|
||||||
|
label: "人员级别",
|
||||||
|
prop: "zdrRyjb",
|
||||||
|
type: "select",
|
||||||
|
options: D_GS_ZDR_RYJB,
|
||||||
|
width: "30%"
|
||||||
|
},
|
||||||
{ label: "户籍地区划", prop: "hjdQh", type: "input", width: "30%" },
|
{ label: "户籍地区划", prop: "hjdQh", type: "input", width: "30%" },
|
||||||
{ label: "户籍地详址", prop: "hjdXz", type: "input", width: "30%" },
|
{ label: "户籍地详址", prop: "hjdXz", type: "input", width: "30%" },
|
||||||
{ label: "户籍地派出所", prop: "hjdPcsmc", type: "input", width: "30%" },
|
{ label: "户籍地派出所", prop: "hjdPcsmc", type: "input", width: "30%" },
|
||||||
{ label: "现住地区划", prop: "xzdQh", type: "input", width: "30%" },
|
{ label: "现住地区划", prop: "xzdQh", type: "input", width: "30%" },
|
||||||
{ label: "现住地详址", prop: "xzdXz", type: "input", width: "30%" },
|
{ label: "现住地详址", prop: "xzdXz", type: "input", width: "30%" },
|
||||||
{ label: "现住地派出所", prop: "xzdPcsdm", depMc: "xzdPcsmc", type: "department", width: "30%" },
|
{
|
||||||
|
label: "现住地派出所",
|
||||||
|
prop: "xzdPcsdm",
|
||||||
|
depMc: "xzdPcsmc",
|
||||||
|
type: "department",
|
||||||
|
width: "30%"
|
||||||
|
},
|
||||||
|
|
||||||
// { label: "民警身份证", prop: "gkmjsfzh", type: "slot" },
|
// { label: "民警身份证", prop: "gkMjSfzh", type: "slot" },
|
||||||
{ label: "诉求单位", prop: "sqSsbmmc", type: "input", width: "30%" },
|
{ label: "诉求单位", prop: "sqSsbmmc", type: "input", width: "30%" },
|
||||||
{ label: "责任单位", prop: "zrSsbmmc", type: "input", width: "30%" },
|
{ label: "责任单位", prop: "zrSsbmmc", type: "input", width: "30%" },
|
||||||
{ label: "所属警种", prop: "zdrSsjz", type: "select", options: D_GS_BK_SSJZ, width: "30%" },
|
{
|
||||||
{ label: "涉及警种", prop: "zdrSjjz", type: "select", options: D_GS_BK_SSJZ, multiple: true, width: "30%" },
|
label: "所属警种",
|
||||||
{ label: "婚姻状态", prop: "hyzk", type: "select", options: D_BZ_HYZK, width: "30%" },
|
prop: "zdrSsjz",
|
||||||
{ label: "处置状态", prop: "zdrCzzt", type: "select", options: D_GS_ZDR_CZZT, width: "30%" },
|
type: "select",
|
||||||
{ label: "布控状态", prop: "zdrBkZt", type: "select", options: D_BZ_RCBKZT, width: "30%" },
|
options: D_GS_BK_SSJZ,
|
||||||
|
width: "30%"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "涉及警种",
|
||||||
|
prop: "zdrSjjz",
|
||||||
|
type: "select",
|
||||||
|
options: D_GS_BK_SSJZ,
|
||||||
|
multiple: true,
|
||||||
|
width: "30%"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "婚姻状态",
|
||||||
|
prop: "hyzk",
|
||||||
|
type: "select",
|
||||||
|
options: D_BZ_HYZK,
|
||||||
|
width: "30%"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "处置状态",
|
||||||
|
prop: "zdrCzzt",
|
||||||
|
type: "select",
|
||||||
|
options: D_GS_ZDR_CZZT,
|
||||||
|
width: "30%"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "布控状态",
|
||||||
|
prop: "zdrBkZt",
|
||||||
|
type: "select",
|
||||||
|
options: D_BZ_RCBKZT,
|
||||||
|
width: "30%"
|
||||||
|
},
|
||||||
// { label: "人员类型", prop: "rylx", type: "select", options: D_ZDRY_RYLX },
|
// { label: "人员类型", prop: "rylx", type: "select", options: D_ZDRY_RYLX },
|
||||||
|
|
||||||
{ label: "Mac地址", prop: "macDz", type: "input", width: "30%" },
|
{ label: "Mac地址", prop: "macDz", type: "input", width: "30%" },
|
||||||
// { label: "标签选择", prop: "tags", type: "slot", width: "100%" },
|
// { label: "标签选择", prop: "tags", type: "slot", width: "100%" },
|
||||||
{ label: "管控原因", prop: "zdrLkyy", type: "textarea", width: "100%" },
|
{ label: "管控原因", prop: "zdrLkyy", type: "textarea", width: "100%" }
|
||||||
]);
|
]);
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
const elform = ref();
|
const elform = ref();
|
||||||
@ -125,14 +261,14 @@ const disabled = ref(false);
|
|||||||
// phoneList已重构为listQuery.value.ryLxdh
|
// phoneList已重构为listQuery.value.ryLxdh
|
||||||
// 创建一个工具函数进行深拷贝
|
// 创建一个工具函数进行深拷贝
|
||||||
const deepClone = (obj) => {
|
const deepClone = (obj) => {
|
||||||
if (obj === null || typeof obj !== 'object') {
|
if (obj === null || typeof obj !== "object") {
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
if (obj instanceof Date) {
|
if (obj instanceof Date) {
|
||||||
return new Date(obj.getTime());
|
return new Date(obj.getTime());
|
||||||
}
|
}
|
||||||
if (obj instanceof Array) {
|
if (obj instanceof Array) {
|
||||||
return obj.map(item => deepClone(item));
|
return obj.map((item) => deepClone(item));
|
||||||
}
|
}
|
||||||
const clonedObj = {};
|
const clonedObj = {};
|
||||||
for (const key in obj) {
|
for (const key in obj) {
|
||||||
@ -143,64 +279,79 @@ const deepClone = (obj) => {
|
|||||||
return clonedObj;
|
return clonedObj;
|
||||||
};
|
};
|
||||||
// 监听身份证号变化,自动填充性别、出生日期和民族
|
// 监听身份证号变化,自动填充性别、出生日期和民族
|
||||||
watch(() => listQuery.value.rySfzh, (val) => {
|
watch(
|
||||||
if (val && val.length === 18) {
|
() => listQuery.value.rySfzh,
|
||||||
// 使用IdCard方法提取出生日期
|
(val) => {
|
||||||
listQuery.value.ryCsrq = IdCard(val, 1);
|
if (val && val.length === 18) {
|
||||||
// 使用IdCard方法提取性别
|
// 使用IdCard方法提取出生日期
|
||||||
const genderText = IdCard(val, 2);
|
listQuery.value.ryCsrq = IdCard(val, 1);
|
||||||
listQuery.value.ryXb = D_BZ_XB.value.find(item => item.zdmc === genderText).dm;
|
// 使用IdCard方法提取性别
|
||||||
}
|
const genderText = IdCard(val, 2);
|
||||||
});
|
listQuery.value.ryXb = D_BZ_XB.value.find(
|
||||||
|
(item) => item.zdmc === genderText
|
||||||
// 监听props.dataList变化,处理初始化数据
|
).dm;
|
||||||
watch(() => props.dataList, (val) => {
|
|
||||||
if (val) {
|
|
||||||
console.log(val);
|
|
||||||
|
|
||||||
// 使用深拷贝避免直接引用同一个对象
|
|
||||||
listQuery.value = deepClone(val);
|
|
||||||
// 处理照片数据
|
|
||||||
listQuery.value.ryzp = val.ryzp == null || val.ryzp == '' ? [] : [val.ryzp];
|
|
||||||
listQuery.value.zdrSjjz = val.zdrSjjz == null || val.zdrSjjz == '' ? [] : JSON.parse(val.zdrSjjz);
|
|
||||||
// 处理标签ID数据,确保数据回显
|
|
||||||
if (val.tagIds && Array.isArray(val.tagIds) && val.tagIds.length > 0) {
|
|
||||||
roleIds.value = [...val.tagIds];
|
|
||||||
} else if (val.bqIds && Array.isArray(val.bqIds) && val.bqIds.length > 0) {
|
|
||||||
roleIds.value = [...val.bqIds];
|
|
||||||
} else {
|
|
||||||
roleIds.value = [];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, { deep: true })
|
);
|
||||||
|
|
||||||
|
// 监听props.dataList变化,处理初始化数据
|
||||||
|
watch(
|
||||||
|
() => props.dataList,
|
||||||
|
(val) => {
|
||||||
|
if (val) {
|
||||||
|
console.log(val);
|
||||||
|
|
||||||
|
// 使用深拷贝避免直接引用同一个对象
|
||||||
|
listQuery.value = deepClone(val);
|
||||||
|
// 处理照片数据
|
||||||
|
listQuery.value.ryzp =
|
||||||
|
val.ryzp == null || val.ryzp == "" ? [] : [val.ryzp];
|
||||||
|
listQuery.value.zdrSjjz =
|
||||||
|
val.zdrSjjz == null || val.zdrSjjz == "" ? [] : JSON.parse(val.zdrSjjz);
|
||||||
|
// 处理标签ID数据,确保数据回显
|
||||||
|
if (val.tagIds && Array.isArray(val.tagIds) && val.tagIds.length > 0) {
|
||||||
|
roleIds.value = [...val.tagIds];
|
||||||
|
} else if (
|
||||||
|
val.bqIds &&
|
||||||
|
Array.isArray(val.bqIds) &&
|
||||||
|
val.bqIds.length > 0
|
||||||
|
) {
|
||||||
|
roleIds.value = [...val.bqIds];
|
||||||
|
} else {
|
||||||
|
roleIds.value = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ deep: true }
|
||||||
|
);
|
||||||
// 提交
|
// 提交
|
||||||
const submit = () => {
|
const submit = () => {
|
||||||
loading.value = true
|
loading.value = true;
|
||||||
gettbGsxtZdryUpdate()
|
gettbGsxtZdryUpdate();
|
||||||
};
|
};
|
||||||
//
|
//
|
||||||
const gettbGsxtZdryUpdate = () => {
|
const gettbGsxtZdryUpdate = () => {
|
||||||
const promes = {
|
const promes = {
|
||||||
...listQuery.value,
|
...listQuery.value,
|
||||||
ryzp: listQuery.value.ryzp.length > 0 ? listQuery.value.ryzp.toString() : "",
|
ryzp:
|
||||||
zdrSjjz: JSON.stringify(listQuery.value.zdrSjjz),
|
listQuery.value.ryzp.length > 0 ? listQuery.value.ryzp.toString() : "",
|
||||||
|
zdrSjjz: JSON.stringify(listQuery.value.zdrSjjz)
|
||||||
}
|
};
|
||||||
elform.value.submit((data) => {
|
elform.value.submit((data) => {
|
||||||
tbGsxtZdryUpdate(promes).then((res) => {
|
tbGsxtZdryUpdate(promes)
|
||||||
listQuery.value.ryzp = []
|
.then((res) => {
|
||||||
proxy.$message({
|
listQuery.value.ryzp = [];
|
||||||
message: '更新成功',
|
proxy.$message({
|
||||||
type: 'success',
|
message: "更新成功",
|
||||||
|
type: "success"
|
||||||
|
});
|
||||||
})
|
})
|
||||||
}).catch((err) => {
|
.catch((err) => {})
|
||||||
|
.finally(() => {
|
||||||
}).finally(() => {
|
loading.value = false;
|
||||||
loading.value = false
|
});
|
||||||
});
|
});
|
||||||
})
|
};
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
const throwData = () => {
|
const throwData = () => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
@ -209,37 +360,40 @@ const throwData = () => {
|
|||||||
// 过滤掉空的电话号码
|
// 过滤掉空的电话号码
|
||||||
resolve({
|
resolve({
|
||||||
...listQuery.value,
|
...listQuery.value,
|
||||||
ryzp: listQuery.value.ryzp && listQuery.value.ryzp.length > 0 ? listQuery.value.ryzp.toString() : '',
|
ryzp:
|
||||||
zdrSjjz: JSON.stringify(listQuery.value.zdrSjjz),
|
listQuery.value.ryzp && listQuery.value.ryzp.length > 0
|
||||||
|
? listQuery.value.ryzp.toString()
|
||||||
|
: "",
|
||||||
|
zdrSjjz: JSON.stringify(listQuery.value.zdrSjjz)
|
||||||
});
|
});
|
||||||
})
|
});
|
||||||
} else {
|
} else {
|
||||||
elform.value.submit((data) => {
|
elform.value.submit((data) => {
|
||||||
// 如果没有验证方法,直接返回数据
|
// 如果没有验证方法,直接返回数据
|
||||||
|
|
||||||
resolve({
|
resolve({
|
||||||
...listQuery.value,
|
...listQuery.value,
|
||||||
ryzp: listQuery.value.ryzp && listQuery.value.ryzp.length > 0 ? listQuery.value.ryzp.toString() : '',
|
ryzp:
|
||||||
zdrSjjz: JSON.stringify(listQuery.value.zdrSjjz),
|
listQuery.value.ryzp && listQuery.value.ryzp.length > 0
|
||||||
|
? listQuery.value.ryzp.toString()
|
||||||
|
: "",
|
||||||
|
zdrSjjz: JSON.stringify(listQuery.value.zdrSjjz)
|
||||||
});
|
});
|
||||||
|
});
|
||||||
})
|
|
||||||
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
const choosed = (val) => {
|
const choosed = (val) => {
|
||||||
roleIds.value = [val[0].id]
|
roleIds.value = [val[0].id];
|
||||||
listQuery.value.gkMjXm = val[0].userName
|
listQuery.value.gkMjXm = val[0].userName;
|
||||||
listQuery.value.gkmjsfzh = val[0].idEntityCard
|
listQuery.value.gkMjSfzh = val[0].idEntityCard;
|
||||||
listQuery.value.gkMjLxfs = val[0].mobile
|
listQuery.value.gkMjLxfs = val[0].mobile;
|
||||||
|
listQuery.value.gkMjJh = val[0].inDustRialId;
|
||||||
console.log(listQuery.value);
|
console.log(listQuery.value);
|
||||||
|
|
||||||
};
|
};
|
||||||
defineExpose({
|
defineExpose({
|
||||||
throwData,
|
throwData
|
||||||
});
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@ -283,7 +437,7 @@ defineExpose({
|
|||||||
}
|
}
|
||||||
|
|
||||||
.headClass::after {
|
.headClass::after {
|
||||||
content: '';
|
content: "";
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 0;
|
left: 0;
|
||||||
bottom: -2px;
|
bottom: -2px;
|
||||||
|
|||||||
@ -2,10 +2,21 @@
|
|||||||
<div>
|
<div>
|
||||||
<div class="headClass" style="">
|
<div class="headClass" style="">
|
||||||
<h3>人员标签</h3>
|
<h3>人员标签</h3>
|
||||||
<el-button type="primary" :disabled="disabled" @click="chooseMarksVisible = true">选择</el-button>
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
:disabled="disabled"
|
||||||
|
@click="chooseMarksVisible = true"
|
||||||
|
>选择</el-button
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
<MyTable :tableData="pageData.tableData" :tableColumn="pageData.tableColumn" :tableHeight="pageData.tableHeight"
|
<MyTable
|
||||||
:key="pageData.keyCount" :tableConfiger="pageData.tableConfiger" :controlsWidth="pageData.controlsWidth">
|
:tableData="pageData.tableData"
|
||||||
|
:tableColumn="pageData.tableColumn"
|
||||||
|
:tableHeight="pageData.tableHeight"
|
||||||
|
:key="pageData.keyCount"
|
||||||
|
:tableConfiger="pageData.tableConfiger"
|
||||||
|
:controlsWidth="pageData.controlsWidth"
|
||||||
|
>
|
||||||
<template #bqLx="{ row }">
|
<template #bqLx="{ row }">
|
||||||
<DictTag :tag="false" :value="row.bqLx" :options="D_GS_BQ_DJ" />
|
<DictTag :tag="false" :value="row.bqLx" :options="D_GS_BQ_DJ" />
|
||||||
</template>
|
</template>
|
||||||
@ -18,143 +29,181 @@
|
|||||||
</template>
|
</template>
|
||||||
</MyTable>
|
</MyTable>
|
||||||
</div>
|
</div>
|
||||||
<ChooseMarks v-model="chooseMarksVisible" @choosed="addMarks" :roleIds="roleIds" />
|
<ChooseMarks
|
||||||
|
v-model="chooseMarksVisible"
|
||||||
|
@choosed="addMarks"
|
||||||
|
:roleIds="roleIds"
|
||||||
|
:bqLx="defaultBqLx"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, reactive, watch, toRaw, getCurrentInstance, onMounted, onUnmounted } from "vue";
|
import {
|
||||||
|
ref,
|
||||||
|
reactive,
|
||||||
|
watch,
|
||||||
|
toRaw,
|
||||||
|
computed,
|
||||||
|
getCurrentInstance,
|
||||||
|
onMounted,
|
||||||
|
onUnmounted
|
||||||
|
} from "vue";
|
||||||
import MyTable from "@/components/aboutTable/MyTable.vue";
|
import MyTable from "@/components/aboutTable/MyTable.vue";
|
||||||
import ChooseMarks from "@/components/ChooseList/ChooseMarks/index.vue";
|
import ChooseMarks from "@/components/ChooseList/ChooseMarks/index.vue";
|
||||||
import { tbGsxtZdryUpdate } from '@/api/zdr.js'
|
import { tbGsxtZdryUpdate } from "@/api/zdr.js";
|
||||||
import { ElMessage, ElMessageBox } from "element-plus";
|
import { ElMessage, ElMessageBox } from "element-plus";
|
||||||
const { proxy } = getCurrentInstance();
|
const { proxy } = getCurrentInstance();
|
||||||
const { D_GS_BQ_DJ, D_GS_SSYJ } = proxy.$dict("D_GS_BQ_DJ", "D_GS_SSYJ"); //获取字典数据
|
const { D_GS_BQ_DJ, D_GS_SSYJ } = proxy.$dict("D_GS_BQ_DJ", "D_GS_SSYJ"); //获取字典数据
|
||||||
const chooseMarksVisible = ref(false)
|
const chooseMarksVisible = ref(false);
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
dataList: {
|
dataList: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: () => { },
|
default: () => {}
|
||||||
}, disabled: {
|
},
|
||||||
|
disabled: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
},
|
},
|
||||||
showBut: {
|
showBut: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
},
|
|
||||||
})
|
|
||||||
const listData = ref({})
|
|
||||||
watch(() => props.dataList, (val) => {
|
|
||||||
if (val) {
|
|
||||||
listData.value = val
|
|
||||||
pageData.tableData = val.bqList
|
|
||||||
roleIds.value = val.bqList.map(v => v.bqId)
|
|
||||||
console.log(roleIds.value);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}, { deep: true })
|
});
|
||||||
const roleIds = ref([])
|
|
||||||
|
const listData = ref({});
|
||||||
|
const roleIds = ref([]);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.dataList,
|
||||||
|
(val) => {
|
||||||
|
if (val) {
|
||||||
|
listData.value = val;
|
||||||
|
pageData.tableData = val.bqList;
|
||||||
|
roleIds.value = val.bqList.map((v) => v.bqId);
|
||||||
|
console.log(roleIds.value);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ deep: true }
|
||||||
|
);
|
||||||
|
|
||||||
// 表格数据
|
// 表格数据
|
||||||
const pageData = reactive({
|
const pageData = reactive({
|
||||||
tableData: [],
|
tableData: [],
|
||||||
tableColumn: [{
|
tableColumn: [
|
||||||
prop: 'bqMc',
|
{
|
||||||
label: '标签名称',
|
prop: "bqMc",
|
||||||
showOverflowTooltip: true
|
label: "标签名称",
|
||||||
}, {
|
showOverflowTooltip: true
|
||||||
prop: 'bqDm',
|
},
|
||||||
label: '标签代码',
|
{
|
||||||
}, {
|
prop: "bqDm",
|
||||||
showSolt: true,
|
label: "标签代码"
|
||||||
prop: 'bqLx',
|
},
|
||||||
label: '标签类型',
|
{
|
||||||
}, {
|
showSolt: true,
|
||||||
showSolt: true,
|
prop: "bqLx",
|
||||||
prop: 'bqLb',
|
label: "标签类型"
|
||||||
label: '标签类别',
|
},
|
||||||
}],
|
{
|
||||||
tableHeight: '200px',
|
showSolt: true,
|
||||||
|
prop: "bqLb",
|
||||||
|
label: "标签类别"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
tableHeight: "200px",
|
||||||
keyCount: 0,
|
keyCount: 0,
|
||||||
tableConfiger: {
|
tableConfiger: {
|
||||||
border: true,
|
border: true,
|
||||||
stripe: true,
|
stripe: true,
|
||||||
showHeader: true,
|
showHeader: true,
|
||||||
showIndex: true,
|
showIndex: true,
|
||||||
indexLabel: '序号',
|
indexLabel: "序号",
|
||||||
indexWidth: 60,
|
indexWidth: 60,
|
||||||
align: 'center',
|
align: "center",
|
||||||
showOverflowTooltip: true,
|
showOverflowTooltip: true,
|
||||||
haveControls: !props.disabled
|
haveControls: !props.disabled
|
||||||
},
|
},
|
||||||
controlsWidth: 200,
|
controlsWidth: 200
|
||||||
})
|
});
|
||||||
|
|
||||||
|
// 计算默认的标签类型:如果已选数据中有身份标签则默认显示身份标签,否则默认显示行为标签
|
||||||
|
const defaultBqLx = computed(() => {
|
||||||
|
if (roleIds.value && roleIds.value.length > 0) {
|
||||||
|
const selectedItem = pageData.tableData.find((item) => roleIds.value.includes(item.bqId));
|
||||||
|
if (selectedItem && selectedItem.bqLx) {
|
||||||
|
return selectedItem.bqLx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "02";
|
||||||
|
});
|
||||||
// 修改数据接口
|
// 修改数据接口
|
||||||
const zdqtUpdate = (val) => {
|
const zdqtUpdate = (val) => {
|
||||||
const params = {
|
const params = {
|
||||||
id: listData.value.id,
|
id: listData.value.id,
|
||||||
bqList: pageData.tableData,
|
bqList: pageData.tableData,
|
||||||
rySfzh: listData.value.rySfzh,
|
rySfzh: listData.value.rySfzh
|
||||||
}
|
};
|
||||||
tbGsxtZdryUpdate(params).then(res => {
|
tbGsxtZdryUpdate(params).then((res) => {
|
||||||
proxy.$message({
|
proxy.$message({
|
||||||
message: val,
|
message: val,
|
||||||
type: 'success'
|
type: "success"
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
// 新增标签
|
// 新增标签
|
||||||
const addMarks = (val) => {
|
const addMarks = (val) => {
|
||||||
pageData.tableData = val.map(v => {
|
pageData.tableData = val.map((v) => {
|
||||||
return { bqDm: v.bqDm, bqId: v.id, bqLb: v.bqLb, bqLx: v.bqLx, bqMc: v.bqMc }
|
return {
|
||||||
|
bqDm: v.bqDm,
|
||||||
|
bqId: v.id,
|
||||||
|
bqLb: v.bqLb,
|
||||||
|
bqLx: v.bqLx,
|
||||||
|
bqMc: v.bqMc,
|
||||||
|
bqYs: v.bqYs
|
||||||
|
};
|
||||||
});
|
});
|
||||||
roleIds.value = val.map(v => v.id)
|
roleIds.value = val.map((v) => v.id);
|
||||||
if (!props.disabled && props.showBut) {
|
if (!props.disabled && props.showBut) {
|
||||||
zdqtUpdate("标签添加成功")
|
zdqtUpdate("标签添加成功");
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
// 删除标签
|
// 删除标签
|
||||||
const delDictItem = (val) => {
|
const delDictItem = (val) => {
|
||||||
if (!props.disabled && props.showBut) {
|
if (!props.disabled && props.showBut) {
|
||||||
ElMessageBox.confirm(
|
ElMessageBox.confirm("是否删除标签", "提示", {
|
||||||
'是否删除标签',
|
confirmButtonText: "确认",
|
||||||
'提示',
|
cancelButtonText: "取消",
|
||||||
{
|
type: "warning"
|
||||||
confirmButtonText: '确认',
|
|
||||||
cancelButtonText: '取消',
|
|
||||||
type: 'warning',
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.then(() => {
|
|
||||||
pageData.tableData = pageData.tableData.filter(v => v.bqId != val)
|
|
||||||
roleIds.value = roleIds.value.filter(v => v != val)
|
|
||||||
zdqtUpdate("标签删除成功")
|
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.then(() => {
|
||||||
ElMessage({
|
pageData.tableData = pageData.tableData.filter((v) => v.bqId != val);
|
||||||
type: 'info',
|
roleIds.value = roleIds.value.filter((v) => v != val);
|
||||||
message: '取消删除',
|
zdqtUpdate("标签删除成功");
|
||||||
})
|
})
|
||||||
})
|
.catch(() => {
|
||||||
|
ElMessage({
|
||||||
|
type: "info",
|
||||||
|
message: "取消删除"
|
||||||
|
});
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
pageData.tableData = pageData.tableData.filter(v => v.bqId != val)
|
pageData.tableData = pageData.tableData.filter((v) => v.bqId != val);
|
||||||
roleIds.value = roleIds.value.filter(v => v != val)
|
roleIds.value = roleIds.value.filter((v) => v != val);
|
||||||
}
|
}
|
||||||
|
};
|
||||||
}
|
|
||||||
// 抛出数据并验证标签列表不为空
|
// 抛出数据并验证标签列表不为空
|
||||||
const throwData = () => {
|
const throwData = () => {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
// 验证:确保标签列表不为空
|
// 验证:确保标签列表不为空
|
||||||
if (!pageData.tableData || pageData.tableData.length === 0) {
|
if (!pageData.tableData || pageData.tableData.length === 0) {
|
||||||
throw new Error('请选择群体标签');
|
throw new Error("请选择群体标签");
|
||||||
}
|
}
|
||||||
resolve(pageData.tableData);
|
resolve(pageData.tableData);
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
defineExpose({
|
defineExpose({
|
||||||
throwData
|
throwData
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@ -196,7 +245,7 @@ defineExpose({
|
|||||||
}
|
}
|
||||||
|
|
||||||
.headClass::after {
|
.headClass::after {
|
||||||
content: '';
|
content: "";
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 0;
|
left: 0;
|
||||||
bottom: -2px;
|
bottom: -2px;
|
||||||
|
|||||||
@ -4,34 +4,95 @@
|
|||||||
<div class="query-grid">
|
<div class="query-grid">
|
||||||
<div v-for="field in renderFields" :key="field.key" class="query-cell">
|
<div v-for="field in renderFields" :key="field.key" class="query-cell">
|
||||||
<div class="cell-label">{{ field.label }}</div>
|
<div class="cell-label">{{ field.label }}</div>
|
||||||
<div class="cell-control" :class="{ 'is-checkbox': field.type === 'checkbox' }">
|
<div
|
||||||
<el-input clearable v-if="field.type === 'input'" v-model="formState[field.key]" class="control-input"
|
class="cell-control"
|
||||||
:placeholder="field.placeholder || ''" />
|
:class="{ 'is-checkbox': field.type === 'checkbox' }"
|
||||||
<el-input clearable v-else-if="field.type === 'number'" v-model="formState[field.key]" class="control-input"
|
>
|
||||||
type="number" :placeholder="field.placeholder || ''" />
|
<el-input
|
||||||
<el-select clearable v-else-if="field.type === 'select'" v-model="formState[field.key]" class="control-select"
|
clearable
|
||||||
:placeholder="field.placeholder || '请选择'" :multiple="field.multiple || false" collapse-tags
|
v-if="field.type === 'input'"
|
||||||
collapse-tags-tooltip>
|
v-model="formState[field.key]"
|
||||||
<el-option v-for="item in field.options || []" :key="item.value ?? item" :label="item.label ?? item"
|
class="control-input"
|
||||||
:value="item.value ?? item" />
|
:placeholder="field.placeholder || ''"
|
||||||
|
/>
|
||||||
|
<el-input
|
||||||
|
clearable
|
||||||
|
v-else-if="field.type === 'number'"
|
||||||
|
v-model="formState[field.key]"
|
||||||
|
class="control-input"
|
||||||
|
type="number"
|
||||||
|
:placeholder="field.placeholder || ''"
|
||||||
|
/>
|
||||||
|
<el-select
|
||||||
|
clearable
|
||||||
|
v-else-if="field.type === 'select'"
|
||||||
|
v-model="formState[field.key]"
|
||||||
|
class="control-select"
|
||||||
|
:placeholder="field.placeholder || '请选择'"
|
||||||
|
:multiple="field.multiple || false"
|
||||||
|
collapse-tags
|
||||||
|
collapse-tags-tooltip
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in field.options || []"
|
||||||
|
:key="item.value ?? item"
|
||||||
|
:label="item.label ?? item"
|
||||||
|
:value="item.value ?? item"
|
||||||
|
/>
|
||||||
</el-select>
|
</el-select>
|
||||||
<el-date-picker clearable v-else-if="field.type === 'date'" v-model="formState[field.key]"
|
<el-date-picker
|
||||||
class="control-date" type="date" :placeholder="field.placeholder || '请选择日期'" value-format="YYYY-MM-DD" />
|
clearable
|
||||||
<el-date-picker clearable v-else-if="field.type === 'datetime'" v-model="formState[field.key]"
|
v-else-if="field.type === 'date'"
|
||||||
class="control-date" type="datetime" :placeholder="field.placeholder || '请选择时间'"
|
v-model="formState[field.key]"
|
||||||
value-format="YYYY-MM-DD HH:mm:ss" />
|
class="control-date"
|
||||||
<el-date-picker clearable v-else-if="field.type === 'daterange'" v-model="formState[field.key]"
|
type="date"
|
||||||
class="control-date" type="daterange" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期"
|
:placeholder="field.placeholder || '请选择日期'"
|
||||||
value-format="YYYY-MM-DD" />
|
value-format="YYYY-MM-DD"
|
||||||
<el-date-picker clearable v-else-if="field.type === 'datetimerange'" v-model="formState[field.key]"
|
/>
|
||||||
class="control-date" type="datetimerange" range-separator="至" start-placeholder="开始时间"
|
<el-date-picker
|
||||||
end-placeholder="结束时间" value-format="YYYY-MM-DD HH:mm:ss" />
|
clearable
|
||||||
|
v-else-if="field.type === 'datetime'"
|
||||||
|
v-model="formState[field.key]"
|
||||||
|
class="control-date"
|
||||||
|
type="datetime"
|
||||||
|
:placeholder="field.placeholder || '请选择时间'"
|
||||||
|
value-format="YYYY-MM-DD HH:mm:ss"
|
||||||
|
/>
|
||||||
|
<el-date-picker
|
||||||
|
clearable
|
||||||
|
v-else-if="field.type === 'daterange'"
|
||||||
|
v-model="formState[field.key]"
|
||||||
|
class="control-date"
|
||||||
|
type="daterange"
|
||||||
|
range-separator="至"
|
||||||
|
start-placeholder="开始日期"
|
||||||
|
end-placeholder="结束日期"
|
||||||
|
value-format="YYYY-MM-DD"
|
||||||
|
/>
|
||||||
|
<el-date-picker
|
||||||
|
clearable
|
||||||
|
v-else-if="field.type === 'datetimerange'"
|
||||||
|
v-model="formState[field.key]"
|
||||||
|
class="control-date"
|
||||||
|
type="datetimerange"
|
||||||
|
range-separator="至"
|
||||||
|
start-placeholder="开始时间"
|
||||||
|
end-placeholder="结束时间"
|
||||||
|
value-format="YYYY-MM-DD HH:mm:ss"
|
||||||
|
/>
|
||||||
<template v-else-if="field.type === 'department'">
|
<template v-else-if="field.type === 'department'">
|
||||||
<MOSTY.Department clearable v-model="formState[field.key]" class="control-select" />
|
<MOSTY.Department
|
||||||
|
clearable
|
||||||
|
v-model="formState[field.key]"
|
||||||
|
class="control-select"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
<div v-else-if="field.type === 'checkbox'" class=" checkbox-wrap">
|
<div v-else-if="field.type === 'checkbox'" class="checkbox-wrap">
|
||||||
<el-checkbox v-model="formState[field.key]" />
|
<el-checkbox v-model="formState[field.key]" />
|
||||||
</div>
|
</div>
|
||||||
|
<div v-else-if="field.type === 'slot'" class="checkbox-wrap">
|
||||||
|
<slot :name="field.key" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -40,24 +101,28 @@
|
|||||||
<slot name="but"></slot>
|
<slot name="but"></slot>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<el-button size="small" type="primary" @click="handleSearch">{{ searchText }}</el-button>
|
<el-button size="small" type="primary" @click="handleSearch">{{
|
||||||
<el-button size="small" type="button" @click="handleReset">重置 </el-button>
|
searchText
|
||||||
|
}}</el-button>
|
||||||
|
<el-button size="small" type="button" @click="handleReset"
|
||||||
|
>重置
|
||||||
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed, reactive, watch } from 'vue'
|
import { computed, reactive, watch } from "vue";
|
||||||
import * as MOSTY from "@/components/MyComponents/index";
|
import * as MOSTY from "@/components/MyComponents/index";
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
title: {
|
title: {
|
||||||
type: String,
|
type: String,
|
||||||
default: '查询条件'
|
default: "查询条件"
|
||||||
},
|
},
|
||||||
searchText: {
|
searchText: {
|
||||||
type: String,
|
type: String,
|
||||||
default: '查询'
|
default: "查询"
|
||||||
},
|
},
|
||||||
fields: {
|
fields: {
|
||||||
type: Array,
|
type: Array,
|
||||||
@ -67,100 +132,106 @@ const props = defineProps({
|
|||||||
type: Array,
|
type: Array,
|
||||||
default: () => []
|
default: () => []
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
const emit = defineEmits(['search', 'submit', 'reset'])
|
const emit = defineEmits(["search", "submit", "reset"]);
|
||||||
const formState = reactive({})
|
const formState = reactive({});
|
||||||
|
|
||||||
const renderFields = computed(() => {
|
const renderFields = computed(() => {
|
||||||
const source = props.searchArr.length ? props.searchArr : props.fields
|
const source = props.searchArr.length ? props.searchArr : props.fields;
|
||||||
return source.map((field) => ({
|
return source
|
||||||
...field,
|
.map((field) => ({
|
||||||
key: field.key || field.prop,
|
...field,
|
||||||
type: field.type || field.showType || 'input'
|
key: field.key || field.prop,
|
||||||
})).filter((field) => field.key)
|
type: field.type || field.showType || "input"
|
||||||
})
|
}))
|
||||||
|
.filter((field) => field.key);
|
||||||
|
});
|
||||||
|
|
||||||
const getResetValue = (field) => {
|
const getResetValue = (field) => {
|
||||||
if (field.defaultVal !== undefined) {
|
if (field.defaultVal !== undefined) {
|
||||||
return Array.isArray(field.defaultVal) ? [...field.defaultVal] : field.defaultVal
|
return Array.isArray(field.defaultVal)
|
||||||
|
? [...field.defaultVal]
|
||||||
|
: field.defaultVal;
|
||||||
}
|
}
|
||||||
if (field.type === 'checkbox') {
|
if (field.type === "checkbox") {
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
if (field.type === 'daterange' || field.type === 'datetimerange') {
|
if (field.type === "daterange" || field.type === "datetimerange") {
|
||||||
return []
|
return [];
|
||||||
}
|
}
|
||||||
if (field.type === 'select') {
|
if (field.type === "select") {
|
||||||
if (field.multiple) {
|
if (field.multiple) {
|
||||||
return []
|
return [];
|
||||||
}
|
}
|
||||||
return null
|
return null;
|
||||||
}
|
}
|
||||||
return ''
|
return "";
|
||||||
}
|
};
|
||||||
|
|
||||||
const buildResetPayload = () => {
|
const buildResetPayload = () => {
|
||||||
const payload = {}
|
const payload = {};
|
||||||
renderFields.value.forEach((field) => {
|
renderFields.value.forEach((field) => {
|
||||||
payload[field.key] = getResetValue(field)
|
payload[field.key] = getResetValue(field);
|
||||||
})
|
});
|
||||||
return payload
|
return payload;
|
||||||
}
|
};
|
||||||
|
|
||||||
const setFormState = (value = {}) => {
|
const setFormState = (value = {}) => {
|
||||||
Object.keys(formState).forEach((key) => {
|
Object.keys(formState).forEach((key) => {
|
||||||
delete formState[key]
|
delete formState[key];
|
||||||
})
|
});
|
||||||
renderFields.value.forEach((field) => {
|
renderFields.value.forEach((field) => {
|
||||||
if (value[field.key] !== undefined) {
|
if (value[field.key] !== undefined) {
|
||||||
formState[field.key] = Array.isArray(value[field.key]) ? [...value[field.key]] : value[field.key]
|
formState[field.key] = Array.isArray(value[field.key])
|
||||||
return
|
? [...value[field.key]]
|
||||||
|
: value[field.key];
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
formState[field.key] = getResetValue(field)
|
formState[field.key] = getResetValue(field);
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
const getFormSnapshot = () => {
|
const getFormSnapshot = () => {
|
||||||
const snapshot = {}
|
const snapshot = {};
|
||||||
renderFields.value.forEach((field) => {
|
renderFields.value.forEach((field) => {
|
||||||
const value = formState[field.key]
|
const value = formState[field.key];
|
||||||
if (Array.isArray(value)) {
|
if (Array.isArray(value)) {
|
||||||
snapshot[field.key] = [...value]
|
snapshot[field.key] = [...value];
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
snapshot[field.key] = value
|
snapshot[field.key] = value;
|
||||||
})
|
});
|
||||||
return snapshot
|
return snapshot;
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleSearch = () => {
|
const handleSearch = () => {
|
||||||
const payload = getFormSnapshot()
|
const payload = getFormSnapshot();
|
||||||
emit('search', payload)
|
emit("search", payload);
|
||||||
emit('submit', payload)
|
emit("submit", payload);
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleReset = () => {
|
const handleReset = () => {
|
||||||
const payload = buildResetPayload()
|
const payload = buildResetPayload();
|
||||||
setFormState(payload)
|
setFormState(payload);
|
||||||
emit('reset', true)
|
emit("reset", true);
|
||||||
emit('search', payload)
|
emit("search", payload);
|
||||||
emit('submit', payload)
|
emit("submit", payload);
|
||||||
}
|
};
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
renderFields,
|
renderFields,
|
||||||
() => {
|
() => {
|
||||||
setFormState(buildResetPayload())
|
setFormState(buildResetPayload());
|
||||||
},
|
},
|
||||||
{ immediate: true }
|
{ immediate: true }
|
||||||
)
|
);
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
formState,
|
formState,
|
||||||
handleSearch,
|
handleSearch,
|
||||||
handleReset
|
handleReset
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
|
|||||||
@ -1,32 +1,70 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<PageTitle :malginLeft="10" :height="35" backgroundColor="#ffff" :marginBottom="5" :marginTop="5">
|
<PageTitle
|
||||||
|
:malginLeft="10"
|
||||||
|
:height="35"
|
||||||
|
backgroundColor="#ffff"
|
||||||
|
:marginBottom="5"
|
||||||
|
:marginTop="5"
|
||||||
|
>
|
||||||
<template #left>
|
<template #left>
|
||||||
<!-- -->
|
<!-- -->
|
||||||
<template v-for="(item, index) in butList" :key="index">
|
<template v-for="(item, index) in butList" :key="index">
|
||||||
<el-popover placement="right" :width="240" style='height: 300px;' trigger="click" v-if="item == '布控预警'">
|
<!-- <el-popover
|
||||||
|
placement="right"
|
||||||
|
:width="240"
|
||||||
|
style="height: 300px"
|
||||||
|
trigger="click"
|
||||||
|
v-if="item == '布控预警'"
|
||||||
|
>
|
||||||
<template #reference>
|
<template #reference>
|
||||||
<el-button :type="butStylChange(qh) ? 'primary' : 'default'" size="small">{{ item }}</el-button>
|
<el-button
|
||||||
|
:type="butStylChange(qh) ? 'primary' : 'default'"
|
||||||
|
size="small"
|
||||||
|
>{{ item }}</el-button
|
||||||
|
>
|
||||||
</template>
|
</template>
|
||||||
<el-select v-model="value" placeholder="请选择预警类型" @change="qh = value">
|
<el-select
|
||||||
|
v-model="value"
|
||||||
|
placeholder="请选择预警类型"
|
||||||
|
@change="qh = value"
|
||||||
|
>
|
||||||
<el-option label="人像预警" value="人像预警" />
|
<el-option label="人像预警" value="人像预警" />
|
||||||
<el-option label="车辆预警" value="车辆预警" />
|
<el-option label="车辆预警" value="车辆预警" />
|
||||||
<el-option label="区域预警" value="区域预警" />
|
<el-option label="区域预警" value="区域预警" />
|
||||||
<el-option label="布控预警" value="布控预警" />
|
<el-option label="布控预警" value="布控预警" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-popover>
|
</el-popover> -->
|
||||||
<el-popover placement="right" :width="240" style='height: 300px;' trigger="click" v-else-if="item == '标签预警'">
|
<!-- <el-popover
|
||||||
|
placement="right"
|
||||||
|
:width="240"
|
||||||
|
style="height: 300px"
|
||||||
|
trigger="click"
|
||||||
|
v-if="item == '标签预警'"
|
||||||
|
>
|
||||||
<template #reference>
|
<template #reference>
|
||||||
<el-button :type="BqbutStylChange(qh) ? 'primary' : 'default'" size="small">{{ item }}</el-button>
|
<el-button
|
||||||
|
:type="BqbutStylChange(qh) ? 'primary' : 'default'"
|
||||||
|
size="small"
|
||||||
|
>{{ item }}</el-button
|
||||||
|
>
|
||||||
</template>
|
</template>
|
||||||
<el-select v-model="Bqvalue" placeholder="请选择预警类型" @change="qh = Bqvalue">
|
<el-select
|
||||||
|
v-model="Bqvalue"
|
||||||
|
placeholder="请选择预警类型"
|
||||||
|
@change="qh = Bqvalue"
|
||||||
|
>
|
||||||
<el-option label="身份预警" value="身份预警" />
|
<el-option label="身份预警" value="身份预警" />
|
||||||
<el-option label="行为预警" value="行为预警" />
|
<el-option label="行为预警" value="行为预警" />
|
||||||
<el-option label="组合预警" value="组合预警" />
|
<el-option label="组合预警" value="组合预警" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-popover>
|
</el-popover> -->
|
||||||
<el-button :type="qh == item ? 'primary' : 'default'" @click="qh = item" size="small" v-else>{{ item
|
<el-button
|
||||||
}}</el-button>
|
:type="qh == item ? 'primary' : 'default'"
|
||||||
|
@click="qh = item"
|
||||||
|
size="small"
|
||||||
|
>{{ item }}</el-button
|
||||||
|
>
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
</PageTitle>
|
</PageTitle>
|
||||||
@ -41,57 +79,63 @@
|
|||||||
<IdentityWarning v-if="qh == '身份预警'" />
|
<IdentityWarning v-if="qh == '身份预警'" />
|
||||||
<BehaviorWarning v-if="qh == '行为预警'" />
|
<BehaviorWarning v-if="qh == '行为预警'" />
|
||||||
<CombinedWarning v-if="qh == '组合预警'" />
|
<CombinedWarning v-if="qh == '组合预警'" />
|
||||||
|
<LabelWarning v-if="qh == '标签预警'" />
|
||||||
<!-- <Cs v-if="qh == '测试'" /> -->
|
<!-- <Cs v-if="qh == '测试'" /> -->
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import { getItem } from '@//utils/storage.js'
|
import { getItem } from "@//utils/storage.js";
|
||||||
import PageTitle from "@/components/aboutTable/PageTitle.vue";
|
import PageTitle from "@/components/aboutTable/PageTitle.vue";
|
||||||
import FouColorWarning from "@/views/backOfficeSystem/fourColorManage/warningControl/fouColorWarning/index.vue"
|
import FouColorWarning from "@/views/backOfficeSystem/fourColorManage/warningControl/fouColorWarning/index.vue";
|
||||||
import SevenWarning from "@/views/backOfficeSystem/fourColorManage/warningControl/sevenWarning/index.vue"
|
import SevenWarning from "@/views/backOfficeSystem/fourColorManage/warningControl/sevenWarning/index.vue";
|
||||||
import IdentityWarning from "@/views/backOfficeSystem/fourColorManage/warningControl/identityWarning/index.vue"
|
import IdentityWarning from "@/views/backOfficeSystem/fourColorManage/warningControl/identityWarning/index.vue";
|
||||||
import BehaviorWarning from "@/views/backOfficeSystem/fourColorManage/warningControl/behaviorWarning/index.vue"
|
import BehaviorWarning from "@/views/backOfficeSystem/fourColorManage/warningControl/behaviorWarning/index.vue";
|
||||||
import CombinedWarning from "@/views/backOfficeSystem/fourColorManage/warningControl/combinedWarning/index.vue"
|
import CombinedWarning from "@/views/backOfficeSystem/fourColorManage/warningControl/combinedWarning/index.vue";
|
||||||
import PortraitWarning from "@/views/backOfficeSystem/fourColorManage/warningList/portraitWarning/index.vue"
|
import PortraitWarning from "@/views/backOfficeSystem/fourColorManage/warningList/portraitWarning/index.vue";
|
||||||
import VehicleWarning from "@/views/backOfficeSystem/fourColorManage/warningList/vehicleWarning/index.vue"
|
import VehicleWarning from "@/views/backOfficeSystem/fourColorManage/warningList/vehicleWarning/index.vue";
|
||||||
import ControlWarning from "@/views/backOfficeSystem/fourColorManage/warningControl/controlWarning/index.vue"
|
// import ControlWarning from "@/views/backOfficeSystem/fourColorManage/warningControl/controlWarning/index.vue";
|
||||||
import RegionalControl from "@/views/backOfficeSystem/fourColorManage/warningControl/regionalControl/index.vue"
|
import RegionalControl from "@/views/backOfficeSystem/fourColorManage/warningControl/regionalControl/index.vue";
|
||||||
import WrjWarning from "@/views/backOfficeSystem/fourColorManage/warningControl/wrjWarning/index.vue"
|
import WrjWarning from "@/views/backOfficeSystem/fourColorManage/warningControl/wrjWarning/index.vue";
|
||||||
import PoliticalSecurityWarning from "@/views/backOfficeSystem/fourColorManage/warningControl/politicalSecurity/index.vue"
|
import PoliticalSecurityWarning from "@/views/backOfficeSystem/fourColorManage/warningControl/politicalSecurity/index.vue";
|
||||||
|
import ControlWarning from "@/views/backOfficeSystem/fourColorManage/warningControl/deploymentIntegration/index.vue";
|
||||||
import Cs from '@/views/backOfficeSystem/ces/index.vue'
|
import LabelWarning from "@/views/backOfficeSystem/fourColorManage/warningControl/iabelWarning/index.vue";
|
||||||
import { onMounted, ref } from "vue";
|
import { onMounted, ref } from "vue";
|
||||||
// "人像预警", "车辆预警",, "区域预警","无人机预警"
|
// "人像预警", "车辆预警",, "区域预警","无人机预警"
|
||||||
const butList = ref(["七类重点", '政保预警', "布控预警", "预警整合"])
|
const butList = ref(["七类重点", "政保预警", "布控预警", "预警整合"]);
|
||||||
const qh = ref('七类重点')
|
const qh = ref("七类重点");
|
||||||
const value = ref('人像预警')
|
const value = ref("人像预警");
|
||||||
const Bqvalue = ref('身份预警')
|
const Bqvalue = ref("身份预警");
|
||||||
const butStyle = ref()
|
const butStyle = ref();
|
||||||
const hasPermissin = ref(false)
|
const hasPermissin = ref(false);
|
||||||
const butStylChange = (val) => {
|
const butStylChange = (val) => {
|
||||||
return ["人像预警", "车辆预警", "区域预警", "布控预警"].includes(val)
|
return ["人像预警", "车辆预警", "区域预警", "布控预警"].includes(val);
|
||||||
|
};
|
||||||
}
|
|
||||||
const BqbutStylChange = (val) => {
|
const BqbutStylChange = (val) => {
|
||||||
return ["身份预警", "行为预警", "组合预警"].includes(val)
|
return ["身份预警", "行为预警", "组合预警"].includes(val);
|
||||||
}
|
};
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
// rolCode : 市情指领导(JS_666666)、市情指权限(JS_777777)、县情指权限(JS_888888)、县情指领导权限(JS_999999);
|
// rolCode : 市情指领导(JS_666666)、市情指权限(JS_777777)、县情指权限(JS_888888)、县情指领导权限(JS_999999);
|
||||||
// depCode : 市情指领导(513030199509084123 )、市情指(340827200404141028)、县情指领导(540421196805217650)、朗县公安局指挥中心(县情指)(540422200010197030)、朗县公安局县城派出所(部门)(513425199305205211)
|
// depCode : 市情指领导(513030199509084123 )、市情指(340827200404141028)、县情指领导(540421196805217650)、朗县公安局指挥中心(县情指)(540422200010197030)、朗县公安局县城派出所(部门)(513425199305205211)
|
||||||
let rolCode = ['JS_666666', 'JS_777777', 'JS_888888', 'JS_999999']
|
let rolCode = ["JS_666666", "JS_777777", "JS_888888", "JS_999999"];
|
||||||
let depCode = ['513030199509084123', '340827200404141028', '540421196805217650', '540422200010197030', '513425199305205211']
|
// let depCode = [
|
||||||
let roleData = getItem('roleList');
|
// "513030199509084123",
|
||||||
let deptData = getItem('deptId');
|
// "340827200404141028",
|
||||||
roleData.forEach(item => {
|
// "540421196805217650",
|
||||||
if (rolCode.includes(item.roleCode)) hasPermissin.value = true
|
// "540422200010197030",
|
||||||
})
|
// "513425199305205211"
|
||||||
deptData.forEach(item => {
|
// ];
|
||||||
if (depCode.includes(item.deptCode)) hasPermissin.value = true
|
let roleData = getItem("roleList");
|
||||||
})
|
// let deptData = getItem("deptId");
|
||||||
|
roleData.forEach((item) => {
|
||||||
|
if (rolCode.includes(item.roleCode)) hasPermissin.value = true;
|
||||||
|
});
|
||||||
|
// deptData.forEach((item) => {
|
||||||
|
// if (depCode.includes(item.deptCode)) hasPermissin.value = true;
|
||||||
|
// });
|
||||||
if (hasPermissin.value) {
|
if (hasPermissin.value) {
|
||||||
const data = butList.value.filter(item => item !== "预警整合")
|
const data = butList.value.filter((item) => item !== "预警整合");
|
||||||
// "身份预警", "行为预警", "组合预警"
|
// "身份预警", "行为预警", "组合预警"
|
||||||
butList.value = [...data, ...["标签预警", "预警整合"]]
|
butList.value = [...data, ...["标签预警", "预警整合"]];
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -0,0 +1,79 @@
|
|||||||
|
<template>
|
||||||
|
<div class="dialog" v-if="dialogForm">
|
||||||
|
<div class="head_box">
|
||||||
|
<span class="title">身份预警{{ title }} </span>
|
||||||
|
<div>
|
||||||
|
<!-- <el-button type="primary" size="small" :loading="loading" @click="submit">保存</el-button> -->
|
||||||
|
<el-button size="small" @click="close">关闭</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form_cnt">
|
||||||
|
<FormMessage :formList="formData" disabled v-model="listQuery" ref="elform">
|
||||||
|
</FormMessage>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import FormMessage from "@/components/aboutTable/FormMessage.vue";
|
||||||
|
import { qcckGet, qcckPost } from "@/api/qcckApi.js";
|
||||||
|
import { ref, defineExpose, reactive, defineEmits, getCurrentInstance, watch } from "vue";
|
||||||
|
const emit = defineEmits(["updateDate"]);
|
||||||
|
const props = defineProps({
|
||||||
|
dict: {
|
||||||
|
type: Object,
|
||||||
|
default: () => { }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const { proxy } = getCurrentInstance();
|
||||||
|
const dialogForm = ref(false); //弹窗
|
||||||
|
const formData = ref([])
|
||||||
|
watch(() => props.dict, (res) => {
|
||||||
|
if (res) {
|
||||||
|
formData.value = [
|
||||||
|
{ label: "预警人员姓名", prop: "yjRyxm", type: "input" },
|
||||||
|
{ label: "预警人员身份证号码", prop: "yjRysfzh", type: "input" },
|
||||||
|
{ label: "电话", prop: "dh", type: "input" },
|
||||||
|
{ label: "预警标签", prop: "yjbqmc", type: "input" },
|
||||||
|
{ label: "今日预警次数", prop: "yjJrcs", type: "input",lx:"number" },
|
||||||
|
{ label: "标签颜色", prop: "yjJb", type: "select", options: props.dict.D_GS_SSYJ },
|
||||||
|
{ label: "预警标题", prop: "yjBt", type: "input" },
|
||||||
|
{ label: "预警内容", prop: "yjNr", type: "input" },
|
||||||
|
{ label: "预警时间", prop: "yjFssj", type: "input" },
|
||||||
|
{ label: "处置状态", prop: "czzt", type: "select", options: props.dict.D_GSXT_YJXX_CZZT },
|
||||||
|
{ label: "所属部门", prop: "ssbm", type: "input" },
|
||||||
|
{ label: "所属县局", prop: "ssxgaj", type: "input" },
|
||||||
|
{ label: "所属市局", prop: "sssgaj", type: "input" },
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}, { deep: true, immediate: true })
|
||||||
|
const listQuery = ref({}); //表单
|
||||||
|
const loading = ref(false);
|
||||||
|
const title = ref("详情");
|
||||||
|
const init = (type, row) => {
|
||||||
|
dialogForm.value = true;
|
||||||
|
qcckGet({},'/mosty-gsxt/tbYjxx/getInfo/'+ row.id).then((res) => {
|
||||||
|
listQuery.value = res || {}
|
||||||
|
})
|
||||||
|
|
||||||
|
};
|
||||||
|
// 关闭
|
||||||
|
const close = () => {
|
||||||
|
listQuery.value = {};
|
||||||
|
loading.value = false;
|
||||||
|
dialogForm.value = false;
|
||||||
|
listQuery.value = {}
|
||||||
|
};
|
||||||
|
|
||||||
|
defineExpose({ init });
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "~@/assets/css/layout.scss";
|
||||||
|
@import "~@/assets/css/element-plus.scss";
|
||||||
|
::v-deep {
|
||||||
|
.el-form-item__content {
|
||||||
|
align-items: normal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -0,0 +1,50 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog title="处置建议" v-model="visible" width="50%" v-if="visible" @close="closeHndle">
|
||||||
|
<el-form :model="form" ref="formRef" :rules="rules" label-width="120px" >
|
||||||
|
<el-form-item label="处置建议" prop="jynr">
|
||||||
|
<el-input v-model="form.jynr" placeholder="请输入处置建议" type="textarea"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<div class="flex just-center">
|
||||||
|
<el-button type="primary" @click="okSubmit">确定</el-button>
|
||||||
|
<el-button @click="closeHndle">返回</el-button>
|
||||||
|
</div>
|
||||||
|
</el-form>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { qcckPost } from "@/api/qcckApi.js";
|
||||||
|
import { ref , defineExpose} from 'vue'
|
||||||
|
const emit = defineEmits(['okSubmit'])
|
||||||
|
const visible = ref(false)
|
||||||
|
const formRef = ref()
|
||||||
|
const form = ref({})
|
||||||
|
const rules = ref({
|
||||||
|
jynr: [
|
||||||
|
{ required: true, message: '请输入处置建议', trigger: 'blur' }
|
||||||
|
]
|
||||||
|
})
|
||||||
|
const init = (row) => {
|
||||||
|
visible.value = true;
|
||||||
|
form.value.yjid = row.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
const closeHndle = () => {
|
||||||
|
visible.value = false;
|
||||||
|
form.value = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const okSubmit = async () => {
|
||||||
|
await formRef.value.validate((valid) => {
|
||||||
|
if (!valid) return;
|
||||||
|
let params = {...form.value , lylx:'01'}
|
||||||
|
qcckPost(params,'/mosty-gsxt/yjxx/czjy/insert').then((res) => {
|
||||||
|
emit('okSubmit', {...form.value})
|
||||||
|
closeHndle()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
defineExpose({
|
||||||
|
init
|
||||||
|
})
|
||||||
|
</script>
|
||||||
@ -0,0 +1,478 @@
|
|||||||
|
<!--预警指派展示组件 -->
|
||||||
|
<template>
|
||||||
|
<el-dialog :draggable="true" :model-value="modelValue" :title="title" :width="width" @close="close" append-to-body>
|
||||||
|
<div class="archive-container">
|
||||||
|
<div class="three-column-layout">
|
||||||
|
<!-- 重点人员基本信息页 -->
|
||||||
|
<div class="column">
|
||||||
|
<div class="column-header">重点人员基本信息</div>
|
||||||
|
<div class="info-section">
|
||||||
|
<div class="info-row">
|
||||||
|
<div class="info-item">
|
||||||
|
<span class="info-label">人员姓名:</span>
|
||||||
|
<span class="info-value">{{ dataForm.yjRyxm }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="info-item">
|
||||||
|
<span class="info-label">性别:</span>
|
||||||
|
<span class="info-value">
|
||||||
|
<DictTag :value="dataForm.xbdm" :tag="false" :options="dict.D_BZ_XB" />
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="info-item">
|
||||||
|
<span class="info-label">年龄:</span>
|
||||||
|
<span class="info-value">{{ dataForm.nl }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="info-row">
|
||||||
|
<div class="info-item full-width">
|
||||||
|
<span class="info-label">身份证号码:</span>
|
||||||
|
<span class="info-value">{{ dataForm.yjRysfzh }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="info-row">
|
||||||
|
<div class="info-item full-width">
|
||||||
|
<span class="info-label">户籍地:</span>
|
||||||
|
<span class="info-value">{{ dataForm.hjdXz }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="info-row">
|
||||||
|
<div class="info-item full-width">
|
||||||
|
<span class="info-label">现住地址:</span>
|
||||||
|
<span class="info-value">{{ dataForm.xzdXz }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="info-row">
|
||||||
|
<div class="info-item full-width">
|
||||||
|
<span class="info-label">处置要求:</span>
|
||||||
|
<span class="info-value">
|
||||||
|
<DictTag :value="dataForm.bkczyq" :tag="false" :options="dict.D_GS_BK_CZYQ" />
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="info-row">
|
||||||
|
<div class="info-item full-width">
|
||||||
|
<span class="info-label">预警级别:</span>
|
||||||
|
<span class="info-value warning-level" :class="ys()">
|
||||||
|
<DictTag :value="dataForm.yjJb" :tag="false" :options="dict.D_BZ_YJJB" />
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="info-row">
|
||||||
|
<div class="info-item full-width">
|
||||||
|
<span class="info-label">布控起始时间:</span>
|
||||||
|
<span class="info-value">{{ dataForm.bkkssj }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="info-row">
|
||||||
|
<div class="info-item full-width">
|
||||||
|
<span class="info-label">布控结束时间:</span>
|
||||||
|
<span class="info-value">{{ dataForm.bkjssj }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="info-row">
|
||||||
|
<div class="info-item full-width">
|
||||||
|
<span class="info-label">所属单位:</span>
|
||||||
|
<span class="info-value">{{ dataForm.ssbm }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="info-row">
|
||||||
|
<div class="info-item full-width">
|
||||||
|
<span class="info-label">布控单位:</span>
|
||||||
|
<span class="info-value">{{ dataForm.gkbmmc }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="info-row">
|
||||||
|
<div class="info-item full-width">
|
||||||
|
<span class="info-label">布控原因:</span>
|
||||||
|
<span class="info-value text-area"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="info-row">
|
||||||
|
<div class="info-item full-width">
|
||||||
|
<span class="info-label">一标三实:</span>
|
||||||
|
<span class="info-value text-area"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 重点人员活动信息页 -->
|
||||||
|
<div class="column">
|
||||||
|
<div class="column-header">重点人员活动信息</div>
|
||||||
|
<div class="info-section blue-bg">
|
||||||
|
<div class="info-row">
|
||||||
|
<div class="info-item full-width">
|
||||||
|
<span class="info-label">轨迹类别:</span>
|
||||||
|
<span class="info-value">
|
||||||
|
<DictTag :value="dataForm.yjLylx" :tag="false" :options="dict.D_GS_ZDR_GJLB" />
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="info-row">
|
||||||
|
<div class="info-item full-width">
|
||||||
|
<span class="info-label">核查时间:</span>
|
||||||
|
<span v-if="dataForm.fkList && dataForm.fkList.length > 0">{{ dataForm.fkList[0].czsj }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="info-row">
|
||||||
|
<div class="info-item full-width">
|
||||||
|
<span class="info-label">比对时间:</span>
|
||||||
|
<span class="info-value">{{ dataForm.yjSj }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="info-row">
|
||||||
|
<div class="info-item full-width">
|
||||||
|
<span class="info-label">预警内容:</span>
|
||||||
|
<span class="info-value text-area">{{ dataForm.yjNr }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="info-row">
|
||||||
|
<div class="info-item full-width">
|
||||||
|
<span class="info-label">预警信息提供单位:</span>
|
||||||
|
<span class="info-value">{{ dataForm.jczmc }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="info-row">
|
||||||
|
<div class="info-item full-width">
|
||||||
|
<span class="info-label">预警信息接收单位:</span>
|
||||||
|
<span class="info-value">{{ dataForm.ssbm }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="info-row">
|
||||||
|
<div class="info-item full-width">
|
||||||
|
<span class="info-label">二次指派单位:</span>
|
||||||
|
<span class="info-value">
|
||||||
|
<div v-if="dataForm.zpList && dataForm.zpList.length > 0">
|
||||||
|
<span v-for="(item, index) in dataForm.zpList" :key="item.id">
|
||||||
|
{{ item.zpbm }}<span v-if="index < dataForm.zpList.length - 1">,</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="info-row">
|
||||||
|
<div class="info-item full-width">
|
||||||
|
<span class="info-label">签收时限:</span>
|
||||||
|
<span class="info-value">{{ dataForm.qssj }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="info-row">
|
||||||
|
<div class="info-item full-width">
|
||||||
|
<span class="info-label">反馈时限:</span>
|
||||||
|
<span class="info-value">{{ dataForm.fksj }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="info-row">
|
||||||
|
<div class="info-item full-width">
|
||||||
|
<span class="info-label">处置建议:</span>
|
||||||
|
<span class="info-value text-area">
|
||||||
|
<div v-if="dataForm.czjyList && dataForm.czjyList.length > 0">
|
||||||
|
<div v-for="(item, index) in dataForm.czjyList" :key="item.id">
|
||||||
|
<span>{{ `${index + 1}、` + item.jynr }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="info-row">
|
||||||
|
<div class="info-item full-width">
|
||||||
|
<span class="info-label">反馈内容:</span>
|
||||||
|
<span class="info-value text-area">
|
||||||
|
<div v-if="dataForm.fkList && dataForm.fkList.length > 0">
|
||||||
|
<div v-for="(item, index) in dataForm.fkList" :key="item.id">
|
||||||
|
<span v-if="item.ckczbcxx">{{ `${index + 1}、` + item.ckczbcxx }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 历史预警信息页 -->
|
||||||
|
<div class="column">
|
||||||
|
<div class="column-header">历史预警信息</div>
|
||||||
|
<div class="info-section">
|
||||||
|
<div class="history-item" v-for="(item, index) in dataForm.yjgjList" :key="item.id">
|
||||||
|
<span class="history-index">{{ `${index + 1}:` }}</span>
|
||||||
|
<span class="history-content">{{ item.yjNr }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<template #footer>
|
||||||
|
<div class="dialog-footer" style="text-align: center;">
|
||||||
|
<el-button @click="close">关闭</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import { defineProps, getCurrentInstance, watch, ref } from 'vue';
|
||||||
|
import { qcckGet } from '@/api/qcckApi.js'
|
||||||
|
const { proxy } = getCurrentInstance();
|
||||||
|
const props = defineProps({
|
||||||
|
modelValue: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
default: '预警详情'
|
||||||
|
},
|
||||||
|
width: {
|
||||||
|
type: String,
|
||||||
|
default: '90%'
|
||||||
|
}, dataList: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({})
|
||||||
|
},
|
||||||
|
dict: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({})
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
// 定义事件
|
||||||
|
const emit = defineEmits(['update:modelValue']);
|
||||||
|
const loading = ref(false)
|
||||||
|
let abortController = null
|
||||||
|
const close = () => {
|
||||||
|
if (abortController) {
|
||||||
|
abortController.abort()
|
||||||
|
abortController = null
|
||||||
|
}
|
||||||
|
loading.value = false
|
||||||
|
emit('update:modelValue', false);
|
||||||
|
};
|
||||||
|
const dataForm = ref({});
|
||||||
|
watch(() => props.modelValue, (newVal) => {
|
||||||
|
if (newVal) {
|
||||||
|
getPart(props.dataList.id)
|
||||||
|
}
|
||||||
|
}, { deep: true });
|
||||||
|
const getPart = (id) => {
|
||||||
|
if (abortController) {
|
||||||
|
abortController.abort()
|
||||||
|
}
|
||||||
|
abortController = new AbortController()
|
||||||
|
loading.value = true
|
||||||
|
qcckGet({}, `/mosty-gsxt/tbYjxx/getInfo/${id}`, { signal: abortController.signal }).then(res => {
|
||||||
|
if (res) {
|
||||||
|
dataForm.value = res
|
||||||
|
} else {
|
||||||
|
dataForm.value = {}
|
||||||
|
}
|
||||||
|
}).catch(err => {
|
||||||
|
if (err.name !== 'AbortError') {
|
||||||
|
console.error('请求失败:', err)
|
||||||
|
}
|
||||||
|
}).finally(() => {
|
||||||
|
loading.value = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const ys = () => {
|
||||||
|
switch (dataForm.value.yjJb) {
|
||||||
|
case '01':
|
||||||
|
return 'red';
|
||||||
|
case '02':
|
||||||
|
return 'orange';
|
||||||
|
case '03':
|
||||||
|
return 'yellow';
|
||||||
|
case '04':
|
||||||
|
return 'blue';
|
||||||
|
default:
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.archive-container {
|
||||||
|
padding: 0;
|
||||||
|
max-height: 500px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.three-column-layout {
|
||||||
|
display: flex;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.column {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
min-width: 300px;
|
||||||
|
border: 1px solid #dcdfe6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.column:not(:last-child) {
|
||||||
|
border-right: 1px solid #dcdfe6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.column-header {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: bold;
|
||||||
|
padding: 10px;
|
||||||
|
background: #f5f7fa;
|
||||||
|
color: #303133;
|
||||||
|
text-align: center;
|
||||||
|
border-bottom: 1px solid #dcdfe6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.column .info-section {
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-section {
|
||||||
|
background: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-section.blue-bg {
|
||||||
|
background: #e6f7ff;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-row {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-item {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 300px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-item.full-width {
|
||||||
|
flex: 100%;
|
||||||
|
min-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-label {
|
||||||
|
font-weight: 600;
|
||||||
|
margin-right: 10px;
|
||||||
|
white-space: nowrap;
|
||||||
|
color: #303133;
|
||||||
|
font-size: 14px;
|
||||||
|
width: 100px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-value {
|
||||||
|
flex: 1;
|
||||||
|
padding: 4px 8px;
|
||||||
|
border: 1px solid #dcdfe6;
|
||||||
|
background: #ffffff;
|
||||||
|
min-height: 28px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #606266;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-value.text-area {
|
||||||
|
min-height: 80px;
|
||||||
|
align-items: flex-start;
|
||||||
|
padding: 8px;
|
||||||
|
resize: vertical;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-value.warning-level {
|
||||||
|
background: #fffbe6;
|
||||||
|
border-color: #ffe58f;
|
||||||
|
color: #d48806;
|
||||||
|
font-weight: 600;
|
||||||
|
padding: 2px 6px;
|
||||||
|
font-size: 12px;
|
||||||
|
width: fit-content;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-value.warning-level.red {
|
||||||
|
background: #fef0f0;
|
||||||
|
border-color: #ffccc7;
|
||||||
|
color: #f56c6c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-value.warning-level.orange {
|
||||||
|
background: #fffbe6;
|
||||||
|
border-color: #ffe58f;
|
||||||
|
color: #d48806;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-value.warning-level.yellow {
|
||||||
|
background: #fdf6ec;
|
||||||
|
border-color: #faecd8;
|
||||||
|
color: #e6a23c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-value.warning-level.blue {
|
||||||
|
background: #ecf5ff;
|
||||||
|
border-color: #d9ecff;
|
||||||
|
color: #409eff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.history-item {
|
||||||
|
margin-bottom: 8px;
|
||||||
|
padding: 6px 10px;
|
||||||
|
border: none;
|
||||||
|
background: #ffffff;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.history-index {
|
||||||
|
font-weight: bold;
|
||||||
|
margin-right: 8px;
|
||||||
|
color: #303133;
|
||||||
|
font-size: 14px;
|
||||||
|
min-width: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.history-content {
|
||||||
|
flex: 1;
|
||||||
|
color: #606266;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 滚动条样式 */
|
||||||
|
.archive-container::-webkit-scrollbar,
|
||||||
|
.info-section::-webkit-scrollbar {
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.archive-container::-webkit-scrollbar-track,
|
||||||
|
.info-section::-webkit-scrollbar-track {
|
||||||
|
background: #f1f1f1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.archive-container::-webkit-scrollbar-thumb,
|
||||||
|
.info-section::-webkit-scrollbar-thumb {
|
||||||
|
background: #c1c1c1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.archive-container::-webkit-scrollbar-thumb:hover,
|
||||||
|
.info-section::-webkit-scrollbar-thumb:hover {
|
||||||
|
background: #a8a8a8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 按钮样式 */
|
||||||
|
.dialog-footer {
|
||||||
|
padding: 15px;
|
||||||
|
background: #f9f9f9;
|
||||||
|
border-top: 1px solid #e4e7ed;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -0,0 +1,88 @@
|
|||||||
|
<template>
|
||||||
|
<div class="dialog" v-if="dialogForm">
|
||||||
|
<div class="head_box">
|
||||||
|
<span class="title">身份预警{{ title }} </span>
|
||||||
|
<div>
|
||||||
|
<!-- <el-button type="primary" size="small" :loading="loading" @click="submit">保存</el-button> -->
|
||||||
|
<el-button size="small" @click="close">关闭</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form_cnt">
|
||||||
|
<FormMessage :formList="formData" v-model="listQuery" ref="elform">
|
||||||
|
</FormMessage>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import FormMessage from "@/components/aboutTable/FormMessage.vue";
|
||||||
|
import { tbYjxxGetInfo,yjzxyjzxSfyjSelectList } from "@/api/yj.js";
|
||||||
|
import { IdCard } from '@/utils/validate.js'
|
||||||
|
import { ref, defineExpose, reactive, defineEmits, getCurrentInstance, watch } from "vue";
|
||||||
|
const emit = defineEmits(["updateDate"]);
|
||||||
|
const props = defineProps({
|
||||||
|
dict: {
|
||||||
|
type: Object,
|
||||||
|
default: () => { }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const { proxy } = getCurrentInstance();
|
||||||
|
|
||||||
|
const dialogForm = ref(false); //弹窗
|
||||||
|
const formData = ref([])
|
||||||
|
watch(() => props.dict, (res) => {
|
||||||
|
if (res) {
|
||||||
|
formData.value = [
|
||||||
|
{ label: "预警人姓名", prop: "xm", type: "input" },
|
||||||
|
{ label: "身份证号", prop: "sfzh", type: "input" },
|
||||||
|
{ label: "电话", prop: "dh", type: "input" },
|
||||||
|
{ label: "组合大类", prop: "sfdlmc", type: "input" },
|
||||||
|
{ label: "组合小类", prop: "sfzlmc", type: "input" },
|
||||||
|
{ label: "组合预警次数", prop: "sfcs", type: "input",lx:"number" },
|
||||||
|
{ label: "标签颜色", prop: "bqys", type: "select", options: props.dict.D_GS_SSYJ },
|
||||||
|
{ label: "预警时间", prop: "yjsj", type: "input" },
|
||||||
|
{ label: "预警分值", prop: "sffz", type: "input",lx:"number" },
|
||||||
|
{ label: "处置状态", prop: "czzt", type: "select", options: props.dict.D_GSXT_YJXX_CZZT },
|
||||||
|
{ label: "所属部门", prop: "ssbm", type: "input" },
|
||||||
|
{ label: "所属县局", prop: "ssxgaj", type: "input" },
|
||||||
|
{ label: "所属市局", prop: "sssgaj", type: "input" },
|
||||||
|
{ label: "接警员姓名", prop: "jjyxm", type: "input" },
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
}, { deep: true, immediate: true })
|
||||||
|
const listQuery = ref({}); //表单
|
||||||
|
const loading = ref(false);
|
||||||
|
const elform = ref();
|
||||||
|
const title = ref("详情");
|
||||||
|
const init = (type, row) => {
|
||||||
|
dialogForm.value = true;
|
||||||
|
yjzxyjzxSfyjSelectList(row.id).then(res => {
|
||||||
|
listQuery.value = {
|
||||||
|
...res,
|
||||||
|
nl: IdCard(res.yjRysfzh, 3) || "",
|
||||||
|
xb: IdCard(res.yjRysfzh, 2) || "",
|
||||||
|
xsd: res.xsd + '%'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
|
// 关闭
|
||||||
|
const close = () => {
|
||||||
|
listQuery.value = {};
|
||||||
|
loading.value = false;
|
||||||
|
dialogForm.value = false;
|
||||||
|
listQuery.value = {}
|
||||||
|
};
|
||||||
|
|
||||||
|
defineExpose({ init });
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "~@/assets/css/layout.scss";
|
||||||
|
@import "~@/assets/css/element-plus.scss";
|
||||||
|
::v-deep {
|
||||||
|
.el-form-item__content {
|
||||||
|
align-items: normal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -0,0 +1,88 @@
|
|||||||
|
<template>
|
||||||
|
<div class="dialog" v-if="dialogForm">
|
||||||
|
<div class="head_box">
|
||||||
|
<span class="title">行为预警{{ title }} </span>
|
||||||
|
<div>
|
||||||
|
<!-- <el-button type="primary" size="small" :loading="loading" @click="submit">保存</el-button> -->
|
||||||
|
<el-button size="small" @click="close">关闭</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form_cnt">
|
||||||
|
<FormMessage :formList="formData" v-model="listQuery" ref="elform">
|
||||||
|
</FormMessage>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import FormMessage from "@/components/aboutTable/FormMessage.vue";
|
||||||
|
import { tbYjxxGetInfo,yjzxXwyjSelectList } from "@/api/yj.js";
|
||||||
|
import { IdCard } from '@/utils/validate.js'
|
||||||
|
import { ref, defineExpose, reactive, defineEmits, getCurrentInstance, watch } from "vue";
|
||||||
|
const emit = defineEmits(["updateDate"]);
|
||||||
|
const props = defineProps({
|
||||||
|
dict: {
|
||||||
|
type: Object,
|
||||||
|
default: () => { }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const { proxy } = getCurrentInstance();
|
||||||
|
const dialogForm = ref(false); //弹窗
|
||||||
|
const formData = ref([])
|
||||||
|
watch(() => props.dict, (res) => {
|
||||||
|
if (res) {
|
||||||
|
formData.value = [
|
||||||
|
{ label: "预警人姓名", prop: "xm", type: "input" },
|
||||||
|
{ label: "身份证号", prop: "sfzh", type: "input" },
|
||||||
|
{ label: "电话", prop: "dh", type: "input" },
|
||||||
|
{ label: "行为大类", prop: "xldlmc", type: "input" },
|
||||||
|
{ label: "行为子类", prop: "xwzlmc", type: "input" },
|
||||||
|
{ label: "行为次数", prop: "xwcs", type: "input",lx:"number" },
|
||||||
|
{ label: "标签颜色", prop: "bqys", type: "select", options: props.dict.D_GS_SSYJ },
|
||||||
|
{ label: "预警时间", prop: "yjsj", type: "input" },
|
||||||
|
{ label: "行为分值", prop: "xwfz", type: "input",lx:"number" },
|
||||||
|
{ label: "处置状态", prop: "czzt", type: "select", options: props.dict.D_GSXT_YJXX_CZZT },
|
||||||
|
{ label: "所属部门", prop: "ssbm", type: "input" },
|
||||||
|
{ label: "所属县局", prop: "ssxgaj", type: "input" },
|
||||||
|
{ label: "所属市局", prop: "sssgaj", type: "input" },
|
||||||
|
{ label: "接警员姓名", prop: "jjyxm", type: "input" },
|
||||||
|
{ label: "行为描述", prop: "xwms", type: "textarea", width: "100%" },
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
}, { deep: true, immediate: true })
|
||||||
|
const listQuery = ref({}); //表单
|
||||||
|
const loading = ref(false);
|
||||||
|
const elform = ref();
|
||||||
|
const title = ref("详情");
|
||||||
|
const init = (row) => {
|
||||||
|
dialogForm.value = true;
|
||||||
|
yjzxXwyjSelectList(row.id).then(res => {
|
||||||
|
listQuery.value = {
|
||||||
|
...res,
|
||||||
|
nl: IdCard(res.yjRysfzh, 3) || "",
|
||||||
|
xb: IdCard(res.yjRysfzh, 2) || "",
|
||||||
|
xsd: res.xsd + '%'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
|
// 关闭
|
||||||
|
const close = () => {
|
||||||
|
listQuery.value = {};
|
||||||
|
loading.value = false;
|
||||||
|
dialogForm.value = false;
|
||||||
|
listQuery.value = {}
|
||||||
|
};
|
||||||
|
|
||||||
|
defineExpose({ init });
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "~@/assets/css/layout.scss";
|
||||||
|
@import "~@/assets/css/element-plus.scss";
|
||||||
|
::v-deep {
|
||||||
|
.el-form-item__content {
|
||||||
|
align-items: normal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -0,0 +1,547 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<!-- 搜索 -->
|
||||||
|
<div ref="searchBox" class="mt10">
|
||||||
|
<QueryFormPanel
|
||||||
|
v-model="listQuery"
|
||||||
|
:fields="searchConfiger"
|
||||||
|
@search="onSearch"
|
||||||
|
>
|
||||||
|
<template #but>
|
||||||
|
<el-button type="primary" @click="exportExl" size="small"
|
||||||
|
>导出</el-button
|
||||||
|
>
|
||||||
|
<el-button type="primary" size="small" @click="handleQs"
|
||||||
|
>签收</el-button
|
||||||
|
>
|
||||||
|
</template>
|
||||||
|
</QueryFormPanel>
|
||||||
|
</div>
|
||||||
|
<!-- 表格 -->
|
||||||
|
<div
|
||||||
|
class="tabBox_zdy"
|
||||||
|
:style="{ height: pageData.tableHeight + 40 + 'px' }"
|
||||||
|
>
|
||||||
|
<WarnDataTable
|
||||||
|
:loading="pageData.tableConfiger.loading"
|
||||||
|
:tableHeight="pageData.tableHeight"
|
||||||
|
:data="pageData.tableData"
|
||||||
|
:columns="pageData.tableColumn"
|
||||||
|
table-class="warn-table"
|
||||||
|
@selectionChange="handleChooseData"
|
||||||
|
>
|
||||||
|
<template #czzt="{ row }">
|
||||||
|
<DictTag
|
||||||
|
:value="row.czzt"
|
||||||
|
:color="row.czzt === '01' ? '#ff2424' : '#1d72e8'"
|
||||||
|
:tag="false"
|
||||||
|
:options="D_GSXT_YJXX_CZZT"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<template #xbdm="{ row }">
|
||||||
|
<DictTag :value="row.xbdm" :tag="false" :options="D_BZ_XB" />
|
||||||
|
</template>
|
||||||
|
<template #yjJb="{ row }">
|
||||||
|
<div :style="{ 'background-color': bqYs(row.yjJb) }">
|
||||||
|
<DictTag
|
||||||
|
:value="row.yjJb"
|
||||||
|
color="#fff"
|
||||||
|
:tag="false"
|
||||||
|
:options="D_BZ_YJJB"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #qblyjb="{ row }">
|
||||||
|
<DictTag :value="row.qblyjb" :tag="false" :options="D_BZ_QBLYJB" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #bksj="{ row }">
|
||||||
|
{{ row.bkkssj && row.bkjssj ? `${row.bkkssj} - ${row.bkjssj}` : "" }}
|
||||||
|
</template>
|
||||||
|
<template #xsd="{ row }"> {{ row.xsd }}% </template>
|
||||||
|
<template #cszt="{ row }">
|
||||||
|
<DictTag :value="row.cszt" :tag="false" :options="D_GS_CSZT" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #bkyjlx="{ row }">
|
||||||
|
<DictTag :value="row.bkyjlx" :tag="false" :options="D_BZ_BKYJLX" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #operation="{ row }">
|
||||||
|
<div style="display: flex; justify-content: space-between">
|
||||||
|
<span class="warning" @click="pushAssess(row)">全息档案</span>
|
||||||
|
<span class="primary" @click="handleCzjy(row)" v-if="roleCode"
|
||||||
|
>处置建议</span
|
||||||
|
>
|
||||||
|
<!-- <span type="primary" @click="showDetail(row)">转合成</span> -->
|
||||||
|
<!-- <span type="danger" @click="delDictItem(row.id)">转会商</span> -->
|
||||||
|
<span
|
||||||
|
class="success"
|
||||||
|
@click="handleQsFk(row, '签收')"
|
||||||
|
v-if="row.czzt == '01' && permission_sfqs"
|
||||||
|
>签收</span
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="success"
|
||||||
|
@click="handleQsFk(row, '反馈')"
|
||||||
|
v-else-if="row.czzt == '02' && permission_sfqs"
|
||||||
|
>反馈</span
|
||||||
|
>
|
||||||
|
<!-- <span type="success" @click="handleQsFk(row, '查看反馈')" v-else>查看反馈</span> -->
|
||||||
|
<span class="primary" @click="openBox(row)">详情</span>
|
||||||
|
<span class="primary" @click="pushWarning(row)">指派</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</WarnDataTable>
|
||||||
|
<Pages
|
||||||
|
@changeNo="changeNo"
|
||||||
|
@changeSize="changeSize"
|
||||||
|
:tableHeight="pageData.tableHeight"
|
||||||
|
:pageConfiger="{
|
||||||
|
...pageData.pageConfiger,
|
||||||
|
total: pageData.total
|
||||||
|
}"
|
||||||
|
></Pages>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<FkDialog @change="getList" lx="05" />
|
||||||
|
<AddFrom
|
||||||
|
ref="addModelRef"
|
||||||
|
:dict="{ D_GSXT_YJXX_CZZT, D_BZ_YJJB, D_GS_SSYJ }"
|
||||||
|
/>
|
||||||
|
<!-- 处置建议 -->
|
||||||
|
<Czjy ref="czjyRef" @okSubmit="getList"></Czjy>
|
||||||
|
<ZpForm v-model="warningShow" :dataList="dataList" />
|
||||||
|
<!-- <Pagination v-model="paginationOpen" /> -->
|
||||||
|
<Pagination
|
||||||
|
v-model="paginationOpen"
|
||||||
|
:dataList="dataPres"
|
||||||
|
:dict="{
|
||||||
|
D_BZ_XB,
|
||||||
|
D_BZ_YJJB,
|
||||||
|
D_GS_QLZDRLX,
|
||||||
|
D_GS_ZDR_RYJB,
|
||||||
|
D_GS_ZDR_GJLB,
|
||||||
|
D_GS_BK_CZYQ
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { IdCard } from "@/utils/validate.js";
|
||||||
|
import Czjy from "./components/czjy.vue";
|
||||||
|
import { getItem, setItem } from "@/utils/storage";
|
||||||
|
import WarnDataTable from "@/views/backOfficeSystem/ces/components/WarnDataTable.vue";
|
||||||
|
import QueryFormPanel from "@/views/backOfficeSystem/ces/components/QueryFormPanel.vue";
|
||||||
|
import Pages from "@/components/aboutTable/Pages.vue";
|
||||||
|
import AddFrom from "./components/addFrom.vue";
|
||||||
|
import FkDialog from "@/views/backOfficeSystem/fourColorManage/warningControl/centerHome/components/fkDialog.vue";
|
||||||
|
import ZpForm from "@/views/backOfficeSystem/fourColorManage/warningControl/sevenWarning/zpForm.vue";
|
||||||
|
import { reactive, ref, onMounted, getCurrentInstance, nextTick } from "vue";
|
||||||
|
import { qcckGet, qcckPost } from "@/api/qcckApi.js";
|
||||||
|
import emitter from "@/utils/eventBus.js";
|
||||||
|
import { holographicProfileJump } from "@/utils/tools.js";
|
||||||
|
import { exportExlByObj } from "@/utils/exportExcel.js";
|
||||||
|
import { getMultiDictVal } from "@/utils/dict.js";
|
||||||
|
import Pagination from "./components/particulars.vue";
|
||||||
|
const czjyRef = ref();
|
||||||
|
const { proxy } = getCurrentInstance();
|
||||||
|
const searchBox = ref();
|
||||||
|
const {
|
||||||
|
D_GS_QLZDRLX,
|
||||||
|
D_BZ_YJLY,
|
||||||
|
D_GSXT_YJXX_CZZT,
|
||||||
|
D_GS_SSYJ,
|
||||||
|
D_BZ_YJJB,
|
||||||
|
D_BZ_BKLYS,
|
||||||
|
D_BZ_XB,
|
||||||
|
D_BZ_SF,
|
||||||
|
D_GS_CSZT,
|
||||||
|
D_GS_BKZT,
|
||||||
|
D_GS_ZDR_RYJB,
|
||||||
|
D_GS_ZDR_GJLB,
|
||||||
|
D_GS_BK_CZYQ,
|
||||||
|
D_BZ_SJLY,
|
||||||
|
D_BZ_QBLYJB,
|
||||||
|
D_BZ_BKYJLX
|
||||||
|
} = proxy.$dict(
|
||||||
|
"D_GS_QLZDRLX",
|
||||||
|
"D_BZ_YJLY",
|
||||||
|
"D_GSXT_YJXX_CZZT",
|
||||||
|
"D_GS_SSYJ",
|
||||||
|
"D_BZ_YJJB",
|
||||||
|
"D_BZ_BKLYS",
|
||||||
|
"D_BZ_XB",
|
||||||
|
"D_BZ_SF",
|
||||||
|
"D_GS_CSZT",
|
||||||
|
"D_GS_BKZT",
|
||||||
|
"D_GS_ZDR_RYJB",
|
||||||
|
"D_GS_ZDR_GJLB",
|
||||||
|
"D_GS_BK_CZYQ",
|
||||||
|
"D_BZ_SJLY",
|
||||||
|
"D_BZ_QBLYJB",
|
||||||
|
"D_BZ_BKYJLX"
|
||||||
|
);
|
||||||
|
const dict = reactive({ D_GSXT_YJXX_CZZT, D_GS_SSYJ });
|
||||||
|
// 搜索配置
|
||||||
|
const searchConfiger = ref([
|
||||||
|
{
|
||||||
|
label: "处置状态",
|
||||||
|
prop: "czzt",
|
||||||
|
showType: "select",
|
||||||
|
options: D_GSXT_YJXX_CZZT
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "预警时间",
|
||||||
|
prop: "startTime",
|
||||||
|
showType: "datetimerange",
|
||||||
|
placeholder: "请选择预警时间"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "姓名",
|
||||||
|
prop: "yjRyxm",
|
||||||
|
showType: "input",
|
||||||
|
placeholder: "请输入姓名"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "身份证号",
|
||||||
|
prop: "yjRysfzh",
|
||||||
|
showType: "input",
|
||||||
|
placeholder: "请输入身份证号"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "管控级别",
|
||||||
|
prop: "qblyjb",
|
||||||
|
showType: "select",
|
||||||
|
options: D_BZ_QBLYJB
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "预警级别",
|
||||||
|
prop: "yjJb",
|
||||||
|
showType: "select",
|
||||||
|
options: D_BZ_YJJB,
|
||||||
|
placeholder: "请选择预警级别",
|
||||||
|
multiple: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "布控时间",
|
||||||
|
prop: "bksj",
|
||||||
|
showType: "daterange",
|
||||||
|
placeholder: "请选择布控开始时间"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "接收单位",
|
||||||
|
prop: "ssbmdm",
|
||||||
|
showType: "department",
|
||||||
|
placeholder: "请选择接收单位"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "布控单位",
|
||||||
|
prop: "gkbmdm",
|
||||||
|
showType: "department",
|
||||||
|
placeholder: "请选择布控单位"
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
label: "比对源",
|
||||||
|
prop: "bkyjlx",
|
||||||
|
showType: "select",
|
||||||
|
options: D_BZ_BKYJLX,
|
||||||
|
placeholder: "请选择比对源"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "超时状态",
|
||||||
|
prop: "cszt",
|
||||||
|
placeholder: "请选择超时状态",
|
||||||
|
showType: "select",
|
||||||
|
options: D_GS_CSZT
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "在控状态",
|
||||||
|
prop: "zkzt",
|
||||||
|
showType: "select",
|
||||||
|
options: D_GS_BKZT,
|
||||||
|
placeholder: "请选择在控状态"
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
const ORDIMG = "https://89.40.7.122:38496/image";
|
||||||
|
const IMGYM = "https://sg.lz.dsj.xz/dhimage";
|
||||||
|
const permission_sfqs = ref(false);
|
||||||
|
const roleCode = ref(false);
|
||||||
|
|
||||||
|
const queryFrom = ref({});
|
||||||
|
|
||||||
|
// 页面数据
|
||||||
|
const pageData = reactive({
|
||||||
|
tableData: [],
|
||||||
|
keyCount: 0,
|
||||||
|
tableConfiger: {
|
||||||
|
rowHieght: 61,
|
||||||
|
showSelectType: "checkBox",
|
||||||
|
loading: false,
|
||||||
|
haveControls: true
|
||||||
|
},
|
||||||
|
total: 0,
|
||||||
|
pageConfiger: {
|
||||||
|
pageSize: 20,
|
||||||
|
pageCurrent: 1
|
||||||
|
},
|
||||||
|
controlsWidth: 180, //操作栏宽度
|
||||||
|
tableColumn: [
|
||||||
|
{ type: "index", label: "序号", width: 55, align: "center" },
|
||||||
|
{ label: "处置状态", align: "center", width: 70, slotName: "czzt" },
|
||||||
|
{ prop: "yjSj", label: "预警时间", width: 150 },
|
||||||
|
{ prop: "yjRyxm", label: "人员姓名", width: 70, align: "center" },
|
||||||
|
{ label: "性别", width: 50, align: "center", slotName: "xbdm" },
|
||||||
|
{ prop: "nl", label: "年龄", width: 50, align: "center" },
|
||||||
|
{ prop: "yjRysfzh", label: "身份证号", width: 150, align: "center" },
|
||||||
|
{ label: "管控级别", width: 80, align: "center", slotName: "qblyjb" },
|
||||||
|
{ label: "预警级别", width: 80, align: "center", slotName: "yjJb" },
|
||||||
|
{ label: "布控时间", width: 80, align: "center", slotName: "bksj" },
|
||||||
|
{ prop: "ssbm", label: "接收单位", width: 100, align: "center" },
|
||||||
|
{ label: "布控单位", prop: "gkbmmc", align: "center", width: 100 },
|
||||||
|
{ prop: "bkyjlx", label: "比对源", align: "center", width: 80 },
|
||||||
|
{ label: "相似度", slotName: "xsd", align: "center", width: 50 },
|
||||||
|
{ label: "预警内容", prop: "yjNr", align: "center" },
|
||||||
|
{ label: "操作", width: 180, slotName: "operation" },
|
||||||
|
{ label: "超时状态", width: 80, align: "center", slotName: "cszt" },
|
||||||
|
{ label: "在控状态", width: 70, align: "center", slotName: "zkzt" }
|
||||||
|
// { prop: "bkkssj", label: "布控开始时间", align: "center" },
|
||||||
|
// { prop: "bkjssj", label: "布控结束时间", align: "center" }
|
||||||
|
//
|
||||||
|
// { label: "预警级别", width: 80, align: "center", slotName: "yjJb" },
|
||||||
|
//
|
||||||
|
// { label: "布控来源", align: "center", slotName: "bkly", width: 70 },
|
||||||
|
// { prop: "bkfw", label: "布控范围", align: "center", width: 70 },
|
||||||
|
// { label: "处置要求", width: 70, slotName: "bkczyq", align: "center" },
|
||||||
|
// { label: "预警内容", prop: "yjNr", align: "center" },
|
||||||
|
// { label: "相似度", slotName: "xsd", align: "center", width: 50 },
|
||||||
|
// { label: "所属部门", prop: "ssbm", align: "center" },
|
||||||
|
// { label: "数据来源", slotName: "yjLylx", align: "center" },
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
let str = getItem("deptId") ? getItem("deptId")[0].deptLevel : "";
|
||||||
|
permission_sfqs.value = str.startsWith("2" || "3") ? false : true;
|
||||||
|
let rols = getItem("roleList") ? getItem("roleList") : [];
|
||||||
|
let obj = rols.find((item) => {
|
||||||
|
return ["JS_666666", "JS_777777", "JS_888888"].includes(item.roleCode);
|
||||||
|
});
|
||||||
|
roleCode.value = obj ? true : false;
|
||||||
|
|
||||||
|
tabHeightFn();
|
||||||
|
getList();
|
||||||
|
});
|
||||||
|
|
||||||
|
const onSearch = (val) => {
|
||||||
|
queryFrom.value = {
|
||||||
|
...queryFrom.value,
|
||||||
|
...val,
|
||||||
|
startTime: val.startTime ? val.startTime[0] : "",
|
||||||
|
endTime: val.startTime ? val.startTime[1] : "",
|
||||||
|
bkkssj: val.bksj ? val.bksj[0] : "",
|
||||||
|
bkjssj: val.bksj ? val.bksj[1] : "",
|
||||||
|
yjJb: val.yjJb?.join(",") || ""
|
||||||
|
};
|
||||||
|
|
||||||
|
pageData.pageConfiger.pageCurrent = 1;
|
||||||
|
getList();
|
||||||
|
};
|
||||||
|
|
||||||
|
const reset = () => {
|
||||||
|
delete queryFrom.value.ksfz;
|
||||||
|
delete queryFrom.value.jsfz;
|
||||||
|
};
|
||||||
|
|
||||||
|
const changeNo = (val) => {
|
||||||
|
pageData.pageConfiger.pageCurrent = val;
|
||||||
|
getList();
|
||||||
|
};
|
||||||
|
|
||||||
|
const changeSize = (val) => {
|
||||||
|
pageData.pageConfiger.pageSize = val;
|
||||||
|
getList();
|
||||||
|
};
|
||||||
|
|
||||||
|
const getList = () => {
|
||||||
|
pageData.tableConfiger.loading = true;
|
||||||
|
let params = {
|
||||||
|
...queryFrom.value,
|
||||||
|
pageCurrent: pageData.pageConfiger.pageCurrent,
|
||||||
|
pageSize: pageData.pageConfiger.pageSize,
|
||||||
|
yjlb: "01"
|
||||||
|
};
|
||||||
|
qcckPost(params, "/mosty-gsxt/tbYjxx/getPageList")
|
||||||
|
.then((res) => {
|
||||||
|
pageData.tableData = res?.records || [];
|
||||||
|
pageData.total = res?.total || 0;
|
||||||
|
pageData.tableConfiger.loading = false;
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
pageData.tableConfiger.loading = false;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 处理签收
|
||||||
|
const handleQsFk = (val, type) => {
|
||||||
|
switch (type) {
|
||||||
|
case "签收":
|
||||||
|
proxy
|
||||||
|
.$confirm("是否确定要签收?", "警告", { type: "warning" })
|
||||||
|
.then(() => {
|
||||||
|
qcckPost({ id: val.id }, "/mosty-gsxt/mosty-gsxt/tbYjxx/yjqs").then(
|
||||||
|
() => {
|
||||||
|
val.czzt = "02";
|
||||||
|
getList();
|
||||||
|
proxy.$message({ type: "success", message: "签收成功" });
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case "反馈":
|
||||||
|
case "查看反馈":
|
||||||
|
emitter.emit("openFkDialog", { id: val.id, type });
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const pushAssess = (val) => {
|
||||||
|
return holographicProfileJump(val?.yjLx, val); // 全息档案跳转
|
||||||
|
};
|
||||||
|
|
||||||
|
const bqYs = (val) => {
|
||||||
|
switch (val) {
|
||||||
|
case "01":
|
||||||
|
return "#ff0202";
|
||||||
|
case "02":
|
||||||
|
return "#ff8c00";
|
||||||
|
case "03":
|
||||||
|
return "#bdbd00";
|
||||||
|
case "04":
|
||||||
|
return "#0000ff";
|
||||||
|
default:
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 新增
|
||||||
|
const addModelRef = ref(null);
|
||||||
|
const openAddFrom = (row) => {
|
||||||
|
addModelRef.value.init("add", row);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCzjy = (row) => {
|
||||||
|
czjyRef.value.init(row);
|
||||||
|
};
|
||||||
|
// 表格高度计算
|
||||||
|
const tabHeightFn = () => {
|
||||||
|
pageData.tableHeight =
|
||||||
|
window.innerHeight - searchBox.value.offsetHeight - 230;
|
||||||
|
|
||||||
|
window.onresize = function () {
|
||||||
|
tabHeightFn();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
// 指派
|
||||||
|
const dataList = ref(null);
|
||||||
|
const warningShow = ref(false);
|
||||||
|
const pushWarning = (val) => {
|
||||||
|
warningShow.value = true;
|
||||||
|
dataList.value = val;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 选中项 */
|
||||||
|
const selectRows = ref([]);
|
||||||
|
const handleChooseData = (val) => {
|
||||||
|
selectRows.value = val;
|
||||||
|
};
|
||||||
|
const exportExl = () => {
|
||||||
|
const titleObj = {
|
||||||
|
czzt_cname: "处置状态",
|
||||||
|
yjSj: "预警时间",
|
||||||
|
yjRyxm: "姓名",
|
||||||
|
nl_cname: "年龄", // IdCard(row.yjRysfzh, 3)
|
||||||
|
yjLylx: "数据来源",
|
||||||
|
xb_cname: "性别",
|
||||||
|
yjJb_cname: "预警级别",
|
||||||
|
xsd_cname: "相似度",
|
||||||
|
yjDz: "预警地点",
|
||||||
|
yjCs: "预警次数",
|
||||||
|
yjRysjh: "布控手机号",
|
||||||
|
yjClcph: "布控车牌号",
|
||||||
|
yjRysfzh: "身份证"
|
||||||
|
};
|
||||||
|
/** 导出【选中】的数据 (没有就全部)*/
|
||||||
|
const needArr =
|
||||||
|
selectRows.value?.length > 0 ? selectRows.value : pageData.tableData;
|
||||||
|
const data = needArr.map((item) => {
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
nl_cname: IdCard(item.yjRysfzh, 3),
|
||||||
|
xb_cname: IdCard(item.yjRysfzh, 2),
|
||||||
|
xsd_cname: (item.xsd > 0 ? item.xsd : 0) + "%",
|
||||||
|
yjJb_name: getMultiDictVal(item.yjJb, D_GS_SSYJ),
|
||||||
|
czzt_name: getMultiDictVal(item.czzt, D_GSXT_YJXX_CZZT),
|
||||||
|
yjJb_cname: getMultiDictVal(item.yjJb, D_BZ_YJJB)
|
||||||
|
};
|
||||||
|
});
|
||||||
|
exportExlByObj(titleObj, data, "预警布控");
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleQs = () => {
|
||||||
|
if (selectRows.value?.length === 0)
|
||||||
|
return proxy.$message({ type: "warning", message: "请选择要签收的预警" });
|
||||||
|
let wqs = selectRows.value.filter((item) => item.czzt == "01");
|
||||||
|
if (wqs.length == 0)
|
||||||
|
return proxy.$message({
|
||||||
|
type: "warning",
|
||||||
|
message: "数据都已签收,请选择未签收的数据"
|
||||||
|
});
|
||||||
|
let yqs = selectRows.value.filter((item) => item.czzt == "02");
|
||||||
|
let texy =
|
||||||
|
yqs.length > 0
|
||||||
|
? `${yqs.length}条已签收预警数据,确认要签收${wqs.length}条未签收预警数据吗?`
|
||||||
|
: "确认要签收所有预警数据吗?";
|
||||||
|
proxy
|
||||||
|
.$confirm(texy, "警告", { type: "warning" })
|
||||||
|
.then(() => {
|
||||||
|
let ids = wqs.map((item) => item.id);
|
||||||
|
qcckPost({ ids }, "/mosty-gsxt/tbYjxx/batchQs")
|
||||||
|
.then(() => {
|
||||||
|
proxy.$message({ type: "success", message: "成功" });
|
||||||
|
getList();
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
proxy.$message({ type: "error", message: "失败" });
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(() => {});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 详情
|
||||||
|
const paginationOpen = ref(false);
|
||||||
|
const dataPres = ref({});
|
||||||
|
const openBox = (val) => {
|
||||||
|
paginationOpen.value = true;
|
||||||
|
dataPres.value = val;
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.el-loading-mask {
|
||||||
|
background: rgba(0, 0, 0, 0.5) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabBox_zdy {
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-table .cell {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-table .el-table__cell {
|
||||||
|
padding: 4px 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -0,0 +1,105 @@
|
|||||||
|
<template>
|
||||||
|
<div class="warning-item" >
|
||||||
|
|
||||||
|
<el-divider content-position="left">预警内容</el-divider>
|
||||||
|
<div class="item-row" style="border: none;"> {{ props.row.yjNr }} </div>
|
||||||
|
<el-empty v-if="!props.row.yjNr" :image-size="0.5" description="暂无数据" />
|
||||||
|
|
||||||
|
<el-divider content-position="left">处置建议</el-divider>
|
||||||
|
<div class="item-row" v-for="(it,idx) in list" :key="idx">
|
||||||
|
<div class="info-item">
|
||||||
|
<span class="text">预警人姓名:{{ it.jryXm }}</span>
|
||||||
|
<span class="text">建议时间:{{ it.jysj }}</span>
|
||||||
|
<span class="text">所属部门:{{ it.ssbm }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="info-item">建议内容:<span>{{ it.jynr || '暂无' }}</span></div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<el-empty v-if="list.length === 0" :image-size="0.5" description="暂无数据" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-divider content-position="left">反馈内容</el-divider>
|
||||||
|
<div class="item-row" v-for="(it,idx) in Fklist" :key="idx">
|
||||||
|
<div class="info-item">
|
||||||
|
<span class="text">处置地址:{{ it.czdz }}</span>
|
||||||
|
<span class="text">处置时间:{{ it.czsj }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="info-item">
|
||||||
|
<span class="text">常控不尿检理由:<span>{{ it.ckbnjly || '暂无' }}</span></span>
|
||||||
|
<span class="text">常控处置反馈补充信息:<span>{{ it.ckczbcxx || '暂无' }}</span></span>
|
||||||
|
<span class="text">常控立线侦察评估:<span>{{ it.cklxzcpg || '暂无' }}</span></span>
|
||||||
|
<span class="text">常控立线侦察评估依据:<span>{{ it.cklxzcpgyj || '暂无' }}</span></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<el-empty v-if="Fklist.length === 0" :image-size="0.5" description="暂无数据" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import { ref, computed, onMounted } from 'vue'
|
||||||
|
import { qcckPost,qcckGet } from "@/api/qcckApi.js";
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
/** 表格行数据 */
|
||||||
|
row: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({})
|
||||||
|
},
|
||||||
|
dict: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({
|
||||||
|
D_GS_SSYJ: [],
|
||||||
|
D_GSXT_YJXX_CZZT: []
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})
|
||||||
|
const list = ref([])
|
||||||
|
const Fklist = ref([])
|
||||||
|
onMounted(() => {
|
||||||
|
if(!props.row.id) return;
|
||||||
|
qcckPost({yjid: props.row.id},'/mosty-gsxt/yjxx/czjy/getPageList').then((res) => {
|
||||||
|
list.value = res.records || []
|
||||||
|
})
|
||||||
|
qcckGet({},'/mosty-gsxt/tbYjxx/getInfo/'+ props.row.id).then((res) => {
|
||||||
|
Fklist.value = res.fkList || []
|
||||||
|
})
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.warning-item {
|
||||||
|
width: 100%;
|
||||||
|
padding: 15px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border-radius: 8px;
|
||||||
|
background-color: #fafafa;
|
||||||
|
}
|
||||||
|
.item-row{
|
||||||
|
border-bottom: 1px dashed #e8e8e8;
|
||||||
|
line-height: 36px;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
padding-left: 2rem;
|
||||||
|
box-sizing: border-box;
|
||||||
|
&:nth-last-child(1){
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.info-item{
|
||||||
|
line-height: 36px;
|
||||||
|
width: 100%;
|
||||||
|
.text{
|
||||||
|
display: inline-block;
|
||||||
|
width: 25%;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-empty{
|
||||||
|
--el-empty-padding: 0px;
|
||||||
|
margin-bottom: 18px;
|
||||||
|
--el-empty-description-margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
@ -0,0 +1,50 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog title="处置建议" v-model="visible" width="50%" v-if="visible" @close="closeHndle">
|
||||||
|
<el-form :model="form" ref="formRef" :rules="rules" label-width="120px" >
|
||||||
|
<el-form-item label="处置建议" prop="jynr">
|
||||||
|
<el-input v-model="form.jynr" placeholder="请输入处置建议" type="textarea"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<div class="flex just-center">
|
||||||
|
<el-button type="primary" @click="okSubmit">确定</el-button>
|
||||||
|
<el-button @click="closeHndle">返回</el-button>
|
||||||
|
</div>
|
||||||
|
</el-form>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { qcckPost } from "@/api/qcckApi.js";
|
||||||
|
import { ref , defineExpose} from 'vue'
|
||||||
|
const emit = defineEmits(['okSubmit'])
|
||||||
|
const visible = ref(false)
|
||||||
|
const formRef = ref()
|
||||||
|
const form = ref({})
|
||||||
|
const rules = ref({
|
||||||
|
jynr: [
|
||||||
|
{ required: true, message: '请输入处置建议', trigger: 'blur' }
|
||||||
|
]
|
||||||
|
})
|
||||||
|
const init = (row) => {
|
||||||
|
visible.value = true;
|
||||||
|
form.value.yjid = row.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
const closeHndle = () => {
|
||||||
|
visible.value = false;
|
||||||
|
form.value = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const okSubmit = async () => {
|
||||||
|
await formRef.value.validate((valid) => {
|
||||||
|
if (!valid) return;
|
||||||
|
let params = {...form.value , lylx:'02'}
|
||||||
|
qcckPost(params,'/mosty-gsxt/yjxx/czjy/insert').then((res) => {
|
||||||
|
emit('okSubmit', {...form.value})
|
||||||
|
closeHndle()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
defineExpose({
|
||||||
|
init
|
||||||
|
})
|
||||||
|
</script>
|
||||||
@ -0,0 +1,57 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog :title="`组合预警次数详情(${pageData.tableData.length})`" v-model="dialogVisible" width="60%">
|
||||||
|
<MyTable
|
||||||
|
:tableData="pageData.tableData"
|
||||||
|
:tableColumn="pageData.tableColumn"
|
||||||
|
:tableHeight="pageData.tableHeight"
|
||||||
|
:key="pageData.keyCount"
|
||||||
|
:tableConfiger="pageData.tableConfiger"
|
||||||
|
>
|
||||||
|
</MyTable>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { qcckGet } from "@/api/qcckApi.js";
|
||||||
|
import MyTable from "@/components/aboutTable/MyTable.vue";
|
||||||
|
import { ref , reactive , defineExpose} from 'vue'
|
||||||
|
const dialogVisible = ref(false)
|
||||||
|
const pageData = reactive({
|
||||||
|
tableData: [{jqbh:'JQBH-43',bjr:'张三',bjrdh:'15665255545',bjrsfzh:'510156565656525565',yjnr:'xxxxxxxxx',jsj:'2023-08-24 15:00:00'}], //表格数据
|
||||||
|
keyCount: 0,
|
||||||
|
tableConfiger: {
|
||||||
|
rowHieght: 61,
|
||||||
|
loading: false,
|
||||||
|
haveControls: false,
|
||||||
|
},
|
||||||
|
tableHeight:600,
|
||||||
|
total: 0,
|
||||||
|
pageConfiger: {
|
||||||
|
pageSize: 20,
|
||||||
|
pageCurrent: 1
|
||||||
|
}, //分页
|
||||||
|
tableColumn: [
|
||||||
|
{ label: "警情编号", prop: "jjdbh"},
|
||||||
|
{ label: "报警人", prop: "bjrmc" },
|
||||||
|
{ label: "报警人电话", prop: "bjdh" },
|
||||||
|
{ label: "报警人身份证", prop: "bjrzjhm"},
|
||||||
|
{ label: "预警内容", prop: "bjnr", showOverflowTooltip: true },
|
||||||
|
{ label: "报警时间", prop: "bjsj", showOverflowTooltip: true },
|
||||||
|
]
|
||||||
|
});
|
||||||
|
const init = (row) => {
|
||||||
|
dialogVisible.value = true;
|
||||||
|
pageData.tableConfiger.loading = true;
|
||||||
|
pageData.tableData = []
|
||||||
|
qcckGet({yjid:row.id},'/mosty-gsxt/yjzxSfyjxq/selectList').then((res)=>{
|
||||||
|
pageData.tableData = res || [];
|
||||||
|
pageData.tableConfiger.loading = false;
|
||||||
|
}).catch(()=>{
|
||||||
|
pageData.tableConfiger.loading = false;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
init
|
||||||
|
})
|
||||||
|
</script>
|
||||||
@ -0,0 +1,88 @@
|
|||||||
|
<template>
|
||||||
|
<div class="dialog" v-if="dialogForm">
|
||||||
|
<div class="head_box">
|
||||||
|
<span class="title">身份预警{{ title }} </span>
|
||||||
|
<div>
|
||||||
|
<!-- <el-button type="primary" size="small" :loading="loading" @click="submit">保存</el-button> -->
|
||||||
|
<el-button size="small" @click="close">关闭</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form_cnt">
|
||||||
|
<FormMessage :formList="formData" v-model="listQuery" ref="elform">
|
||||||
|
</FormMessage>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import FormMessage from "@/components/aboutTable/FormMessage.vue";
|
||||||
|
import { tbYjxxGetInfo,yjzxyjzxSfyjSelectList } from "@/api/yj.js";
|
||||||
|
import { IdCard } from '@/utils/validate.js'
|
||||||
|
import { ref, defineExpose, reactive, defineEmits, getCurrentInstance, watch } from "vue";
|
||||||
|
const emit = defineEmits(["updateDate"]);
|
||||||
|
const props = defineProps({
|
||||||
|
dict: {
|
||||||
|
type: Object,
|
||||||
|
default: () => { }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const { proxy } = getCurrentInstance();
|
||||||
|
|
||||||
|
const dialogForm = ref(false); //弹窗
|
||||||
|
const formData = ref([])
|
||||||
|
watch(() => props.dict, (res) => {
|
||||||
|
if (res) {
|
||||||
|
formData.value = [
|
||||||
|
{ label: "预警人姓名", prop: "xm", type: "input" },
|
||||||
|
{ label: "身份证号", prop: "sfzh", type: "input" },
|
||||||
|
{ label: "电话", prop: "dh", type: "input" },
|
||||||
|
{ label: "组合大类", prop: "sfdlmc", type: "input" },
|
||||||
|
{ label: "组合小类", prop: "sfzlmc", type: "input" },
|
||||||
|
{ label: "组合预警次数", prop: "sfcs", type: "input",lx:"number" },
|
||||||
|
{ label: "标签颜色", prop: "bqys", type: "select", options: props.dict.D_GS_SSYJ },
|
||||||
|
{ label: "预警时间", prop: "yjsj", type: "input" },
|
||||||
|
{ label: "预警分值", prop: "sffz", type: "input",lx:"number" },
|
||||||
|
{ label: "处置状态", prop: "czzt", type: "select", options: props.dict.D_GSXT_YJXX_CZZT },
|
||||||
|
{ label: "所属部门", prop: "ssbm", type: "input" },
|
||||||
|
{ label: "所属县局", prop: "ssxgaj", type: "input" },
|
||||||
|
{ label: "所属市局", prop: "sssgaj", type: "input" },
|
||||||
|
{ label: "接警员姓名", prop: "jjyxm", type: "input" },
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
}, { deep: true, immediate: true })
|
||||||
|
const listQuery = ref({}); //表单
|
||||||
|
const loading = ref(false);
|
||||||
|
const elform = ref();
|
||||||
|
const title = ref("详情");
|
||||||
|
const init = (type, row) => {
|
||||||
|
dialogForm.value = true;
|
||||||
|
yjzxyjzxSfyjSelectList(row.id).then(res => {
|
||||||
|
listQuery.value = {
|
||||||
|
...res,
|
||||||
|
nl: IdCard(res.yjRysfzh, 3) || "",
|
||||||
|
xb: IdCard(res.yjRysfzh, 2) || "",
|
||||||
|
xsd: res.xsd + '%'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
|
// 关闭
|
||||||
|
const close = () => {
|
||||||
|
listQuery.value = {};
|
||||||
|
loading.value = false;
|
||||||
|
dialogForm.value = false;
|
||||||
|
listQuery.value = {}
|
||||||
|
};
|
||||||
|
|
||||||
|
defineExpose({ init });
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "~@/assets/css/layout.scss";
|
||||||
|
@import "~@/assets/css/element-plus.scss";
|
||||||
|
::v-deep {
|
||||||
|
.el-form-item__content {
|
||||||
|
align-items: normal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -0,0 +1,88 @@
|
|||||||
|
<template>
|
||||||
|
<div class="dialog" v-if="dialogForm">
|
||||||
|
<div class="head_box">
|
||||||
|
<span class="title">行为预警{{ title }} </span>
|
||||||
|
<div>
|
||||||
|
<!-- <el-button type="primary" size="small" :loading="loading" @click="submit">保存</el-button> -->
|
||||||
|
<el-button size="small" @click="close">关闭</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form_cnt">
|
||||||
|
<FormMessage :formList="formData" v-model="listQuery" ref="elform">
|
||||||
|
</FormMessage>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import FormMessage from "@/components/aboutTable/FormMessage.vue";
|
||||||
|
import { tbYjxxGetInfo,yjzxXwyjSelectList } from "@/api/yj.js";
|
||||||
|
import { IdCard } from '@/utils/validate.js'
|
||||||
|
import { ref, defineExpose, reactive, defineEmits, getCurrentInstance, watch } from "vue";
|
||||||
|
const emit = defineEmits(["updateDate"]);
|
||||||
|
const props = defineProps({
|
||||||
|
dict: {
|
||||||
|
type: Object,
|
||||||
|
default: () => { }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const { proxy } = getCurrentInstance();
|
||||||
|
const dialogForm = ref(false); //弹窗
|
||||||
|
const formData = ref([])
|
||||||
|
watch(() => props.dict, (res) => {
|
||||||
|
if (res) {
|
||||||
|
formData.value = [
|
||||||
|
{ label: "预警人姓名", prop: "xm", type: "input" },
|
||||||
|
{ label: "身份证号", prop: "sfzh", type: "input" },
|
||||||
|
{ label: "电话", prop: "dh", type: "input" },
|
||||||
|
{ label: "行为大类", prop: "xldlmc", type: "input" },
|
||||||
|
{ label: "行为子类", prop: "xwzlmc", type: "input" },
|
||||||
|
{ label: "行为次数", prop: "xwcs", type: "input",lx:"number" },
|
||||||
|
{ label: "标签颜色", prop: "bqys", type: "select", options: props.dict.D_GS_SSYJ },
|
||||||
|
{ label: "预警时间", prop: "yjsj", type: "input" },
|
||||||
|
{ label: "行为分值", prop: "xwfz", type: "input",lx:"number" },
|
||||||
|
{ label: "处置状态", prop: "czzt", type: "select", options: props.dict.D_GSXT_YJXX_CZZT },
|
||||||
|
{ label: "所属部门", prop: "ssbm", type: "input" },
|
||||||
|
{ label: "所属县局", prop: "ssxgaj", type: "input" },
|
||||||
|
{ label: "所属市局", prop: "sssgaj", type: "input" },
|
||||||
|
{ label: "接警员姓名", prop: "jjyxm", type: "input" },
|
||||||
|
{ label: "行为描述", prop: "xwms", type: "textarea", width: "100%" },
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
}, { deep: true, immediate: true })
|
||||||
|
const listQuery = ref({}); //表单
|
||||||
|
const loading = ref(false);
|
||||||
|
const elform = ref();
|
||||||
|
const title = ref("详情");
|
||||||
|
const init = (row) => {
|
||||||
|
dialogForm.value = true;
|
||||||
|
yjzxXwyjSelectList(row.id).then(res => {
|
||||||
|
listQuery.value = {
|
||||||
|
...res,
|
||||||
|
nl: IdCard(res.yjRysfzh, 3) || "",
|
||||||
|
xb: IdCard(res.yjRysfzh, 2) || "",
|
||||||
|
xsd: res.xsd + '%'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
|
// 关闭
|
||||||
|
const close = () => {
|
||||||
|
listQuery.value = {};
|
||||||
|
loading.value = false;
|
||||||
|
dialogForm.value = false;
|
||||||
|
listQuery.value = {}
|
||||||
|
};
|
||||||
|
|
||||||
|
defineExpose({ init });
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "~@/assets/css/layout.scss";
|
||||||
|
@import "~@/assets/css/element-plus.scss";
|
||||||
|
::v-deep {
|
||||||
|
.el-form-item__content {
|
||||||
|
align-items: normal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -0,0 +1,109 @@
|
|||||||
|
<template>
|
||||||
|
<div class="dialog" v-if="dialogForm">
|
||||||
|
<div class="head_box">
|
||||||
|
<span class="title">组合预警{{ title }} </span>
|
||||||
|
<div>
|
||||||
|
<!-- <el-button type="primary" size="small" :loading="loading" @click="submit">保存</el-button> -->
|
||||||
|
<el-button size="small" @click="close">关闭</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form_cnt">
|
||||||
|
<FormMessage :formList="formData" v-model="listQuery" ref="elform">
|
||||||
|
</FormMessage>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import FormMessage from "@/components/aboutTable/FormMessage.vue";
|
||||||
|
import { tbYjxxGetInfo, yjzxZhyjSelectList } from "@/api/yj.js";
|
||||||
|
import { IdCard } from "@/utils/validate.js";
|
||||||
|
import {
|
||||||
|
ref,
|
||||||
|
defineExpose,
|
||||||
|
reactive,
|
||||||
|
defineEmits,
|
||||||
|
getCurrentInstance,
|
||||||
|
watch
|
||||||
|
} from "vue";
|
||||||
|
const emit = defineEmits(["updateDate"]);
|
||||||
|
const props = defineProps({
|
||||||
|
dict: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const { proxy } = getCurrentInstance();
|
||||||
|
|
||||||
|
const dialogForm = ref(false); //弹窗
|
||||||
|
const formData = ref([]);
|
||||||
|
watch(
|
||||||
|
() => props.dict,
|
||||||
|
(res) => {
|
||||||
|
if (res) {
|
||||||
|
formData.value = [
|
||||||
|
{ label: "预警人姓名", prop: "xm", type: "input" },
|
||||||
|
{ label: "身份证号", prop: "sfzh", type: "input" },
|
||||||
|
{ label: "电话", prop: "dh", type: "input" },
|
||||||
|
{ label: "组合大类", prop: "sfdlmc", type: "input" },
|
||||||
|
{ label: "组合小类", prop: "sfzlmc", type: "input" },
|
||||||
|
{ label: "组合预警次数", prop: "sfcs", type: "input", lx: "number" },
|
||||||
|
{
|
||||||
|
label: "标签颜色",
|
||||||
|
prop: "bqys",
|
||||||
|
type: "select",
|
||||||
|
options: props.dict.D_GS_SSYJ
|
||||||
|
},
|
||||||
|
{ label: "预警时间", prop: "yjsj", type: "input" },
|
||||||
|
{ label: "预警分值", prop: "sffz", type: "input", lx: "number" },
|
||||||
|
{
|
||||||
|
label: "处置状态",
|
||||||
|
prop: "czzt",
|
||||||
|
type: "select",
|
||||||
|
options: props.dict.D_GSXT_YJXX_CZZT
|
||||||
|
},
|
||||||
|
{ label: "所属部门", prop: "ssbm", type: "input" },
|
||||||
|
{ label: "所属县局", prop: "ssxgaj", type: "input" },
|
||||||
|
{ label: "所属市局", prop: "sssgaj", type: "input" },
|
||||||
|
{ label: "接警员姓名", prop: "jjyxm", type: "input" }
|
||||||
|
// { label: "预警内容", prop: "yjNr", type: "textarea", width: "100%" },
|
||||||
|
];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ deep: true, immediate: true }
|
||||||
|
);
|
||||||
|
const listQuery = ref({}); //表单
|
||||||
|
const loading = ref(false);
|
||||||
|
const elform = ref();
|
||||||
|
const title = ref("详情");
|
||||||
|
const init = (row) => {
|
||||||
|
dialogForm.value = true;
|
||||||
|
yjzxZhyjSelectList(row.id).then((res) => {
|
||||||
|
listQuery.value = {
|
||||||
|
...res,
|
||||||
|
nl: IdCard(res.yjRysfzh, 3) || "",
|
||||||
|
xb: IdCard(res.yjRysfzh, 2) || "",
|
||||||
|
xsd: res.xsd + "%"
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
// 关闭
|
||||||
|
const close = () => {
|
||||||
|
listQuery.value = {};
|
||||||
|
loading.value = false;
|
||||||
|
dialogForm.value = false;
|
||||||
|
listQuery.value = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
defineExpose({ init });
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "~@/assets/css/layout.scss";
|
||||||
|
@import "~@/assets/css/element-plus.scss";
|
||||||
|
::v-deep {
|
||||||
|
.el-form-item__content {
|
||||||
|
align-items: normal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -0,0 +1,402 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<!-- 搜索 -->
|
||||||
|
<div ref="searchBox" class="mt10 mb10">
|
||||||
|
<Searchs :searchArr="searchConfiger" @submit="onSearch" @reset="reset" :key="pageData.keyCount">
|
||||||
|
<template #jfd>
|
||||||
|
<div>
|
||||||
|
<el-input v-model="queryFrom.ksfz" type="number" placeholder="开始身份分值" style="width: 130px"></el-input>
|
||||||
|
<span style="color: #333;margin: 0 4px;">至</span>
|
||||||
|
<el-input v-model="queryFrom.jsfz" type="number" placeholder="结束身份分值" style="width: 130px"></el-input>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</Searchs>
|
||||||
|
</div>
|
||||||
|
<PageTitle :malginLeft="10" :height="35" backgroundColor="#ffff" :marginBottom="5" :marginTop="5">
|
||||||
|
<template #left>
|
||||||
|
<el-button type="primary" size="small" @click="exportExl">导出</el-button>
|
||||||
|
<el-button type="primary" size="small" @click="handleQs">签收</el-button>
|
||||||
|
</template>
|
||||||
|
</PageTitle>
|
||||||
|
<!-- 表格 -->
|
||||||
|
<div class="tabBox tabBox_zdy heightBox" :style="{ height: (pageData.tableHeight + 40) + 'px' }">
|
||||||
|
<MyTable :tableData="pageData.tableData" :tableColumn="pageData.tableColumn" :tableHeight="pageData.tableHeight"
|
||||||
|
:key="pageData.keyCount" :tableConfiger="pageData.tableConfiger" :controlsWidth="pageData.controlsWidth" expand
|
||||||
|
@chooseData="handleChooseData">
|
||||||
|
<template #expand="{ props }">
|
||||||
|
<div style="max-width: 100%">
|
||||||
|
<Items :row="props || {}" :dict="dict" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #sfcs="{ row }">
|
||||||
|
<span style="color: #0072ff;" @click="handleClick(row)">{{ row.sfcs }}</span>
|
||||||
|
</template>
|
||||||
|
<template #czzt="{ row }">
|
||||||
|
<DictTag :value="row.czzt" :options="D_GSXT_YJXX_CZZT" />
|
||||||
|
</template>
|
||||||
|
<template #sffz>
|
||||||
|
<el-table-column prop="bqfz" width="80" align="center" label="标签分值" />
|
||||||
|
<el-table-column prop="pzxs" width="60" align="center" label="系数" />
|
||||||
|
<el-table-column prop="sffz" width="90" align="center" label="计算分值"/>
|
||||||
|
</template>
|
||||||
|
<template #controls="{ row }">
|
||||||
|
<el-link type="warning" @click="pushAssess(row)">全息档案</el-link>
|
||||||
|
<el-link type="primary" @click="handleCzjy(row)" v-if="roleCode">处置建议</el-link>
|
||||||
|
<el-link type="primary" @click="chooseJfFun(row)">配置系统</el-link>
|
||||||
|
<!-- <el-link type="primary" @click="showDetail(row)">转合成</el-link>
|
||||||
|
<el-link type="danger" @click="handleQsFk(row)">转会商</el-link> -->
|
||||||
|
<el-link type="success" @click="handleQsFk(row, '签收')" v-if="row.czzt == '01' && permission_sfqs">签收</el-link>
|
||||||
|
<el-link type="success" @click="handleQsFk(row, '反馈')"
|
||||||
|
v-else-if="row.czzt == '02' && permission_sfqs">反馈</el-link>
|
||||||
|
<!-- <el-link type="success" @click="handleQsFk(row, '查看反馈')" v-else>查看反馈</el-link> -->
|
||||||
|
<el-link type="primary" @click="openAddFrom(row)">详情</el-link>
|
||||||
|
</template>
|
||||||
|
</MyTable>
|
||||||
|
<Pages @changeNo="changeNo" @changeSize="changeSize" :tableHeight="pageData.tableHeight" :pageConfiger="{
|
||||||
|
...pageData.pageConfiger,
|
||||||
|
total: pageData.total
|
||||||
|
}"></Pages>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Detail ref="detailRef" />
|
||||||
|
<HolographicArchive v-model="assessShow" :dataList="dataList" />
|
||||||
|
<FkDialog @change="getList" lx="03" />
|
||||||
|
<Information v-model="showDialog" title="发送指令" @submit='submit' @close='closeFszl'>
|
||||||
|
<SemdFqzl ref="semdFqzlRef" :itemData="itemData" @handleClose="handleClose" identification="yj"
|
||||||
|
:tacitly="tacitly" />
|
||||||
|
</Information>
|
||||||
|
<AddFrom ref="addModelRef" :dict="{ D_GSXT_YJXX_CZZT, D_BZ_YJJB, D_GS_SSYJ }" />
|
||||||
|
|
||||||
|
<!-- 处置建议 -->
|
||||||
|
<Czjy ref="czjyRef" @okSubmit="getList"></Czjy>
|
||||||
|
|
||||||
|
<ChooseJf v-model="chooseJfShow" titleValue="选择系数" :Single="false" :chooseJfBh="chooseJfBh" url="/yjzxSfyj/sjxspz"
|
||||||
|
:roleIds="roleIds" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import Czjy from './components/czjy.vue'
|
||||||
|
import { getItem, setItem } from '@/utils/storage'
|
||||||
|
import PageTitle from "@/components/aboutTable/PageTitle.vue";
|
||||||
|
import Searchs from "@/components/aboutTable/Search.vue";
|
||||||
|
import MyTable from "@/components/aboutTable/MyTable.vue";
|
||||||
|
import Pages from "@/components/aboutTable/Pages.vue";
|
||||||
|
import HolographicArchive from '@/views/home/components/holographicArchive.vue'
|
||||||
|
import Information from "@/views/home/model/information.vue";
|
||||||
|
import SemdFqzl from '@/components/instructionHasBeen/sendFqzl.vue'
|
||||||
|
import AddFrom from "./components/addFrom.vue";
|
||||||
|
import ChooseJf from '@/components/ChooseList/ChooseJf/index.vue'
|
||||||
|
import FkDialog from "@/views/backOfficeSystem/fourColorManage/warningControl/centerHome/components/fkDialog.vue";
|
||||||
|
import { reactive, ref, onMounted, getCurrentInstance, nextTick } from "vue";
|
||||||
|
import { qcckGet, qcckPost } from "@/api/qcckApi.js";
|
||||||
|
import { yjzxSfyjSelectList, yjzxyjzxSfyjSelectList } from "@/api/yj.js";
|
||||||
|
import { tbGsxtBqglSelectList } from '@/api/zdr'
|
||||||
|
import Detail from './components/detail.vue'
|
||||||
|
import { watch } from "vue";
|
||||||
|
import emitter from "@/utils/eventBus.js";
|
||||||
|
import { holographicProfileJump } from "@/utils/tools.js"
|
||||||
|
import Items from "./item/items.vue"
|
||||||
|
import { exportExlByObj } from "@/utils/exportExcel.js"
|
||||||
|
import { getMultiDictVal } from "@/utils/dict.js"
|
||||||
|
const czjyRef = ref()
|
||||||
|
const { proxy } = getCurrentInstance();
|
||||||
|
const searchBox = ref();
|
||||||
|
const { D_GSXT_YJXX_CZZT, D_GS_SSYJ, D_BZ_YJJB } = proxy.$dict("D_GSXT_YJXX_CZZT", "D_GS_SSYJ", 'D_BZ_YJJB')
|
||||||
|
const dict = reactive({ D_GSXT_YJXX_CZZT, D_GS_SSYJ })
|
||||||
|
// 搜索配置
|
||||||
|
const searchConfiger = ref([
|
||||||
|
{ label: "姓名", prop: 'xm', placeholder: "请输入姓名", showType: "input" },
|
||||||
|
{ label: "身份证号码", prop: 'sfzh', placeholder: "请输入身份证号码", showType: "input" },
|
||||||
|
{ label: "预警标签", prop: 'yjbqmc', placeholder: "请输入预警标签", showType: "input" },
|
||||||
|
{ label: "部门", prop: 'ssbmdm', placeholder: "请选择部门", showType: "department" },
|
||||||
|
{ label: "级别", prop: 'bqys', placeholder: "请选择级别", showType: "select", options: D_BZ_YJJB },
|
||||||
|
{ label: "积分段", prop: 'jfd', placeholder: "请选择积分段", showType: "Slot" },
|
||||||
|
{ label: "预警时间", prop: 'times', showType: "datetimerange" },
|
||||||
|
]);
|
||||||
|
|
||||||
|
const permission_sfqs = ref(false)
|
||||||
|
const roleCode = ref(false)
|
||||||
|
|
||||||
|
const queryFrom = ref({});
|
||||||
|
|
||||||
|
// 页面数据
|
||||||
|
const pageData = reactive({
|
||||||
|
tableData: [],
|
||||||
|
keyCount: 0,
|
||||||
|
tableConfiger: {
|
||||||
|
rowHieght: 61,
|
||||||
|
showSelectType: "checkBox",
|
||||||
|
loading: false,
|
||||||
|
haveControls: true,
|
||||||
|
},
|
||||||
|
total: 0,
|
||||||
|
pageConfiger: {
|
||||||
|
pageSize: 20,
|
||||||
|
pageCurrent: 1
|
||||||
|
},
|
||||||
|
controlsWidth: 300, //操作栏宽度
|
||||||
|
tableColumn: [
|
||||||
|
{ label: "状态", prop: "czzt", showSolt: true },
|
||||||
|
{ label: "预警时间", prop: "yjsj" ,width: 180},
|
||||||
|
{ label: "姓名", prop: "xm" },
|
||||||
|
{ label: "身份证号", prop: "sfzh" ,width: 180},
|
||||||
|
{ label: "标签", prop: "yjbqmc" },
|
||||||
|
{ label: "接收单位", prop: "ssbm" },
|
||||||
|
{ label: "活动频次", prop: "sfcs",width: 90 },
|
||||||
|
{ label: "预警分值", prop: "sffz",showSolt: true },
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
let str = getItem('deptId') ? getItem('deptId')[0].deptLevel : ''
|
||||||
|
permission_sfqs.value = str.startsWith('2' || '3') ? false : true;
|
||||||
|
let rols = getItem('roleList') ? getItem('roleList') : []
|
||||||
|
let obj = rols.find(item => {
|
||||||
|
return ['JS_666666', 'JS_777777', 'JS_888888'].includes(item.roleCode)
|
||||||
|
})
|
||||||
|
roleCode.value = obj ? true : false;
|
||||||
|
|
||||||
|
gettbGsxtBqglSelectList()
|
||||||
|
tabHeightFn();
|
||||||
|
getList();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
const onSearch = (val) => {
|
||||||
|
queryFrom.value = { ...queryFrom.value, ...val };
|
||||||
|
queryFrom.value.startTime = val.times ? val.times[0] : ''
|
||||||
|
queryFrom.value.endTime = val.times ? val.times[1] : ''
|
||||||
|
pageData.pageConfiger.pageCurrent = 1;
|
||||||
|
getList();
|
||||||
|
};
|
||||||
|
|
||||||
|
const reset = () => {
|
||||||
|
delete queryFrom.value.ksfz
|
||||||
|
delete queryFrom.value.jsfz
|
||||||
|
}
|
||||||
|
|
||||||
|
const changeNo = (val) => {
|
||||||
|
pageData.pageConfiger.pageCurrent = val;
|
||||||
|
getList();
|
||||||
|
};
|
||||||
|
|
||||||
|
const changeSize = (val) => {
|
||||||
|
pageData.pageConfiger.pageSize = val;
|
||||||
|
getList();
|
||||||
|
};
|
||||||
|
|
||||||
|
const getList = () => {
|
||||||
|
pageData.tableConfiger.loading = true;
|
||||||
|
// TODO: 替换为实际的身份预警API接口
|
||||||
|
let params = {
|
||||||
|
...queryFrom.value,
|
||||||
|
pageCurrent: pageData.pageConfiger.pageCurrent,
|
||||||
|
pageSize: pageData.pageConfiger.pageSize,
|
||||||
|
}
|
||||||
|
delete params.times;
|
||||||
|
yjzxSfyjSelectList(params).then((res) => {
|
||||||
|
pageData.tableData = Array.isArray(res?.records) ? res.records : [];
|
||||||
|
pageData.tableData = pageData.tableData.map(item => {
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
bqys_cname: getMultiDictVal(item.bqys, D_GS_SSYJ),
|
||||||
|
czzt_cname: getMultiDictVal(item.czzt, D_GSXT_YJXX_CZZT),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
pageData.total = res?.total || 0;
|
||||||
|
pageData.tableConfiger.loading = false;
|
||||||
|
}).catch(() => {
|
||||||
|
pageData.tableConfiger.loading = false;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
// 标签
|
||||||
|
const bqLbData = ref({
|
||||||
|
bqDl: [],
|
||||||
|
bqXl: []
|
||||||
|
})
|
||||||
|
const gettbGsxtBqglSelectList = (val) => {
|
||||||
|
const promes = {
|
||||||
|
bqLx: '01',
|
||||||
|
bqLb: val ? '02' : "01",
|
||||||
|
bqDlId: val ? bqLbData.value.bqDl.find(item => item.value == val)?.id : ""
|
||||||
|
}
|
||||||
|
tbGsxtBqglSelectList(promes).then((res) => {
|
||||||
|
if (val) {
|
||||||
|
queryFrom.value.bqxl = ''
|
||||||
|
bqLbData.value.bqXl = res.data ? res.data.map(item => {
|
||||||
|
return {
|
||||||
|
label: item.bqMc,
|
||||||
|
value: item.bqDm,
|
||||||
|
}
|
||||||
|
}) : []
|
||||||
|
} else {
|
||||||
|
bqLbData.value.bqDl = res ? res.map(item => {
|
||||||
|
return {
|
||||||
|
label: item.bqMc,
|
||||||
|
value: item.bqDm,
|
||||||
|
id: item.id
|
||||||
|
}
|
||||||
|
}) : []
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(() => bqLbData.value.bqXl, (res) => {
|
||||||
|
bqLbData.value.bqXl = res
|
||||||
|
}, { deep: true })
|
||||||
|
|
||||||
|
// 查看详情
|
||||||
|
const detailRef = ref()
|
||||||
|
const handleClick = (row) => {
|
||||||
|
detailRef.value.init(row)
|
||||||
|
}
|
||||||
|
// 处理签收
|
||||||
|
const handleQsFk = (val, type) => {
|
||||||
|
switch (type) {
|
||||||
|
case '签收':
|
||||||
|
proxy.$confirm("是否确定要签收?", "警告", { type: "warning" }).then(() => {
|
||||||
|
qcckPost({ id: val.id }, "/mosty-gsxt//yjzxSfyj/yjqs").then(() => {
|
||||||
|
val.czzt = '02'
|
||||||
|
getList()
|
||||||
|
proxy.$message({ type: "success", message: "签收成功" });
|
||||||
|
});
|
||||||
|
})
|
||||||
|
break;
|
||||||
|
case '反馈':
|
||||||
|
case '查看反馈':
|
||||||
|
emitter.emit("openFkDialog", { id: val.id, type });
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 全息档案
|
||||||
|
const assessShow = ref(false)
|
||||||
|
const dataList = ref()
|
||||||
|
const pushAssess = (val) => {
|
||||||
|
return holographicProfileJump(val.yjlb, val) // 全息档案跳转
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送指令
|
||||||
|
const showDialog = ref(false)
|
||||||
|
const itemData = ref()
|
||||||
|
const showDetail = (item) => {
|
||||||
|
showDialog.value = true;
|
||||||
|
itemData.value = item
|
||||||
|
}
|
||||||
|
const handleClose = () => {
|
||||||
|
showDialog.value = false;
|
||||||
|
}
|
||||||
|
const semdFqzlRef = ref()
|
||||||
|
const tacitly = {
|
||||||
|
title: 'yjbt',
|
||||||
|
instructionContent: 'yjnr'
|
||||||
|
}
|
||||||
|
const submit = () => {
|
||||||
|
semdFqzlRef.value.getsendFqzl()
|
||||||
|
}
|
||||||
|
const closeFszl = () => {
|
||||||
|
semdFqzlRef.value.close()
|
||||||
|
}
|
||||||
|
const bqYs = (val) => {
|
||||||
|
if (val == '01') {
|
||||||
|
return '#ff0202'
|
||||||
|
} else if (val == '02') {
|
||||||
|
return '#ff8c00'
|
||||||
|
} else if (val == '03') {
|
||||||
|
return '#ffff00'
|
||||||
|
} else if (val == '04') {
|
||||||
|
return '#0000ff'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增
|
||||||
|
const addModelRef = ref(null)
|
||||||
|
const openAddFrom = (row) => {
|
||||||
|
addModelRef.value.init('add', row)
|
||||||
|
}
|
||||||
|
// 选择系数
|
||||||
|
const chooseJfShow = ref(false)
|
||||||
|
const chooseJfBh = ref()
|
||||||
|
const roleIds = ref()
|
||||||
|
const chooseJfFun = (val) => {
|
||||||
|
chooseJfBh.value = val.id
|
||||||
|
yjzxyjzxSfyjSelectList(val.id).then(res => {
|
||||||
|
roleIds.value = res.sjxspzList.map(item => item.xsid)
|
||||||
|
chooseJfShow.value = true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const handleCzjy = (row) => {
|
||||||
|
czjyRef.value.init(row)
|
||||||
|
}
|
||||||
|
// 表格高度计算
|
||||||
|
const tabHeightFn = () => {
|
||||||
|
pageData.tableHeight = window.innerHeight - searchBox.value.offsetHeight - 280;
|
||||||
|
window.onresize = function () {
|
||||||
|
tabHeightFn();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** 选中项 */
|
||||||
|
const selectRows = ref([])
|
||||||
|
const handleChooseData = (val) => {
|
||||||
|
selectRows.value = val
|
||||||
|
}
|
||||||
|
const exportExl = () => {
|
||||||
|
const titleObj = {
|
||||||
|
czzt_cname: "状态",
|
||||||
|
yjsj: "预警时间",
|
||||||
|
xm: "姓名",
|
||||||
|
sfzh: "身份证号",
|
||||||
|
yjbqmc: "标签",
|
||||||
|
ssbm: "接收单位",
|
||||||
|
sfcs: "活动频次",
|
||||||
|
sffz: "预警分值",
|
||||||
|
}
|
||||||
|
/** 导出【选中】的数据 (没有就全部)*/
|
||||||
|
const needArr = selectRows.value?.length > 0 ? selectRows.value : pageData.tableData
|
||||||
|
const data = needArr.map(item => {
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
bqys_cname: getMultiDictVal(item.bqys, D_GS_SSYJ),
|
||||||
|
czzt_cname: getMultiDictVal(item.czzt, D_GSXT_YJXX_CZZT),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
exportExlByObj(titleObj, data, '身份预警')
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleQs = () => {
|
||||||
|
if (selectRows.value?.length === 0) return proxy.$message({ type: "warning", message: "请选择要签收的预警" });
|
||||||
|
let wqs = selectRows.value.filter(item => item.czzt == '01');
|
||||||
|
if (wqs.length == 0) return proxy.$message({ type: "warning", message: "数据都已签收,请选择未签收的数据" });
|
||||||
|
let yqs = selectRows.value.filter(item => item.czzt == '02');
|
||||||
|
let texy = yqs.length > 0 ? `${yqs.length}条已签收预警数据,确认要签收${wqs.length}条未签收预警数据吗?` : '确认要签收所有预警数据吗?'
|
||||||
|
proxy.$confirm(texy, "警告", { type: "warning" }).then(() => {
|
||||||
|
let ids = wqs.map(item => item.id)
|
||||||
|
qcckPost({ids}, '/mosty-gsxt/yjzxSfyj/batchQs').then(() => {
|
||||||
|
proxy.$message({ type: "success", message: "成功" });
|
||||||
|
getList();
|
||||||
|
}).catch(() => {
|
||||||
|
proxy.$message({ type: "error", message: "失败" });
|
||||||
|
});
|
||||||
|
}).catch(() => { });
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
|
<style lang="scss">
|
||||||
|
.el-loading-mask {
|
||||||
|
background: rgba(0, 0, 0, 0.5) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tabBox_zdy {
|
||||||
|
.el-table--fit {
|
||||||
|
overflow: unset !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -0,0 +1,564 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<!-- 搜索 -->
|
||||||
|
<div ref="searchBox" class="mt10">
|
||||||
|
<QueryFormPanel :fields="searchConfiger" @search="onSearch">
|
||||||
|
<template #yjfz>
|
||||||
|
<div>
|
||||||
|
<el-input
|
||||||
|
v-model="queryFrom.yjksfz"
|
||||||
|
type="number"
|
||||||
|
placeholder="开始分值"
|
||||||
|
style="width: 130px"
|
||||||
|
clearable
|
||||||
|
></el-input>
|
||||||
|
<el-input
|
||||||
|
v-model="queryFrom.yjjsfz"
|
||||||
|
type="number"
|
||||||
|
placeholder="结束分值"
|
||||||
|
style="width: 130px"
|
||||||
|
clearable
|
||||||
|
></el-input>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #but>
|
||||||
|
<el-button type="primary" @click="exportExl" size="small"
|
||||||
|
>导出</el-button
|
||||||
|
>
|
||||||
|
<el-button type="primary" size="small" @click="handleQs"
|
||||||
|
>签收</el-button
|
||||||
|
>
|
||||||
|
</template>
|
||||||
|
</QueryFormPanel>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 表格 -->
|
||||||
|
<div :style="{ height: pageData.tableHeight + 40 + 'px' }" class="bgTable">
|
||||||
|
<WarnDataTable
|
||||||
|
:loading="pageData.tableConfiger.loading"
|
||||||
|
:tableHeight="pageData.tableHeight"
|
||||||
|
:data="pageData.tableData"
|
||||||
|
:columns="pageData.tableColumn"
|
||||||
|
table-class="warn-table"
|
||||||
|
@selectionChange="handleChooseData"
|
||||||
|
>
|
||||||
|
<template #sfcs="{ row }">
|
||||||
|
<span style="color: #0072ff" @click="handleClick(row)">{{
|
||||||
|
row.sfcs
|
||||||
|
}}</span>
|
||||||
|
</template>
|
||||||
|
<template #czzt="{ row }">
|
||||||
|
<DictTag
|
||||||
|
:value="row.czzt"
|
||||||
|
:color="row.czzt === '01' ? '#ff2424' : '#1d72e8'"
|
||||||
|
:tag="false"
|
||||||
|
:options="D_GSXT_YJXX_CZZT"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<template #yjLylx="{ row }">
|
||||||
|
<DictTag :value="row.yjLylx" :tag="false" :options="D_BZ_YJBQLX" />
|
||||||
|
</template>
|
||||||
|
<template #yjjb="{ row }">
|
||||||
|
<div :style="{ 'background-color': ys(row) }">
|
||||||
|
<DictTag
|
||||||
|
:value="row.yjjb"
|
||||||
|
color="#fff"
|
||||||
|
:tag="false"
|
||||||
|
:options="D_BZ_YJJB"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template #nl="{ row }">
|
||||||
|
<div>{{ IdCard(row.rysfzh, 3) }}</div>
|
||||||
|
</template>
|
||||||
|
<template #xb="{ row }">
|
||||||
|
<div>{{ IdCard(row.rysfzh, 2) }}</div>
|
||||||
|
</template>
|
||||||
|
<template #operation="{ row }">
|
||||||
|
<div style="display: flex; justify-content: space-between">
|
||||||
|
<span class="warning" @click="pushAssess(row)">全息档案</span>
|
||||||
|
<span class="primary" @click="handleCzjy(row)" v-if="roleCode"
|
||||||
|
>处置建议</span
|
||||||
|
>
|
||||||
|
<span class="primary" @click="chooseJfFun(row)">配置系统</span>
|
||||||
|
<span
|
||||||
|
class="success"
|
||||||
|
@click="handleQsFk(row, '签收')"
|
||||||
|
v-if="row.czzt == '01' && permission_sfqs"
|
||||||
|
>签收</span
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="success"
|
||||||
|
@click="handleQsFk(row, '反馈')"
|
||||||
|
v-else-if="row.czzt == '02' && permission_sfqs"
|
||||||
|
>反馈</span
|
||||||
|
>
|
||||||
|
<span class="primary" @click="openAddFrom(row)">详情</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</WarnDataTable>
|
||||||
|
<Pages
|
||||||
|
@changeNo="changeNo"
|
||||||
|
@changeSize="changeSize"
|
||||||
|
:tableHeight="pageData.tableHeight"
|
||||||
|
:pageConfiger="{
|
||||||
|
...pageData.pageConfiger,
|
||||||
|
total: pageData.total
|
||||||
|
}"
|
||||||
|
></Pages>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Detail ref="detailRef" />
|
||||||
|
<HolographicArchive v-model="assessShow" :dataList="dataList" />
|
||||||
|
<FkDialog @change="getList" lx="03" />
|
||||||
|
<Information
|
||||||
|
v-model="showDialog"
|
||||||
|
title="发送指令"
|
||||||
|
@submit="submit"
|
||||||
|
@close="closeFszl"
|
||||||
|
>
|
||||||
|
<SemdFqzl
|
||||||
|
ref="semdFqzlRef"
|
||||||
|
:itemData="itemData"
|
||||||
|
@handleClose="handleClose"
|
||||||
|
identification="yj"
|
||||||
|
:tacitly="tacitly"
|
||||||
|
/>
|
||||||
|
</Information>
|
||||||
|
<AddFrom
|
||||||
|
ref="addModelRef"
|
||||||
|
:dict="{ D_GSXT_YJXX_CZZT, D_BZ_YJJB, D_GS_SSYJ }"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Xwbq ref="xwbqRef" :dict="{ D_GSXT_YJXX_CZZT, D_BZ_YJJB, D_GS_SSYJ }" />
|
||||||
|
<Sfbq ref="sfbqRef" :dict="{ D_GSXT_YJXX_CZZT, D_BZ_YJJB, D_GS_SSYJ }" />
|
||||||
|
<!-- 处置建议 -->
|
||||||
|
<Czjy ref="czjyRef" @okSubmit="getList"></Czjy>
|
||||||
|
|
||||||
|
<ChooseJf
|
||||||
|
v-model="chooseJfShow"
|
||||||
|
titleValue="选择系数"
|
||||||
|
:Single="false"
|
||||||
|
:chooseJfBh="chooseJfBh"
|
||||||
|
url="/yjzxSfyj/sjxspz"
|
||||||
|
:roleIds="roleIds"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import Czjy from "./components/czjy.vue";
|
||||||
|
import { getItem } from "@/utils/storage";
|
||||||
|
import Pages from "@/components/aboutTable/Pages.vue";
|
||||||
|
import HolographicArchive from "@/views/home/components/holographicArchive.vue";
|
||||||
|
import Information from "@/views/home/model/information.vue";
|
||||||
|
import SemdFqzl from "@/components/instructionHasBeen/sendFqzl.vue";
|
||||||
|
import AddFrom from "./components/zhbq.vue";
|
||||||
|
import Xwbq from "./components/xwbq.vue";
|
||||||
|
import Sfbq from "./components/sfbq.vue";
|
||||||
|
import ChooseJf from "@/components/ChooseList/ChooseJf/index.vue";
|
||||||
|
import FkDialog from "@/views/backOfficeSystem/fourColorManage/warningControl/centerHome/components/fkDialog.vue";
|
||||||
|
import { reactive, ref, onMounted, getCurrentInstance } from "vue";
|
||||||
|
import { qcckPost, qcckGet } from "@/api/qcckApi.js";
|
||||||
|
import { yjzxSfyjSelectList, yjzxyjzxSfyjSelectList } from "@/api/yj.js";
|
||||||
|
import { tbGsxtBqglSelectList } from "@/api/zdr";
|
||||||
|
import Detail from "./components/detail.vue";
|
||||||
|
import { watch } from "vue";
|
||||||
|
import emitter from "@/utils/eventBus.js";
|
||||||
|
import { holographicProfileJump, bqYs } from "@/utils/tools.js";
|
||||||
|
import { exportExlByObj } from "@/utils/exportExcel.js";
|
||||||
|
import { getMultiDictVal } from "@/utils/dict.js";
|
||||||
|
import WarnDataTable from "@/views/backOfficeSystem/ces/components/WarnDataTable.vue";
|
||||||
|
import QueryFormPanel from "@/views/backOfficeSystem/ces/components/QueryFormPanel.vue";
|
||||||
|
import { IdCard } from "@/utils/dict.js";
|
||||||
|
const czjyRef = ref();
|
||||||
|
const { proxy } = getCurrentInstance();
|
||||||
|
const searchBox = ref();
|
||||||
|
const { D_GSXT_YJXX_CZZT, D_GS_SSYJ, D_BZ_YJJB, D_BZ_YJBQLX } = proxy.$dict(
|
||||||
|
"D_GSXT_YJXX_CZZT",
|
||||||
|
"D_GS_SSYJ",
|
||||||
|
"D_BZ_YJJB",
|
||||||
|
"D_BZ_YJBQLX"
|
||||||
|
);
|
||||||
|
const dict = reactive({ D_GSXT_YJXX_CZZT, D_GS_SSYJ });
|
||||||
|
|
||||||
|
// 搜索配置
|
||||||
|
const searchConfiger = ref([
|
||||||
|
{
|
||||||
|
key: "czzt",
|
||||||
|
label: "处置状态",
|
||||||
|
type: "select",
|
||||||
|
options: D_GSXT_YJXX_CZZT,
|
||||||
|
placeholder: "请选择级别"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "startTime",
|
||||||
|
label: "预警时间",
|
||||||
|
type: "datetimerange",
|
||||||
|
placeholder: "请选择预警时间"
|
||||||
|
},
|
||||||
|
{ key: "ryxm", label: "姓名", type: "input", placeholder: "请输入姓名" },
|
||||||
|
{
|
||||||
|
key: "rysfzh",
|
||||||
|
label: "身份证号码",
|
||||||
|
type: "input",
|
||||||
|
placeholder: "请输入身份证号码"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "yjLylx",
|
||||||
|
label: "标签类型",
|
||||||
|
type: "select",
|
||||||
|
options: D_BZ_YJBQLX,
|
||||||
|
placeholder: "请选择预警标签"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "yjjb",
|
||||||
|
label: "标签级别",
|
||||||
|
type: "select",
|
||||||
|
options: D_BZ_YJJB,
|
||||||
|
placeholder: "请选择预警标签"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "ssbmdm",
|
||||||
|
label: "接收部门",
|
||||||
|
type: "department",
|
||||||
|
placeholder: "请选择接收部门"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "yjcs",
|
||||||
|
label: "活动频次",
|
||||||
|
type: "input",
|
||||||
|
placeholder: "请输入活动频次"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "yjfz",
|
||||||
|
label: "标签分值",
|
||||||
|
type: "slot",
|
||||||
|
placeholder: "请输入标签分值"
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
const permission_sfqs = ref(false);
|
||||||
|
const roleCode = ref(false);
|
||||||
|
|
||||||
|
const queryFrom = ref({});
|
||||||
|
|
||||||
|
// 页面数据
|
||||||
|
const pageData = reactive({
|
||||||
|
tableData: [],
|
||||||
|
keyCount: 0,
|
||||||
|
tableConfiger: {
|
||||||
|
rowHieght: 61,
|
||||||
|
showSelectType: "checkBox",
|
||||||
|
loading: false,
|
||||||
|
haveControls: true
|
||||||
|
},
|
||||||
|
total: 0,
|
||||||
|
pageConfiger: {
|
||||||
|
pageSize: 20,
|
||||||
|
pageCurrent: 1
|
||||||
|
},
|
||||||
|
controlsWidth: 300, //操作栏宽度
|
||||||
|
tableColumn: [
|
||||||
|
{ type: "index", label: "序号", width: 55, align: "center" },
|
||||||
|
{ label: "处置状态", align: "center", slotName: "czzt" },
|
||||||
|
{ prop: "yjsj", label: "预警时间", align: "center", width: 200 },
|
||||||
|
{ prop: "ryxm", label: "姓名", align: "center" },
|
||||||
|
{ label: "性别", align: "center", slotName: "xb", align: "center" },
|
||||||
|
{ prop: "rysfzh", label: "身份证号", align: "center", width: 200 },
|
||||||
|
{ label: "年龄", align: "center", slotName: "nl", align: "center" },
|
||||||
|
{ label: "标签类型", align: "center", slotName: "yjLylx" },
|
||||||
|
{ label: "标签级别", align: "center", slotName: "yjjb" },
|
||||||
|
{ prop: "ssbm", label: "接收单位", align: "center", width: 200 },
|
||||||
|
{ prop: "yjcs", label: "活动频次", align: "center" },
|
||||||
|
{ prop: "yjfz", label: "标签分值", align: "center" },
|
||||||
|
{ label: "操作", width: 200, slotName: "operation" }
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
let str = getItem("deptId") ? getItem("deptId")[0].deptLevel : "";
|
||||||
|
permission_sfqs.value = str.startsWith("2" || "3") ? false : true;
|
||||||
|
let rols = getItem("roleList") ? getItem("roleList") : [];
|
||||||
|
let obj = rols.find((item) => {
|
||||||
|
return ["JS_666666", "JS_777777", "JS_888888"].includes(item.roleCode);
|
||||||
|
});
|
||||||
|
roleCode.value = obj ? true : false;
|
||||||
|
|
||||||
|
gettbGsxtBqglSelectList();
|
||||||
|
tabHeightFn();
|
||||||
|
getList();
|
||||||
|
});
|
||||||
|
|
||||||
|
const onSearch = (val) => {
|
||||||
|
queryFrom.value = { ...queryFrom.value, ...val };
|
||||||
|
if (val.startTime && Array.isArray(val.startTime)) {
|
||||||
|
queryFrom.value.startTime = val.startTime[0];
|
||||||
|
queryFrom.value.endTime = val.startTime[1];
|
||||||
|
}
|
||||||
|
pageData.pageConfiger.pageCurrent = 1;
|
||||||
|
getList();
|
||||||
|
};
|
||||||
|
|
||||||
|
const changeNo = (val) => {
|
||||||
|
pageData.pageConfiger.pageCurrent = val;
|
||||||
|
getList();
|
||||||
|
};
|
||||||
|
|
||||||
|
const changeSize = (val) => {
|
||||||
|
pageData.pageConfiger.pageSize = val;
|
||||||
|
getList();
|
||||||
|
};
|
||||||
|
|
||||||
|
const getList = () => {
|
||||||
|
pageData.tableConfiger.loading = true;
|
||||||
|
let params = {
|
||||||
|
...queryFrom.value,
|
||||||
|
pageCurrent: pageData.pageConfiger.pageCurrent,
|
||||||
|
pageSize: pageData.pageConfiger.pageSize
|
||||||
|
};
|
||||||
|
qcckPost(params, "/mosty-gsxt/tbYjxx/getPageBqyjList")
|
||||||
|
.then((res) => {
|
||||||
|
pageData.tableData = Array.isArray(res?.records) ? res.records : [];
|
||||||
|
pageData.total = res?.total || 0;
|
||||||
|
pageData.tableConfiger.loading = false;
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
pageData.tableConfiger.loading = false;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
// 标签
|
||||||
|
const bqLbData = ref({
|
||||||
|
bqDl: [],
|
||||||
|
bqXl: []
|
||||||
|
});
|
||||||
|
const gettbGsxtBqglSelectList = (val) => {
|
||||||
|
const promes = {
|
||||||
|
bqLx: "01",
|
||||||
|
bqLb: val ? "02" : "01",
|
||||||
|
bqDlId: val ? bqLbData.value.bqDl.find((item) => item.value == val)?.id : ""
|
||||||
|
};
|
||||||
|
tbGsxtBqglSelectList(promes).then((res) => {
|
||||||
|
if (val) {
|
||||||
|
queryFrom.value.bqxl = "";
|
||||||
|
bqLbData.value.bqXl = res.data
|
||||||
|
? res.data.map((item) => {
|
||||||
|
return {
|
||||||
|
label: item.bqMc,
|
||||||
|
value: item.bqDm
|
||||||
|
};
|
||||||
|
})
|
||||||
|
: [];
|
||||||
|
} else {
|
||||||
|
bqLbData.value.bqDl = res
|
||||||
|
? res.map((item) => {
|
||||||
|
return {
|
||||||
|
label: item.bqMc,
|
||||||
|
value: item.bqDm,
|
||||||
|
id: item.id
|
||||||
|
};
|
||||||
|
})
|
||||||
|
: [];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => bqLbData.value.bqXl,
|
||||||
|
(res) => {
|
||||||
|
bqLbData.value.bqXl = res;
|
||||||
|
},
|
||||||
|
{ deep: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
// 查看详情
|
||||||
|
const detailRef = ref();
|
||||||
|
const handleClick = (row) => {
|
||||||
|
detailRef.value.init(row);
|
||||||
|
};
|
||||||
|
// 处理签收
|
||||||
|
const handleQsFk = (val, type) => {
|
||||||
|
switch (type) {
|
||||||
|
case "签收":
|
||||||
|
proxy
|
||||||
|
.$confirm("是否确定要签收?", "警告", { type: "warning" })
|
||||||
|
.then(() => {
|
||||||
|
qcckPost({ id: val.id }, "/mosty-gsxt//yjzxSfyj/yjqs").then(() => {
|
||||||
|
val.czzt = "02";
|
||||||
|
getList();
|
||||||
|
proxy.$message({ type: "success", message: "签收成功" });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case "反馈":
|
||||||
|
case "查看反馈":
|
||||||
|
emitter.emit("openFkDialog", { id: val.id, type });
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 全息档案
|
||||||
|
const assessShow = ref(false);
|
||||||
|
const dataList = ref();
|
||||||
|
const pushAssess = (val) => {
|
||||||
|
return holographicProfileJump(val.yjlb, val); // 全息档案跳转
|
||||||
|
};
|
||||||
|
|
||||||
|
// 发送指令
|
||||||
|
const showDialog = ref(false);
|
||||||
|
const itemData = ref();
|
||||||
|
const showDetail = (item) => {
|
||||||
|
showDialog.value = true;
|
||||||
|
itemData.value = item;
|
||||||
|
};
|
||||||
|
const handleClose = () => {
|
||||||
|
showDialog.value = false;
|
||||||
|
};
|
||||||
|
const semdFqzlRef = ref();
|
||||||
|
const tacitly = {
|
||||||
|
title: "yjbt",
|
||||||
|
instructionContent: "yjnr"
|
||||||
|
};
|
||||||
|
const submit = () => {
|
||||||
|
semdFqzlRef.value.getsendFqzl();
|
||||||
|
};
|
||||||
|
const closeFszl = () => {
|
||||||
|
semdFqzlRef.value.close();
|
||||||
|
};
|
||||||
|
|
||||||
|
// 新增
|
||||||
|
const addModelRef = ref(null);
|
||||||
|
const xwbqRef = ref(null);
|
||||||
|
const sfbqRef = ref(null);
|
||||||
|
// 21 身份预警 22 行为预警 23 组合预警
|
||||||
|
const openAddFrom = (row) => {
|
||||||
|
switch (row.yjLylx) {
|
||||||
|
case "22":
|
||||||
|
xwbqRef.value.init(row);
|
||||||
|
break;
|
||||||
|
case "21":
|
||||||
|
sfbqRef.value.init("add", row);
|
||||||
|
break;
|
||||||
|
case "23":
|
||||||
|
addModelRef.value.init(row);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// 选择系数
|
||||||
|
const chooseJfShow = ref(false);
|
||||||
|
const chooseJfBh = ref();
|
||||||
|
const roleIds = ref();
|
||||||
|
const chooseJfFun = (val) => {
|
||||||
|
chooseJfBh.value = val.id;
|
||||||
|
yjzxyjzxSfyjSelectList(val.id).then((res) => {
|
||||||
|
roleIds.value = res.sjxspzList.map((item) => item.xsid);
|
||||||
|
chooseJfShow.value = true;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCzjy = (row) => {
|
||||||
|
czjyRef.value.init(row);
|
||||||
|
};
|
||||||
|
// 表格高度计算
|
||||||
|
const tabHeightFn = () => {
|
||||||
|
pageData.tableHeight =
|
||||||
|
window.innerHeight - searchBox.value.offsetHeight - 230;
|
||||||
|
window.onresize = function () {
|
||||||
|
tabHeightFn();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** 选中项 */
|
||||||
|
const selectRows = ref([]);
|
||||||
|
const handleChooseData = (val) => {
|
||||||
|
selectRows.value = val;
|
||||||
|
};
|
||||||
|
const exportExl = () => {
|
||||||
|
const titleObj = {
|
||||||
|
czzt_cname: "状态",
|
||||||
|
yjsj: "预警时间",
|
||||||
|
xm: "姓名",
|
||||||
|
sfzh: "身份证号",
|
||||||
|
yjbqmc: "标签",
|
||||||
|
bqys_cname: "级别",
|
||||||
|
ssbm: "接收单位",
|
||||||
|
sfcs: "活动频次",
|
||||||
|
bqfz: "标签分值",
|
||||||
|
pzxs: "系数",
|
||||||
|
sffz: "计算分值"
|
||||||
|
};
|
||||||
|
/** 导出【选中】的数据 (没有就全部)*/
|
||||||
|
const needArr =
|
||||||
|
selectRows.value?.length > 0 ? selectRows.value : pageData.tableData;
|
||||||
|
const data = needArr.map((item) => {
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
bqys_cname: getMultiDictVal(item.bqys, D_GS_SSYJ),
|
||||||
|
czzt_cname: getMultiDictVal(item.czzt, D_GSXT_YJXX_CZZT)
|
||||||
|
};
|
||||||
|
});
|
||||||
|
exportExlByObj(titleObj, data, "身份预警");
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleQs = () => {
|
||||||
|
if (selectRows.value?.length === 0)
|
||||||
|
return proxy.$message({ type: "warning", message: "请选择要签收的预警" });
|
||||||
|
let wqs = selectRows.value.filter((item) => item.czzt == "01");
|
||||||
|
if (wqs.length == 0)
|
||||||
|
return proxy.$message({
|
||||||
|
type: "warning",
|
||||||
|
message: "数据都已签收,请选择未签收的数据"
|
||||||
|
});
|
||||||
|
let yqs = selectRows.value.filter((item) => item.czzt == "02");
|
||||||
|
let texy =
|
||||||
|
yqs.length > 0
|
||||||
|
? `${yqs.length}条已签收预警数据,确认要签收${wqs.length}条未签收预警数据吗?`
|
||||||
|
: "确认要签收所有预警数据吗?";
|
||||||
|
proxy
|
||||||
|
.$confirm(texy, "警告", { type: "warning" })
|
||||||
|
.then(() => {
|
||||||
|
let ids = wqs.map((item) => item.id);
|
||||||
|
qcckPost({ ids }, "/mosty-gsxt/yjzxSfyj/batchQs")
|
||||||
|
.then(() => {
|
||||||
|
proxy.$message({ type: "success", message: "成功" });
|
||||||
|
getList();
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
proxy.$message({ type: "error", message: "失败" });
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(() => {});
|
||||||
|
};
|
||||||
|
const ys = (item) => {
|
||||||
|
switch (item.yjjb) {
|
||||||
|
case "01":
|
||||||
|
return "red";
|
||||||
|
case "02":
|
||||||
|
return "orange";
|
||||||
|
case "03":
|
||||||
|
return "yellow";
|
||||||
|
case "04":
|
||||||
|
return "blue";
|
||||||
|
default:
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.el-loading-mask {
|
||||||
|
background: rgba(0, 0, 0, 0.5) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-table .cell {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-table .el-table__cell {
|
||||||
|
padding: 4px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bgTable {
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -0,0 +1,91 @@
|
|||||||
|
<template>
|
||||||
|
<div class="warning-item" >
|
||||||
|
<el-divider content-position="left">预警内容</el-divider>
|
||||||
|
<div class="item-row" style="border: none;"> {{ props.row.yjnr }} </div>
|
||||||
|
<el-empty v-if="!props.row.yjnr" :image-size="0.5" description="暂无数据" />
|
||||||
|
|
||||||
|
<el-divider content-position="left">处置建议</el-divider>
|
||||||
|
<div class="item-row" v-for="(it,idx) in list" :key="idx">
|
||||||
|
<div class="info-item">
|
||||||
|
<span class="text">预警人姓名:{{ it.jryXm }}</span>
|
||||||
|
<span class="text">建议时间:{{ it.jysj }}</span>
|
||||||
|
<span class="text">所属部门:{{ it.ssbm }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="info-item">建议内容:<span>{{ it.jynr || '暂无' }}</span></div>
|
||||||
|
</div>
|
||||||
|
<el-empty v-if="list.length === 0" :image-size="0.5" description="暂无数据" />
|
||||||
|
<el-divider content-position="left">反馈内容</el-divider>
|
||||||
|
<div class="item-row" v-for="(it,idx) in Fklist" :key="idx">
|
||||||
|
<div class="info-item">
|
||||||
|
<span class="text">处置地址:{{ it.czdz }}</span>
|
||||||
|
<span class="text">处置时间:{{ it.czsj }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="info-item">
|
||||||
|
<span class="text">常控不尿检理由:<span>{{ it.ckbnjly || '暂无' }}</span></span>
|
||||||
|
<span class="text">常控处置反馈补充信息:<span>{{ it.ckczbcxx || '暂无' }}</span></span>
|
||||||
|
<span class="text">常控立线侦察评估:<span>{{ it.cklxzcpg || '暂无' }}</span></span>
|
||||||
|
<span class="text">常控立线侦察评估依据:<span>{{ it.cklxzcpgyj || '暂无' }}</span></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<el-empty :image-size="0.5" v-if="Fklist.length === 0" description="暂无数据" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import { ref, onMounted ,defineProps} from 'vue'
|
||||||
|
import { qcckPost,qcckGet } from "@/api/qcckApi.js";
|
||||||
|
const props = defineProps({
|
||||||
|
row: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({})
|
||||||
|
},
|
||||||
|
})
|
||||||
|
const list = ref([])
|
||||||
|
const Fklist = ref([])
|
||||||
|
onMounted(() => {
|
||||||
|
if(props.row.id){
|
||||||
|
qcckPost({yjid: props.row.id},'/mosty-gsxt/yjxx/czjy/getPageList').then((res) => {
|
||||||
|
list.value = res.records || []
|
||||||
|
})
|
||||||
|
qcckGet({},'/mosty-gsxt/yjzxSfyj/'+ props.row.id).then((res) => {
|
||||||
|
Fklist.value = res.fkList || []
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.warning-item {
|
||||||
|
width: 100%;
|
||||||
|
padding: 15px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border-radius: 8px;
|
||||||
|
background-color: #fafafa;
|
||||||
|
}
|
||||||
|
.item-row{
|
||||||
|
border-bottom: 1px dashed #e8e8e8;
|
||||||
|
line-height: 36px;
|
||||||
|
padding-left: 2rem;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
&:nth-last-child(1){
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-item{
|
||||||
|
line-height: 36px;
|
||||||
|
width: 100%;
|
||||||
|
.text{
|
||||||
|
display: inline-block;
|
||||||
|
width: 25%;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-empty{
|
||||||
|
--el-empty-padding: 0px;
|
||||||
|
margin-bottom: 18px;
|
||||||
|
--el-empty-description-margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
@ -4,12 +4,25 @@
|
|||||||
<div ref="searchBox" class="mt10 mb10">
|
<div ref="searchBox" class="mt10 mb10">
|
||||||
<!-- <Search :searchArr="searchConfiger" @submit="onSearch" ref="searchDom" :key="pageData.keyCount">
|
<!-- <Search :searchArr="searchConfiger" @submit="onSearch" ref="searchDom" :key="pageData.keyCount">
|
||||||
</Search> -->
|
</Search> -->
|
||||||
<QueryFormPanel v-model="queryFrom" :fields="searchConfiger" ref="searchDom" @search='onSearch'>
|
<QueryFormPanel
|
||||||
|
v-model="queryFrom"
|
||||||
|
:fields="searchConfiger"
|
||||||
|
ref="searchDom"
|
||||||
|
@search="onSearch"
|
||||||
|
>
|
||||||
<template #but>
|
<template #but>
|
||||||
<el-button type="primary" size="small" @click="exportExl">批量导出</el-button>
|
<el-button type="primary" size="small" @click="exportExl"
|
||||||
<el-button type="primary" size="small" @click="handleQs">批量签收</el-button>
|
>批量导出</el-button
|
||||||
<el-button type="primary" size="small" @click="handleQs">批量分析</el-button>
|
>
|
||||||
<el-button type="primary" size="small" @click="countPeople">计算人数</el-button>
|
<el-button type="primary" size="small" @click="handleQs"
|
||||||
|
>批量签收</el-button
|
||||||
|
>
|
||||||
|
<el-button type="primary" size="small" @click="handleQs"
|
||||||
|
>批量分析</el-button
|
||||||
|
>
|
||||||
|
<el-button type="primary" size="small" @click="countPeople"
|
||||||
|
>计算人数</el-button
|
||||||
|
>
|
||||||
</template>
|
</template>
|
||||||
</QueryFormPanel>
|
</QueryFormPanel>
|
||||||
</div>
|
</div>
|
||||||
@ -22,20 +35,34 @@
|
|||||||
</template>
|
</template>
|
||||||
</PageTitle> -->
|
</PageTitle> -->
|
||||||
<!-- 表格 -->
|
<!-- 表格 -->
|
||||||
<div style="background-color: #fff;">
|
<div style="background-color: #fff">
|
||||||
<WarnDataTable :loading="pageData.tableConfiger.loading" :tableHeight="pageData.tableHeight"
|
<WarnDataTable
|
||||||
:data="pageData.tableData" :columns="pageData.tableColumn" table-class="warn-table"
|
:loading="pageData.tableConfiger.loading"
|
||||||
@selectionChange="handleChooseData">
|
:tableHeight="pageData.tableHeight"
|
||||||
|
:data="pageData.tableData"
|
||||||
|
:columns="pageData.tableColumn"
|
||||||
|
table-class="warn-table"
|
||||||
|
@selectionChange="handleChooseData"
|
||||||
|
>
|
||||||
<template #status="{ row }">
|
<template #status="{ row }">
|
||||||
<DictTag :value="row.czzt" :color="row.czzt === '01' ? '#ff2424' : '#1d72e8'" :tag="false"
|
<DictTag
|
||||||
:options="D_GSXT_YJXX_CZZT" />
|
:value="row.czzt"
|
||||||
|
:color="row.czzt === '01' ? '#ff2424' : '#1d72e8'"
|
||||||
|
:tag="false"
|
||||||
|
:options="D_GSXT_YJXX_CZZT"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
<template #xbdm="{ row }">
|
<template #xbdm="{ row }">
|
||||||
<DictTag :value="row.xbdm" :tag="false" :options="D_BZ_XB" />
|
<DictTag :value="row.xbdm" :tag="false" :options="D_BZ_XB" />
|
||||||
</template>
|
</template>
|
||||||
<template #yjJb="{ row }">
|
<template #yjJb="{ row }">
|
||||||
<div :style="{ 'background-color': bqYs(row.yjJb) }">
|
<div :style="{ 'background-color': bqYs(row.yjJb) }">
|
||||||
<DictTag :value="row.yjJb" color="#fff" :tag="false" :options="D_BZ_YJJB" />
|
<DictTag
|
||||||
|
:value="row.yjJb"
|
||||||
|
color="#fff"
|
||||||
|
:tag="false"
|
||||||
|
:options="D_BZ_YJJB"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #bqdl="{ row }">
|
<template #bqdl="{ row }">
|
||||||
@ -47,69 +74,210 @@
|
|||||||
<template #cszt="{ row }">
|
<template #cszt="{ row }">
|
||||||
<DictTag :value="row.cszt" :tag="false" :options="D_GS_CSZT" />
|
<DictTag :value="row.cszt" :tag="false" :options="D_GS_CSZT" />
|
||||||
</template>
|
</template>
|
||||||
|
<template #qbly="{ row }">
|
||||||
|
<DictTag :value="row.qbly" :tag="false" :options="D_BZ_QBLY" />
|
||||||
|
</template>
|
||||||
|
<template #qblyjb="{ row }">
|
||||||
|
<DictTag :value="row.qblyjb" :tag="false" :options="D_BZ_QBLYJB" />
|
||||||
|
</template>
|
||||||
<template #operation="{ row }">
|
<template #operation="{ row }">
|
||||||
<div style="display: flex;justify-content: space-between;">
|
<div style="display: flex; justify-content: space-between">
|
||||||
<span class="primary" @click="handleQsSingle(row)">签收</span>
|
<span class="primary" @click="handleQsSingle(row)">签收</span>
|
||||||
<span class="primary" @click="particularsOpen(row)">详情</span>
|
<span class="primary" @click="particularsOpen(row)">详情</span>
|
||||||
<span class="warning" @click="pushWarning(row)">指派</span>
|
<span class="warning" @click="pushWarning(row)">指派</span>
|
||||||
<span class="warning" v-if="row.sfbc != '1'" @click="failWarning(row)">报错</span>
|
<span
|
||||||
|
class="warning"
|
||||||
|
v-if="row.sfbc != '1'"
|
||||||
|
@click="failWarning(row)"
|
||||||
|
>报错</span
|
||||||
|
>
|
||||||
<span class="primary" @click="payAttention(row)">关注</span>
|
<span class="primary" @click="payAttention(row)">关注</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</WarnDataTable>
|
</WarnDataTable>
|
||||||
<Pages @changeNo="changeNo" @changeSize="changeSize" :tableHeight="pageData.tableHeight" :pageConfiger="{
|
<Pages
|
||||||
...pageData.pageConfiger,
|
@changeNo="changeNo"
|
||||||
total: pageData.total
|
@changeSize="changeSize"
|
||||||
}"></Pages>
|
:tableHeight="pageData.tableHeight"
|
||||||
|
:pageConfiger="{
|
||||||
|
...pageData.pageConfiger,
|
||||||
|
total: pageData.total
|
||||||
|
}"
|
||||||
|
></Pages>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<ZpForm v-model="warningShow" :dataList="dataList" />
|
<ZpForm v-model="warningShow" :dataList="dataList" />
|
||||||
<Particulars v-model="particularsShow" :dataList="dataPres"
|
<Particulars
|
||||||
:dict="{ D_BZ_XB, D_BZ_YJJB, D_GS_QLZDRLX, D_GS_ZDR_RYJB, D_GS_ZDR_GJLB }" />
|
v-model="particularsShow"
|
||||||
|
:dataList="dataPres"
|
||||||
|
:dict="{ D_BZ_XB, D_BZ_YJJB, D_GS_QLZDRLX, D_GS_ZDR_RYJB, D_GS_ZDR_GJLB }"
|
||||||
|
/>
|
||||||
<peopleConut v-model="searchOpen" :dataConut="dataConut" />
|
<peopleConut v-model="searchOpen" :dataConut="dataConut" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { getMultiDictVal } from "@/utils/dict.js"
|
import { getMultiDictVal } from "@/utils/dict.js";
|
||||||
import { exportExlByObj } from "@/utils/exportExcel.js"
|
import { exportExlByObj } from "@/utils/exportExcel.js";
|
||||||
import ZpForm from "./zpForm.vue";
|
import ZpForm from "./zpForm.vue";
|
||||||
import { bqYs } from '@/utils/tools.js'
|
import { bqYs } from "@/utils/tools.js";
|
||||||
import Particulars from "./particulars.vue";
|
import Particulars from "./particulars.vue";
|
||||||
import Search from "@/components/aboutTable/Search.vue";
|
import Search from "@/components/aboutTable/Search.vue";
|
||||||
import WarnDataTable from '@/views/backOfficeSystem/ces/components/WarnDataTable.vue'
|
import WarnDataTable from "@/views/backOfficeSystem/ces/components/WarnDataTable.vue";
|
||||||
import QueryFormPanel from "@/views/backOfficeSystem/ces/components/QueryFormPanel.vue";
|
import QueryFormPanel from "@/views/backOfficeSystem/ces/components/QueryFormPanel.vue";
|
||||||
import PageTitle from "@/components/aboutTable/PageTitle.vue";
|
import PageTitle from "@/components/aboutTable/PageTitle.vue";
|
||||||
// import MyTable from "@/components/aboutTable/MyTable.vue";
|
// import MyTable from "@/components/aboutTable/MyTable.vue";
|
||||||
import Pages from "@/components/aboutTable/Pages.vue";
|
import Pages from "@/components/aboutTable/Pages.vue";
|
||||||
import { qcckGet, qcckPost } from "@/api/qcckApi.js";
|
import { qcckGet, qcckPost } from "@/api/qcckApi.js";
|
||||||
import { reactive, ref, onMounted, getCurrentInstance, } from "vue";
|
import { reactive, ref, onMounted, getCurrentInstance } from "vue";
|
||||||
import peopleConut from "./peopleConut.vue";
|
import peopleConut from "./peopleConut.vue";
|
||||||
const { proxy } = getCurrentInstance();
|
const { proxy } = getCurrentInstance();
|
||||||
const { D_BZ_YJLY, D_GS_QLZDRLX, D_GS_ZDR_GJLB, D_BZ_YJJB, D_GS_CSZT, D_GS_QLZDRYXX, D_BZ_XB, D_GSXT_YJXX_CZZT, D_GS_ZDR_RYJB, D_BZ_SF } = proxy.$dict('D_BZ_YJLY', 'D_GS_QLZDRLX', "D_BZ_YJJB", "D_GS_QLZDRYXX", "D_BZ_XB", "D_GSXT_YJXX_CZZT", "D_GS_ZDR_RYJB", 'D_GS_ZDR_GJLB', 'D_GS_CSZT', "D_BZ_SF"); //获取字典数据
|
const {
|
||||||
|
D_BZ_YJLY,
|
||||||
|
D_GS_QLZDRLX,
|
||||||
|
D_GS_ZDR_GJLB,
|
||||||
|
D_BZ_YJJB,
|
||||||
|
D_GS_CSZT,
|
||||||
|
D_GS_QLZDRYXX,
|
||||||
|
D_BZ_XB,
|
||||||
|
D_GSXT_YJXX_CZZT,
|
||||||
|
D_GS_ZDR_RYJB,
|
||||||
|
D_BZ_SF,
|
||||||
|
D_BZ_QBLY,
|
||||||
|
D_BZ_QBLYJB
|
||||||
|
} = proxy.$dict(
|
||||||
|
"D_BZ_YJLY",
|
||||||
|
"D_GS_QLZDRLX",
|
||||||
|
"D_BZ_YJJB",
|
||||||
|
"D_GS_QLZDRYXX",
|
||||||
|
"D_BZ_XB",
|
||||||
|
"D_GSXT_YJXX_CZZT",
|
||||||
|
"D_GS_ZDR_RYJB",
|
||||||
|
"D_GS_ZDR_GJLB",
|
||||||
|
"D_GS_CSZT",
|
||||||
|
"D_BZ_SF",
|
||||||
|
"D_BZ_QBLY",
|
||||||
|
"D_BZ_QBLYJB"
|
||||||
|
); //获取字典数据
|
||||||
const searchBox = ref(); //搜索框
|
const searchBox = ref(); //搜索框
|
||||||
const warningShow = ref(false);
|
const warningShow = ref(false);
|
||||||
const dataList = ref([]);
|
const dataList = ref([]);
|
||||||
const searchConfiger = ref(
|
const searchConfiger = ref([
|
||||||
[
|
{
|
||||||
{ key: 'startTime', label: '预警时间', type: 'datetimerange', placeholder: '请选择预警时间' },
|
key: "startTime",
|
||||||
{ key: 'yjJb', label: '预警级别', type: 'select', options: D_BZ_YJJB, multiple: true, placeholder: '请选择预警级别' },
|
label: "预警时间",
|
||||||
{ key: 'ssbmdm', label: '接收单位', type: 'department', placeholder: '请选择接收单位' },
|
type: "datetimerange",
|
||||||
{ key: 'sfglyj', label: '关联预警', type: 'select', options: D_BZ_SF, placeholder: '请选择关联预警' },
|
placeholder: "请选择预警时间"
|
||||||
{ key: 'yjRyxm', label: '姓名', type: 'input', placeholder: '请输入姓名' },
|
},
|
||||||
{ key: 'xbdm', label: '性别', type: 'select', options: D_BZ_XB, placeholder: '请选择性别' },
|
{
|
||||||
{ key: 'cszt', label: '超时状态', type: 'select', options: D_GS_CSZT, placeholder: '请选择超时状态' },
|
key: "yjJb",
|
||||||
{ key: 'bqdl', label: '人员类别', type: 'select', options: D_GS_QLZDRLX, placeholder: '请选择人员类别' },
|
label: "预警级别",
|
||||||
{ key: 'sfgz', label: '重点关注', type: 'select', options: D_BZ_SF, placeholder: '请选择重点关注' },
|
type: "select",
|
||||||
{ key: 'sfzp', label: '二次指派', type: 'select', options: D_BZ_SF, placeholder: '请选择二次指派' },
|
options: D_BZ_YJJB,
|
||||||
{ key: 'yjRysfzh', label: '身份证号码', type: 'input', placeholder: '请输入身份证号码' },
|
multiple: true,
|
||||||
{ key: 'ksnl', label: '开始年龄', type: 'input', placeholder: '请输入开始年龄' },
|
placeholder: "请选择预警级别"
|
||||||
{ key: 'jsnl', label: '结束年龄', type: 'input', placeholder: '请输入结束年龄' },
|
},
|
||||||
{ key: 'yjCs', label: '预警次数', type: 'input', placeholder: '请输入预警次数' },
|
{
|
||||||
{ key: 'bqdl', label: '人员级别', type: 'select', options: D_GS_ZDR_RYJB },
|
key: "ssbmdm",
|
||||||
{ key: 'yjLylx', label: '轨迹类别', type: 'select', options: D_GS_ZDR_GJLB },
|
label: "接收单位",
|
||||||
{ key: 'yjDz', label: '活动发生地', type: 'input', placeholder: '请输入活动发生地' },
|
type: "department",
|
||||||
{ key: 'yjbqmc', label: '人员细类', type: 'input', placeholder: '请输入人员细类' }
|
placeholder: "请选择接收单位"
|
||||||
])
|
},
|
||||||
|
{
|
||||||
|
key: "sfglyj",
|
||||||
|
label: "关联预警",
|
||||||
|
type: "select",
|
||||||
|
options: D_BZ_SF,
|
||||||
|
placeholder: "请选择关联预警"
|
||||||
|
},
|
||||||
|
{ key: "yjRyxm", label: "姓名", type: "input", placeholder: "请输入姓名" },
|
||||||
|
{
|
||||||
|
key: "xbdm",
|
||||||
|
label: "性别",
|
||||||
|
type: "select",
|
||||||
|
options: D_BZ_XB,
|
||||||
|
placeholder: "请选择性别"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "cszt",
|
||||||
|
label: "超时状态",
|
||||||
|
type: "select",
|
||||||
|
options: D_GS_CSZT,
|
||||||
|
placeholder: "请选择超时状态"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "bqdl",
|
||||||
|
label: "人员类别",
|
||||||
|
type: "select",
|
||||||
|
options: D_GS_QLZDRLX,
|
||||||
|
placeholder: "请选择人员类别"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "sfgz",
|
||||||
|
label: "重点关注",
|
||||||
|
type: "select",
|
||||||
|
options: D_BZ_SF,
|
||||||
|
placeholder: "请选择重点关注"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "sfzp",
|
||||||
|
label: "二次指派",
|
||||||
|
type: "select",
|
||||||
|
options: D_BZ_SF,
|
||||||
|
placeholder: "请选择二次指派"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "yjRysfzh",
|
||||||
|
label: "身份证号码",
|
||||||
|
type: "input",
|
||||||
|
placeholder: "请输入身份证号码"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "ksnl",
|
||||||
|
label: "开始年龄",
|
||||||
|
type: "input",
|
||||||
|
placeholder: "请输入开始年龄"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "jsnl",
|
||||||
|
label: "结束年龄",
|
||||||
|
type: "input",
|
||||||
|
placeholder: "请输入结束年龄"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "yjCs",
|
||||||
|
label: "预警次数",
|
||||||
|
type: "input",
|
||||||
|
placeholder: "请输入预警次数"
|
||||||
|
},
|
||||||
|
{ key: "bqdl", label: "人员级别", type: "select", options: D_GS_ZDR_RYJB },
|
||||||
|
{ key: "yjLylx", label: "轨迹类别", type: "select", options: D_GS_ZDR_GJLB },
|
||||||
|
{
|
||||||
|
key: "yjDz",
|
||||||
|
label: "活动发生地",
|
||||||
|
type: "input",
|
||||||
|
placeholder: "请输入活动发生地"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "yjbqmc",
|
||||||
|
label: "人员细类",
|
||||||
|
type: "input",
|
||||||
|
placeholder: "请输入人员细类"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "qbly",
|
||||||
|
label: "情报来源",
|
||||||
|
type: "select",
|
||||||
|
options: D_BZ_QBLY,
|
||||||
|
placeholder: "请选择情报来源"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "qblyjb",
|
||||||
|
label: "情报来源级别",
|
||||||
|
type: "select",
|
||||||
|
options: D_BZ_QBLYJB,
|
||||||
|
placeholder: "请选择情报来源级别"
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
const queryFrom = ref({});
|
const queryFrom = ref({});
|
||||||
const pageData = reactive({
|
const pageData = reactive({
|
||||||
@ -129,91 +297,92 @@ const pageData = reactive({
|
|||||||
}, //分页
|
}, //分页
|
||||||
controlsWidth: 200, //操作栏宽度
|
controlsWidth: 200, //操作栏宽度
|
||||||
tableColumn: [
|
tableColumn: [
|
||||||
{ type: 'index', label: '序号', width: 55, align: 'center' },
|
{ type: "index", label: "序号", width: 55, align: "center" },
|
||||||
{ label: '预警状态', width: 86, align: 'center', slotName: 'status' },
|
{ label: "预警状态", width: 80, align: "center", slotName: "status" },
|
||||||
{ prop: 'yjSj', label: '预警时间', width: 150 },
|
{ prop: "yjSj", label: "预警时间", width: 145 },
|
||||||
{ prop: 'yjRyxm', label: '人员姓名', width: 80 },
|
{ prop: "yjRyxm", label: "人员姓名", width: 80 },
|
||||||
{ prop: 'yjRysfzh', label: '身份证号', width: 158 },
|
{ prop: "yjRysfzh", label: "身份证号", width: 158 },
|
||||||
{ label: '性别', width: 56, align: 'center', slotName: 'xbdm' },
|
{ label: "性别", width: 55, align: "center", slotName: "xbdm" },
|
||||||
{ prop: 'nl', label: '年龄', width: 56, align: 'center' },
|
{ prop: "nl", label: "年龄", width: 55, align: "center" },
|
||||||
{ label: '预警级别', width: 88, align: 'center', slotName: 'yjJb' },
|
{ label: "预警级别", width: 80, align: "center", slotName: "yjJb" },
|
||||||
{ label: '人员类别', width: 90, align: 'center', slotName: 'bqdl' },
|
{ label: "人员类别", width: 80, align: "center", slotName: "bqdl" },
|
||||||
{ prop: 'yjbqmc', label: '人员细类', width: 92 },
|
{ prop: "yjbqmc", label: "人员细类", width: 80 },
|
||||||
{ label: '轨迹类别', width: 92, align: 'center', slotName: 'yjLylx' },
|
{ label: "轨迹类别", width: 80, align: "center", slotName: "yjLylx" },
|
||||||
{ prop: 'yjDz', label: '活动发生地' },
|
{ prop: "yjDz", label: "活动发生地", width: 100 },
|
||||||
{ prop: 'ssbm', label: '接收单位' },
|
{ prop: "ssbm", label: "接收单位" },
|
||||||
{ prop: 'yjCs', label: '次数', width: 60, align: 'center' },
|
{ label: "情报来源", width: 80, align: "center", slotName: "qbly" },
|
||||||
{ label: '操作', width: 180, slotName: 'operation' },
|
{ label: "来源级别", width: 80, align: "center", slotName: "qblyjb" },
|
||||||
{ label: '超时状态', width: 80, align: 'center', slotName: 'cszt' }
|
{ prop: "yjCs", label: "次数", width: 55, align: "center" },
|
||||||
|
{ label: "操作", width: 180, slotName: "operation" },
|
||||||
|
{ label: "超时状态", width: 80, align: "center", slotName: "cszt" }
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
tabHeightFn();
|
tabHeightFn();
|
||||||
getList()
|
getList();
|
||||||
});
|
});
|
||||||
|
|
||||||
// 搜索
|
// 搜索
|
||||||
const onSearch = (val) => {
|
const onSearch = (val) => {
|
||||||
queryFrom.value = { ...val, yjJb: val.yjJb?.join(',') || '' }
|
queryFrom.value = { ...val, yjJb: val.yjJb?.join(",") || "" };
|
||||||
queryFrom.value.startTime = val.startTime ? val.startTime[0] : ''
|
queryFrom.value.startTime = val.startTime ? val.startTime[0] : "";
|
||||||
queryFrom.value.endTime = val.startTime ? val.startTime[1] : ''
|
queryFrom.value.endTime = val.startTime ? val.startTime[1] : "";
|
||||||
// queryFrom.value.sfglyj = val.sfglyj?.join(',') || ''
|
// queryFrom.value.sfglyj = val.sfglyj?.join(',') || ''
|
||||||
// queryFrom.value.sfgz = val.sfgz?.join(',') || ''
|
// queryFrom.value.sfgz = val.sfgz?.join(',') || ''
|
||||||
// queryFrom.value.sfzp = val.sfzp?.join(',') || ''
|
// queryFrom.value.sfzp = val.sfzp?.join(',') || ''
|
||||||
pageData.pageConfiger.pageCurrent = 1;
|
pageData.pageConfiger.pageCurrent = 1;
|
||||||
getList()
|
getList();
|
||||||
}
|
};
|
||||||
const changeNo = (val) => {
|
const changeNo = (val) => {
|
||||||
pageData.pageConfiger.pageCurrent = val;
|
pageData.pageConfiger.pageCurrent = val;
|
||||||
getList()
|
getList();
|
||||||
}
|
};
|
||||||
const changeSize = (val) => {
|
const changeSize = (val) => {
|
||||||
pageData.pageConfiger.pageSize = val;
|
pageData.pageConfiger.pageSize = val;
|
||||||
getList()
|
getList();
|
||||||
}
|
};
|
||||||
const getList = () => {
|
const getList = () => {
|
||||||
pageData.tableConfiger.loading = true;
|
pageData.tableConfiger.loading = true;
|
||||||
const promes = {
|
const promes = {
|
||||||
...queryFrom.value,
|
...queryFrom.value,
|
||||||
pageCurrent: pageData.pageConfiger.pageCurrent,
|
pageCurrent: pageData.pageConfiger.pageCurrent,
|
||||||
pageSize: pageData.pageConfiger.pageSize,
|
pageSize: pageData.pageConfiger.pageSize
|
||||||
|
};
|
||||||
}
|
|
||||||
delete promes.times;
|
delete promes.times;
|
||||||
qcckPost(promes, '/mosty-gsxt/tbYjxx/getQlzdrPageList').then((res) => {
|
qcckPost(promes, "/mosty-gsxt/tbYjxx/getQlzdrPageList")
|
||||||
pageData.total = res.total || 0;
|
.then((res) => {
|
||||||
pageData.tableConfiger.loading = false;
|
pageData.total = res.total || 0;
|
||||||
pageData.tableData = res.records || []
|
pageData.tableConfiger.loading = false;
|
||||||
}).catch(() => {
|
pageData.tableData = res.records || [];
|
||||||
pageData.tableConfiger.loading = false;
|
})
|
||||||
})
|
.catch(() => {
|
||||||
}
|
pageData.tableConfiger.loading = false;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const pushWarning = (val) => {
|
const pushWarning = (val) => {
|
||||||
warningShow.value = true;
|
warningShow.value = true;
|
||||||
dataList.value = val;
|
dataList.value = val;
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|
||||||
const failWarning = (val) => {
|
const failWarning = (val) => {
|
||||||
let ids = [val.id]
|
let ids = [val.id];
|
||||||
qcckPost({ ids }, '/mosty-gsxt/tbYjxx/yjbc').then((res) => {
|
qcckPost({ ids }, "/mosty-gsxt/tbYjxx/yjbc")
|
||||||
proxy.$message({ type: "success", message: "成功" });
|
.then((res) => {
|
||||||
getList();
|
proxy.$message({ type: "success", message: "成功" });
|
||||||
}).catch(() => {
|
getList();
|
||||||
proxy.$message({ type: "error", message: "失败" });
|
})
|
||||||
});
|
.catch(() => {
|
||||||
}
|
proxy.$message({ type: "error", message: "失败" });
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
/** 选中项 */
|
/** 选中项 */
|
||||||
const selectRows = ref([])
|
const selectRows = ref([]);
|
||||||
const handleChooseData = (val) => {
|
const handleChooseData = (val) => {
|
||||||
selectRows.value = val
|
selectRows.value = val;
|
||||||
}
|
};
|
||||||
const exportExl = () => {
|
const exportExl = () => {
|
||||||
const titleObj = {
|
const titleObj = {
|
||||||
czzt_name: "状态",
|
czzt_name: "状态",
|
||||||
@ -225,102 +394,138 @@ const exportExl = () => {
|
|||||||
yjbqmc: "细类",
|
yjbqmc: "细类",
|
||||||
yjDz: "活动发生地",
|
yjDz: "活动发生地",
|
||||||
ssbm: "接收单位",
|
ssbm: "接收单位",
|
||||||
yjCs: "预警次数",
|
yjCs: "预警次数"
|
||||||
}
|
};
|
||||||
/** 导出【选中】的数据 (没有就全部)*/
|
/** 导出【选中】的数据 (没有就全部)*/
|
||||||
const needArr = selectRows.value?.length > 0 ? selectRows.value : pageData.tableData
|
const needArr =
|
||||||
const data = needArr.map(item => {
|
selectRows.value?.length > 0 ? selectRows.value : pageData.tableData;
|
||||||
|
const data = needArr.map((item) => {
|
||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
czzt_name: getMultiDictVal(item.czzt, D_GSXT_YJXX_CZZT),
|
czzt_name: getMultiDictVal(item.czzt, D_GSXT_YJXX_CZZT),
|
||||||
yjJb_name: getMultiDictVal(item.yjJb, D_BZ_YJJB),
|
yjJb_name: getMultiDictVal(item.yjJb, D_BZ_YJJB),
|
||||||
bqdl_name: getMultiDictVal(item.bqdl, D_GS_QLZDRLX),
|
bqdl_name: getMultiDictVal(item.bqdl, D_GS_QLZDRLX)
|
||||||
}
|
};
|
||||||
})
|
});
|
||||||
exportExlByObj(titleObj, data, '七类重点')
|
exportExlByObj(titleObj, data, "七类重点");
|
||||||
}
|
};
|
||||||
// 批量签收
|
// 批量签收
|
||||||
const handleQs = () => {
|
const handleQs = () => {
|
||||||
if (selectRows.value?.length === 0) return proxy.$message({ type: "warning", message: "请选择要签收的预警" });
|
if (selectRows.value?.length === 0)
|
||||||
let wqs = selectRows.value.filter(item => item.czzt == '01');
|
return proxy.$message({ type: "warning", message: "请选择要签收的预警" });
|
||||||
if (wqs.length == 0) return proxy.$message({ type: "warning", message: "数据都已签收,请选择未签收的数据" });
|
let wqs = selectRows.value.filter((item) => item.czzt == "01");
|
||||||
let yqs = selectRows.value.filter(item => item.czzt == '02');
|
if (wqs.length == 0)
|
||||||
let texy = yqs.length > 0 ? `${yqs.length}条已签收预警数据,确认要签收${wqs.length}条未签收预警数据吗?` : '确认要签收所有预警数据吗?'
|
return proxy.$message({
|
||||||
proxy.$confirm(texy, "警告", { type: "warning" }).then(() => {
|
type: "warning",
|
||||||
let ids = wqs.map(item => item.id)
|
message: "数据都已签收,请选择未签收的数据"
|
||||||
qcckPost({ ids }, '/mosty-gsxt/tbYjxx/batchQs').then(() => {
|
|
||||||
proxy.$message({ type: "success", message: "成功" });
|
|
||||||
getList();
|
|
||||||
}).catch(() => {
|
|
||||||
proxy.$message({ type: "error", message: "失败" });
|
|
||||||
});
|
});
|
||||||
}).catch(() => { });
|
let yqs = selectRows.value.filter((item) => item.czzt == "02");
|
||||||
}
|
let texy =
|
||||||
|
yqs.length > 0
|
||||||
|
? `${yqs.length}条已签收预警数据,确认要签收${wqs.length}条未签收预警数据吗?`
|
||||||
|
: "确认要签收所有预警数据吗?";
|
||||||
|
proxy
|
||||||
|
.$confirm(texy, "警告", { type: "warning" })
|
||||||
|
.then(() => {
|
||||||
|
let ids = wqs.map((item) => item.id);
|
||||||
|
qcckPost({ ids }, "/mosty-gsxt/tbYjxx/batchQs")
|
||||||
|
.then(() => {
|
||||||
|
proxy.$message({ type: "success", message: "成功" });
|
||||||
|
getList();
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
proxy.$message({ type: "error", message: "失败" });
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(() => {});
|
||||||
|
};
|
||||||
// 详情
|
// 详情
|
||||||
const dataPres = ref({})
|
const dataPres = ref({});
|
||||||
const particularsShow = ref(false);
|
const particularsShow = ref(false);
|
||||||
const particularsOpen = (row) => {
|
const particularsOpen = (row) => {
|
||||||
dataPres.value = row
|
dataPres.value = row;
|
||||||
|
|
||||||
particularsShow.value = true;
|
particularsShow.value = true;
|
||||||
}
|
};
|
||||||
// 单条签收
|
// 单条签收
|
||||||
const handleQsSingle = (row) => {
|
const handleQsSingle = (row) => {
|
||||||
if (row.czzt == '02') return proxy.$message({ type: "warning", message: "数据已签收,无需重复签收" });
|
if (row.czzt == "02")
|
||||||
proxy.$confirm('确认要签收该条预警数据吗?', "警告", { type: "warning" }).then(() => {
|
return proxy.$message({
|
||||||
qcckPost({ ids: [row.id] }, '/mosty-gsxt/tbYjxx/batchQs').then(() => {
|
type: "warning",
|
||||||
proxy.$message({ type: "success", message: "成功" });
|
message: "数据已签收,无需重复签收"
|
||||||
getList();
|
|
||||||
}).catch(() => {
|
|
||||||
proxy.$message({ type: "error", message: "失败" });
|
|
||||||
});
|
});
|
||||||
}).catch(() => { });
|
proxy
|
||||||
}
|
.$confirm("确认要签收该条预警数据吗?", "警告", { type: "warning" })
|
||||||
|
.then(() => {
|
||||||
|
qcckPost({ ids: [row.id] }, "/mosty-gsxt/tbYjxx/batchQs")
|
||||||
|
.then(() => {
|
||||||
|
proxy.$message({ type: "success", message: "成功" });
|
||||||
|
getList();
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
proxy.$message({ type: "error", message: "失败" });
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(() => {});
|
||||||
|
};
|
||||||
// 关注
|
// 关注
|
||||||
const payAttention = (row) => {
|
const payAttention = (row) => {
|
||||||
let promes = {}
|
let promes = {};
|
||||||
if (row.sfgz == '1') {
|
if (row.sfgz == "1") {
|
||||||
promes.sfgz = '0'
|
promes.sfgz = "0";
|
||||||
promes.msg = '取消关注'
|
promes.msg = "取消关注";
|
||||||
} else {
|
} else {
|
||||||
promes.sfgz = '1'
|
promes.sfgz = "1";
|
||||||
promes.msg = '关注'
|
promes.msg = "关注";
|
||||||
}
|
}
|
||||||
|
|
||||||
proxy.$confirm('确认要关注该条预警数据吗?', "警告", { type: "warning" }).then(() => {
|
proxy
|
||||||
qcckPost({ sfgz: promes.sfgz, id: row.id }, '/mosty-gsxt/tbYjxx/yjgz').then(() => {
|
.$confirm("确认要关注该条预警数据吗?", "警告", { type: "warning" })
|
||||||
proxy.$message({ type: "success", message: `${promes.msg}成功` });
|
.then(() => {
|
||||||
getList();
|
qcckPost({ sfgz: promes.sfgz, id: row.id }, "/mosty-gsxt/tbYjxx/yjgz")
|
||||||
}).catch(() => {
|
.then(() => {
|
||||||
proxy.$message({ type: "error", message: `${promes.msg}失败` });
|
proxy.$message({ type: "success", message: `${promes.msg}成功` });
|
||||||
});
|
getList();
|
||||||
}).catch(() => { });
|
})
|
||||||
}
|
.catch(() => {
|
||||||
|
proxy.$message({ type: "error", message: `${promes.msg}失败` });
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(() => {});
|
||||||
|
};
|
||||||
// 人数计算
|
// 人数计算
|
||||||
const searchDom = ref(null)
|
const searchDom = ref(null);
|
||||||
const dataConut = ref(0)
|
const dataConut = ref(0);
|
||||||
const searchOpen = ref(false)
|
const searchOpen = ref(false);
|
||||||
const countPeople = () => {
|
const countPeople = () => {
|
||||||
|
|
||||||
const promes = {
|
const promes = {
|
||||||
...searchDom.value.formState,
|
...searchDom.value.formState,
|
||||||
yjJb: searchDom.value.formState.yjJb?.join(',') || '',
|
yjJb: searchDom.value.formState.yjJb?.join(",") || "",
|
||||||
startTime: searchDom.value.formState.startTime ? searchDom.value.formState.startTime[0] : '',
|
startTime: searchDom.value.formState.startTime
|
||||||
endTime: searchDom.value.formState.endTime ? searchDom.value.formState.endTime[1] : '',
|
? searchDom.value.formState.startTime[0]
|
||||||
}
|
: "",
|
||||||
qcckPost(promes, '/mosty-gsxt/tbYjxx/bkyjQctj').then((res) => {
|
endTime: searchDom.value.formState.endTime
|
||||||
dataConut.value = res || 0
|
? searchDom.value.formState.endTime[1]
|
||||||
searchOpen.value = true
|
: ""
|
||||||
}).catch(() => {
|
};
|
||||||
// proxy.$message({ type: "error", message: `${promes.msg}失败` });
|
qcckPost(promes, "/mosty-gsxt/tbYjxx/bkyjQctj")
|
||||||
});
|
.then((res) => {
|
||||||
}
|
dataConut.value = res || 0;
|
||||||
|
searchOpen.value = true;
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
// proxy.$message({ type: "error", message: `${promes.msg}失败` });
|
||||||
|
});
|
||||||
|
};
|
||||||
// 表格高度计算
|
// 表格高度计算
|
||||||
const tabHeightFn = () => {
|
const tabHeightFn = () => {
|
||||||
console.log("xxxxxxx");
|
console.log("xxxxxxx");
|
||||||
|
|
||||||
pageData.tableHeight = window.innerHeight - searchBox.value.offsetHeight - 230;
|
pageData.tableHeight =
|
||||||
window.onresize = function () { tabHeightFn(); };
|
window.innerHeight - searchBox.value.offsetHeight - 230;
|
||||||
|
window.onresize = function () {
|
||||||
|
tabHeightFn();
|
||||||
|
};
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,226 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog
|
||||||
|
class="luntan-tech-dialog"
|
||||||
|
:model-value="modelValue"
|
||||||
|
center
|
||||||
|
width="500px"
|
||||||
|
:destroy-on-close="true"
|
||||||
|
:title="title"
|
||||||
|
@close="close"
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
>
|
||||||
|
<div class="avatar-upload-container">
|
||||||
|
<div class="avatar-preview">
|
||||||
|
<img v-if="avatarUrl" :src="avatarUrl" alt="预览头像" class="preview-image">
|
||||||
|
<div v-else class="preview-placeholder">
|
||||||
|
<el-icon class="placeholder-icon">
|
||||||
|
<User />
|
||||||
|
</el-icon>
|
||||||
|
<span>请上传头像</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="upload-section">
|
||||||
|
<el-upload class="avatar-uploader" :auto-upload="false" :show-file-list="false"
|
||||||
|
:on-change="handleAvatarChange" :before-upload="beforeAvatarUpload" accept="image/*">
|
||||||
|
<el-button size="small" type="primary">选择图片</el-button>
|
||||||
|
</el-upload>
|
||||||
|
<div class="upload-tips">
|
||||||
|
<p>• 支持 JPG、PNG 格式</p>
|
||||||
|
<p>• 图片大小不超过 2MB</p>
|
||||||
|
<p>• 建议尺寸为 200x200 像素</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
|
<el-button @click="close">取消</el-button>
|
||||||
|
<el-button type="primary" @click="confirmUpload" :loading="uploading" :disabled="!avatarUrl || uploading">
|
||||||
|
{{ uploading ? '上传中...' : '确认更换' }}
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, watch } from "vue";
|
||||||
|
import { ElMessage } from 'element-plus';
|
||||||
|
import { User } from '@element-plus/icons-vue';
|
||||||
|
import { upImageUploadId } from '@/api/commit';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
modelValue: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
default: "更换头像"
|
||||||
|
},
|
||||||
|
heightNumber: {
|
||||||
|
type: Number,
|
||||||
|
default: 250
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const emits = defineEmits(["update:modelValue", "avatarUpdated"]);
|
||||||
|
|
||||||
|
// 头像相关状态
|
||||||
|
const avatarUrl = ref('');
|
||||||
|
const uploading = ref(false);
|
||||||
|
|
||||||
|
// 监听对话框显示状态,重置头像预览
|
||||||
|
watch(() => props.modelValue, (newVal) => {
|
||||||
|
if (!newVal) {
|
||||||
|
// 对话框关闭时重置头像预览
|
||||||
|
avatarUrl.value = '';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 当前选择的文件
|
||||||
|
const selectedFile = ref(null);
|
||||||
|
|
||||||
|
// 处理头像选择
|
||||||
|
const handleAvatarChange = (file) => {
|
||||||
|
selectedFile.value = file.raw;
|
||||||
|
// 创建临时预览URL
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = (e) => {
|
||||||
|
avatarUrl.value = e.target.result;
|
||||||
|
};
|
||||||
|
reader.readAsDataURL(file.raw);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 上传前检查
|
||||||
|
const beforeAvatarUpload = (file) => {
|
||||||
|
const isJPG = file.type === 'image/jpeg';
|
||||||
|
const isPNG = file.type === 'image/png';
|
||||||
|
const isLt2M = file.size / 1024 / 1024 < 2;
|
||||||
|
|
||||||
|
if (!isJPG && !isPNG) {
|
||||||
|
ElMessage.error('请上传 JPG 或 PNG 格式的图片!');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!isLt2M) {
|
||||||
|
ElMessage.error('图片大小不能超过 2MB!');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 确认上传头像
|
||||||
|
const confirmUpload = async () => {
|
||||||
|
if (!avatarUrl.value || !selectedFile.value) {
|
||||||
|
ElMessage.warning('请先选择头像图片');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uploading.value = true;
|
||||||
|
try {
|
||||||
|
// 创建FormData对象
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('file', selectedFile.value);
|
||||||
|
// 调用实际的上传接口
|
||||||
|
const response = await upImageUploadId(formData);
|
||||||
|
console.log(response);
|
||||||
|
emits('avatarUpdated', response);
|
||||||
|
// 关闭对话框
|
||||||
|
close();
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('上传头像失败:', error);
|
||||||
|
ElMessage.error('上传头像失败,请重试');
|
||||||
|
} finally {
|
||||||
|
uploading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 关闭对话框
|
||||||
|
const close = () => {
|
||||||
|
emits("update:modelValue", false);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import '../styles/luntan-tech.scss';
|
||||||
|
|
||||||
|
.avatar-upload-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
padding: 12px 0 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar-preview {
|
||||||
|
width: 160px;
|
||||||
|
height: 160px;
|
||||||
|
border-radius: 50%;
|
||||||
|
overflow: hidden;
|
||||||
|
border: 2px solid rgba(0, 227, 255, 0.4);
|
||||||
|
margin-bottom: 20px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
background: rgba(10, 30, 60, 0.6);
|
||||||
|
box-shadow: 0 0 20px rgba(0, 120, 200, 0.2);
|
||||||
|
|
||||||
|
.preview-image {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview-placeholder {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
color: $lt-text-muted;
|
||||||
|
|
||||||
|
.placeholder-icon {
|
||||||
|
font-size: 48px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
color: rgba(0, 227, 255, 0.45);
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-section {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar-uploader {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
|
||||||
|
:deep(.el-button--primary) {
|
||||||
|
background: linear-gradient(180deg, #00a3ff 0%, #0066bb 100%);
|
||||||
|
border-color: rgba(0, 227, 255, 0.5);
|
||||||
|
box-shadow: 0 0 12px rgba(0, 163, 255, 0.35);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-tips {
|
||||||
|
width: 100%;
|
||||||
|
padding: 12px;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: $lt-text-muted;
|
||||||
|
background: rgba(10, 30, 60, 0.65);
|
||||||
|
border: 1px solid $lt-border-dim;
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin: 4px 0;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
@import '../styles/luntan-dialog-tech.scss';
|
||||||
|
</style>
|
||||||
@ -0,0 +1,534 @@
|
|||||||
|
<template>
|
||||||
|
<div class="comment-list">
|
||||||
|
<div v-for="comment in comments" :key="comment.id" class="comment-item">
|
||||||
|
<!-- 一级评论 -->
|
||||||
|
<div class="comment-main">
|
||||||
|
<el-avatar :size="40" :src="comment.userAvatar" class="comment-avatar">
|
||||||
|
<img src="@/assets/images/mr.png" />
|
||||||
|
</el-avatar>
|
||||||
|
|
||||||
|
<div class="comment-content">
|
||||||
|
<div class="comment-header">
|
||||||
|
<div class="user-info">
|
||||||
|
<span class="user-name">{{ comment.userName }}</span>
|
||||||
|
<div v-if="comment.ssbm" class="author-tag">
|
||||||
|
{{ comment.ssbm }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="comment-text">{{ comment.content }}</div>
|
||||||
|
|
||||||
|
<div class="comment-footer">
|
||||||
|
<span class="comment-time">{{ comment.publishTime }}</span>
|
||||||
|
<div class="comment-actions">
|
||||||
|
<!-- <div class="action-btn" :class="{ active: comment.isLiked }" @click="handleLike(comment)">
|
||||||
|
<el-icon>
|
||||||
|
<Promotion />
|
||||||
|
</el-icon>
|
||||||
|
<span>{{ comment.likeCount || 0 }}</span>
|
||||||
|
</div> -->
|
||||||
|
<div class="action-btn" @click="handleReply(comment)">
|
||||||
|
回复
|
||||||
|
</div>
|
||||||
|
<div v-if="comment.replies && comment.replies.length > 0" class="action-btn toggle-btn"
|
||||||
|
@click="toggleReplies(comment)">
|
||||||
|
{{ comment.showReplies ? '收起' : `展开${comment.replies.length}条回复` }}
|
||||||
|
<el-icon :class="{ 'rotate-icon': comment.showReplies }">
|
||||||
|
<ArrowDown />
|
||||||
|
</el-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 回复输入框 -->
|
||||||
|
<transition name="slide-fade">
|
||||||
|
<div v-if="activeReplyId === comment.id" class="reply-input-box">
|
||||||
|
<div class="reply-label">回复 {{ comment.userName }}</div>
|
||||||
|
<el-input v-model="replyContent" type="textarea" :rows="3" placeholder="输入回复内容..."
|
||||||
|
class="reply-textarea" />
|
||||||
|
<div class="reply-actions">
|
||||||
|
<V3Emoji :options-name="optionsName" @click-emoji="onEmojiClick" :recent="true" style="width: 40px;" />
|
||||||
|
<div class="reply-buttons">
|
||||||
|
<el-button size="small" @click="cancelReply">取消</el-button>
|
||||||
|
<el-button size="small" type="primary" @click="submitReply(comment)">
|
||||||
|
回复
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</transition>
|
||||||
|
|
||||||
|
<!-- 二级评论列表 -->
|
||||||
|
<div v-if="comment.replies && comment.replies.length > 0 && comment.showReplies" class="replies-list">
|
||||||
|
<div v-for="reply in comment.replies" :key="reply.id" class="reply-item">
|
||||||
|
<el-avatar :size="32" :src="reply.userAvatar" class="reply-avatar">
|
||||||
|
<img src="@/assets/images/mr.png" />
|
||||||
|
</el-avatar>
|
||||||
|
|
||||||
|
<div class="reply-content">
|
||||||
|
<div class="reply-header">
|
||||||
|
<span class="user-name">{{ reply.userName }}</span>
|
||||||
|
<div v-if="reply.ssbm" class="author-tag">
|
||||||
|
{{ reply.ssbm }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="reply-text">
|
||||||
|
<span v-if="reply.replyToUser" class="reply-to">
|
||||||
|
回复 {{ reply.replyToUser }}:
|
||||||
|
</span>
|
||||||
|
{{ reply.content }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="reply-footer">
|
||||||
|
<span class="reply-time">{{ reply.publishTime }}</span>
|
||||||
|
<div class="reply-actions">
|
||||||
|
<!-- <div class="action-btn" :class="{ active: reply.isLiked }" @click="handleLike(reply)">
|
||||||
|
<el-icon>
|
||||||
|
<Promotion />
|
||||||
|
</el-icon>
|
||||||
|
<span v-if="reply.likeCount">{{ reply.likeCount }}</span>
|
||||||
|
</div> -->
|
||||||
|
<div class="action-btn" @click="handleReplyToReply(reply, comment)">
|
||||||
|
回复
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 二级回复输入框 -->
|
||||||
|
<transition name="slide-fade">
|
||||||
|
<div v-if="activeReplyId === reply.id" class="reply-input-box">
|
||||||
|
<div class="reply-label">回复 {{ reply.userName }}</div>
|
||||||
|
<el-input v-model="replyContent" type="textarea" :rows="3" placeholder="输入回复内容..."
|
||||||
|
class="reply-textarea" />
|
||||||
|
<div class="reply-actions">
|
||||||
|
<V3Emoji :options-name="optionsName" @click-emoji="onEmojiClick" :recent="true"
|
||||||
|
style="width: 40px;" />
|
||||||
|
<div class="reply-buttons">
|
||||||
|
<el-button size="small" @click="cancelReply">取消</el-button>
|
||||||
|
<el-button size="small" type="primary" @click="submitReply(comment, reply)">
|
||||||
|
回复
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</transition>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { Promotion, ArrowDown } from '@element-plus/icons-vue'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
import V3Emoji from 'vue3-emoji'
|
||||||
|
import { tbGsxtXxltHfid, tbGsxtXxltHfSave, tbGsxtXxltHfSelectList } from '@/api/tbGsxtXxltHf.js'
|
||||||
|
import { getItem } from '@/utils/storage.js'
|
||||||
|
import { setAddress } from '@/utils/tools'
|
||||||
|
|
||||||
|
const optionsName = {
|
||||||
|
'Smileys & Emotion': '笑脸&表情',
|
||||||
|
'Food & Drink': '食物&饮料',
|
||||||
|
'Animals & Nature': '动物&自然',
|
||||||
|
'Travel & Places': '旅行&地点',
|
||||||
|
'People & Body': '人物&身体',
|
||||||
|
Objects: '物品',
|
||||||
|
Symbols: '符号',
|
||||||
|
Flags: '旗帜',
|
||||||
|
Activities: '活动'
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
comments: {
|
||||||
|
type: Array,
|
||||||
|
default: () => []
|
||||||
|
}, replyTo: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits(['reply', 'like'])
|
||||||
|
|
||||||
|
const activeReplyId = ref(null)
|
||||||
|
const replyContent = ref('')
|
||||||
|
|
||||||
|
const getTagType = (tag) => {
|
||||||
|
const tagMap = {
|
||||||
|
'户外活动部': 'success',
|
||||||
|
'校长': 'warning',
|
||||||
|
'校本部': 'info'
|
||||||
|
}
|
||||||
|
return tagMap[tag] || 'info'
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleLike = (comment) => {
|
||||||
|
emit('like', comment)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleReply = (comment) => {
|
||||||
|
emit('reply')
|
||||||
|
activeReplyId.value = comment.id
|
||||||
|
replyContent.value = ''
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleReplyToReply = (reply, parentComment) => {
|
||||||
|
emit('reply')
|
||||||
|
activeReplyId.value = reply.id
|
||||||
|
replyContent.value = `@${reply.userName}:`
|
||||||
|
}
|
||||||
|
|
||||||
|
const onEmojiClick = (emoji) => {
|
||||||
|
replyContent.value += emoji
|
||||||
|
}
|
||||||
|
|
||||||
|
const cancelReply = () => {
|
||||||
|
activeReplyId.value = null
|
||||||
|
replyContent.value = ''
|
||||||
|
}
|
||||||
|
|
||||||
|
// 切换回复列表的展开/收起
|
||||||
|
const toggleReplies = (comment) => {
|
||||||
|
if (!comment.showReplies) {
|
||||||
|
comment.showReplies = true
|
||||||
|
} else {
|
||||||
|
comment.showReplies = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const formatReplyItem = (reply) => {
|
||||||
|
return {
|
||||||
|
...reply,
|
||||||
|
id: reply.id,
|
||||||
|
userName: reply.hfrxm || '匿名用户',
|
||||||
|
userAvatar: reply.userAvatar || (reply.hfrtx ? setAddress(reply.hfrtx) : ''),
|
||||||
|
userTag: reply.userTag || '',
|
||||||
|
content: reply.content || reply.hfnr || '',
|
||||||
|
publishTime: reply.publishTime || reply.hfsj || '',
|
||||||
|
likeCount: reply.likeCount || 0,
|
||||||
|
isLiked: reply.isLiked || false,
|
||||||
|
ssbm: reply.ssbm || '',
|
||||||
|
replyToUser: reply.replyToUser || reply.sjhfrxm || ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const submitReply = async (parentComment, replyToComment = null) => {
|
||||||
|
console.log(parentComment);
|
||||||
|
|
||||||
|
if (!replyContent.value.trim()) {
|
||||||
|
ElMessage.warning('请输入回复内容')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const ltmasg = getItem("ltmasg")
|
||||||
|
let pureContent = replyContent.value
|
||||||
|
if (pureContent.startsWith('@') && pureContent.includes(':')) {
|
||||||
|
const colonIndex = pureContent.indexOf(':')
|
||||||
|
if (colonIndex !== -1 && colonIndex < pureContent.length - 1) {
|
||||||
|
pureContent = pureContent.substring(colonIndex + 1).trim()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!pureContent) {
|
||||||
|
ElMessage.warning('请输入回复内容')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const targetReply = replyToComment || null
|
||||||
|
const newReply = {
|
||||||
|
hfnr: pureContent,
|
||||||
|
hfrsfzh: ltmasg.sfzh,
|
||||||
|
hfrtx: ltmasg.tx,
|
||||||
|
hfrxm: ltmasg.xm,
|
||||||
|
ltid: props.replyTo.id,
|
||||||
|
sfyjhf: 0,
|
||||||
|
sjhfid: parentComment.id,
|
||||||
|
sjhfrxm: targetReply ? targetReply.userName : ''
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const res = await tbGsxtXxltHfSave(newReply)
|
||||||
|
if (res) {
|
||||||
|
const dataxhf = await tbGsxtXxltHfSelectList({ sjhfid: parentComment.id })
|
||||||
|
const replyList = Array.isArray(dataxhf) ? dataxhf : (dataxhf?.records || [])
|
||||||
|
parentComment.replies = replyList.map(formatReplyItem)
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
// if (!parentComment.replies) {
|
||||||
|
// parentComment.replies = []
|
||||||
|
// }
|
||||||
|
// parentComment.replies.push(newReply)
|
||||||
|
|
||||||
|
// 自动展开回复列表
|
||||||
|
parentComment.showReplies = true
|
||||||
|
ElMessage.success('回复成功')
|
||||||
|
cancelReply()
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
|
||||||
|
ElMessage.error('回复失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
@import '../styles/luntan-tech.scss';
|
||||||
|
|
||||||
|
.comment-list {
|
||||||
|
.comment-item {
|
||||||
|
margin-bottom: 18px;
|
||||||
|
padding-bottom: 18px;
|
||||||
|
border-bottom: 1px solid $lt-border-dim;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
padding-bottom: 0;
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.comment-main {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comment-avatar {
|
||||||
|
flex-shrink: 0;
|
||||||
|
border: 1px solid rgba(0, 227, 255, 0.3);
|
||||||
|
box-shadow: 0 0 8px rgba(0, 120, 180, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.comment-content {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
padding-top: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comment-header {
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-info {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-name {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: $lt-text;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comment-text {
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 1.65;
|
||||||
|
color: $lt-text-dim;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
word-break: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comment-footer {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comment-time {
|
||||||
|
font-size: 12px;
|
||||||
|
color: $lt-text-muted;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comment-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-btn {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: $lt-text-muted;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: color 0.2s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: $lt-cyan;
|
||||||
|
text-shadow: 0 0 8px rgba(0, 227, 255, 0.35);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
color: $lt-cyan;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.toggle-btn {
|
||||||
|
.el-icon {
|
||||||
|
transition: transform 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rotate-icon {
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.reply-input-box {
|
||||||
|
margin-top: 12px;
|
||||||
|
padding: 12px;
|
||||||
|
border-radius: 4px;
|
||||||
|
@include lt-panel-soft-bg;
|
||||||
|
}
|
||||||
|
|
||||||
|
.reply-label {
|
||||||
|
font-size: 12px;
|
||||||
|
color: $lt-text-muted;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.reply-textarea {
|
||||||
|
margin-bottom: 8px;
|
||||||
|
|
||||||
|
:deep(.el-textarea__inner) {
|
||||||
|
background: rgba(10, 28, 58, 0.88) !important;
|
||||||
|
color: $lt-text-dim;
|
||||||
|
border: 1px solid rgba(0, 227, 255, 0.28);
|
||||||
|
border-radius: 4px;
|
||||||
|
box-shadow: 0 0 12px rgba(0, 80, 140, 0.15) inset;
|
||||||
|
|
||||||
|
&::placeholder {
|
||||||
|
color: $lt-text-muted;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.reply-actions {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.reply-buttons {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
|
||||||
|
:deep(.el-button) {
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-button--default) {
|
||||||
|
background: rgba(0, 40, 70, 0.5);
|
||||||
|
border-color: rgba(0, 163, 255, 0.35);
|
||||||
|
color: $lt-text-dim;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-button--primary) {
|
||||||
|
background: linear-gradient(180deg, #00a3ff 0%, #0066bb 100%);
|
||||||
|
border-color: rgba(0, 227, 255, 0.45);
|
||||||
|
box-shadow: 0 0 12px rgba(0, 163, 255, 0.35);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.replies-list {
|
||||||
|
margin-top: 14px;
|
||||||
|
padding-left: 12px;
|
||||||
|
border-left: 2px solid rgba(0, 227, 255, 0.25);
|
||||||
|
box-shadow: -2px 0 12px rgba(0, 100, 160, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
.reply-item {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
align-items: flex-start;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.reply-avatar {
|
||||||
|
flex-shrink: 0;
|
||||||
|
border: 1px solid rgba(0, 227, 255, 0.22);
|
||||||
|
}
|
||||||
|
|
||||||
|
.reply-content {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
padding-top: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.reply-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.reply-text {
|
||||||
|
font-size: 13px;
|
||||||
|
line-height: 1.6;
|
||||||
|
color: $lt-text-dim;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
word-break: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
.reply-to {
|
||||||
|
color: $lt-cyan;
|
||||||
|
margin-right: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.reply-footer {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.reply-time {
|
||||||
|
font-size: 12px;
|
||||||
|
color: $lt-text-muted;
|
||||||
|
}
|
||||||
|
|
||||||
|
.reply-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slide-fade-enter-active {
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slide-fade-leave-active {
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slide-fade-enter-from,
|
||||||
|
.slide-fade-leave-to {
|
||||||
|
transform: translateY(-10px);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.author-tag {
|
||||||
|
padding: 2px 8px;
|
||||||
|
border-radius: 2px;
|
||||||
|
background: rgba(0, 163, 255, 0.22);
|
||||||
|
color: #b8ecff;
|
||||||
|
font-size: 11px;
|
||||||
|
line-height: 18px;
|
||||||
|
border: 1px solid rgba(0, 227, 255, 0.35);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
@import '../styles/luntan-v3emoji-tech.scss';
|
||||||
|
</style>
|
||||||
565
src/views/backOfficeSystem/luntan copy/components/PostDetail.vue
Normal file
565
src/views/backOfficeSystem/luntan copy/components/PostDetail.vue
Normal file
@ -0,0 +1,565 @@
|
|||||||
|
<template>
|
||||||
|
<div class="post-detail luntan-tech-detail">
|
||||||
|
<!-- 头部 -->
|
||||||
|
<div class="detail-header">
|
||||||
|
<el-button class="detail-back-btn" @click="handleBack">
|
||||||
|
<el-icon>
|
||||||
|
<ArrowLeft />
|
||||||
|
</el-icon>
|
||||||
|
返回
|
||||||
|
</el-button>
|
||||||
|
<div class="header-title">帖子详情</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 帖子内容 -->
|
||||||
|
<div class="post-main">
|
||||||
|
<div class="premium-badge" v-if="postData.isPremium">置顶</div>
|
||||||
|
|
||||||
|
<div class="post-author">
|
||||||
|
<el-avatar :size="50" :src="postData.userAvatar" class="author-avatar">
|
||||||
|
<img src="@/assets/images/mr.png" />
|
||||||
|
</el-avatar>
|
||||||
|
<div class="author-info">
|
||||||
|
<div class="author-name-row">
|
||||||
|
<span class="author-name">{{ postData.userName }}</span>
|
||||||
|
<span v-if="postData.userTag" class="level-badge">{{
|
||||||
|
postData.userTag
|
||||||
|
}}</span>
|
||||||
|
<div v-if="postData.ssbm" class="author-tag">
|
||||||
|
{{ postData.ssbm }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="publish-time">{{ postData.publishTime }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="post-content-text">{{ postData.content }}</div>
|
||||||
|
|
||||||
|
<!-- 图片展示 -->
|
||||||
|
<div
|
||||||
|
class="post-images"
|
||||||
|
v-if="postData.images && postData.images.length > 0"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-for="(img, index) in postData.images"
|
||||||
|
:key="index"
|
||||||
|
class="image-item"
|
||||||
|
>
|
||||||
|
<el-image
|
||||||
|
:preview-teleported="true"
|
||||||
|
:src="img"
|
||||||
|
fit="cover"
|
||||||
|
:preview-src-list="postData.images"
|
||||||
|
:initial-index="index"
|
||||||
|
>
|
||||||
|
<template #error>
|
||||||
|
<div class="image-error">
|
||||||
|
<el-icon>
|
||||||
|
<Picture />
|
||||||
|
</el-icon>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-image>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 统计信息 -->
|
||||||
|
<div class="post-stats">
|
||||||
|
<div class="stat-item">
|
||||||
|
<el-icon>
|
||||||
|
<ChatDotRound />
|
||||||
|
</el-icon>
|
||||||
|
<span>{{ postData.commentCount || 0 }}</span>
|
||||||
|
</div>
|
||||||
|
<!-- <div class="stat-item" :class="{ active: postData.isLiked }" @click="handleLike">
|
||||||
|
<el-icon>
|
||||||
|
<Promotion />
|
||||||
|
</el-icon>
|
||||||
|
<span>{{ postData.likeCount || 0 }}</span>
|
||||||
|
</div> -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 评论区 -->
|
||||||
|
<div class="comment-section">
|
||||||
|
<!-- Tab切换 -->
|
||||||
|
<div class="comment-tabs">
|
||||||
|
<div
|
||||||
|
class="tab-item"
|
||||||
|
:class="{ active: activeTab === 'all' }"
|
||||||
|
@click="activeTab = 'all'"
|
||||||
|
>
|
||||||
|
全部回复({{ comments.length }})
|
||||||
|
</div>
|
||||||
|
<!-- <div class="tab-item" :class="{ active: activeTab === 'author' }" @click="activeTab = 'author'">
|
||||||
|
只看楼主
|
||||||
|
</div> -->
|
||||||
|
|
||||||
|
<!-- <div class="sort-buttons">
|
||||||
|
<el-button text size="small">热门</el-button>
|
||||||
|
<el-button text size="small">正序</el-button>
|
||||||
|
<el-button text size="small">倒序</el-button>
|
||||||
|
</div> -->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 顶部输入框 - 点击打开弹窗 -->
|
||||||
|
<div class="top-input" @click="replyToData">
|
||||||
|
<el-input placeholder="发点干货 文明第一步" readonly />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 评论列表 -->
|
||||||
|
|
||||||
|
<CommentList
|
||||||
|
:comments="filteredComments"
|
||||||
|
@reply="handleReply"
|
||||||
|
:replyTo="replyTo"
|
||||||
|
@like="handleCommentLike"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 回复弹窗 -->
|
||||||
|
<ReplyDialog
|
||||||
|
v-model="showReplyDialog"
|
||||||
|
:reply-to="replyTo"
|
||||||
|
@success="handleReplySuccess"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, computed, onMounted } from "vue";
|
||||||
|
import {
|
||||||
|
ArrowLeft,
|
||||||
|
ChatDotRound,
|
||||||
|
Promotion,
|
||||||
|
Picture
|
||||||
|
} from "@element-plus/icons-vue";
|
||||||
|
import { ElMessage } from "element-plus";
|
||||||
|
import CommentList from "./CommentList.vue";
|
||||||
|
import ReplyDialog from "./ReplyDialog.vue";
|
||||||
|
import { tbGsxtXxltHfid } from "@/api/tbGsxtXxltHf";
|
||||||
|
import { setAddress } from "@/utils/tools";
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
postId: {
|
||||||
|
type: [String, Number],
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(["back"]);
|
||||||
|
|
||||||
|
const activeTab = ref("all");
|
||||||
|
const showReplyDialog = ref(false);
|
||||||
|
const replyTo = ref(null);
|
||||||
|
const loading = ref(false);
|
||||||
|
|
||||||
|
// 帖子数据
|
||||||
|
const postData = ref({
|
||||||
|
id: null,
|
||||||
|
userName: "",
|
||||||
|
userAvatar: "",
|
||||||
|
userTag: "",
|
||||||
|
publishTime: "",
|
||||||
|
content: "",
|
||||||
|
images: [],
|
||||||
|
commentCount: 0,
|
||||||
|
likeCount: 0,
|
||||||
|
isPremium: false,
|
||||||
|
isLiked: false
|
||||||
|
});
|
||||||
|
|
||||||
|
// 评论数据
|
||||||
|
const comments = ref([]);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
loadPostDetail();
|
||||||
|
});
|
||||||
|
|
||||||
|
const loadPostDetail = async () => {
|
||||||
|
loading.value = true;
|
||||||
|
try {
|
||||||
|
const res = await tbGsxtXxltHfid(props.postId);
|
||||||
|
|
||||||
|
// 设置帖子数据
|
||||||
|
postData.value = {
|
||||||
|
id: res.id,
|
||||||
|
userName: res.fbrxm || "匿名用户",
|
||||||
|
userAvatar: res.fbrtx ? setAddress(res.fbrtx) : "",
|
||||||
|
userTag: res.userTag || "",
|
||||||
|
publishTime: res.time || "",
|
||||||
|
content: res.content || "",
|
||||||
|
images: res.tp ? res.tp.split(",").map((img) => setAddress(img)) : [],
|
||||||
|
commentCount: res.commentCount || 0,
|
||||||
|
likeCount: res.likeCount || 0,
|
||||||
|
isPremium: res.sfzd === 1,
|
||||||
|
isLiked: false,
|
||||||
|
ssbm: res.ssbm
|
||||||
|
};
|
||||||
|
|
||||||
|
// 设置评论数据
|
||||||
|
if (res.replyList && res.replyList.length > 0) {
|
||||||
|
comments.value = res.replyList.map((item) => ({
|
||||||
|
id: item.id,
|
||||||
|
userName: item.hfrxm || "匿名用户",
|
||||||
|
userAvatar: item.hfrtx ? setAddress(item.hfrtx) : "",
|
||||||
|
userTag: item.userTag || "",
|
||||||
|
content: item.hfnr || "",
|
||||||
|
publishTime: item.hfsj || "",
|
||||||
|
likeCount: item.likeCount || 0,
|
||||||
|
isLiked: false,
|
||||||
|
showReplies: false,
|
||||||
|
ssbm: item.ssbm,
|
||||||
|
replies: item.xjfhList
|
||||||
|
? item.xjfhList.map((reply) => ({
|
||||||
|
id: reply.id,
|
||||||
|
userName: reply.hfrxm || "匿名用户",
|
||||||
|
userAvatar: reply.hfrtx ? setAddress(reply.hfrtx) : "",
|
||||||
|
userTag: reply.userTag || "",
|
||||||
|
content: reply.hfnr || "",
|
||||||
|
publishTime: reply.hfsj || "",
|
||||||
|
likeCount: reply.likeCount || 0,
|
||||||
|
isLiked: false,
|
||||||
|
replyToUser: reply.sjhfrxm || "",
|
||||||
|
ssbm: reply.ssbm
|
||||||
|
}))
|
||||||
|
: []
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("加载详情失败", error);
|
||||||
|
ElMessage.error("加载详情失败");
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const filteredComments = computed(() => {
|
||||||
|
if (activeTab.value === "author") {
|
||||||
|
return comments.value.filter((c) => c.userName === postData.value.userName);
|
||||||
|
}
|
||||||
|
return comments.value;
|
||||||
|
});
|
||||||
|
|
||||||
|
const getTagType = (tag) => {
|
||||||
|
const tagMap = {
|
||||||
|
户外活动部: "success",
|
||||||
|
校长: "warning",
|
||||||
|
校本部: "info"
|
||||||
|
};
|
||||||
|
return tagMap[tag] || "info";
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleBack = () => {
|
||||||
|
emit("back");
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleLike = () => {
|
||||||
|
postData.value.isLiked = !postData.value.isLiked;
|
||||||
|
postData.value.likeCount += postData.value.isLiked ? 1 : -1;
|
||||||
|
ElMessage.success(postData.value.isLiked ? "点赞成功" : "取消点赞");
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleReply = () => {
|
||||||
|
replyTo.value = {
|
||||||
|
...postData.value
|
||||||
|
};
|
||||||
|
// showReplyDialog.value = true
|
||||||
|
};
|
||||||
|
const replyToData = () => {
|
||||||
|
replyTo.value = {
|
||||||
|
...postData.value
|
||||||
|
};
|
||||||
|
showReplyDialog.value = true;
|
||||||
|
};
|
||||||
|
const handleCommentLike = (comment) => {
|
||||||
|
comment.isLiked = !comment.isLiked;
|
||||||
|
comment.likeCount += comment.isLiked ? 1 : -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleReplySuccess = () => {
|
||||||
|
ElMessage.success("回复成功");
|
||||||
|
loadPostDetail();
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
@import "../styles/luntan-tech.scss";
|
||||||
|
|
||||||
|
.luntan-tech-detail {
|
||||||
|
background: transparent;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-header {
|
||||||
|
padding: 14px 18px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-shrink: 0;
|
||||||
|
border-bottom: 1px solid $lt-border-dim;
|
||||||
|
background: linear-gradient(
|
||||||
|
90deg,
|
||||||
|
rgba(0, 163, 255, 0.08) 0%,
|
||||||
|
transparent 55%
|
||||||
|
);
|
||||||
|
|
||||||
|
:deep(.detail-back-btn.el-button) {
|
||||||
|
height: 36px;
|
||||||
|
padding: 0 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
border-radius: 4px;
|
||||||
|
background: rgba(10, 30, 60, 0.75) !important;
|
||||||
|
border: 1px solid $lt-border-dim !important;
|
||||||
|
color: $lt-text-dim !important;
|
||||||
|
box-shadow: inset 0 1px 0 rgba(0, 220, 255, 0.08),
|
||||||
|
0 0 12px rgba(0, 80, 140, 0.2);
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&:focus {
|
||||||
|
color: $lt-cyan !important;
|
||||||
|
border-color: rgba(0, 227, 255, 0.45) !important;
|
||||||
|
background: rgba(12, 40, 75, 0.92) !important;
|
||||||
|
box-shadow: 0 0 16px rgba(0, 163, 255, 0.28),
|
||||||
|
inset 0 1px 0 rgba(0, 220, 255, 0.1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.detail-back-btn .el-icon) {
|
||||||
|
margin-right: 4px;
|
||||||
|
font-size: 16px;
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-title {
|
||||||
|
flex: 1;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: $lt-text;
|
||||||
|
margin-right: 60px;
|
||||||
|
letter-spacing: 0.08em;
|
||||||
|
text-shadow: 0 0 16px rgba(0, 227, 255, 0.35);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.post-main {
|
||||||
|
padding: 20px 18px 18px;
|
||||||
|
margin: 12px 12px 0;
|
||||||
|
position: relative;
|
||||||
|
flex-shrink: 0;
|
||||||
|
border-radius: 4px;
|
||||||
|
@include lt-panel-soft-bg;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comment-section {
|
||||||
|
padding: 8px 12px 32px;
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
min-height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.premium-badge {
|
||||||
|
position: absolute;
|
||||||
|
top: 16px;
|
||||||
|
right: 16px;
|
||||||
|
background: linear-gradient(
|
||||||
|
180deg,
|
||||||
|
rgba(0, 227, 255, 0.35) 0%,
|
||||||
|
rgba(0, 100, 180, 0.5) 100%
|
||||||
|
);
|
||||||
|
color: #fff;
|
||||||
|
padding: 4px 12px;
|
||||||
|
border-radius: 2px;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 600;
|
||||||
|
border: 1px solid rgba(0, 227, 255, 0.55);
|
||||||
|
box-shadow: 0 0 14px rgba(0, 227, 255, 0.35);
|
||||||
|
}
|
||||||
|
|
||||||
|
.post-author {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.author-avatar {
|
||||||
|
border: 2px solid rgba(0, 227, 255, 0.35);
|
||||||
|
box-shadow: 0 0 12px rgba(0, 163, 255, 0.25);
|
||||||
|
}
|
||||||
|
|
||||||
|
.author-info {
|
||||||
|
flex: 1;
|
||||||
|
padding-top: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.author-name-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 8px;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.author-name {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: $lt-text;
|
||||||
|
}
|
||||||
|
|
||||||
|
.level-badge {
|
||||||
|
font-size: 11px;
|
||||||
|
padding: 2px 8px;
|
||||||
|
border-radius: 2px;
|
||||||
|
background: rgba(0, 227, 255, 0.15);
|
||||||
|
color: $lt-cyan;
|
||||||
|
font-weight: 600;
|
||||||
|
border: 1px solid rgba(0, 227, 255, 0.35);
|
||||||
|
}
|
||||||
|
|
||||||
|
.author-tag {
|
||||||
|
padding: 2px 8px;
|
||||||
|
border-radius: 2px;
|
||||||
|
background: rgba(0, 163, 255, 0.25);
|
||||||
|
color: #b8ecff;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 18px;
|
||||||
|
border: 1px solid rgba(0, 227, 255, 0.35);
|
||||||
|
}
|
||||||
|
|
||||||
|
.publish-time {
|
||||||
|
font-size: 12px;
|
||||||
|
color: $lt-text-muted;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post-content-text {
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 1.85;
|
||||||
|
color: $lt-text-dim;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
word-break: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post-images {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-item {
|
||||||
|
width: 200px;
|
||||||
|
height: 140px;
|
||||||
|
border-radius: 4px;
|
||||||
|
overflow: hidden;
|
||||||
|
border: 1px solid $lt-border-dim;
|
||||||
|
box-shadow: 0 0 12px rgba(0, 100, 160, 0.2);
|
||||||
|
|
||||||
|
:deep(.el-image) {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-error {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: rgba(10, 30, 60, 0.6);
|
||||||
|
color: $lt-text-muted;
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post-stats {
|
||||||
|
display: flex;
|
||||||
|
gap: 24px;
|
||||||
|
padding-top: 16px;
|
||||||
|
border-top: 1px solid $lt-border-dim;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
color: $lt-text-muted;
|
||||||
|
font-size: 14px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: color 0.2s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: $lt-cyan;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-icon {
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.comment-tabs {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 14px;
|
||||||
|
border-bottom: 1px solid $lt-border-dim;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-item {
|
||||||
|
padding: 12px 14px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: $lt-text-muted;
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
transition: color 0.2s ease;
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
color: $lt-cyan;
|
||||||
|
font-weight: 600;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
height: 2px;
|
||||||
|
background: linear-gradient(90deg, transparent, $lt-cyan, transparent);
|
||||||
|
box-shadow: 0 0 10px rgba(0, 227, 255, 0.6);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.sort-buttons {
|
||||||
|
margin-left: auto;
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-input {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
:deep(.el-input__wrapper) {
|
||||||
|
cursor: pointer;
|
||||||
|
background: rgba(10, 30, 60, 0.65) !important;
|
||||||
|
border-radius: 4px !important;
|
||||||
|
box-shadow: 0 0 0 1px rgba(0, 227, 255, 0.28) inset,
|
||||||
|
0 0 16px rgba(0, 100, 180, 0.15) !important;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
box-shadow: 0 0 0 1px rgba(0, 227, 255, 0.45) inset,
|
||||||
|
0 0 20px rgba(0, 163, 255, 0.25) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-input__inner) {
|
||||||
|
color: $lt-text-dim;
|
||||||
|
|
||||||
|
&::placeholder {
|
||||||
|
color: $lt-text-muted;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
332
src/views/backOfficeSystem/luntan copy/components/PostItem.vue
Normal file
332
src/views/backOfficeSystem/luntan copy/components/PostItem.vue
Normal file
@ -0,0 +1,332 @@
|
|||||||
|
<template>
|
||||||
|
<div class="post-item" @click="handleClick">
|
||||||
|
<div class="premium-badge" v-if="post.isPremium">置顶</div>
|
||||||
|
<div class="post-main-content">
|
||||||
|
<el-avatar :size="44" :src="post.userAvatar" class="post-avatar">
|
||||||
|
<img src="@/assets/images/mr.png" />
|
||||||
|
</el-avatar>
|
||||||
|
|
||||||
|
<div class="post-right">
|
||||||
|
<div class="post-header">
|
||||||
|
<div class="user-name-row">
|
||||||
|
<span class="user-name">{{ post.userName }}</span>
|
||||||
|
<span v-if="post.userTag" class="level-badge">{{
|
||||||
|
post.userTag
|
||||||
|
}}</span>
|
||||||
|
<div v-if="post.ssbm" class="author-tag">
|
||||||
|
{{ post.ssbm }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="post-time">{{ post.publishTime }}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="post-content" v-if="postTitle || bodySource">
|
||||||
|
<div v-if="postTitle" class="post-title">{{ postTitle }}</div>
|
||||||
|
<div v-if="bodySource" class="post-text-wrap">
|
||||||
|
<div class="post-text">{{ displayBody }}</div>
|
||||||
|
<span
|
||||||
|
v-if="showFullLink"
|
||||||
|
class="full-text-link"
|
||||||
|
@click.stop="handleClick"
|
||||||
|
>全文</span
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 图片展示 -->
|
||||||
|
<div
|
||||||
|
class="post-images"
|
||||||
|
v-if="post.images && post.images.length > 0"
|
||||||
|
:class="{ 'is-three': post.images.length >= 3 }"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-for="(img, index) in post.images"
|
||||||
|
:key="index"
|
||||||
|
class="image-item"
|
||||||
|
@click.stop
|
||||||
|
>
|
||||||
|
<el-image
|
||||||
|
:preview-teleported="true"
|
||||||
|
:src="img"
|
||||||
|
fit="cover"
|
||||||
|
:preview-src-list="post.images"
|
||||||
|
:initial-index="index"
|
||||||
|
>
|
||||||
|
<template #error>
|
||||||
|
<div class="image-error">
|
||||||
|
<el-icon>
|
||||||
|
<Picture />
|
||||||
|
</el-icon>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-image>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="post-footer">
|
||||||
|
<div class="action-item">
|
||||||
|
<el-icon>
|
||||||
|
<ChatDotRound />
|
||||||
|
</el-icon>
|
||||||
|
<span>{{ post.commentCount || 0 }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { computed } from "vue";
|
||||||
|
import { ChatDotRound, Picture } from "@element-plus/icons-vue";
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
post: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(["like", "click"]);
|
||||||
|
|
||||||
|
const EXCERPT_LEN = 160;
|
||||||
|
|
||||||
|
const rawContent = computed(() => (props.post.content || "").trim());
|
||||||
|
|
||||||
|
const postTitle = computed(() => {
|
||||||
|
const t = rawContent.value;
|
||||||
|
if (!t) return "";
|
||||||
|
const idx = t.indexOf("\n");
|
||||||
|
if (idx === -1) return "";
|
||||||
|
const first = t.slice(0, idx).trim();
|
||||||
|
return first.length > 0 ? first : "";
|
||||||
|
});
|
||||||
|
|
||||||
|
const bodySource = computed(() => {
|
||||||
|
const t = rawContent.value;
|
||||||
|
if (!t) return "";
|
||||||
|
const idx = t.indexOf("\n");
|
||||||
|
if (idx === -1) return t;
|
||||||
|
const rest = t.slice(idx + 1).trim();
|
||||||
|
return rest;
|
||||||
|
});
|
||||||
|
|
||||||
|
const showFullLink = computed(() => bodySource.value.length > EXCERPT_LEN);
|
||||||
|
|
||||||
|
const displayBody = computed(() => {
|
||||||
|
const b = bodySource.value;
|
||||||
|
if (!b) return "";
|
||||||
|
if (b.length <= EXCERPT_LEN) return b;
|
||||||
|
return `${b.slice(0, EXCERPT_LEN)}…`;
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleClick = () => {
|
||||||
|
emit("click", props.post);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
@import "../styles/luntan-tech.scss";
|
||||||
|
|
||||||
|
.post-item {
|
||||||
|
position: relative;
|
||||||
|
padding: 18px 18px 14px;
|
||||||
|
margin-bottom: 14px;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
@include lt-panel-frame;
|
||||||
|
transition: border-color 0.2s ease, box-shadow 0.2s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border-color: rgba(0, 227, 255, 0.55);
|
||||||
|
box-shadow: $lt-glow-strong, inset 0 1px 0 rgba(0, 220, 255, 0.18);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.premium-badge {
|
||||||
|
position: absolute;
|
||||||
|
top: 14px;
|
||||||
|
right: 14px;
|
||||||
|
background: linear-gradient(
|
||||||
|
180deg,
|
||||||
|
rgba(0, 227, 255, 0.35) 0%,
|
||||||
|
rgba(0, 100, 180, 0.45) 100%
|
||||||
|
);
|
||||||
|
color: #fff;
|
||||||
|
padding: 3px 10px;
|
||||||
|
border-radius: 2px;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 600;
|
||||||
|
letter-spacing: 0.04em;
|
||||||
|
border: 1px solid rgba(0, 227, 255, 0.55);
|
||||||
|
box-shadow: 0 0 12px rgba(0, 227, 255, 0.35);
|
||||||
|
}
|
||||||
|
|
||||||
|
.post-main-content {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post-avatar {
|
||||||
|
flex-shrink: 0;
|
||||||
|
border: 2px solid rgba(0, 227, 255, 0.35);
|
||||||
|
box-shadow: 0 0 10px rgba(0, 163, 255, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.post-right {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
padding-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post-header {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-name-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 6px 8px;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-name {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: $lt-text;
|
||||||
|
}
|
||||||
|
|
||||||
|
.level-badge {
|
||||||
|
font-size: 11px;
|
||||||
|
padding: 2px 8px;
|
||||||
|
border-radius: 2px;
|
||||||
|
background: rgba(0, 227, 255, 0.12);
|
||||||
|
color: $lt-cyan;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 1.3;
|
||||||
|
border: 1px solid rgba(0, 227, 255, 0.35);
|
||||||
|
}
|
||||||
|
|
||||||
|
.post-time {
|
||||||
|
font-size: 12px;
|
||||||
|
color: $lt-text-muted;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post-content {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post-title {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: $lt-text;
|
||||||
|
line-height: 1.45;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
word-break: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post-text-wrap {
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 1.65;
|
||||||
|
color: $lt-text-dim;
|
||||||
|
word-break: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post-text {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.full-text-link {
|
||||||
|
margin-left: 4px;
|
||||||
|
color: $lt-cyan;
|
||||||
|
font-weight: 500;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
text-shadow: 0 0 8px rgba(0, 227, 255, 0.5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.post-images {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
margin-top: 12px;
|
||||||
|
|
||||||
|
&.is-three .image-item {
|
||||||
|
width: calc((100% - 16px) / 3);
|
||||||
|
min-width: 0;
|
||||||
|
aspect-ratio: 4 / 3;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-item {
|
||||||
|
width: 160px;
|
||||||
|
height: 112px;
|
||||||
|
border-radius: 4px;
|
||||||
|
overflow: hidden;
|
||||||
|
cursor: pointer;
|
||||||
|
flex-shrink: 0;
|
||||||
|
border: 1px solid $lt-border-dim;
|
||||||
|
box-shadow: 0 0 10px rgba(0, 80, 140, 0.25);
|
||||||
|
|
||||||
|
:deep(.el-image) {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.post-images.is-three .image-item {
|
||||||
|
max-width: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-error {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: rgba(10, 30, 60, 0.65);
|
||||||
|
color: $lt-text-muted;
|
||||||
|
font-size: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post-footer {
|
||||||
|
display: flex;
|
||||||
|
gap: 20px;
|
||||||
|
padding-top: 10px;
|
||||||
|
border-top: 1px solid $lt-border-dim;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
color: $lt-text-muted;
|
||||||
|
font-size: 13px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: color 0.2s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: $lt-cyan;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-icon {
|
||||||
|
font-size: 17px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.author-tag {
|
||||||
|
padding: 2px 8px;
|
||||||
|
border-radius: 2px;
|
||||||
|
background: rgba(0, 200, 180, 0.18);
|
||||||
|
color: #9ff;
|
||||||
|
font-size: 11px;
|
||||||
|
line-height: 18px;
|
||||||
|
font-weight: 600;
|
||||||
|
border: 1px solid rgba(0, 227, 255, 0.35);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
463
src/views/backOfficeSystem/luntan copy/components/PostList.vue
Normal file
463
src/views/backOfficeSystem/luntan copy/components/PostList.vue
Normal file
@ -0,0 +1,463 @@
|
|||||||
|
<template>
|
||||||
|
<div class="post-list">
|
||||||
|
<!-- 贴吧风格顶栏:左信息 + 右操作(页面背景仍为外层网格,不变) -->
|
||||||
|
<div class="bar-head">
|
||||||
|
<div class="bar-head-left">
|
||||||
|
<div class="bar-logo">
|
||||||
|
<el-icon><ChatDotRound /></el-icon>
|
||||||
|
</div>
|
||||||
|
<div class="bar-head-text">
|
||||||
|
<div class="bar-title">信息论坛</div>
|
||||||
|
<div class="bar-meta">帖子 {{ totalDisplay }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="bar-actions">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="bar-pill bar-pill-primary"
|
||||||
|
@click="showPublishDialog = true"
|
||||||
|
>
|
||||||
|
<el-icon><Plus /></el-icon>
|
||||||
|
发帖
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 帖子列表 -->
|
||||||
|
<div
|
||||||
|
class="posts-container"
|
||||||
|
v-loading="loading"
|
||||||
|
v-infinite-scroll="loadMore"
|
||||||
|
:infinite-scroll-disabled="scrollDisabled"
|
||||||
|
:infinite-scroll-distance="100"
|
||||||
|
>
|
||||||
|
<!-- 置顶:仅标题缩略列表 -->
|
||||||
|
<div v-if="pinnedList.length" class="pinned-block">
|
||||||
|
<div class="pinned-list">
|
||||||
|
<div
|
||||||
|
v-for="post in pinnedList"
|
||||||
|
:key="'zd-' + post.id"
|
||||||
|
class="pinned-row"
|
||||||
|
@click="handlePostClick(post)"
|
||||||
|
>
|
||||||
|
<span class="pinned-badge">置顶</span>
|
||||||
|
<span class="pinned-title">{{ displayTitle(post) }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 分界线 -->
|
||||||
|
<div v-if="pinnedList.length && normalList.length" class="list-divider">
|
||||||
|
<span class="divider-line" />
|
||||||
|
<span class="divider-text">全部帖子</span>
|
||||||
|
<span class="divider-line" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 普通帖子 -->
|
||||||
|
<PostItem
|
||||||
|
v-for="post in normalList"
|
||||||
|
:key="post.id"
|
||||||
|
:post="post"
|
||||||
|
@like="handleLike"
|
||||||
|
@click="handlePostClick(post)"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- 加载更多提示 -->
|
||||||
|
<div v-if="loadingMore" class="loading-more">
|
||||||
|
<el-icon class="is-loading">
|
||||||
|
<Loading />
|
||||||
|
</el-icon>
|
||||||
|
<span>加载中...</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 没有更多数据提示 -->
|
||||||
|
<div v-if="noMore && normalList.length > 0" class="no-more">
|
||||||
|
没有更多数据了
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 空状态 -->
|
||||||
|
<el-empty
|
||||||
|
v-if="!loading && postList.length === 0"
|
||||||
|
class="post-empty"
|
||||||
|
description="暂无帖子"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 发布对话框 -->
|
||||||
|
<PublishDialog
|
||||||
|
v-model="showPublishDialog"
|
||||||
|
@success="handlePublishSuccess"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, onMounted, computed } from "vue";
|
||||||
|
import { ChatDotRound, Loading, Plus } from "@element-plus/icons-vue";
|
||||||
|
import PostItem from "./PostItem.vue";
|
||||||
|
import PublishDialog from "./PublishDialog.vue";
|
||||||
|
import { ElMessage } from "element-plus";
|
||||||
|
import { tbGsxtXxltSelectPage } from "@/api/tbGsxtXxltHf";
|
||||||
|
import { setAddress } from "@/utils/tools";
|
||||||
|
|
||||||
|
const loading = ref(false);
|
||||||
|
const loadingMore = ref(false);
|
||||||
|
const postList = ref([]);
|
||||||
|
const showPublishDialog = ref(false);
|
||||||
|
|
||||||
|
const listQuery = ref({
|
||||||
|
pageCurrent: 1,
|
||||||
|
pageSize: 10
|
||||||
|
});
|
||||||
|
|
||||||
|
const total = ref(0);
|
||||||
|
|
||||||
|
const totalDisplay = computed(() => {
|
||||||
|
const n = total.value;
|
||||||
|
if (n >= 10000) return `${(n / 10000).toFixed(1)}W`;
|
||||||
|
if (n >= 1000) return `${(n / 1000).toFixed(1)}k`;
|
||||||
|
return String(n);
|
||||||
|
});
|
||||||
|
|
||||||
|
const pinnedList = computed(() => postList.value.filter((p) => p.isPremium));
|
||||||
|
|
||||||
|
const normalList = computed(() => postList.value.filter((p) => !p.isPremium));
|
||||||
|
|
||||||
|
/** 置顶行展示标题:优先接口 title,否则从正文首行截取 */
|
||||||
|
function displayTitle(post) {
|
||||||
|
const tit = (post.title || "").trim();
|
||||||
|
if (tit) {
|
||||||
|
return tit.length <= 56 ? tit : `${tit.slice(0, 56)}…`;
|
||||||
|
}
|
||||||
|
const t = (post.content || "").trim();
|
||||||
|
if (!t) return "无标题";
|
||||||
|
const idx = t.indexOf("\n");
|
||||||
|
const firstLine = idx === -1 ? t : t.slice(0, idx).trim();
|
||||||
|
const line = firstLine || t.slice(0, 80);
|
||||||
|
if (line.length <= 56) return line;
|
||||||
|
return `${line.slice(0, 56)}…`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算是否禁用滚动加载
|
||||||
|
const scrollDisabled = computed(() => {
|
||||||
|
return loadingMore.value || noMore.value;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 计算是否没有更多数据
|
||||||
|
const noMore = computed(() => {
|
||||||
|
return postList.value.length >= total.value && total.value > 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
loadPosts();
|
||||||
|
});
|
||||||
|
|
||||||
|
const loadPosts = async (isLoadMore = false) => {
|
||||||
|
if (isLoadMore) {
|
||||||
|
loadingMore.value = true;
|
||||||
|
} else {
|
||||||
|
loading.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await tbGsxtXxltSelectPage(listQuery.value);
|
||||||
|
const data = (res.records || []).map((item) => ({
|
||||||
|
id: item.id,
|
||||||
|
title: item.title || "",
|
||||||
|
userName: item.fbrxm || "匿名用户",
|
||||||
|
userAvatar: item.fbrtx ? setAddress(item.fbrtx) : "",
|
||||||
|
userTag: item.userTag || "",
|
||||||
|
publishTime: item.time || "",
|
||||||
|
content: item.content || "",
|
||||||
|
images: item.tp ? item.tp.split(",").map((img) => setAddress(img)) : [],
|
||||||
|
commentCount: item.hfsl || 0,
|
||||||
|
likeCount: item.likeCount || 0,
|
||||||
|
isPremium: item.sfzd === 1,
|
||||||
|
isLiked: false,
|
||||||
|
ssbm: item.ssbm,
|
||||||
|
// 保存原始数据
|
||||||
|
rawData: item
|
||||||
|
}));
|
||||||
|
|
||||||
|
if (isLoadMore) {
|
||||||
|
postList.value = [...postList.value, ...data];
|
||||||
|
} else {
|
||||||
|
postList.value = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
total.value = res.total || 0;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("加载失败", error);
|
||||||
|
ElMessage.error("加载失败");
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
loadingMore.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 加载更多
|
||||||
|
const loadMore = () => {
|
||||||
|
if (postList.value.length >= total.value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
listQuery.value.pageCurrent++;
|
||||||
|
loadPosts(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleLike = (post) => {
|
||||||
|
post.isLiked = !post.isLiked;
|
||||||
|
post.likeCount += post.isLiked ? 1 : -1;
|
||||||
|
ElMessage.success(post.isLiked ? "点赞成功" : "取消点赞");
|
||||||
|
};
|
||||||
|
|
||||||
|
const handlePublishSuccess = () => {
|
||||||
|
// 重置分页并重新加载
|
||||||
|
listQuery.value.pageCurrent = 1;
|
||||||
|
loadPosts();
|
||||||
|
};
|
||||||
|
|
||||||
|
const emit = defineEmits(["openDetail"]);
|
||||||
|
|
||||||
|
const handlePostClick = (post) => {
|
||||||
|
emit("openDetail", post);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
@import "../styles/luntan-tech.scss";
|
||||||
|
|
||||||
|
.post-list {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 贴吧式顶栏:圆角条 + 左图标标题统计 + 右胶囊按钮(外层页面仍为原深蓝网格背景)
|
||||||
|
.bar-head {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 16px;
|
||||||
|
margin-bottom: 18px;
|
||||||
|
padding: 14px 18px;
|
||||||
|
border-radius: 12px;
|
||||||
|
background: linear-gradient(
|
||||||
|
160deg,
|
||||||
|
rgba(16, 46, 96, 0.88) 0%,
|
||||||
|
rgba(12, 34, 76, 0.82) 100%
|
||||||
|
);
|
||||||
|
border: 1px solid rgba(0, 163, 255, 0.28);
|
||||||
|
box-shadow: inset 0 1px 0 rgba(0, 220, 255, 0.1),
|
||||||
|
0 4px 20px rgba(0, 0, 0, 0.25);
|
||||||
|
}
|
||||||
|
|
||||||
|
.bar-head-left {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 14px;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bar-logo {
|
||||||
|
flex-shrink: 0;
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
border-radius: 10px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: rgba(255, 255, 255, 0.96);
|
||||||
|
box-shadow: 0 2px 10px rgba(0, 100, 180, 0.2);
|
||||||
|
|
||||||
|
.el-icon {
|
||||||
|
font-size: 26px;
|
||||||
|
color: #00a3ff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.bar-head-text {
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bar-title {
|
||||||
|
font-size: 17px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: $lt-text;
|
||||||
|
letter-spacing: 0.02em;
|
||||||
|
line-height: 1.3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bar-meta {
|
||||||
|
margin-top: 4px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: $lt-text-muted;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bar-actions {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bar-pill {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 4px;
|
||||||
|
padding: 8px 18px;
|
||||||
|
border-radius: 999px;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: rgba(230, 240, 255, 0.95);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.22);
|
||||||
|
background: rgba(255, 255, 255, 0.06);
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease;
|
||||||
|
|
||||||
|
.el-icon {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: rgba(255, 255, 255, 0.1);
|
||||||
|
border-color: rgba(0, 227, 255, 0.35);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.bar-pill-primary {
|
||||||
|
border-color: rgba(0, 227, 255, 0.4);
|
||||||
|
background: rgba(0, 60, 120, 0.35);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: rgba(0, 100, 180, 0.45);
|
||||||
|
box-shadow: 0 0 14px rgba(0, 163, 255, 0.25);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 置顶缩略区(仅标题)
|
||||||
|
.pinned-block {
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pinned-list {
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 10px 12px;
|
||||||
|
background: rgba(220, 235, 255, 0.12);
|
||||||
|
border: 1px solid rgba(0, 163, 255, 0.22);
|
||||||
|
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.06);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pinned-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 10px;
|
||||||
|
padding: 8px 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 4px;
|
||||||
|
transition: background 0.15s ease;
|
||||||
|
|
||||||
|
& + .pinned-row {
|
||||||
|
border-top: 1px solid rgba(0, 163, 255, 0.12);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: rgba(0, 163, 255, 0.08);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.pinned-badge {
|
||||||
|
flex-shrink: 0;
|
||||||
|
padding: 2px 8px;
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: $lt-cyan-mid;
|
||||||
|
border: 1px solid rgba(0, 163, 255, 0.45);
|
||||||
|
border-radius: 4px;
|
||||||
|
background: rgba(0, 40, 90, 0.35);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pinned-title {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: $lt-text;
|
||||||
|
line-height: 1.45;
|
||||||
|
word-break: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 置顶与普通帖之间的分界
|
||||||
|
.list-divider {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
margin: 16px 0 14px;
|
||||||
|
padding: 0 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.divider-line {
|
||||||
|
flex: 1;
|
||||||
|
height: 1px;
|
||||||
|
background: linear-gradient(
|
||||||
|
90deg,
|
||||||
|
transparent,
|
||||||
|
rgba(0, 163, 255, 0.45),
|
||||||
|
transparent
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
.divider-text {
|
||||||
|
flex-shrink: 0;
|
||||||
|
font-size: 12px;
|
||||||
|
color: $lt-text-muted;
|
||||||
|
letter-spacing: 0.08em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.posts-container {
|
||||||
|
min-height: 400px;
|
||||||
|
|
||||||
|
:deep(.el-loading-mask) {
|
||||||
|
background-color: rgba(0, 5, 16, 0.65);
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-loading-spinner .path) {
|
||||||
|
stroke: #3db8ff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.post-empty {
|
||||||
|
padding: 48px 0;
|
||||||
|
|
||||||
|
:deep(.el-empty__description) {
|
||||||
|
color: rgba(180, 200, 230, 0.65);
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-empty__image) {
|
||||||
|
opacity: 0.85;
|
||||||
|
filter: brightness(0.95);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-more {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 20px;
|
||||||
|
color: rgba(160, 185, 215, 0.75);
|
||||||
|
font-size: 14px;
|
||||||
|
gap: 8px;
|
||||||
|
|
||||||
|
.el-icon {
|
||||||
|
font-size: 16px;
|
||||||
|
color: #3db8ff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-more {
|
||||||
|
text-align: center;
|
||||||
|
padding: 20px;
|
||||||
|
color: rgba(140, 165, 200, 0.55);
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -0,0 +1,172 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog
|
||||||
|
v-model="dialogVisible"
|
||||||
|
class="luntan-tech-dialog"
|
||||||
|
title="发布帖子"
|
||||||
|
width="60%"
|
||||||
|
:before-close="handleClose"
|
||||||
|
>
|
||||||
|
<div style="overflow: auto; height: 60vh">
|
||||||
|
<el-form :model="form" :rules="rules" ref="formRef" label-width="80px">
|
||||||
|
<el-form-item label="标题" prop="title">
|
||||||
|
<el-input
|
||||||
|
v-model="form.title"
|
||||||
|
placeholder="请输入帖子标题"
|
||||||
|
maxlength="50"
|
||||||
|
show-word-limit
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="内容" prop="content">
|
||||||
|
<el-input
|
||||||
|
v-model="form.content"
|
||||||
|
type="textarea"
|
||||||
|
:rows="6"
|
||||||
|
placeholder="请输入帖子内容"
|
||||||
|
maxlength="500"
|
||||||
|
show-word-limit
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="表情">
|
||||||
|
<V3Emoji
|
||||||
|
:options-name="optionsName"
|
||||||
|
@click-emoji="onEmojiClick"
|
||||||
|
:recent="true"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="图片">
|
||||||
|
<Upload v-model="imageIds" :limit="9" :isImg="true" :isAll="true" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
|
<el-button @click="handleClose">取消</el-button>
|
||||||
|
<el-button type="primary" @click="handleSubmit" :loading="submitting">
|
||||||
|
发布
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, watch } from "vue";
|
||||||
|
import { ElMessage } from "element-plus";
|
||||||
|
import V3Emoji from "vue3-emoji";
|
||||||
|
import { tbGsxtXxltSave } from "@/api/tbGsxtXxltHf";
|
||||||
|
import { getItem } from "@/utils/storage.js";
|
||||||
|
import Upload from "@/components/MyComponents/Upload/index.vue";
|
||||||
|
|
||||||
|
const optionsName = {
|
||||||
|
"Smileys & Emotion": "笑脸&表情",
|
||||||
|
"Food & Drink": "食物&饮料",
|
||||||
|
"Animals & Nature": "动物&自然",
|
||||||
|
"Travel & Places": "旅行&地点",
|
||||||
|
"People & Body": "人物&身体",
|
||||||
|
Objects: "物品",
|
||||||
|
Symbols: "符号",
|
||||||
|
Flags: "旗帜",
|
||||||
|
Activities: "活动"
|
||||||
|
};
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
modelValue: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(["update:modelValue", "success"]);
|
||||||
|
|
||||||
|
const dialogVisible = ref(false);
|
||||||
|
const formRef = ref();
|
||||||
|
const submitting = ref(false);
|
||||||
|
const imageIds = ref([]);
|
||||||
|
|
||||||
|
const form = ref({
|
||||||
|
title: "",
|
||||||
|
content: ""
|
||||||
|
});
|
||||||
|
|
||||||
|
const rules = {
|
||||||
|
title: [{ required: true, message: "请输入标题", trigger: "blur" }],
|
||||||
|
content: [{ required: true, message: "请输入内容", trigger: "blur" }]
|
||||||
|
};
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.modelValue,
|
||||||
|
(val) => {
|
||||||
|
dialogVisible.value = val;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
watch(dialogVisible, (val) => {
|
||||||
|
emit("update:modelValue", val);
|
||||||
|
if (!val) {
|
||||||
|
resetForm();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const onEmojiClick = (emoji) => {
|
||||||
|
form.value.content += emoji;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleClose = () => {
|
||||||
|
dialogVisible.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSubmit = async () => {
|
||||||
|
if (!formRef.value) return;
|
||||||
|
|
||||||
|
await formRef.value.validate(async (valid) => {
|
||||||
|
if (valid) {
|
||||||
|
submitting.value = true;
|
||||||
|
try {
|
||||||
|
const ltmasg = getItem("ltmasg");
|
||||||
|
|
||||||
|
const postData = {
|
||||||
|
title: form.value.title,
|
||||||
|
content: form.value.content,
|
||||||
|
tp: imageIds.value.join(","),
|
||||||
|
fbrsfzh: ltmasg?.sfzh || "",
|
||||||
|
fbrxm: ltmasg?.xm || "",
|
||||||
|
fbrtx: ltmasg?.tx || ""
|
||||||
|
};
|
||||||
|
|
||||||
|
await tbGsxtXxltSave(postData);
|
||||||
|
|
||||||
|
ElMessage.success("发布成功");
|
||||||
|
emit("success");
|
||||||
|
handleClose();
|
||||||
|
} catch (error) {
|
||||||
|
console.error("发布失败", error);
|
||||||
|
ElMessage.error("发布失败");
|
||||||
|
} finally {
|
||||||
|
submitting.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const resetForm = () => {
|
||||||
|
form.value = {
|
||||||
|
title: "",
|
||||||
|
content: ""
|
||||||
|
};
|
||||||
|
imageIds.value = [];
|
||||||
|
formRef.value?.resetFields();
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
// Upload 等子组件样式在各自内部
|
||||||
|
::v-deep .form-item-box {
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
@import "../styles/luntan-dialog-tech.scss";
|
||||||
|
</style>
|
||||||
@ -0,0 +1,162 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog
|
||||||
|
v-model="dialogVisible"
|
||||||
|
class="luntan-tech-dialog"
|
||||||
|
title="发表回复"
|
||||||
|
width="600px"
|
||||||
|
:before-close="handleClose"
|
||||||
|
>
|
||||||
|
<el-form :model="form" :rules="rules" ref="formRef">
|
||||||
|
<el-form-item prop="content">
|
||||||
|
<el-input
|
||||||
|
v-model="form.content"
|
||||||
|
type="textarea"
|
||||||
|
:rows="8"
|
||||||
|
placeholder="发点干货 文明第一步"
|
||||||
|
maxlength="500"
|
||||||
|
show-word-limit
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item>
|
||||||
|
<div class="emoji-row">
|
||||||
|
<V3Emoji
|
||||||
|
:options-name="optionsName"
|
||||||
|
@click-emoji="onEmojiClick"
|
||||||
|
:recent="true"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
|
<el-button @click="handleClose">取消</el-button>
|
||||||
|
<el-button type="primary" @click="handleSubmit" :loading="submitting">
|
||||||
|
回复
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, watch } from "vue";
|
||||||
|
import { ElMessage } from "element-plus";
|
||||||
|
import V3Emoji from "vue3-emoji";
|
||||||
|
import { getItem } from "@/utils/storage.js";
|
||||||
|
import {
|
||||||
|
tbGsxtXxltHfid,
|
||||||
|
tbGsxtXxltHfSave,
|
||||||
|
tbGsxtXxltHfSelectList
|
||||||
|
} from "@/api/tbGsxtXxltHf.js";
|
||||||
|
|
||||||
|
const optionsName = {
|
||||||
|
"Smileys & Emotion": "笑脸&表情",
|
||||||
|
"Food & Drink": "食物&饮料",
|
||||||
|
"Animals & Nature": "动物&自然",
|
||||||
|
"Travel & Places": "旅行&地点",
|
||||||
|
"People & Body": "人物&身体",
|
||||||
|
Objects: "物品",
|
||||||
|
Symbols: "符号",
|
||||||
|
Flags: "旗帜",
|
||||||
|
Activities: "活动"
|
||||||
|
};
|
||||||
|
const props = defineProps({
|
||||||
|
modelValue: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
replyTo: {
|
||||||
|
type: Object,
|
||||||
|
default: null
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(["update:modelValue", "success"]);
|
||||||
|
|
||||||
|
const dialogVisible = ref(false);
|
||||||
|
const formRef = ref();
|
||||||
|
const submitting = ref(false);
|
||||||
|
|
||||||
|
const form = ref({
|
||||||
|
content: ""
|
||||||
|
});
|
||||||
|
|
||||||
|
const rules = {
|
||||||
|
content: [{ required: true, message: "请输入回复内容", trigger: "blur" }]
|
||||||
|
};
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.modelValue,
|
||||||
|
(val) => {
|
||||||
|
dialogVisible.value = val;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
watch(dialogVisible, (val) => {
|
||||||
|
emit("update:modelValue", val);
|
||||||
|
if (!val) {
|
||||||
|
resetForm();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const onEmojiClick = (emoji) => {
|
||||||
|
form.value.content += emoji;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleClose = () => {
|
||||||
|
dialogVisible.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSubmit = async () => {
|
||||||
|
if (!formRef.value) return;
|
||||||
|
await formRef.value.validate(async (valid) => {
|
||||||
|
if (valid) {
|
||||||
|
submitting.value = true;
|
||||||
|
try {
|
||||||
|
const ltmasg = getItem("ltmasg");
|
||||||
|
const promes = {
|
||||||
|
hfnr: form.value.content,
|
||||||
|
hfrsfzh: ltmasg.sfzh,
|
||||||
|
hfrtx: ltmasg.tx,
|
||||||
|
hfrxm: ltmasg.xm,
|
||||||
|
ltid: props.replyTo.id,
|
||||||
|
sfyjhf: "1"
|
||||||
|
// hftp: hfrsfzh.value.hftp ? hfrsfzh.value.hftp.join(',') : ''
|
||||||
|
};
|
||||||
|
|
||||||
|
// 这里替换为实际的API调用
|
||||||
|
await tbGsxtXxltHfSave(promes);
|
||||||
|
// await new Promise(resolve => setTimeout(resolve, 1000))
|
||||||
|
ElMessage.success("回复成功");
|
||||||
|
emit("success", form.value);
|
||||||
|
handleClose();
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
|
||||||
|
ElMessage.error("回复失败");
|
||||||
|
} finally {
|
||||||
|
submitting.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const resetForm = () => {
|
||||||
|
form.value = {
|
||||||
|
content: ""
|
||||||
|
};
|
||||||
|
formRef.value?.resetFields();
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.emoji-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
@import '../styles/luntan-dialog-tech.scss';
|
||||||
|
</style>
|
||||||
346
src/views/backOfficeSystem/luntan copy/components/UserCard.vue
Normal file
346
src/views/backOfficeSystem/luntan copy/components/UserCard.vue
Normal file
@ -0,0 +1,346 @@
|
|||||||
|
<template>
|
||||||
|
<div class="user-card">
|
||||||
|
<div class="user-card-head">
|
||||||
|
<div class="user-avatar">
|
||||||
|
<div class="avatar-wrapper" @click="showAvatarDialog = true">
|
||||||
|
<el-avatar :size="56" :src="avatarUrl">
|
||||||
|
<img src="@/assets/images/mr.png" />
|
||||||
|
</el-avatar>
|
||||||
|
<div class="avatar-overlay">
|
||||||
|
<el-icon class="upload-icon">
|
||||||
|
<Camera />
|
||||||
|
</el-icon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="user-card-head-text">
|
||||||
|
<div class="name-row">
|
||||||
|
<span class="nickname">{{ userInfo.nickname || '用户信息' }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="sub-stats">内部论坛 · 已登录</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="user-info">
|
||||||
|
<div class="info-item clickable" @click="showNicknameDialog = true">
|
||||||
|
<span class="label">昵称</span>
|
||||||
|
<span class="value">{{ userInfo.nickname || '-' }}</span>
|
||||||
|
<el-icon class="edit-icon">
|
||||||
|
<Edit />
|
||||||
|
</el-icon>
|
||||||
|
</div>
|
||||||
|
<div class="info-item">
|
||||||
|
<span class="label">账号</span>
|
||||||
|
<span class="value">{{ userInfo.account || '-' }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="info-item">
|
||||||
|
<span class="label">姓名</span>
|
||||||
|
<span class="value">{{ userInfo.name || '-' }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="info-item">
|
||||||
|
<span class="label">部门</span>
|
||||||
|
<span class="value">{{ userInfo.department || '-' }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 更换头像对话框 -->
|
||||||
|
<ChangeAvatar v-model="showAvatarDialog" title="更换头像" @avatarUpdated="handleAvatarUpdated" />
|
||||||
|
|
||||||
|
<!-- 编辑昵称对话框 -->
|
||||||
|
<el-dialog
|
||||||
|
v-model="showNicknameDialog"
|
||||||
|
class="luntan-tech-dialog"
|
||||||
|
title="编辑昵称"
|
||||||
|
width="400px"
|
||||||
|
center
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
>
|
||||||
|
<el-form ref="nicknameFormRef" :model="nicknameForm" :rules="nicknameRules" label-width="80px">
|
||||||
|
<el-form-item label="昵称" prop="nickname">
|
||||||
|
<el-input v-model="nicknameForm.nickname" placeholder="请输入昵称" maxlength="20" show-word-limit />
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<el-button @click="showNicknameDialog = false">取消</el-button>
|
||||||
|
<el-button type="primary" @click="handleSaveNickname">保存</el-button>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, reactive, computed, onMounted } from 'vue'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
import { Camera, Edit } from '@element-plus/icons-vue'
|
||||||
|
import { getItem, setItem, removeItem } from '@/utils/storage.js'
|
||||||
|
import { setAddress } from '@/utils/tools'
|
||||||
|
import { tbGsxtXxltTxTxQueryBySfzh, tbGsxtXxltTxTxSave } from '@/api/tbGsxtXxltHf.js'
|
||||||
|
import ChangeAvatar from './ChangeAvatar.vue'
|
||||||
|
|
||||||
|
const showAvatarDialog = ref(false)
|
||||||
|
const showNicknameDialog = ref(false)
|
||||||
|
const nicknameFormRef = ref()
|
||||||
|
|
||||||
|
const userInfo = ref({
|
||||||
|
avatar: '',
|
||||||
|
account: '',
|
||||||
|
name: '',
|
||||||
|
department: '',
|
||||||
|
nickname: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
const nicknameForm = reactive({
|
||||||
|
nickname: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
const nicknameRules = {
|
||||||
|
nickname: [
|
||||||
|
{ required: true, message: '请输入昵称', trigger: 'blur' },
|
||||||
|
{ min: 2, max: 20, message: '昵称长度在 2 到 20 个字符', trigger: 'blur' }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
const avatarUrl = computed(() => {
|
||||||
|
return userInfo.value.avatar ? setAddress(userInfo.value.avatar) : ''
|
||||||
|
})
|
||||||
|
|
||||||
|
// 加载用户信息
|
||||||
|
const loadUserInfo = async () => {
|
||||||
|
const sfzh = getItem('idEntityCard')
|
||||||
|
let ltmasg = getItem('ltmasg')
|
||||||
|
|
||||||
|
if (!ltmasg) {
|
||||||
|
try {
|
||||||
|
const res = await tbGsxtXxltTxTxQueryBySfzh({ sfzh: sfzh })
|
||||||
|
console.log(res);
|
||||||
|
|
||||||
|
const deptId = getItem('deptId')?.[0]
|
||||||
|
ltmasg = {
|
||||||
|
...res,
|
||||||
|
deptName: deptId?.deptName || ''
|
||||||
|
}
|
||||||
|
setItem('ltmasg', ltmasg)
|
||||||
|
} catch (error) {
|
||||||
|
console.error('加载用户信息失败:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ltmasg) {
|
||||||
|
userInfo.value = {
|
||||||
|
avatar: ltmasg.tx || '',
|
||||||
|
account: ltmasg.sfzh || '',
|
||||||
|
name: ltmasg.xm || '',
|
||||||
|
department: ltmasg.deptName || ltmasg.bm || '',
|
||||||
|
nickname: ltmasg.nc || ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理头像更新
|
||||||
|
const handleAvatarUpdated = async (newAvatar) => {
|
||||||
|
try {
|
||||||
|
const ltmasg = getItem('ltmasg')
|
||||||
|
const updateData = {
|
||||||
|
...ltmasg,
|
||||||
|
tx: newAvatar
|
||||||
|
}
|
||||||
|
|
||||||
|
await tbGsxtXxltTxTxSave(updateData)
|
||||||
|
removeItem('ltmasg')
|
||||||
|
await loadUserInfo()
|
||||||
|
ElMessage.success('头像更新成功')
|
||||||
|
} catch (error) {
|
||||||
|
console.error('更新头像失败:', error)
|
||||||
|
ElMessage.error('头像更新失败,请重试')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理保存昵称
|
||||||
|
const handleSaveNickname = async () => {
|
||||||
|
if (!nicknameFormRef.value) return
|
||||||
|
|
||||||
|
await nicknameFormRef.value.validate(async (valid) => {
|
||||||
|
if (valid) {
|
||||||
|
try {
|
||||||
|
const ltmasg = getItem('ltmasg')
|
||||||
|
const updateData = {
|
||||||
|
...ltmasg,
|
||||||
|
nc: nicknameForm.nickname
|
||||||
|
}
|
||||||
|
|
||||||
|
await tbGsxtXxltTxTxSave(updateData)
|
||||||
|
removeItem('ltmasg')
|
||||||
|
await loadUserInfo()
|
||||||
|
showNicknameDialog.value = false
|
||||||
|
ElMessage.success('昵称保存成功')
|
||||||
|
} catch (error) {
|
||||||
|
console.error('保存昵称失败:', error)
|
||||||
|
ElMessage.error('昵称保存失败,请重试')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 监听昵称对话框打开,初始化表单
|
||||||
|
const openNicknameDialog = () => {
|
||||||
|
nicknameForm.nickname = userInfo.value.nickname
|
||||||
|
}
|
||||||
|
|
||||||
|
// 监听对话框显示状态
|
||||||
|
const unwatchNickname = () => {
|
||||||
|
if (showNicknameDialog.value) {
|
||||||
|
openNicknameDialog()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
loadUserInfo()
|
||||||
|
})
|
||||||
|
|
||||||
|
// 监听昵称对话框
|
||||||
|
const stopWatch = () => {
|
||||||
|
if (showNicknameDialog.value) {
|
||||||
|
nicknameForm.nickname = userInfo.value.nickname
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用 watch 监听对话框状态
|
||||||
|
import { watch } from 'vue'
|
||||||
|
watch(showNicknameDialog, (newVal) => {
|
||||||
|
if (newVal) {
|
||||||
|
nicknameForm.nickname = userInfo.value.nickname
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
@import '../styles/luntan-tech.scss';
|
||||||
|
|
||||||
|
.user-card {
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 18px 16px 16px;
|
||||||
|
@include lt-panel-frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-card-head {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 14px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
padding-bottom: 14px;
|
||||||
|
border-bottom: 1px solid rgba(255, 255, 255, 0.06);
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-avatar {
|
||||||
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
.avatar-wrapper {
|
||||||
|
position: relative;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 50%;
|
||||||
|
overflow: hidden;
|
||||||
|
border: 2px solid rgba(100, 180, 255, 0.35);
|
||||||
|
|
||||||
|
&:hover .avatar-overlay {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar-overlay {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: rgba(0, 0, 0, 0.55);
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.3s ease;
|
||||||
|
border-radius: 50%;
|
||||||
|
|
||||||
|
.upload-icon {
|
||||||
|
font-size: 22px;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-card-head-text {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.name-row {
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nickname {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #f0f6ff;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sub-stats {
|
||||||
|
font-size: 12px;
|
||||||
|
color: rgba(180, 200, 230, 0.55);
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-info {
|
||||||
|
.info-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
font-size: 13px;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.clickable {
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 6px 8px;
|
||||||
|
margin-left: -8px;
|
||||||
|
margin-right: -8px;
|
||||||
|
border-radius: 6px;
|
||||||
|
transition: background-color 0.2s ease;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: rgba(255, 255, 255, 0.06);
|
||||||
|
|
||||||
|
.edit-icon {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.label {
|
||||||
|
color: rgba(160, 185, 215, 0.55);
|
||||||
|
min-width: 40px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.value {
|
||||||
|
color: rgba(220, 230, 245, 0.88);
|
||||||
|
flex: 1;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
.edit-icon {
|
||||||
|
margin-left: 6px;
|
||||||
|
color: #5eb8ff;
|
||||||
|
font-size: 14px;
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.2s ease;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
@import '../styles/luntan-dialog-tech.scss';
|
||||||
|
</style>
|
||||||
333
src/views/backOfficeSystem/luntan copy/index.vue
Normal file
333
src/views/backOfficeSystem/luntan copy/index.vue
Normal file
@ -0,0 +1,333 @@
|
|||||||
|
<template>
|
||||||
|
<div class="luntan-container">
|
||||||
|
<!-- 列表页:主列帖子 + 右侧信息栏 -->
|
||||||
|
<template v-if="!showDetail">
|
||||||
|
<div class="luntan-main">
|
||||||
|
<PostList @openDetail="handleOpenDetail" />
|
||||||
|
</div>
|
||||||
|
<aside class="luntan-sidebar">
|
||||||
|
<UserCard />
|
||||||
|
<div class="hot-news-card" v-loading="hotLoading">
|
||||||
|
<div class="hot-news-head">
|
||||||
|
<span class="hot-news-title">热度消息</span>
|
||||||
|
<span class="hot-news-badge">HOT</span>
|
||||||
|
</div>
|
||||||
|
<ul class="hot-news-list">
|
||||||
|
<li
|
||||||
|
v-for="(item, index) in hotList"
|
||||||
|
:key="item.id"
|
||||||
|
class="hot-news-item"
|
||||||
|
@click="handleOpenDetail(item)"
|
||||||
|
>
|
||||||
|
<span class="hot-rank" :class="{ 'is-top': index < 3 }">{{
|
||||||
|
index + 1
|
||||||
|
}}</span>
|
||||||
|
<span class="hot-item-title">{{ item.lineTitle }}</span>
|
||||||
|
</li>
|
||||||
|
<li
|
||||||
|
v-if="!hotLoading && hotList.length === 0"
|
||||||
|
class="hot-news-empty"
|
||||||
|
>
|
||||||
|
暂无热度内容
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</aside>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 详情页 -->
|
||||||
|
<template v-else>
|
||||||
|
<div class="luntan-detail-wrap">
|
||||||
|
<div class="luntan-detail">
|
||||||
|
<PostDetail :post-id="currentPostId" @back="handleBack" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, computed, onMounted } from "vue";
|
||||||
|
import UserCard from "./components/UserCard.vue";
|
||||||
|
import PostList from "./components/PostList.vue";
|
||||||
|
import PostDetail from "./components/PostDetail.vue";
|
||||||
|
import { tbGsxtXxltSelectPage } from "@/api/tbGsxtXxltHf";
|
||||||
|
import { setAddress } from "@/utils/tools";
|
||||||
|
|
||||||
|
const showDetail = ref(false);
|
||||||
|
const currentPostId = ref(null);
|
||||||
|
|
||||||
|
const hotList = ref([]);
|
||||||
|
const hotLoading = ref(false);
|
||||||
|
|
||||||
|
function lineTitleFromRecord(item) {
|
||||||
|
const tit = (item.title || "").trim();
|
||||||
|
if (tit) {
|
||||||
|
return tit.length > 40 ? `${tit.slice(0, 40)}…` : tit;
|
||||||
|
}
|
||||||
|
const t = (item.content || "").trim();
|
||||||
|
if (!t) return "无标题";
|
||||||
|
const idx = t.indexOf("\n");
|
||||||
|
const first = idx === -1 ? t : t.slice(0, idx).trim();
|
||||||
|
const line = first || t.slice(0, 60);
|
||||||
|
return line.length > 40 ? `${line.slice(0, 40)}…` : line;
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapHotPost(item) {
|
||||||
|
return {
|
||||||
|
id: item.id,
|
||||||
|
lineTitle: lineTitleFromRecord(item),
|
||||||
|
userName: item.fbrxm || "匿名用户",
|
||||||
|
userAvatar: item.fbrtx ? setAddress(item.fbrtx) : "",
|
||||||
|
userTag: item.userTag || "",
|
||||||
|
publishTime: item.time || "",
|
||||||
|
content: item.content || "",
|
||||||
|
images: item.tp ? item.tp.split(",").map((img) => setAddress(img)) : [],
|
||||||
|
commentCount: item.hfsl || 0,
|
||||||
|
likeCount: item.likeCount || 0,
|
||||||
|
isPremium: item.sfzd === 1,
|
||||||
|
isLiked: false,
|
||||||
|
ssbm: item.ssbm,
|
||||||
|
rawData: item
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadHotNews = async () => {
|
||||||
|
hotLoading.value = true;
|
||||||
|
try {
|
||||||
|
const res = await tbGsxtXxltSelectPage({
|
||||||
|
pageCurrent: 1,
|
||||||
|
pageSize: 12
|
||||||
|
});
|
||||||
|
const records = res.records || [];
|
||||||
|
hotList.value = records.map(mapHotPost);
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
hotList.value = [];
|
||||||
|
} finally {
|
||||||
|
hotLoading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
loadHotNews();
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleOpenDetail = (post) => {
|
||||||
|
currentPostId.value = post.id;
|
||||||
|
showDetail.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleBack = () => {
|
||||||
|
showDetail.value = false;
|
||||||
|
currentPostId.value = null;
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
@import "./styles/luntan-tech.scss";
|
||||||
|
|
||||||
|
.luntan-container {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
gap: 24px;
|
||||||
|
padding: 20px 24px;
|
||||||
|
min-height: calc(100vh - 60px);
|
||||||
|
max-height: calc(100vh - 60px);
|
||||||
|
overflow: hidden;
|
||||||
|
background: linear-gradient(165deg, $lt-bg 0%, $lt-bg-soft 42%, #0a1830 100%);
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
background-image: linear-gradient(
|
||||||
|
rgba(0, 163, 255, 0.04) 1px,
|
||||||
|
transparent 1px
|
||||||
|
),
|
||||||
|
linear-gradient(90deg, rgba(0, 163, 255, 0.04) 1px, transparent 1px);
|
||||||
|
background-size: 32px 32px;
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.luntan-main {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
overflow-y: auto;
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.luntan-sidebar {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
width: 300px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
height: calc(100vh - 100px);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 16px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hot-news-card {
|
||||||
|
position: relative;
|
||||||
|
// flex: 1;
|
||||||
|
height: calc(80% - 100px);
|
||||||
|
min-height: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
padding: 0;
|
||||||
|
border-radius: 6px;
|
||||||
|
@include lt-panel-frame;
|
||||||
|
background: linear-gradient(
|
||||||
|
165deg,
|
||||||
|
rgba(14, 40, 82, 0.9) 0%,
|
||||||
|
rgba(10, 28, 58, 0.88) 100%
|
||||||
|
) !important;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
:deep(.el-loading-mask) {
|
||||||
|
background-color: rgba(4, 12, 28, 0.55);
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-loading-spinner .path) {
|
||||||
|
stroke: $lt-cyan-mid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.hot-news-head {
|
||||||
|
flex-shrink: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 10px;
|
||||||
|
padding: 14px 16px 12px;
|
||||||
|
border-bottom: 1px solid rgba(0, 163, 255, 0.22);
|
||||||
|
background: linear-gradient(
|
||||||
|
90deg,
|
||||||
|
rgba(0, 163, 255, 0.1) 0%,
|
||||||
|
transparent 70%
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hot-news-title {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: $lt-text;
|
||||||
|
letter-spacing: 0.08em;
|
||||||
|
text-shadow: 0 0 14px rgba(0, 227, 255, 0.35);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hot-news-badge {
|
||||||
|
flex-shrink: 0;
|
||||||
|
padding: 3px 10px;
|
||||||
|
font-size: 10px;
|
||||||
|
font-weight: 800;
|
||||||
|
letter-spacing: 0.12em;
|
||||||
|
color: #1a0a00;
|
||||||
|
border-radius: 4px;
|
||||||
|
background: linear-gradient(180deg, #ffb347 0%, #ff9900 100%);
|
||||||
|
border: 1px solid rgba(255, 200, 120, 0.5);
|
||||||
|
box-shadow: 0 0 12px rgba(255, 153, 0, 0.35);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hot-news-list {
|
||||||
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
|
margin: 0;
|
||||||
|
padding: 8px 10px 12px;
|
||||||
|
list-style: none;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hot-news-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 10px;
|
||||||
|
padding: 10px 8px;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.15s ease, box-shadow 0.15s ease;
|
||||||
|
|
||||||
|
& + .hot-news-item {
|
||||||
|
border-top: 1px solid rgba(0, 163, 255, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: rgba(0, 163, 255, 0.1);
|
||||||
|
box-shadow: inset 0 0 0 1px rgba(0, 227, 255, 0.12);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.hot-rank {
|
||||||
|
flex-shrink: 0;
|
||||||
|
width: 22px;
|
||||||
|
height: 22px;
|
||||||
|
line-height: 22px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: rgba(210, 225, 245, 0.92);
|
||||||
|
border-radius: 4px;
|
||||||
|
background: rgba(0, 40, 80, 0.45);
|
||||||
|
border: 1px solid rgba(0, 163, 255, 0.2);
|
||||||
|
|
||||||
|
&.is-top {
|
||||||
|
color: #1a0a00;
|
||||||
|
background: linear-gradient(180deg, #ffd699 0%, #ff9900 100%);
|
||||||
|
border-color: rgba(255, 180, 80, 0.55);
|
||||||
|
box-shadow: 0 0 8px rgba(255, 153, 0, 0.25);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.hot-item-title {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
font-size: 13px;
|
||||||
|
line-height: 1.5;
|
||||||
|
color: rgba(236, 245, 255, 0.94);
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hot-news-item:hover .hot-item-title {
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hot-news-empty {
|
||||||
|
padding: 28px 12px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 13px;
|
||||||
|
color: rgba(200, 218, 240, 0.82);
|
||||||
|
list-style: none;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.luntan-detail-wrap {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
display: flex;
|
||||||
|
min-height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.luntan-detail {
|
||||||
|
height: 83vh;
|
||||||
|
flex: 1;
|
||||||
|
border-radius: 4px;
|
||||||
|
overflow-y: auto;
|
||||||
|
overflow-x: hidden;
|
||||||
|
@include lt-panel-frame;
|
||||||
|
box-shadow: $lt-glow-strong, 0 12px 40px rgba(0, 0, 0, 0.45);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<!-- 非 scoped:el-image-viewer 通过 Teleport 挂到 body,需全局选择器 -->
|
||||||
|
<style lang="scss">
|
||||||
|
@import "./styles/luntan-tech.scss";
|
||||||
|
</style>
|
||||||
@ -0,0 +1,104 @@
|
|||||||
|
@import "./luntan-tech.scss";
|
||||||
|
@import "./luntan-v3emoji-tech.scss";
|
||||||
|
|
||||||
|
.luntan-tech-dialog.el-dialog {
|
||||||
|
background: rgba(8, 20, 48, 0.98) !important;
|
||||||
|
border: 1px solid $lt-border;
|
||||||
|
border-radius: 4px;
|
||||||
|
box-shadow: $lt-glow-strong, 0 16px 48px rgba(0, 0, 0, 0.55);
|
||||||
|
}
|
||||||
|
|
||||||
|
.luntan-tech-dialog .el-dialog__header {
|
||||||
|
border-bottom: 1px solid $lt-border-dim;
|
||||||
|
padding: 14px 18px;
|
||||||
|
margin: 0;
|
||||||
|
background: rgba(8, 20, 48, 0.98) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.luntan-tech-dialog .el-dialog__title {
|
||||||
|
color: $lt-text;
|
||||||
|
font-weight: 600;
|
||||||
|
letter-spacing: 0.06em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.luntan-tech-dialog .el-dialog__headerbtn .el-dialog__close {
|
||||||
|
color: $lt-text-muted;
|
||||||
|
}
|
||||||
|
|
||||||
|
.luntan-tech-dialog .el-dialog__headerbtn:hover .el-dialog__close {
|
||||||
|
color: $lt-cyan;
|
||||||
|
}
|
||||||
|
|
||||||
|
.luntan-tech-dialog .el-dialog__body {
|
||||||
|
padding: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.luntan-tech-dialog .el-dialog__footer {
|
||||||
|
border-top: 1px solid $lt-border-dim;
|
||||||
|
padding: 12px 18px;
|
||||||
|
background: rgba(8, 20, 48, 0.98) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.luntan-tech-dialog .el-form-item__label {
|
||||||
|
color: $lt-text-muted;
|
||||||
|
}
|
||||||
|
|
||||||
|
.luntan-tech-dialog .el-input__wrapper {
|
||||||
|
background: rgba(10, 28, 58, 0.85) !important;
|
||||||
|
box-shadow: 0 0 0 1px rgba(0, 227, 255, 0.28) inset !important;
|
||||||
|
border-radius: 4px;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
box-shadow: 0 0 0 1px rgba(0, 227, 255, 0.4) inset !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-focus {
|
||||||
|
box-shadow: 0 0 0 1px rgba(0, 227, 255, 0.55) inset,
|
||||||
|
0 0 14px rgba(0, 163, 255, 0.22) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.luntan-tech-dialog .el-input__inner {
|
||||||
|
color: $lt-text-dim;
|
||||||
|
}
|
||||||
|
|
||||||
|
.luntan-tech-dialog .el-input__count,
|
||||||
|
.luntan-tech-dialog .el-input__count .el-input__count-inner {
|
||||||
|
background: transparent !important;
|
||||||
|
color: $lt-text-muted;
|
||||||
|
}
|
||||||
|
|
||||||
|
.luntan-tech-dialog .el-textarea__inner {
|
||||||
|
background: rgba(10, 28, 58, 0.9) !important;
|
||||||
|
color: $lt-text-dim;
|
||||||
|
border: 1px solid rgba(0, 227, 255, 0.3);
|
||||||
|
border-radius: 4px;
|
||||||
|
box-shadow: inset 0 0 20px rgba(20, 80, 140, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.luntan-tech-dialog .el-button--default {
|
||||||
|
background: rgba(15, 40, 75, 0.65);
|
||||||
|
border-color: rgba(0, 163, 255, 0.35);
|
||||||
|
color: $lt-text-dim;
|
||||||
|
}
|
||||||
|
|
||||||
|
.luntan-tech-dialog .el-button--primary {
|
||||||
|
background: linear-gradient(180deg, #00a3ff 0%, #0066bb 100%);
|
||||||
|
border-color: rgba(0, 227, 255, 0.5);
|
||||||
|
box-shadow: 0 0 16px rgba(0, 163, 255, 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.luntan-tech-dialog .el-upload--picture-card {
|
||||||
|
background: rgba(10, 28, 58, 0.75) !important;
|
||||||
|
border-color: rgba(0, 227, 255, 0.35) !important;
|
||||||
|
|
||||||
|
.el-icon {
|
||||||
|
color: $lt-cyan;
|
||||||
|
font-size: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border-color: rgba(0, 227, 255, 0.55) !important;
|
||||||
|
box-shadow: 0 0 14px rgba(0, 163, 255, 0.25);
|
||||||
|
}
|
||||||
|
}
|
||||||
103
src/views/backOfficeSystem/luntan copy/styles/luntan-tech.scss
Normal file
103
src/views/backOfficeSystem/luntan copy/styles/luntan-tech.scss
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
// 论坛模块 — 大屏科技风主题变量
|
||||||
|
$lt-bg: #0a1628;
|
||||||
|
$lt-bg-soft: #0d1f3c;
|
||||||
|
$lt-cyan: #00e5ff;
|
||||||
|
$lt-cyan-mid: #00a3ff;
|
||||||
|
$lt-panel: rgba(10, 30, 60, 0.85);
|
||||||
|
$lt-panel-soft: rgba(8, 24, 52, 0.65);
|
||||||
|
$lt-border: rgba(0, 227, 255, 0.38);
|
||||||
|
$lt-border-dim: rgba(0, 163, 255, 0.2);
|
||||||
|
$lt-text: #e8f4ff;
|
||||||
|
$lt-text-dim: rgba(140, 200, 230, 0.78);
|
||||||
|
$lt-text-muted: rgba(120, 170, 210, 0.55);
|
||||||
|
$lt-glow: 0 0 18px rgba(0, 163, 255, 0.35);
|
||||||
|
$lt-glow-strong: 0 0 28px rgba(0, 227, 255, 0.28);
|
||||||
|
|
||||||
|
@mixin lt-panel-frame {
|
||||||
|
background: $lt-panel;
|
||||||
|
border: 1px solid $lt-border;
|
||||||
|
box-shadow: $lt-glow, inset 0 1px 0 rgba(0, 220, 255, 0.12);
|
||||||
|
backdrop-filter: blur(8px);
|
||||||
|
}
|
||||||
|
|
||||||
|
@mixin lt-panel-soft-bg {
|
||||||
|
background: $lt-panel-soft;
|
||||||
|
border: 1px solid $lt-border-dim;
|
||||||
|
box-shadow: inset 0 1px 0 rgba(0, 220, 255, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
@mixin lt-corner-brackets {
|
||||||
|
position: relative;
|
||||||
|
&::before,
|
||||||
|
&::after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
border-color: $lt-cyan-mid;
|
||||||
|
border-style: solid;
|
||||||
|
pointer-events: none;
|
||||||
|
opacity: 0.85;
|
||||||
|
}
|
||||||
|
&::before {
|
||||||
|
top: -1px;
|
||||||
|
left: -1px;
|
||||||
|
border-width: 2px 0 0 2px;
|
||||||
|
box-shadow: -1px -1px 8px rgba(0, 227, 255, 0.4);
|
||||||
|
}
|
||||||
|
&::after {
|
||||||
|
bottom: -1px;
|
||||||
|
right: -1px;
|
||||||
|
border-width: 0 2px 2px 0;
|
||||||
|
box-shadow: 1px 1px 8px rgba(0, 227, 255, 0.4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// el-image-viewer 全屏预览覆盖 — Teleport 到 body,全局生效
|
||||||
|
.el-image-viewer__wrapper {
|
||||||
|
background: rgba(4, 10, 24, 0.95) !important;
|
||||||
|
backdrop-filter: blur(4px);
|
||||||
|
|
||||||
|
.el-image-viewer__mask {
|
||||||
|
background: rgba(0, 10, 30, 0.78) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-image-viewer__btn {
|
||||||
|
color: $lt-cyan;
|
||||||
|
border: 1px solid rgba(0, 227, 255, 0.3);
|
||||||
|
background: rgba(10, 28, 58, 0.65);
|
||||||
|
box-shadow: 0 0 10px rgba(0, 120, 200, 0.2);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: rgba(15, 45, 80, 0.88);
|
||||||
|
border-color: rgba(0, 227, 255, 0.55);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.el-image-viewer__close {
|
||||||
|
top: 24px;
|
||||||
|
right: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.el-image-viewer__prev {
|
||||||
|
left: 24px;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.el-image-viewer__next {
|
||||||
|
right: 24px;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-image-viewer__canvas {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-icon {
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,64 @@
|
|||||||
|
@import './luntan-tech.scss';
|
||||||
|
|
||||||
|
// vue3-emoji(dist/style.css)默认浅色/白底,与论坛科技风统一
|
||||||
|
@mixin lt-v3-emoji-vars {
|
||||||
|
--V3Emoji-backgroundColor: rgba(10, 28, 58, 0.96);
|
||||||
|
--V3Emoji-hoverColor: rgba(0, 100, 160, 0.22);
|
||||||
|
--V3Emoji-activeColor: rgba(0, 130, 200, 0.3);
|
||||||
|
--V3Emoji-fontColor: #{$lt-text};
|
||||||
|
--V3Emoji-borderColor: #{rgba(0, 227, 255, 0.38)};
|
||||||
|
--V3Emoji-borderFocusColor: #{$lt-cyan};
|
||||||
|
--V3Emoji-shadowColor: rgba(0, 40, 90, 0.45);
|
||||||
|
}
|
||||||
|
|
||||||
|
.luntan-tech-dialog,
|
||||||
|
.comment-list .reply-input-box,
|
||||||
|
.luntan-tech-dialog .emoji-row {
|
||||||
|
@include lt-v3-emoji-vars;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 组件内未使用 CSS 变量的原生 input / textarea(仍为白底)
|
||||||
|
.luntan-tech-dialog [class*='emojiInput'] input,
|
||||||
|
.comment-list .reply-input-box [class*='emojiInput'] input {
|
||||||
|
background: rgba(10, 28, 58, 0.92) !important;
|
||||||
|
color: $lt-text-dim !important;
|
||||||
|
border-color: rgba(0, 227, 255, 0.35) !important;
|
||||||
|
box-shadow: inset 0 0 12px rgba(0, 50, 100, 0.25) !important;
|
||||||
|
|
||||||
|
&::placeholder {
|
||||||
|
color: $lt-text-muted;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.luntan-tech-dialog [class*='emojiTextarea'] textarea,
|
||||||
|
.comment-list .reply-input-box [class*='emojiTextarea'] textarea {
|
||||||
|
background: rgba(10, 28, 58, 0.92) !important;
|
||||||
|
color: $lt-text-dim !important;
|
||||||
|
border-color: rgba(0, 227, 255, 0.35) !important;
|
||||||
|
box-shadow: inset 0 0 12px rgba(0, 50, 100, 0.25) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.luntan-tech-dialog [class*='emojiContainerOpenBtn'],
|
||||||
|
.luntan-tech-dialog [class*='emojiTextareaOpenBtn'],
|
||||||
|
.comment-list .reply-input-box [class*='emojiContainerOpenBtn'],
|
||||||
|
.comment-list .reply-input-box [class*='emojiTextareaOpenBtn'] {
|
||||||
|
color: $lt-cyan !important;
|
||||||
|
filter: drop-shadow(0 0 6px rgba(0, 227, 255, 0.35));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 表情面板可能 teleport / 挂到 body,需单独写选择器
|
||||||
|
[class*='V3Emoji-vue'][class*='__pollup___'],
|
||||||
|
[class*='PollUp-vue'][class*='__pollup___'] {
|
||||||
|
@include lt-v3-emoji-vars;
|
||||||
|
}
|
||||||
|
|
||||||
|
[id='EmojiItem'],
|
||||||
|
[id*='EmojiItem'] {
|
||||||
|
::-webkit-scrollbar-thumb {
|
||||||
|
background-color: rgba(0, 163, 255, 0.45) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-track {
|
||||||
|
background: rgba(8, 20, 48, 0.88) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,6 +1,14 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-dialog :model-value="modelValue" center width="500px" :destroy-on-close="true" :title="title" @close="close"
|
<el-dialog
|
||||||
:close-on-click-modal="false">
|
class="luntan-tech-dialog"
|
||||||
|
:model-value="modelValue"
|
||||||
|
center
|
||||||
|
width="500px"
|
||||||
|
:destroy-on-close="true"
|
||||||
|
:title="title"
|
||||||
|
@close="close"
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
>
|
||||||
<div class="avatar-upload-container">
|
<div class="avatar-upload-container">
|
||||||
<div class="avatar-preview">
|
<div class="avatar-preview">
|
||||||
<img v-if="avatarUrl" :src="avatarUrl" alt="预览头像" class="preview-image">
|
<img v-if="avatarUrl" :src="avatarUrl" alt="预览头像" class="preview-image">
|
||||||
@ -133,11 +141,13 @@ const close = () => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@import '../styles/luntan-tech.scss';
|
||||||
|
|
||||||
.avatar-upload-container {
|
.avatar-upload-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 20px;
|
padding: 12px 0 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.avatar-preview {
|
.avatar-preview {
|
||||||
@ -145,12 +155,13 @@ const close = () => {
|
|||||||
height: 160px;
|
height: 160px;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
border: 2px solid #e8e8e8;
|
border: 2px solid rgba(0, 227, 255, 0.4);
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
background-color: #f5f7fa;
|
background: rgba(10, 30, 60, 0.6);
|
||||||
|
box-shadow: 0 0 20px rgba(0, 120, 200, 0.2);
|
||||||
|
|
||||||
.preview-image {
|
.preview-image {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@ -163,11 +174,12 @@ const close = () => {
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
color: #909399;
|
color: $lt-text-muted;
|
||||||
|
|
||||||
.placeholder-icon {
|
.placeholder-icon {
|
||||||
font-size: 48px;
|
font-size: 48px;
|
||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
|
color: rgba(0, 227, 255, 0.45);
|
||||||
}
|
}
|
||||||
|
|
||||||
span {
|
span {
|
||||||
@ -185,15 +197,22 @@ const close = () => {
|
|||||||
|
|
||||||
.avatar-uploader {
|
.avatar-uploader {
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
|
|
||||||
|
:deep(.el-button--primary) {
|
||||||
|
background: linear-gradient(180deg, #00a3ff 0%, #0066bb 100%);
|
||||||
|
border-color: rgba(0, 227, 255, 0.5);
|
||||||
|
box-shadow: 0 0 12px rgba(0, 163, 255, 0.35);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.upload-tips {
|
.upload-tips {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 12px;
|
padding: 12px;
|
||||||
background-color: #f5f7fa;
|
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: #909399;
|
color: $lt-text-muted;
|
||||||
|
background: rgba(10, 30, 60, 0.65);
|
||||||
|
border: 1px solid $lt-border-dim;
|
||||||
|
|
||||||
p {
|
p {
|
||||||
margin: 4px 0;
|
margin: 4px 0;
|
||||||
@ -201,3 +220,7 @@ const close = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
@import '../styles/luntan-dialog-tech.scss';
|
||||||
|
</style>
|
||||||
|
|||||||
@ -28,12 +28,17 @@
|
|||||||
</el-icon>
|
</el-icon>
|
||||||
<span>{{ comment.likeCount || 0 }}</span>
|
<span>{{ comment.likeCount || 0 }}</span>
|
||||||
</div> -->
|
</div> -->
|
||||||
<div class="action-btn" @click="handleReply(comment)">
|
<div class="action-btn" @click="handleReply(comment)">回复</div>
|
||||||
回复
|
<div
|
||||||
</div>
|
v-if="comment.replies && comment.replies.length > 0"
|
||||||
<div v-if="comment.replies && comment.replies.length > 0" class="action-btn toggle-btn"
|
class="action-btn toggle-btn"
|
||||||
@click="toggleReplies(comment)">
|
@click="toggleReplies(comment)"
|
||||||
{{ comment.showReplies ? '收起' : `展开${comment.replies.length}条回复` }}
|
>
|
||||||
|
{{
|
||||||
|
comment.showReplies
|
||||||
|
? "收起"
|
||||||
|
: `展开${comment.replies.length}条回复`
|
||||||
|
}}
|
||||||
<el-icon :class="{ 'rotate-icon': comment.showReplies }">
|
<el-icon :class="{ 'rotate-icon': comment.showReplies }">
|
||||||
<ArrowDown />
|
<ArrowDown />
|
||||||
</el-icon>
|
</el-icon>
|
||||||
@ -45,13 +50,27 @@
|
|||||||
<transition name="slide-fade">
|
<transition name="slide-fade">
|
||||||
<div v-if="activeReplyId === comment.id" class="reply-input-box">
|
<div v-if="activeReplyId === comment.id" class="reply-input-box">
|
||||||
<div class="reply-label">回复 {{ comment.userName }}</div>
|
<div class="reply-label">回复 {{ comment.userName }}</div>
|
||||||
<el-input v-model="replyContent" type="textarea" :rows="3" placeholder="输入回复内容..."
|
<el-input
|
||||||
class="reply-textarea" />
|
v-model="replyContent"
|
||||||
|
type="textarea"
|
||||||
|
:rows="3"
|
||||||
|
placeholder="输入回复内容..."
|
||||||
|
class="reply-textarea"
|
||||||
|
/>
|
||||||
<div class="reply-actions">
|
<div class="reply-actions">
|
||||||
<V3Emoji :options-name="optionsName" @click-emoji="onEmojiClick" :recent="true" style="width: 40px;" />
|
<V3Emoji
|
||||||
|
:options-name="optionsName"
|
||||||
|
@click-emoji="onEmojiClick"
|
||||||
|
:recent="true"
|
||||||
|
style="width: 40px"
|
||||||
|
/>
|
||||||
<div class="reply-buttons">
|
<div class="reply-buttons">
|
||||||
<el-button size="small" @click="cancelReply">取消</el-button>
|
<el-button size="small" @click="cancelReply">取消</el-button>
|
||||||
<el-button size="small" type="primary" @click="submitReply(comment)">
|
<el-button
|
||||||
|
size="small"
|
||||||
|
type="primary"
|
||||||
|
@click="submitReply(comment)"
|
||||||
|
>
|
||||||
回复
|
回复
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
@ -60,9 +79,24 @@
|
|||||||
</transition>
|
</transition>
|
||||||
|
|
||||||
<!-- 二级评论列表 -->
|
<!-- 二级评论列表 -->
|
||||||
<div v-if="comment.replies && comment.replies.length > 0 && comment.showReplies" class="replies-list">
|
<div
|
||||||
<div v-for="reply in comment.replies" :key="reply.id" class="reply-item">
|
v-if="
|
||||||
<el-avatar :size="32" :src="reply.userAvatar" class="reply-avatar">
|
comment.replies &&
|
||||||
|
comment.replies.length > 0 &&
|
||||||
|
comment.showReplies
|
||||||
|
"
|
||||||
|
class="replies-list"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-for="reply in comment.replies"
|
||||||
|
:key="reply.id"
|
||||||
|
class="reply-item"
|
||||||
|
>
|
||||||
|
<el-avatar
|
||||||
|
:size="32"
|
||||||
|
:src="reply.userAvatar"
|
||||||
|
class="reply-avatar"
|
||||||
|
>
|
||||||
<img src="@/assets/images/mr.png" />
|
<img src="@/assets/images/mr.png" />
|
||||||
</el-avatar>
|
</el-avatar>
|
||||||
|
|
||||||
@ -90,7 +124,10 @@
|
|||||||
</el-icon>
|
</el-icon>
|
||||||
<span v-if="reply.likeCount">{{ reply.likeCount }}</span>
|
<span v-if="reply.likeCount">{{ reply.likeCount }}</span>
|
||||||
</div> -->
|
</div> -->
|
||||||
<div class="action-btn" @click="handleReplyToReply(reply, comment)">
|
<div
|
||||||
|
class="action-btn"
|
||||||
|
@click="handleReplyToReply(reply, comment)"
|
||||||
|
>
|
||||||
回复
|
回复
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -98,16 +135,34 @@
|
|||||||
|
|
||||||
<!-- 二级回复输入框 -->
|
<!-- 二级回复输入框 -->
|
||||||
<transition name="slide-fade">
|
<transition name="slide-fade">
|
||||||
<div v-if="activeReplyId === reply.id" class="reply-input-box">
|
<div
|
||||||
|
v-if="activeReplyId === reply.id"
|
||||||
|
class="reply-input-box"
|
||||||
|
>
|
||||||
<div class="reply-label">回复 {{ reply.userName }}</div>
|
<div class="reply-label">回复 {{ reply.userName }}</div>
|
||||||
<el-input v-model="replyContent" type="textarea" :rows="3" placeholder="输入回复内容..."
|
<el-input
|
||||||
class="reply-textarea" />
|
v-model="replyContent"
|
||||||
|
type="textarea"
|
||||||
|
:rows="3"
|
||||||
|
placeholder="输入回复内容..."
|
||||||
|
class="reply-textarea"
|
||||||
|
/>
|
||||||
<div class="reply-actions">
|
<div class="reply-actions">
|
||||||
<V3Emoji :options-name="optionsName" @click-emoji="onEmojiClick" :recent="true"
|
<V3Emoji
|
||||||
style="width: 40px;" />
|
:options-name="optionsName"
|
||||||
|
@click-emoji="onEmojiClick"
|
||||||
|
:recent="true"
|
||||||
|
style="width: 40px"
|
||||||
|
/>
|
||||||
<div class="reply-buttons">
|
<div class="reply-buttons">
|
||||||
<el-button size="small" @click="cancelReply">取消</el-button>
|
<el-button size="small" @click="cancelReply"
|
||||||
<el-button size="small" type="primary" @click="submitReply(comment, reply)">
|
>取消</el-button
|
||||||
|
>
|
||||||
|
<el-button
|
||||||
|
size="small"
|
||||||
|
type="primary"
|
||||||
|
@click="submitReply(comment, reply)"
|
||||||
|
>
|
||||||
回复
|
回复
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
@ -124,122 +179,128 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref } from 'vue'
|
import { ref } from "vue";
|
||||||
import { Promotion, ArrowDown } from '@element-plus/icons-vue'
|
import { Promotion, ArrowDown } from "@element-plus/icons-vue";
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from "element-plus";
|
||||||
import V3Emoji from 'vue3-emoji'
|
import V3Emoji from "vue3-emoji";
|
||||||
import { tbGsxtXxltHfid, tbGsxtXxltHfSave, tbGsxtXxltHfSelectList } from '@/api/tbGsxtXxltHf.js'
|
import {
|
||||||
import { getItem } from '@/utils/storage.js'
|
tbGsxtXxltHfid,
|
||||||
import { setAddress } from '@/utils/tools'
|
tbGsxtXxltHfSave,
|
||||||
|
tbGsxtXxltHfSelectList
|
||||||
|
} from "@/api/tbGsxtXxltHf.js";
|
||||||
|
import { getItem } from "@/utils/storage.js";
|
||||||
|
import { setAddress } from "@/utils/tools";
|
||||||
|
|
||||||
const optionsName = {
|
const optionsName = {
|
||||||
'Smileys & Emotion': '笑脸&表情',
|
"Smileys & Emotion": "笑脸&表情",
|
||||||
'Food & Drink': '食物&饮料',
|
"Food & Drink": "食物&饮料",
|
||||||
'Animals & Nature': '动物&自然',
|
"Animals & Nature": "动物&自然",
|
||||||
'Travel & Places': '旅行&地点',
|
"Travel & Places": "旅行&地点",
|
||||||
'People & Body': '人物&身体',
|
"People & Body": "人物&身体",
|
||||||
Objects: '物品',
|
Objects: "物品",
|
||||||
Symbols: '符号',
|
Symbols: "符号",
|
||||||
Flags: '旗帜',
|
Flags: "旗帜",
|
||||||
Activities: '活动'
|
Activities: "活动"
|
||||||
}
|
};
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
comments: {
|
comments: {
|
||||||
type: Array,
|
type: Array,
|
||||||
default: () => []
|
default: () => []
|
||||||
}, replyTo: {
|
},
|
||||||
|
replyTo: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: () => ({})
|
default: () => ({})
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
const emit = defineEmits(['reply', 'like'])
|
const emit = defineEmits(["reply", "like"]);
|
||||||
|
|
||||||
const activeReplyId = ref(null)
|
const activeReplyId = ref(null);
|
||||||
const replyContent = ref('')
|
const replyContent = ref("");
|
||||||
|
|
||||||
const getTagType = (tag) => {
|
const getTagType = (tag) => {
|
||||||
const tagMap = {
|
const tagMap = {
|
||||||
'户外活动部': 'success',
|
户外活动部: "success",
|
||||||
'校长': 'warning',
|
校长: "warning",
|
||||||
'校本部': 'info'
|
校本部: "info"
|
||||||
}
|
};
|
||||||
return tagMap[tag] || 'info'
|
return tagMap[tag] || "info";
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleLike = (comment) => {
|
const handleLike = (comment) => {
|
||||||
emit('like', comment)
|
emit("like", comment);
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleReply = (comment) => {
|
const handleReply = (comment) => {
|
||||||
emit('reply')
|
emit("reply");
|
||||||
activeReplyId.value = comment.id
|
activeReplyId.value = comment.id;
|
||||||
replyContent.value = ''
|
replyContent.value = "";
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleReplyToReply = (reply, parentComment) => {
|
const handleReplyToReply = (reply, parentComment) => {
|
||||||
emit('reply')
|
emit("reply");
|
||||||
activeReplyId.value = reply.id
|
activeReplyId.value = reply.id;
|
||||||
replyContent.value = `@${reply.userName}:`
|
replyContent.value = `@${reply.userName}:`;
|
||||||
}
|
};
|
||||||
|
|
||||||
const onEmojiClick = (emoji) => {
|
const onEmojiClick = (emoji) => {
|
||||||
replyContent.value += emoji
|
replyContent.value += emoji;
|
||||||
}
|
};
|
||||||
|
|
||||||
const cancelReply = () => {
|
const cancelReply = () => {
|
||||||
activeReplyId.value = null
|
activeReplyId.value = null;
|
||||||
replyContent.value = ''
|
replyContent.value = "";
|
||||||
}
|
};
|
||||||
|
|
||||||
// 切换回复列表的展开/收起
|
// 切换回复列表的展开/收起
|
||||||
const toggleReplies = (comment) => {
|
const toggleReplies = (comment) => {
|
||||||
if (!comment.showReplies) {
|
if (!comment.showReplies) {
|
||||||
comment.showReplies = true
|
comment.showReplies = true;
|
||||||
} else {
|
} else {
|
||||||
comment.showReplies = false
|
comment.showReplies = false;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const formatReplyItem = (reply) => {
|
const formatReplyItem = (reply) => {
|
||||||
return {
|
return {
|
||||||
...reply,
|
...reply,
|
||||||
id: reply.id,
|
id: reply.id,
|
||||||
userName: reply.hfrxm || '匿名用户',
|
userName: reply.hfrxm || "匿名用户",
|
||||||
userAvatar: reply.userAvatar || (reply.hfrtx ? setAddress(reply.hfrtx) : ''),
|
userAvatar:
|
||||||
userTag: reply.userTag || '',
|
reply.userAvatar || (reply.hfrtx ? setAddress(reply.hfrtx) : ""),
|
||||||
content: reply.content || reply.hfnr || '',
|
userTag: reply.userTag || "",
|
||||||
publishTime: reply.publishTime || reply.hfsj || '',
|
content: reply.content || reply.hfnr || "",
|
||||||
|
publishTime: reply.publishTime || reply.hfsj || "",
|
||||||
likeCount: reply.likeCount || 0,
|
likeCount: reply.likeCount || 0,
|
||||||
isLiked: reply.isLiked || false,
|
isLiked: reply.isLiked || false,
|
||||||
ssbm: reply.ssbm || '',
|
ssbm: reply.ssbm || "",
|
||||||
replyToUser: reply.replyToUser || reply.sjhfrxm || ''
|
replyToUser: reply.replyToUser || reply.sjhfrxm || ""
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
const submitReply = async (parentComment, replyToComment = null) => {
|
const submitReply = async (parentComment, replyToComment = null) => {
|
||||||
console.log(parentComment);
|
console.log(parentComment);
|
||||||
|
|
||||||
if (!replyContent.value.trim()) {
|
if (!replyContent.value.trim()) {
|
||||||
ElMessage.warning('请输入回复内容')
|
ElMessage.warning("请输入回复内容");
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const ltmasg = getItem("ltmasg")
|
const ltmasg = getItem("ltmasg");
|
||||||
let pureContent = replyContent.value
|
let pureContent = replyContent.value;
|
||||||
if (pureContent.startsWith('@') && pureContent.includes(':')) {
|
if (pureContent.startsWith("@") && pureContent.includes(":")) {
|
||||||
const colonIndex = pureContent.indexOf(':')
|
const colonIndex = pureContent.indexOf(":");
|
||||||
if (colonIndex !== -1 && colonIndex < pureContent.length - 1) {
|
if (colonIndex !== -1 && colonIndex < pureContent.length - 1) {
|
||||||
pureContent = pureContent.substring(colonIndex + 1).trim()
|
pureContent = pureContent.substring(colonIndex + 1).trim();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!pureContent) {
|
if (!pureContent) {
|
||||||
ElMessage.warning('请输入回复内容')
|
ElMessage.warning("请输入回复内容");
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
const targetReply = replyToComment || null
|
const targetReply = replyToComment || null;
|
||||||
const newReply = {
|
const newReply = {
|
||||||
hfnr: pureContent,
|
hfnr: pureContent,
|
||||||
hfrsfzh: ltmasg.sfzh,
|
hfrsfzh: ltmasg.sfzh,
|
||||||
@ -248,14 +309,18 @@ const submitReply = async (parentComment, replyToComment = null) => {
|
|||||||
ltid: props.replyTo.id,
|
ltid: props.replyTo.id,
|
||||||
sfyjhf: 0,
|
sfyjhf: 0,
|
||||||
sjhfid: parentComment.id,
|
sjhfid: parentComment.id,
|
||||||
sjhfrxm: targetReply ? targetReply.userName : ''
|
sjhfrxm: targetReply ? targetReply.userName : ""
|
||||||
}
|
};
|
||||||
try {
|
try {
|
||||||
const res = await tbGsxtXxltHfSave(newReply)
|
const res = await tbGsxtXxltHfSave(newReply);
|
||||||
if (res) {
|
if (res) {
|
||||||
const dataxhf = await tbGsxtXxltHfSelectList({ sjhfid: parentComment.id })
|
const dataxhf = await tbGsxtXxltHfSelectList({
|
||||||
const replyList = Array.isArray(dataxhf) ? dataxhf : (dataxhf?.records || [])
|
sjhfid: parentComment.id
|
||||||
parentComment.replies = replyList.map(formatReplyItem)
|
});
|
||||||
|
const replyList = Array.isArray(dataxhf)
|
||||||
|
? dataxhf
|
||||||
|
: dataxhf?.records || [];
|
||||||
|
parentComment.replies = replyList.map(formatReplyItem);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
@ -266,24 +331,32 @@ const submitReply = async (parentComment, replyToComment = null) => {
|
|||||||
// parentComment.replies.push(newReply)
|
// parentComment.replies.push(newReply)
|
||||||
|
|
||||||
// 自动展开回复列表
|
// 自动展开回复列表
|
||||||
parentComment.showReplies = true
|
parentComment.showReplies = true;
|
||||||
ElMessage.success('回复成功')
|
ElMessage.success("回复成功");
|
||||||
cancelReply()
|
cancelReply();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
|
|
||||||
ElMessage.error('回复失败')
|
ElMessage.error("回复失败");
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
|
@import "../styles/luntan-tech.scss";
|
||||||
|
|
||||||
.comment-list {
|
.comment-list {
|
||||||
|
background: #ffffff;
|
||||||
|
|
||||||
.comment-item {
|
.comment-item {
|
||||||
margin-bottom: 20px;
|
margin-bottom: 18px;
|
||||||
|
padding-bottom: 18px;
|
||||||
|
border-bottom: 1px solid $lt-border-dim;
|
||||||
|
|
||||||
&:last-child {
|
&:last-child {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
|
padding-bottom: 0;
|
||||||
|
border-bottom: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -296,6 +369,8 @@ const submitReply = async (parentComment, replyToComment = null) => {
|
|||||||
|
|
||||||
.comment-avatar {
|
.comment-avatar {
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
|
border: 1px solid lt-blue(0.28);
|
||||||
|
box-shadow: 0 0 8px lt-blue(0.12);
|
||||||
}
|
}
|
||||||
|
|
||||||
.comment-content {
|
.comment-content {
|
||||||
@ -312,18 +387,19 @@ const submitReply = async (parentComment, replyToComment = null) => {
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.user-name {
|
.user-name {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-weight: 500;
|
font-weight: 600;
|
||||||
color: #303133;
|
color: $lt-text;
|
||||||
}
|
}
|
||||||
|
|
||||||
.comment-text {
|
.comment-text {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
line-height: 1.6;
|
line-height: 1.65;
|
||||||
color: #606266;
|
color: $lt-text-dim;
|
||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
}
|
}
|
||||||
@ -336,7 +412,7 @@ const submitReply = async (parentComment, replyToComment = null) => {
|
|||||||
|
|
||||||
.comment-time {
|
.comment-time {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: #909399;
|
color: $lt-text-muted;
|
||||||
}
|
}
|
||||||
|
|
||||||
.comment-actions {
|
.comment-actions {
|
||||||
@ -349,16 +425,17 @@ const submitReply = async (parentComment, replyToComment = null) => {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 4px;
|
gap: 4px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: #909399;
|
color: $lt-text-muted;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.3s ease;
|
transition: color 0.2s ease;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
color: #409eff;
|
color: $lt-bar-blue-end;
|
||||||
|
text-shadow: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.active {
|
&.active {
|
||||||
color: #409eff;
|
color: $lt-bar-blue-end;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.toggle-btn {
|
&.toggle-btn {
|
||||||
@ -375,18 +452,30 @@ const submitReply = async (parentComment, replyToComment = null) => {
|
|||||||
.reply-input-box {
|
.reply-input-box {
|
||||||
margin-top: 12px;
|
margin-top: 12px;
|
||||||
padding: 12px;
|
padding: 12px;
|
||||||
background: #f5f7fa;
|
border-radius: 4px;
|
||||||
border-radius: 8px;
|
@include lt-panel-soft-bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
.reply-label {
|
.reply-label {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: #606266;
|
color: $lt-text-muted;
|
||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.reply-textarea {
|
.reply-textarea {
|
||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
|
|
||||||
|
:deep(.el-textarea__inner) {
|
||||||
|
background: rgba(10, 28, 58, 0.88) !important;
|
||||||
|
color: $lt-text-dim;
|
||||||
|
border: 1px solid rgba(0, 227, 255, 0.28);
|
||||||
|
border-radius: 4px;
|
||||||
|
box-shadow: 0 0 12px rgba(0, 80, 140, 0.15) inset;
|
||||||
|
|
||||||
|
&::placeholder {
|
||||||
|
color: $lt-text-muted;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.reply-actions {
|
.reply-actions {
|
||||||
@ -398,12 +487,29 @@ const submitReply = async (parentComment, replyToComment = null) => {
|
|||||||
.reply-buttons {
|
.reply-buttons {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
|
|
||||||
|
:deep(.el-button) {
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-button--default) {
|
||||||
|
background: rgba(0, 40, 70, 0.5);
|
||||||
|
border-color: rgba(0, 163, 255, 0.35);
|
||||||
|
color: $lt-text-dim;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-button--primary) {
|
||||||
|
background: linear-gradient(180deg, #00a3ff 0%, #0066bb 100%);
|
||||||
|
border-color: rgba(0, 227, 255, 0.45);
|
||||||
|
box-shadow: 0 0 12px rgba(0, 163, 255, 0.35);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.replies-list {
|
.replies-list {
|
||||||
margin-top: 16px;
|
margin-top: 14px;
|
||||||
padding-left: 12px;
|
padding-left: 12px;
|
||||||
border-left: 2px solid #f0f0f0;
|
border-left: 2px solid lt-blue(0.22);
|
||||||
|
box-shadow: -2px 0 12px lt-blue(0.06);
|
||||||
}
|
}
|
||||||
|
|
||||||
.reply-item {
|
.reply-item {
|
||||||
@ -419,6 +525,7 @@ const submitReply = async (parentComment, replyToComment = null) => {
|
|||||||
|
|
||||||
.reply-avatar {
|
.reply-avatar {
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
|
border: 1px solid lt-blue(0.22);
|
||||||
}
|
}
|
||||||
|
|
||||||
.reply-content {
|
.reply-content {
|
||||||
@ -432,18 +539,19 @@ const submitReply = async (parentComment, replyToComment = null) => {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
margin-bottom: 6px;
|
margin-bottom: 6px;
|
||||||
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.reply-text {
|
.reply-text {
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
line-height: 1.6;
|
line-height: 1.6;
|
||||||
color: #606266;
|
color: $lt-text-dim;
|
||||||
margin-bottom: 6px;
|
margin-bottom: 6px;
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
}
|
}
|
||||||
|
|
||||||
.reply-to {
|
.reply-to {
|
||||||
color: #409eff;
|
color: $lt-bar-btn-text;
|
||||||
margin-right: 4px;
|
margin-right: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -455,7 +563,7 @@ const submitReply = async (parentComment, replyToComment = null) => {
|
|||||||
|
|
||||||
.reply-time {
|
.reply-time {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: #909399;
|
color: $lt-text-muted;
|
||||||
}
|
}
|
||||||
|
|
||||||
.reply-actions {
|
.reply-actions {
|
||||||
@ -480,9 +588,15 @@ const submitReply = async (parentComment, replyToComment = null) => {
|
|||||||
.author-tag {
|
.author-tag {
|
||||||
padding: 2px 8px;
|
padding: 2px 8px;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
background-color: #409EFF;
|
background: lt-blue(0.1);
|
||||||
color: #fff;
|
color: $lt-bar-btn-text;
|
||||||
font-size: 12px;
|
font-size: 11px;
|
||||||
|
font-weight: 600;
|
||||||
line-height: 18px;
|
line-height: 18px;
|
||||||
|
border: 1px solid lt-blue(0.25);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
@import "../styles/luntan-v3emoji-tech.scss";
|
||||||
|
</style>
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="post-detail">
|
<div class="post-detail luntan-tech-detail">
|
||||||
<!-- 头部 -->
|
<!-- 头部 -->
|
||||||
<div class="detail-header">
|
<div class="detail-header">
|
||||||
<el-button text @click="handleBack">
|
<el-button class="detail-back-btn" @click="handleBack">
|
||||||
<el-icon>
|
<el-icon>
|
||||||
<ArrowLeft />
|
<ArrowLeft />
|
||||||
</el-icon>
|
</el-icon>
|
||||||
@ -13,15 +13,18 @@
|
|||||||
|
|
||||||
<!-- 帖子内容 -->
|
<!-- 帖子内容 -->
|
||||||
<div class="post-main">
|
<div class="post-main">
|
||||||
<div class="premium-badge" v-if="postData.isPremium">精品</div>
|
<div class="premium-badge" v-if="postData.isPremium">置顶</div>
|
||||||
|
|
||||||
<div class="post-author">
|
<div class="post-author">
|
||||||
<el-avatar :size="50" :src="postData.userAvatar">
|
<el-avatar :size="50" :src="postData.userAvatar" class="author-avatar">
|
||||||
<img src="@/assets/images/mr.png" />
|
<img src="@/assets/images/mr.png" />
|
||||||
</el-avatar>
|
</el-avatar>
|
||||||
<div class="author-info">
|
<div class="author-info">
|
||||||
<div class="author-name-row">
|
<div class="author-name-row">
|
||||||
<span class="author-name">{{ postData.userName }}</span>
|
<span class="author-name">{{ postData.userName }}</span>
|
||||||
|
<span v-if="postData.userTag" class="level-badge">{{
|
||||||
|
postData.userTag
|
||||||
|
}}</span>
|
||||||
<div v-if="postData.ssbm" class="author-tag">
|
<div v-if="postData.ssbm" class="author-tag">
|
||||||
{{ postData.ssbm }}
|
{{ postData.ssbm }}
|
||||||
</div>
|
</div>
|
||||||
@ -33,9 +36,22 @@
|
|||||||
<div class="post-content-text">{{ postData.content }}</div>
|
<div class="post-content-text">{{ postData.content }}</div>
|
||||||
|
|
||||||
<!-- 图片展示 -->
|
<!-- 图片展示 -->
|
||||||
<div class="post-images" v-if="postData.images && postData.images.length > 0">
|
<div
|
||||||
<div v-for="(img, index) in postData.images" :key="index" class="image-item">
|
class="post-images"
|
||||||
<el-image :src="img" fit="cover" :preview-src-list="postData.images" :initial-index="index">
|
v-if="postData.images && postData.images.length > 0"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-for="(img, index) in postData.images"
|
||||||
|
:key="index"
|
||||||
|
class="image-item"
|
||||||
|
>
|
||||||
|
<el-image
|
||||||
|
:preview-teleported="true"
|
||||||
|
:src="img"
|
||||||
|
fit="cover"
|
||||||
|
:preview-src-list="postData.images"
|
||||||
|
:initial-index="index"
|
||||||
|
>
|
||||||
<template #error>
|
<template #error>
|
||||||
<div class="image-error">
|
<div class="image-error">
|
||||||
<el-icon>
|
<el-icon>
|
||||||
@ -68,7 +84,11 @@
|
|||||||
<div class="comment-section">
|
<div class="comment-section">
|
||||||
<!-- Tab切换 -->
|
<!-- Tab切换 -->
|
||||||
<div class="comment-tabs">
|
<div class="comment-tabs">
|
||||||
<div class="tab-item" :class="{ active: activeTab === 'all' }" @click="activeTab = 'all'">
|
<div
|
||||||
|
class="tab-item"
|
||||||
|
:class="{ active: activeTab === 'all' }"
|
||||||
|
@click="activeTab = 'all'"
|
||||||
|
>
|
||||||
全部回复({{ comments.length }})
|
全部回复({{ comments.length }})
|
||||||
</div>
|
</div>
|
||||||
<!-- <div class="tab-item" :class="{ active: activeTab === 'author' }" @click="activeTab = 'author'">
|
<!-- <div class="tab-item" :class="{ active: activeTab === 'author' }" @click="activeTab = 'author'">
|
||||||
@ -89,225 +109,272 @@
|
|||||||
|
|
||||||
<!-- 评论列表 -->
|
<!-- 评论列表 -->
|
||||||
|
|
||||||
<CommentList :comments="filteredComments" @reply="handleReply" :replyTo="replyTo" @like="handleCommentLike" />
|
<CommentList
|
||||||
|
:comments="filteredComments"
|
||||||
|
@reply="handleReply"
|
||||||
|
:replyTo="replyTo"
|
||||||
|
@like="handleCommentLike"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 回复弹窗 -->
|
<!-- 回复弹窗 -->
|
||||||
<ReplyDialog v-model="showReplyDialog" :reply-to="replyTo" @success="handleReplySuccess" />
|
<ReplyDialog
|
||||||
|
v-model="showReplyDialog"
|
||||||
|
:reply-to="replyTo"
|
||||||
|
@success="handleReplySuccess"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed, onMounted } from 'vue'
|
import { ref, computed, onMounted } from "vue";
|
||||||
import { ArrowLeft, ChatDotRound, Promotion, Picture } from '@element-plus/icons-vue'
|
import {
|
||||||
import { ElMessage } from 'element-plus'
|
ArrowLeft,
|
||||||
import CommentList from './CommentList.vue'
|
ChatDotRound,
|
||||||
import ReplyDialog from './ReplyDialog.vue'
|
Promotion,
|
||||||
import { tbGsxtXxltHfid } from '@/api/tbGsxtXxltHf'
|
Picture
|
||||||
import { setAddress } from '@/utils/tools'
|
} from "@element-plus/icons-vue";
|
||||||
|
import { ElMessage } from "element-plus";
|
||||||
|
import CommentList from "./CommentList.vue";
|
||||||
|
import ReplyDialog from "./ReplyDialog.vue";
|
||||||
|
import { tbGsxtXxltHfid } from "@/api/tbGsxtXxltHf";
|
||||||
|
import { setAddress } from "@/utils/tools";
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
postId: {
|
postId: {
|
||||||
type: [String, Number],
|
type: [String, Number],
|
||||||
required: true
|
required: true
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
const emit = defineEmits(['back'])
|
const emit = defineEmits(["back"]);
|
||||||
|
|
||||||
const activeTab = ref('all')
|
const activeTab = ref("all");
|
||||||
const showReplyDialog = ref(false)
|
const showReplyDialog = ref(false);
|
||||||
const replyTo = ref(null)
|
const replyTo = ref(null);
|
||||||
const loading = ref(false)
|
const loading = ref(false);
|
||||||
|
|
||||||
// 帖子数据
|
// 帖子数据
|
||||||
const postData = ref({
|
const postData = ref({
|
||||||
id: null,
|
id: null,
|
||||||
userName: '',
|
userName: "",
|
||||||
userAvatar: '',
|
userAvatar: "",
|
||||||
userTag: '',
|
userTag: "",
|
||||||
publishTime: '',
|
publishTime: "",
|
||||||
content: '',
|
content: "",
|
||||||
images: [],
|
images: [],
|
||||||
commentCount: 0,
|
commentCount: 0,
|
||||||
likeCount: 0,
|
likeCount: 0,
|
||||||
isPremium: false,
|
isPremium: false,
|
||||||
isLiked: false
|
isLiked: false
|
||||||
})
|
});
|
||||||
|
|
||||||
// 评论数据
|
// 评论数据
|
||||||
const comments = ref([])
|
const comments = ref([]);
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
loadPostDetail()
|
loadPostDetail();
|
||||||
})
|
});
|
||||||
|
|
||||||
const loadPostDetail = async () => {
|
const loadPostDetail = async () => {
|
||||||
loading.value = true
|
loading.value = true;
|
||||||
try {
|
try {
|
||||||
const res = await tbGsxtXxltHfid(props.postId)
|
const res = await tbGsxtXxltHfid(props.postId);
|
||||||
|
|
||||||
// 设置帖子数据
|
// 设置帖子数据
|
||||||
postData.value = {
|
postData.value = {
|
||||||
id: res.id,
|
id: res.id,
|
||||||
userName: res.fbrxm || '匿名用户',
|
userName: res.fbrxm || "匿名用户",
|
||||||
userAvatar: res.fbrtx ? setAddress(res.fbrtx) : '',
|
userAvatar: res.fbrtx ? setAddress(res.fbrtx) : "",
|
||||||
userTag: res.userTag || '',
|
userTag: res.userTag || "",
|
||||||
publishTime: res.time || '',
|
publishTime: res.time || "",
|
||||||
content: res.content || '',
|
content: res.content || "",
|
||||||
images: res.tp ? res.tp.split(',').map(img => setAddress(img)) : [],
|
images: res.tp ? res.tp.split(",").map((img) => setAddress(img)) : [],
|
||||||
commentCount: res.commentCount || 0,
|
commentCount: res.commentCount || 0,
|
||||||
likeCount: res.likeCount || 0,
|
likeCount: res.likeCount || 0,
|
||||||
isPremium: res.sfzd === 1,
|
isPremium: res.sfzd === 1,
|
||||||
isLiked: false,
|
isLiked: false,
|
||||||
ssbm: res.ssbm,
|
ssbm: res.ssbm
|
||||||
}
|
};
|
||||||
|
|
||||||
// 设置评论数据
|
// 设置评论数据
|
||||||
if (res.replyList && res.replyList.length > 0) {
|
if (res.replyList && res.replyList.length > 0) {
|
||||||
comments.value = res.replyList.map(item => ({
|
comments.value = res.replyList.map((item) => ({
|
||||||
id: item.id,
|
id: item.id,
|
||||||
userName: item.hfrxm || '匿名用户',
|
userName: item.hfrxm || "匿名用户",
|
||||||
userAvatar: item.hfrtx ? setAddress(item.hfrtx) : '',
|
userAvatar: item.hfrtx ? setAddress(item.hfrtx) : "",
|
||||||
userTag: item.userTag || '',
|
userTag: item.userTag || "",
|
||||||
content: item.hfnr || '',
|
content: item.hfnr || "",
|
||||||
publishTime: item.hfsj || '',
|
publishTime: item.hfsj || "",
|
||||||
likeCount: item.likeCount || 0,
|
likeCount: item.likeCount || 0,
|
||||||
isLiked: false,
|
isLiked: false,
|
||||||
showReplies: false,
|
showReplies: false,
|
||||||
ssbm: item.ssbm,
|
ssbm: item.ssbm,
|
||||||
replies: item.xjfhList ? item.xjfhList.map(reply => ({
|
replies: item.xjfhList
|
||||||
id: reply.id,
|
? item.xjfhList.map((reply) => ({
|
||||||
userName: reply.hfrxm || '匿名用户',
|
id: reply.id,
|
||||||
userAvatar: reply.hfrtx ? setAddress(reply.hfrtx) : '',
|
userName: reply.hfrxm || "匿名用户",
|
||||||
userTag: reply.userTag || '',
|
userAvatar: reply.hfrtx ? setAddress(reply.hfrtx) : "",
|
||||||
content: reply.hfnr || '',
|
userTag: reply.userTag || "",
|
||||||
publishTime: reply.hfsj || '',
|
content: reply.hfnr || "",
|
||||||
likeCount: reply.likeCount || 0,
|
publishTime: reply.hfsj || "",
|
||||||
isLiked: false,
|
likeCount: reply.likeCount || 0,
|
||||||
replyToUser: reply.sjhfrxm || '',
|
isLiked: false,
|
||||||
ssbm: reply.ssbm,
|
replyToUser: reply.sjhfrxm || "",
|
||||||
})) : []
|
ssbm: reply.ssbm
|
||||||
}))
|
}))
|
||||||
|
: []
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('加载详情失败', error)
|
console.error("加载详情失败", error);
|
||||||
ElMessage.error('加载详情失败')
|
ElMessage.error("加载详情失败");
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false
|
loading.value = false;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const filteredComments = computed(() => {
|
const filteredComments = computed(() => {
|
||||||
if (activeTab.value === 'author') {
|
if (activeTab.value === "author") {
|
||||||
return comments.value.filter(c => c.userName === postData.value.userName)
|
return comments.value.filter((c) => c.userName === postData.value.userName);
|
||||||
}
|
}
|
||||||
console.log(comments.value);
|
return comments.value;
|
||||||
|
});
|
||||||
return comments.value
|
|
||||||
})
|
|
||||||
|
|
||||||
const getTagType = (tag) => {
|
const getTagType = (tag) => {
|
||||||
const tagMap = {
|
const tagMap = {
|
||||||
'户外活动部': 'success',
|
户外活动部: "success",
|
||||||
'校长': 'warning',
|
校长: "warning",
|
||||||
'校本部': 'info'
|
校本部: "info"
|
||||||
}
|
};
|
||||||
return tagMap[tag] || 'info'
|
return tagMap[tag] || "info";
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleBack = () => {
|
const handleBack = () => {
|
||||||
emit('back')
|
emit("back");
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleLike = () => {
|
const handleLike = () => {
|
||||||
postData.value.isLiked = !postData.value.isLiked
|
postData.value.isLiked = !postData.value.isLiked;
|
||||||
postData.value.likeCount += postData.value.isLiked ? 1 : -1
|
postData.value.likeCount += postData.value.isLiked ? 1 : -1;
|
||||||
ElMessage.success(postData.value.isLiked ? '点赞成功' : '取消点赞')
|
ElMessage.success(postData.value.isLiked ? "点赞成功" : "取消点赞");
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleReply = () => {
|
const handleReply = () => {
|
||||||
replyTo.value = {
|
replyTo.value = {
|
||||||
...postData.value,
|
...postData.value
|
||||||
}
|
};
|
||||||
// showReplyDialog.value = true
|
// showReplyDialog.value = true
|
||||||
}
|
};
|
||||||
const replyToData = () => {
|
const replyToData = () => {
|
||||||
replyTo.value = {
|
replyTo.value = {
|
||||||
...postData.value,
|
...postData.value
|
||||||
}
|
};
|
||||||
showReplyDialog.value = true
|
showReplyDialog.value = true;
|
||||||
}
|
};
|
||||||
const handleCommentLike = (comment) => {
|
const handleCommentLike = (comment) => {
|
||||||
comment.isLiked = !comment.isLiked
|
comment.isLiked = !comment.isLiked;
|
||||||
comment.likeCount += comment.isLiked ? 1 : -1
|
comment.likeCount += comment.isLiked ? 1 : -1;
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleReplySuccess = () => {
|
const handleReplySuccess = () => {
|
||||||
ElMessage.success('回复成功')
|
ElMessage.success("回复成功");
|
||||||
loadPostDetail()
|
loadPostDetail();
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.post-detail {
|
@import "../styles/luntan-tech.scss";
|
||||||
background: #f5f7fa;
|
|
||||||
|
.luntan-tech-detail {
|
||||||
|
background: transparent;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
.detail-header {
|
.detail-header {
|
||||||
background: #fff;
|
padding: 14px 18px;
|
||||||
padding: 16px 20px;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
border-bottom: 1px solid #f0f0f0;
|
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
|
border-bottom: 1px solid lt-blue(0.12);
|
||||||
|
background: linear-gradient(
|
||||||
|
135deg,
|
||||||
|
lt-blue-light(0.14) 0%,
|
||||||
|
lt-blue(0.07) 48%,
|
||||||
|
transparent 100%
|
||||||
|
);
|
||||||
|
|
||||||
|
:deep(.detail-back-btn.el-button) {
|
||||||
|
height: 36px;
|
||||||
|
padding: 0 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
border-radius: 8px;
|
||||||
|
background: #ffffff !important;
|
||||||
|
border: 1px solid lt-blue(0.22) !important;
|
||||||
|
color: $lt-bar-btn-text !important;
|
||||||
|
box-shadow: 0 1px 4px lt-blue(0.12);
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&:focus {
|
||||||
|
color: $lt-bar-blue-end !important;
|
||||||
|
border-color: lt-blue(0.4) !important;
|
||||||
|
background: #f8fafc !important;
|
||||||
|
box-shadow: 0 2px 10px lt-blue(0.18);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.detail-back-btn .el-icon) {
|
||||||
|
margin-right: 4px;
|
||||||
|
font-size: 16px;
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
.header-title {
|
.header-title {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
font-weight: 500;
|
font-weight: 600;
|
||||||
color: #303133;
|
color: $lt-text;
|
||||||
margin-right: 60px;
|
margin-right: 60px;
|
||||||
|
letter-spacing: 0.08em;
|
||||||
|
text-shadow: 0 0 14px lt-blue(0.18);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.post-main {
|
.post-main {
|
||||||
background: #fff;
|
padding: 20px 18px 18px;
|
||||||
padding: 20px;
|
margin: 12px 12px 0;
|
||||||
margin-bottom: 12px;
|
|
||||||
position: relative;
|
position: relative;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
|
border-radius: 4px;
|
||||||
|
@include lt-panel-soft-bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
.comment-section {
|
.comment-section {
|
||||||
background: #fff;
|
padding: 8px 12px 32px;
|
||||||
padding: 16px 20px 40px 20px;
|
|
||||||
flex: 1;
|
flex: 1;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
min-height: 0;
|
||||||
|
|
||||||
.post-main {
|
|
||||||
background: #fff;
|
|
||||||
padding: 20px;
|
|
||||||
margin-bottom: 12px;
|
|
||||||
position: relative;
|
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.premium-badge {
|
.premium-badge {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 20px;
|
top: 16px;
|
||||||
right: 20px;
|
right: 16px;
|
||||||
background: linear-gradient(135deg, #ff9a56 0%, #ff6b6b 100%);
|
background: linear-gradient(
|
||||||
|
135deg,
|
||||||
|
$lt-bar-blue-start 0%,
|
||||||
|
$lt-bar-blue-end 100%
|
||||||
|
);
|
||||||
color: #fff;
|
color: #fff;
|
||||||
padding: 4px 12px;
|
padding: 4px 12px;
|
||||||
border-radius: 4px;
|
border-radius: 2px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-weight: 500;
|
font-weight: 600;
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.35);
|
||||||
|
box-shadow: 0 2px 10px lt-blue(0.3);
|
||||||
}
|
}
|
||||||
|
|
||||||
.post-author {
|
.post-author {
|
||||||
@ -317,6 +384,11 @@ const handleReplySuccess = () => {
|
|||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.author-avatar {
|
||||||
|
border: 2px solid lt-blue(0.35);
|
||||||
|
box-shadow: 0 0 12px lt-blue(0.22);
|
||||||
|
}
|
||||||
|
|
||||||
.author-info {
|
.author-info {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
padding-top: 2px;
|
padding-top: 2px;
|
||||||
@ -325,34 +397,46 @@ const handleReplySuccess = () => {
|
|||||||
.author-name-row {
|
.author-name-row {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
margin-bottom: 4px;
|
margin-bottom: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.author-name {
|
.author-name {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
font-weight: 500;
|
font-weight: 700;
|
||||||
color: #303133;
|
color: $lt-text;
|
||||||
|
}
|
||||||
|
|
||||||
|
.level-badge {
|
||||||
|
font-size: 11px;
|
||||||
|
padding: 2px 8px;
|
||||||
|
border-radius: 2px;
|
||||||
|
background: lt-blue(0.1);
|
||||||
|
color: $lt-bar-blue-end;
|
||||||
|
font-weight: 600;
|
||||||
|
border: 1px solid lt-blue(0.28);
|
||||||
}
|
}
|
||||||
|
|
||||||
.author-tag {
|
.author-tag {
|
||||||
padding: 2px 8px;
|
padding: 2px 8px;
|
||||||
border-radius: 4px;
|
border-radius: 2px;
|
||||||
background-color: #409EFF;
|
background: lt-blue(0.08);
|
||||||
color: #fff;
|
color: $lt-bar-btn-text;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
line-height: 18px;
|
line-height: 18px;
|
||||||
|
border: 1px solid lt-blue(0.25);
|
||||||
}
|
}
|
||||||
|
|
||||||
.publish-time {
|
.publish-time {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: #909399;
|
color: $lt-text-muted;
|
||||||
}
|
}
|
||||||
|
|
||||||
.post-content-text {
|
.post-content-text {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
line-height: 1.8;
|
line-height: 1.85;
|
||||||
color: #303133;
|
color: $lt-text-dim;
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
}
|
}
|
||||||
@ -367,8 +451,10 @@ const handleReplySuccess = () => {
|
|||||||
.image-item {
|
.image-item {
|
||||||
width: 200px;
|
width: 200px;
|
||||||
height: 140px;
|
height: 140px;
|
||||||
border-radius: 8px;
|
border-radius: 4px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
border: 1px solid $lt-border-dim;
|
||||||
|
box-shadow: 0 0 12px rgba(0, 100, 160, 0.2);
|
||||||
|
|
||||||
:deep(.el-image) {
|
:deep(.el-image) {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@ -382,8 +468,8 @@ const handleReplySuccess = () => {
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background: #f5f7fa;
|
background: rgba(10, 30, 60, 0.6);
|
||||||
color: #c0c4cc;
|
color: $lt-text-muted;
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -391,24 +477,20 @@ const handleReplySuccess = () => {
|
|||||||
display: flex;
|
display: flex;
|
||||||
gap: 24px;
|
gap: 24px;
|
||||||
padding-top: 16px;
|
padding-top: 16px;
|
||||||
border-top: 1px solid #f0f0f0;
|
border-top: 1px solid $lt-border-dim;
|
||||||
}
|
}
|
||||||
|
|
||||||
.stat-item {
|
.stat-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 6px;
|
gap: 6px;
|
||||||
color: #909399;
|
color: $lt-text-muted;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.3s ease;
|
transition: color 0.2s ease;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
color: #409eff;
|
color: $lt-cyan;
|
||||||
}
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
color: #409eff;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-icon {
|
.el-icon {
|
||||||
@ -416,40 +498,34 @@ const handleReplySuccess = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.comment-section {
|
|
||||||
background: #fff;
|
|
||||||
padding: 16px 20px 40px 20px;
|
|
||||||
flex: 1;
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.comment-tabs {
|
.comment-tabs {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-bottom: 16px;
|
margin-bottom: 14px;
|
||||||
border-bottom: 1px solid #f0f0f0;
|
border-bottom: 1px solid $lt-border-dim;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab-item {
|
.tab-item {
|
||||||
padding: 12px 16px;
|
padding: 12px 14px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: #606266;
|
color: $lt-text-muted;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
position: relative;
|
position: relative;
|
||||||
transition: all 0.3s ease;
|
transition: color 0.2s ease;
|
||||||
|
|
||||||
&.active {
|
&.active {
|
||||||
color: #409eff;
|
color: $lt-cyan;
|
||||||
font-weight: 500;
|
font-weight: 600;
|
||||||
|
|
||||||
&::after {
|
&::after {
|
||||||
content: '';
|
content: "";
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
height: 2px;
|
height: 2px;
|
||||||
background: #409eff;
|
background: linear-gradient(90deg, transparent, $lt-cyan, transparent);
|
||||||
|
box-shadow: 0 0 10px rgba(0, 227, 255, 0.6);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -461,11 +537,28 @@ const handleReplySuccess = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.top-input {
|
.top-input {
|
||||||
margin-bottom: 20px;
|
margin-bottom: 16px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
:deep(.el-input__wrapper) {
|
:deep(.el-input__wrapper) {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
background: rgba(10, 30, 60, 0.65) !important;
|
||||||
|
border-radius: 4px !important;
|
||||||
|
box-shadow: 0 0 0 1px rgba(0, 227, 255, 0.28) inset,
|
||||||
|
0 0 16px rgba(0, 100, 180, 0.15) !important;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
box-shadow: 0 0 0 1px rgba(0, 227, 255, 0.45) inset,
|
||||||
|
0 0 20px rgba(0, 163, 255, 0.25) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-input__inner) {
|
||||||
|
color: $lt-text-dim;
|
||||||
|
|
||||||
|
&::placeholder {
|
||||||
|
color: $lt-text-muted;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -1,9 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="post-item" @click="handleClick">
|
<div class="post-item" @click="handleClick">
|
||||||
<!-- 精品标签 -->
|
<div class="premium-badge" v-if="post.isPremium">置顶</div>
|
||||||
<div class="premium-badge" v-if="post.isPremium">精品</div>
|
|
||||||
<div class="post-main-content">
|
<div class="post-main-content">
|
||||||
<el-avatar :size="50" :src="post.userAvatar" class="post-avatar">
|
<el-avatar :size="44" :src="post.userAvatar" class="post-avatar">
|
||||||
<img src="@/assets/images/mr.png" />
|
<img src="@/assets/images/mr.png" />
|
||||||
</el-avatar>
|
</el-avatar>
|
||||||
|
|
||||||
@ -11,6 +10,9 @@
|
|||||||
<div class="post-header">
|
<div class="post-header">
|
||||||
<div class="user-name-row">
|
<div class="user-name-row">
|
||||||
<span class="user-name">{{ post.userName }}</span>
|
<span class="user-name">{{ post.userName }}</span>
|
||||||
|
<span v-if="post.userTag" class="level-badge">{{
|
||||||
|
post.userTag
|
||||||
|
}}</span>
|
||||||
<div v-if="post.ssbm" class="author-tag">
|
<div v-if="post.ssbm" class="author-tag">
|
||||||
{{ post.ssbm }}
|
{{ post.ssbm }}
|
||||||
</div>
|
</div>
|
||||||
@ -18,13 +20,37 @@
|
|||||||
<div class="post-time">{{ post.publishTime }}</div>
|
<div class="post-time">{{ post.publishTime }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="post-content">
|
<div class="post-content" v-if="postTitle || bodySource">
|
||||||
<div class="post-text">{{ post.content }}</div>
|
<div v-if="postTitle" class="post-title">{{ postTitle }}</div>
|
||||||
|
<div v-if="bodySource" class="post-text-wrap">
|
||||||
|
<div class="post-text">{{ displayBody }}</div>
|
||||||
|
<span
|
||||||
|
v-if="showFullLink"
|
||||||
|
class="full-text-link"
|
||||||
|
@click.stop="handleClick"
|
||||||
|
>全文</span
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- 图片展示 -->
|
<!-- 图片展示 -->
|
||||||
<div class="post-images" v-if="post.images && post.images.length > 0">
|
<div
|
||||||
<div v-for="(img, index) in post.images" :key="index" class="image-item" @click.stop>
|
class="post-images"
|
||||||
<el-image :src="img" fit="cover" :preview-src-list="post.images" :initial-index="index">
|
v-if="post.images && post.images.length > 0"
|
||||||
|
:class="{ 'is-three': post.images.length >= 3 }"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-for="(img, index) in post.images"
|
||||||
|
:key="index"
|
||||||
|
class="image-item"
|
||||||
|
@click.stop
|
||||||
|
>
|
||||||
|
<el-image
|
||||||
|
:preview-teleported="true"
|
||||||
|
:src="img"
|
||||||
|
fit="cover"
|
||||||
|
:preview-src-list="post.images"
|
||||||
|
:initial-index="index"
|
||||||
|
>
|
||||||
<template #error>
|
<template #error>
|
||||||
<div class="image-error">
|
<div class="image-error">
|
||||||
<el-icon>
|
<el-icon>
|
||||||
@ -44,12 +70,15 @@
|
|||||||
</el-icon>
|
</el-icon>
|
||||||
<span>{{ post.commentCount || 0 }}</span>
|
<span>{{ post.commentCount || 0 }}</span>
|
||||||
</div>
|
</div>
|
||||||
<!-- <div class="action-item" :class="{ active: post.isLiked }" @click.stop="handleLike">
|
<button
|
||||||
<el-icon>
|
v-if="!post.isPremium"
|
||||||
<Promotion />
|
type="button"
|
||||||
</el-icon>
|
class="post-pin-btn"
|
||||||
<span>{{ post.likeCount || 0 }}</span>
|
:disabled="pinning"
|
||||||
</div> -->
|
@click.stop="handlePinTop"
|
||||||
|
>
|
||||||
|
置顶
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -57,179 +86,311 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ChatDotRound, Promotion, Picture } from '@element-plus/icons-vue'
|
import { computed, ref } from "vue";
|
||||||
|
import { ChatDotRound, Picture } from "@element-plus/icons-vue";
|
||||||
|
import { ElMessage } from "element-plus";
|
||||||
|
import { tbGsxtXxltHfid, tbGsxtXxltUpdate } from "@/api/tbGsxtXxltHf.js";
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
post: {
|
post: {
|
||||||
type: Object,
|
type: Object,
|
||||||
required: true
|
required: true
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
const emit = defineEmits(['like', 'click'])
|
const emit = defineEmits(["like", "click", "pin"]);
|
||||||
|
|
||||||
const getTagType = (tag) => {
|
const pinning = ref(false);
|
||||||
const tagMap = {
|
|
||||||
'已动态': 'success',
|
const handlePinTop = async () => {
|
||||||
'校长': 'warning',
|
if (pinning.value) return;
|
||||||
'校本部': 'info'
|
pinning.value = true;
|
||||||
|
try {
|
||||||
|
const detail = await tbGsxtXxltHfid(props.post.id);
|
||||||
|
await tbGsxtXxltUpdate({ ...detail, sfzd: 1 });
|
||||||
|
ElMessage.success("置顶成功");
|
||||||
|
emit("pin");
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
ElMessage.error("置顶失败");
|
||||||
|
} finally {
|
||||||
|
pinning.value = false;
|
||||||
}
|
}
|
||||||
return 'warning'
|
};
|
||||||
}
|
|
||||||
|
|
||||||
const handleLike = () => {
|
const EXCERPT_LEN = 160;
|
||||||
emit('like', props.post)
|
|
||||||
}
|
const rawContent = computed(() => (props.post.content || "").trim());
|
||||||
|
|
||||||
|
const postTitle = computed(() => {
|
||||||
|
const t = rawContent.value;
|
||||||
|
if (!t) return "";
|
||||||
|
const idx = t.indexOf("\n");
|
||||||
|
if (idx === -1) return "";
|
||||||
|
const first = t.slice(0, idx).trim();
|
||||||
|
return first.length > 0 ? first : "";
|
||||||
|
});
|
||||||
|
|
||||||
|
const bodySource = computed(() => {
|
||||||
|
const t = rawContent.value;
|
||||||
|
if (!t) return "";
|
||||||
|
const idx = t.indexOf("\n");
|
||||||
|
if (idx === -1) return t;
|
||||||
|
const rest = t.slice(idx + 1).trim();
|
||||||
|
return rest;
|
||||||
|
});
|
||||||
|
|
||||||
|
const showFullLink = computed(() => bodySource.value.length > EXCERPT_LEN);
|
||||||
|
|
||||||
|
const displayBody = computed(() => {
|
||||||
|
const b = bodySource.value;
|
||||||
|
if (!b) return "";
|
||||||
|
if (b.length <= EXCERPT_LEN) return b;
|
||||||
|
return `${b.slice(0, EXCERPT_LEN)}…`;
|
||||||
|
});
|
||||||
|
|
||||||
const handleClick = () => {
|
const handleClick = () => {
|
||||||
emit('click', props.post)
|
emit("click", props.post);
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
|
@import "../styles/luntan-tech.scss";
|
||||||
|
|
||||||
.post-item {
|
.post-item {
|
||||||
background: #fff !important;
|
position: relative;
|
||||||
border-radius: 8px !important;
|
display: flex;
|
||||||
padding: 20px !important;
|
align-items: flex-start;
|
||||||
margin-bottom: 16px !important;
|
gap: 12px;
|
||||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08) !important;
|
padding: 18px 18px 14px;
|
||||||
position: relative !important;
|
margin-bottom: 14px;
|
||||||
transition: all 0.3s ease !important;
|
border-radius: 4px;
|
||||||
cursor: pointer !important;
|
cursor: pointer;
|
||||||
|
@include lt-panel-frame;
|
||||||
|
transition: border-color 0.2s ease, box-shadow 0.2s ease;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12) !important;
|
border-color: lt-blue(0.35);
|
||||||
|
box-shadow: $lt-glow-strong, inset 0 1px 0 lt-blue(0.12);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.post-pin-btn {
|
||||||
|
flex-shrink: 0;
|
||||||
|
padding: 3px 10px;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #fff;
|
||||||
|
cursor: pointer;
|
||||||
|
border: none;
|
||||||
|
border-radius: 3px;
|
||||||
|
background: linear-gradient(
|
||||||
|
135deg,
|
||||||
|
$lt-bar-blue-start 0%,
|
||||||
|
$lt-bar-blue-end 100%
|
||||||
|
);
|
||||||
|
box-shadow: 0 1px 5px lt-blue(0.2);
|
||||||
|
transition: opacity 0.2s ease, transform 0.15s ease;
|
||||||
|
|
||||||
|
&:hover:not(:disabled) {
|
||||||
|
opacity: 0.9;
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
opacity: 0.65;
|
||||||
|
cursor: not-allowed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.premium-badge {
|
.premium-badge {
|
||||||
position: absolute !important;
|
position: absolute;
|
||||||
top: 16px !important;
|
top: 14px;
|
||||||
right: 16px !important;
|
right: 14px;
|
||||||
background: linear-gradient(135deg, #ff9a56 0%, #ff6b6b 100%) !important;
|
background: linear-gradient(
|
||||||
color: #fff !important;
|
135deg,
|
||||||
padding: 4px 12px !important;
|
$lt-bar-blue-start 0%,
|
||||||
border-radius: 4px !important;
|
$lt-bar-blue-end 100%
|
||||||
font-size: 12px !important;
|
);
|
||||||
font-weight: 500 !important;
|
color: #fff;
|
||||||
box-shadow: 0 2px 4px rgba(255, 107, 107, 0.3) !important;
|
padding: 3px 10px;
|
||||||
|
border-radius: 2px;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 600;
|
||||||
|
letter-spacing: 0.04em;
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.35);
|
||||||
|
box-shadow: 0 2px 10px lt-blue(0.28);
|
||||||
}
|
}
|
||||||
|
|
||||||
.post-main-content {
|
.post-main-content {
|
||||||
display: flex !important;
|
flex: 1;
|
||||||
gap: 12px !important;
|
min-width: 0;
|
||||||
align-items: flex-start !important;
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
align-items: flex-start;
|
||||||
}
|
}
|
||||||
|
|
||||||
.post-avatar {
|
.post-avatar {
|
||||||
flex-shrink: 0 !important;
|
flex-shrink: 0;
|
||||||
|
border: 2px solid lt-blue(0.35);
|
||||||
|
box-shadow: 0 0 10px lt-blue(0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.post-right {
|
.post-right {
|
||||||
flex: 1 !important;
|
flex: 1;
|
||||||
min-width: 0 !important;
|
min-width: 0;
|
||||||
padding-top: 2px !important;
|
padding-top: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.post-header {
|
.post-header {
|
||||||
margin-bottom: 12px !important;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.user-name-row {
|
.user-name-row {
|
||||||
display: flex !important;
|
display: flex;
|
||||||
align-items: center !important;
|
align-items: center;
|
||||||
gap: 8px !important;
|
flex-wrap: wrap;
|
||||||
margin-bottom: 4px !important;
|
gap: 6px 8px;
|
||||||
|
margin-bottom: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.user-name {
|
.user-name {
|
||||||
font-size: 16px !important;
|
font-size: 16px;
|
||||||
font-weight: 500 !important;
|
font-weight: 700;
|
||||||
color: #303133 !important;
|
color: $lt-text;
|
||||||
|
}
|
||||||
|
|
||||||
|
.level-badge {
|
||||||
|
font-size: 11px;
|
||||||
|
padding: 2px 8px;
|
||||||
|
border-radius: 2px;
|
||||||
|
background: lt-blue(0.1);
|
||||||
|
color: $lt-bar-blue-end;
|
||||||
|
font-weight: 600;
|
||||||
|
line-height: 1.3;
|
||||||
|
border: 1px solid lt-blue(0.28);
|
||||||
}
|
}
|
||||||
|
|
||||||
.post-time {
|
.post-time {
|
||||||
font-size: 12px !important;
|
font-size: 12px;
|
||||||
color: #909399 !important;
|
color: $lt-text-muted;
|
||||||
}
|
}
|
||||||
|
|
||||||
.post-content {
|
.post-content {
|
||||||
margin-bottom: 16px !important;
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post-title {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: $lt-text;
|
||||||
|
line-height: 1.45;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
word-break: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post-text-wrap {
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 1.65;
|
||||||
|
color: $lt-text-dim;
|
||||||
|
word-break: break-word;
|
||||||
}
|
}
|
||||||
|
|
||||||
.post-text {
|
.post-text {
|
||||||
font-size: 14px !important;
|
display: inline;
|
||||||
line-height: 1.6 !important;
|
}
|
||||||
color: #606266 !important;
|
|
||||||
margin-bottom: 12px !important;
|
.full-text-link {
|
||||||
word-break: break-word !important;
|
margin-left: 4px;
|
||||||
|
color: $lt-bar-blue-end;
|
||||||
|
font-weight: 500;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
text-shadow: 0 0 8px lt-blue(0.35);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.post-images {
|
.post-images {
|
||||||
display: flex !important;
|
display: flex;
|
||||||
gap: 8px !important;
|
gap: 8px;
|
||||||
flex-wrap: wrap !important;
|
flex-wrap: wrap;
|
||||||
|
margin-top: 12px;
|
||||||
|
|
||||||
|
&.is-three .image-item {
|
||||||
|
width: calc((100% - 16px) / 3);
|
||||||
|
min-width: 0;
|
||||||
|
aspect-ratio: 4 / 3;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.image-item {
|
.image-item {
|
||||||
width: 200px !important;
|
width: 160px;
|
||||||
height: 140px !important;
|
height: 112px;
|
||||||
border-radius: 8px !important;
|
border-radius: 4px;
|
||||||
overflow: hidden !important;
|
overflow: hidden;
|
||||||
cursor: pointer !important;
|
cursor: pointer;
|
||||||
|
flex-shrink: 0;
|
||||||
|
border: 1px solid $lt-border-dim;
|
||||||
|
box-shadow: 0 0 10px rgba(0, 80, 140, 0.25);
|
||||||
|
|
||||||
:deep(.el-image) {
|
:deep(.el-image) {
|
||||||
width: 100% !important;
|
width: 100%;
|
||||||
height: 100% !important;
|
height: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.post-images.is-three .image-item {
|
||||||
|
max-width: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
.image-error {
|
.image-error {
|
||||||
display: flex !important;
|
display: flex;
|
||||||
align-items: center !important;
|
align-items: center;
|
||||||
justify-content: center !important;
|
justify-content: center;
|
||||||
width: 100% !important;
|
width: 100%;
|
||||||
height: 100% !important;
|
height: 100%;
|
||||||
background: #f5f7fa !important;
|
background: rgba(10, 30, 60, 0.65);
|
||||||
color: #c0c4cc !important;
|
color: $lt-text-muted;
|
||||||
font-size: 24px !important;
|
font-size: 22px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.post-footer {
|
.post-footer {
|
||||||
display: flex !important;
|
display: flex;
|
||||||
gap: 24px !important;
|
align-items: center;
|
||||||
padding-top: 12px !important;
|
flex-wrap: wrap;
|
||||||
border-top: 1px solid #f0f0f0 !important;
|
gap: 12px 20px;
|
||||||
|
padding-top: 10px;
|
||||||
|
border-top: 1px solid $lt-border-dim;
|
||||||
}
|
}
|
||||||
|
|
||||||
.action-item {
|
.action-item {
|
||||||
display: flex !important;
|
display: flex;
|
||||||
align-items: center !important;
|
align-items: center;
|
||||||
gap: 6px !important;
|
gap: 6px;
|
||||||
color: #909399 !important;
|
color: $lt-text-muted;
|
||||||
font-size: 14px !important;
|
font-size: 13px;
|
||||||
cursor: pointer !important;
|
cursor: pointer;
|
||||||
transition: all 0.3s ease !important;
|
transition: color 0.2s ease;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
color: #409eff !important;
|
color: $lt-bar-blue-end;
|
||||||
}
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
color: #409eff !important;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-icon {
|
.el-icon {
|
||||||
font-size: 18px !important;
|
font-size: 17px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.author-tag {
|
.author-tag {
|
||||||
padding: 2px 8px;
|
padding: 2px 8px;
|
||||||
border-radius: 4px;
|
border-radius: 2px;
|
||||||
background-color: #409EFF;
|
background: lt-blue(0.08);
|
||||||
color: #fff;
|
color: $lt-bar-btn-text;
|
||||||
font-size: 12px;
|
font-size: 11px;
|
||||||
line-height: 18px;
|
line-height: 18px;
|
||||||
|
font-weight: 600;
|
||||||
|
border: 1px solid lt-blue(0.25);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -1,186 +1,555 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="post-list">
|
<div class="post-list">
|
||||||
<!-- 发布按钮 -->
|
<!-- 贴吧风格顶栏:左信息 + 右操作(页面背景仍为外层网格,不变) -->
|
||||||
<div class="publish-section">
|
<div class="bar-head">
|
||||||
<el-button type="primary" @click="showPublishDialog = true">
|
<div class="bar-logo">
|
||||||
<el-icon>
|
<el-icon><ChatDotRound /></el-icon>
|
||||||
<Edit />
|
</div>
|
||||||
</el-icon>
|
<div class="bar-text-block">
|
||||||
发布帖子
|
<div class="bar-title">信息论坛</div>
|
||||||
</el-button>
|
<div class="bar-meta-row">
|
||||||
|
<span class="bar-meta-item">帖子 {{ replyCountStub.fts }}</span>
|
||||||
|
<span class="bar-meta-sep">·</span>
|
||||||
|
<span class="bar-meta-item bar-meta-reply"
|
||||||
|
>回复 {{ replyCountStub.hfs }}</span
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<!-- 帖子列表 -->
|
<div class="bar-actions">
|
||||||
<div class="posts-container" v-loading="loading" v-infinite-scroll="loadMore"
|
<button
|
||||||
:infinite-scroll-disabled="scrollDisabled" :infinite-scroll-distance="100">
|
type="button"
|
||||||
<PostItem v-for="post in postList" :key="post.id" :post="post" @like="handleLike"
|
class="bar-pill bar-pill-primary"
|
||||||
@click="handlePostClick(post)" />
|
@click="showPublishDialog = true"
|
||||||
|
>
|
||||||
<!-- 加载更多提示 -->
|
<el-icon><Plus /></el-icon>
|
||||||
<div v-if="loadingMore" class="loading-more">
|
发帖
|
||||||
<el-icon class="is-loading">
|
</button>
|
||||||
<Loading />
|
</div>
|
||||||
</el-icon>
|
|
||||||
<span>加载中...</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 没有更多数据提示 -->
|
|
||||||
<div v-if="noMore && postList.length > 0" class="no-more">
|
|
||||||
没有更多数据了
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 空状态 -->
|
|
||||||
<el-empty v-if="!loading && postList.length === 0" description="暂无帖子" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 发布对话框 -->
|
|
||||||
<PublishDialog v-model="showPublishDialog" @success="handlePublishSuccess" />
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 帖子列表 -->
|
||||||
|
<div
|
||||||
|
class="posts-container"
|
||||||
|
v-loading="loading"
|
||||||
|
v-infinite-scroll="loadMore"
|
||||||
|
:infinite-scroll-disabled="scrollDisabled"
|
||||||
|
:infinite-scroll-distance="100"
|
||||||
|
>
|
||||||
|
<!-- 置顶:仅标题缩略列表 -->
|
||||||
|
<div v-if="pinnedList.length" class="pinned-block">
|
||||||
|
<div class="pinned-list">
|
||||||
|
<div
|
||||||
|
v-for="post in pinnedList"
|
||||||
|
:key="'zd-' + post.id"
|
||||||
|
class="pinned-row"
|
||||||
|
@click="handlePostClick(post)"
|
||||||
|
>
|
||||||
|
<span class="pinned-badge">置顶</span>
|
||||||
|
<span class="pinned-title">{{ displayTitle(post) }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 分界线 -->
|
||||||
|
<div v-if="pinnedList.length && normalList.length" class="list-divider">
|
||||||
|
<span class="divider-line" />
|
||||||
|
<span class="divider-text">全部帖子</span>
|
||||||
|
<span class="divider-line" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 普通帖子 -->
|
||||||
|
<PostItem
|
||||||
|
v-for="post in normalList"
|
||||||
|
:key="post.id"
|
||||||
|
:post="post"
|
||||||
|
@like="handleLike"
|
||||||
|
@pin="handlePostPinned"
|
||||||
|
@click="handlePostClick(post)"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- 加载更多提示 -->
|
||||||
|
<div v-if="loadingMore" class="loading-more">
|
||||||
|
<el-icon class="is-loading">
|
||||||
|
<Loading />
|
||||||
|
</el-icon>
|
||||||
|
<span>加载中...</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 没有更多数据提示 -->
|
||||||
|
<div v-if="noMore && normalList.length > 0" class="no-more">
|
||||||
|
没有更多数据了
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 空状态 -->
|
||||||
|
<el-empty
|
||||||
|
v-if="!loading && postList.length === 0"
|
||||||
|
class="post-empty"
|
||||||
|
description="暂无帖子"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 发布对话框 -->
|
||||||
|
<PublishDialog
|
||||||
|
v-model="showPublishDialog"
|
||||||
|
@success="handlePublishSuccess"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted, computed } from 'vue'
|
import { ref, onMounted, computed } from "vue";
|
||||||
import { Edit, Loading } from '@element-plus/icons-vue'
|
import { ChatDotRound, Loading, Plus } from "@element-plus/icons-vue";
|
||||||
import PostItem from './PostItem.vue'
|
import PostItem from "./PostItem.vue";
|
||||||
import PublishDialog from './PublishDialog.vue'
|
import PublishDialog from "./PublishDialog.vue";
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from "element-plus";
|
||||||
import { tbGsxtXxltSelectPage } from '@/api/tbGsxtXxltHf'
|
import { tbGsxtXxltSelectPage } from "@/api/tbGsxtXxltHf";
|
||||||
import { setAddress } from '@/utils/tools'
|
import { setAddress } from "@/utils/tools";
|
||||||
|
import { qcckGet } from "@/api/qcckApi.js";
|
||||||
const loading = ref(false)
|
const loading = ref(false);
|
||||||
const loadingMore = ref(false)
|
const loadingMore = ref(false);
|
||||||
const postList = ref([])
|
const postList = ref([]);
|
||||||
const showPublishDialog = ref(false)
|
const showPublishDialog = ref(false);
|
||||||
|
|
||||||
const listQuery = ref({
|
const listQuery = ref({
|
||||||
pageCurrent: 1,
|
pageCurrent: 1,
|
||||||
pageSize: 10
|
pageSize: 10
|
||||||
})
|
});
|
||||||
|
|
||||||
const total = ref(0)
|
const total = ref(0);
|
||||||
|
// 获取置顶数据
|
||||||
|
const pinnedList = ref([]);
|
||||||
|
const getpinnedList = () => {
|
||||||
|
const params = {
|
||||||
|
pageCurrent: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
sfzd: 1
|
||||||
|
};
|
||||||
|
tbGsxtXxltSelectPage(params).then((res) => {
|
||||||
|
pinnedList.value = (res.records || []).map((item) => ({
|
||||||
|
id: item.id,
|
||||||
|
title: item.title || "",
|
||||||
|
userName: item.fbrxm || "匿名用户",
|
||||||
|
userAvatar: item.fbrtx ? setAddress(item.fbrtx) : "",
|
||||||
|
userTag: item.userTag || "",
|
||||||
|
publishTime: item.time || "",
|
||||||
|
content: item.content || "",
|
||||||
|
images: item.tp ? item.tp.split(",").map((img) => setAddress(img)) : [],
|
||||||
|
commentCount: item.hfsl || 0,
|
||||||
|
likeCount: item.likeCount || 0,
|
||||||
|
isPremium: item.sfzd === 1,
|
||||||
|
isLiked: false,
|
||||||
|
ssbm: item.ssbm,
|
||||||
|
// 保存原始数据
|
||||||
|
rawData: item
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
const normalList = computed(() => postList.value);
|
||||||
|
|
||||||
|
/** 置顶行展示标题:优先接口 title,否则从正文首行截取 */
|
||||||
|
function displayTitle(post) {
|
||||||
|
const tit = (post.title || "").trim();
|
||||||
|
if (tit) {
|
||||||
|
return tit.length <= 56 ? tit : `${tit.slice(0, 56)}…`;
|
||||||
|
}
|
||||||
|
const t = (post.content || "").trim();
|
||||||
|
if (!t) return "无标题";
|
||||||
|
const idx = t.indexOf("\n");
|
||||||
|
const firstLine = idx === -1 ? t : t.slice(0, idx).trim();
|
||||||
|
const line = firstLine || t.slice(0, 80);
|
||||||
|
if (line.length <= 56) return line;
|
||||||
|
return `${line.slice(0, 56)}…`;
|
||||||
|
}
|
||||||
|
|
||||||
// 计算是否禁用滚动加载
|
// 计算是否禁用滚动加载
|
||||||
const scrollDisabled = computed(() => {
|
const scrollDisabled = computed(() => {
|
||||||
return loadingMore.value || noMore.value
|
return loadingMore.value || noMore.value;
|
||||||
})
|
});
|
||||||
|
|
||||||
// 计算是否没有更多数据
|
// 计算是否没有更多数据
|
||||||
const noMore = computed(() => {
|
const noMore = computed(() => {
|
||||||
return postList.value.length >= total.value && total.value > 0
|
return postList.value.length >= total.value && total.value > 0;
|
||||||
})
|
});
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
loadPosts()
|
getpinnedList();
|
||||||
})
|
loadPosts();
|
||||||
|
getStatistics();
|
||||||
|
});
|
||||||
|
|
||||||
const loadPosts = async (isLoadMore = false) => {
|
const loadPosts = async (isLoadMore = false) => {
|
||||||
|
if (isLoadMore) {
|
||||||
|
loadingMore.value = true;
|
||||||
|
} else {
|
||||||
|
loading.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await tbGsxtXxltSelectPage(listQuery.value);
|
||||||
|
const data = (res.records || []).map((item) => ({
|
||||||
|
id: item.id,
|
||||||
|
title: item.title || "",
|
||||||
|
userName: item.fbrxm || "匿名用户",
|
||||||
|
userAvatar: item.fbrtx ? setAddress(item.fbrtx) : "",
|
||||||
|
userTag: item.userTag || "",
|
||||||
|
publishTime: item.time || "",
|
||||||
|
content: item.content || "",
|
||||||
|
images: item.tp ? item.tp.split(",").map((img) => setAddress(img)) : [],
|
||||||
|
commentCount: item.hfsl || 0,
|
||||||
|
likeCount: item.likeCount || 0,
|
||||||
|
isPremium: item.sfzd === 1,
|
||||||
|
isLiked: false,
|
||||||
|
ssbm: item.ssbm,
|
||||||
|
// 保存原始数据
|
||||||
|
rawData: item
|
||||||
|
}));
|
||||||
|
|
||||||
if (isLoadMore) {
|
if (isLoadMore) {
|
||||||
loadingMore.value = true
|
postList.value = [...postList.value, ...data];
|
||||||
} else {
|
} else {
|
||||||
loading.value = true
|
postList.value = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
total.value = res.total || 0;
|
||||||
const res = await tbGsxtXxltSelectPage(listQuery.value)
|
} catch (error) {
|
||||||
const data = (res.records || []).map(item => ({
|
console.error("加载失败", error);
|
||||||
id: item.id,
|
ElMessage.error("加载失败");
|
||||||
userName: item.fbrxm || '匿名用户',
|
} finally {
|
||||||
userAvatar: item.fbrtx ? setAddress(item.fbrtx) : '',
|
loading.value = false;
|
||||||
userTag: item.userTag || '',
|
loadingMore.value = false;
|
||||||
publishTime: item.time || '',
|
}
|
||||||
content: item.content || '',
|
};
|
||||||
images: item.tp ? item.tp.split(',').map(img => setAddress(img)) : [],
|
|
||||||
commentCount: item.hfsl || 0,
|
|
||||||
likeCount: item.likeCount || 0,
|
|
||||||
isPremium: item.sfzd === 1,
|
|
||||||
isLiked: false,
|
|
||||||
ssbm: item.ssbm,
|
|
||||||
// 保存原始数据
|
|
||||||
rawData: item
|
|
||||||
}))
|
|
||||||
|
|
||||||
if (isLoadMore) {
|
|
||||||
postList.value = [...postList.value, ...data]
|
|
||||||
} else {
|
|
||||||
postList.value = data
|
|
||||||
}
|
|
||||||
|
|
||||||
total.value = res.total || 0
|
|
||||||
} catch (error) {
|
|
||||||
console.error('加载失败', error)
|
|
||||||
ElMessage.error('加载失败')
|
|
||||||
} finally {
|
|
||||||
loading.value = false
|
|
||||||
loadingMore.value = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 加载更多
|
// 加载更多
|
||||||
const loadMore = () => {
|
const loadMore = () => {
|
||||||
if (postList.value.length >= total.value) {
|
if (postList.value.length >= total.value) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
listQuery.value.pageCurrent++
|
listQuery.value.pageCurrent++;
|
||||||
loadPosts(true)
|
loadPosts(true);
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleLike = (post) => {
|
const handleLike = (post) => {
|
||||||
post.isLiked = !post.isLiked
|
post.isLiked = !post.isLiked;
|
||||||
post.likeCount += post.isLiked ? 1 : -1
|
post.likeCount += post.isLiked ? 1 : -1;
|
||||||
ElMessage.success(post.isLiked ? '点赞成功' : '取消点赞')
|
ElMessage.success(post.isLiked ? "点赞成功" : "取消点赞");
|
||||||
}
|
};
|
||||||
|
|
||||||
const handlePublishSuccess = () => {
|
const handlePublishSuccess = () => {
|
||||||
// 重置分页并重新加载
|
// 重置分页并重新加载
|
||||||
listQuery.value.pageCurrent = 1
|
listQuery.value.pageCurrent = 1;
|
||||||
loadPosts()
|
loadPosts();
|
||||||
}
|
getStatistics();
|
||||||
|
};
|
||||||
|
|
||||||
const emit = defineEmits(['openDetail'])
|
const handlePostPinned = () => {
|
||||||
|
listQuery.value.pageCurrent = 1;
|
||||||
|
loadPosts(false);
|
||||||
|
getpinnedList();
|
||||||
|
getStatistics();
|
||||||
|
};
|
||||||
|
const replyCountStub = ref({
|
||||||
|
fts: 0,
|
||||||
|
hfs: 0
|
||||||
|
});
|
||||||
|
const totalDisplay = (n) => {
|
||||||
|
if (n >= 10000) return `${(n / 10000).toFixed(1)}W`;
|
||||||
|
if (n >= 1000) return `${(n / 1000).toFixed(1)}k`;
|
||||||
|
return String(n);
|
||||||
|
};
|
||||||
|
// 获取统计数量
|
||||||
|
const getStatistics = () => {
|
||||||
|
qcckGet({}, "/mosty-gsxt/tbGsxtXxlt/lttj").then((res) => {
|
||||||
|
console.log(res);
|
||||||
|
replyCountStub.value = {
|
||||||
|
fts: totalDisplay(res.fts),
|
||||||
|
hfs: totalDisplay(res.hfs)
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const emit = defineEmits(["openDetail"]);
|
||||||
|
|
||||||
const handlePostClick = (post) => {
|
const handlePostClick = (post) => {
|
||||||
emit('openDetail', post)
|
emit("openDetail", post);
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
|
@import "../styles/luntan-tech.scss";
|
||||||
|
|
||||||
.post-list {
|
.post-list {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
.publish-section {
|
.bar-head {
|
||||||
margin-bottom: 20px;
|
--bar-logo-size: 72px;
|
||||||
display: flex;
|
--bar-logo-gap: 18px;
|
||||||
justify-content: flex-end;
|
display: grid;
|
||||||
background: #fff;
|
grid-template-columns: auto 1fr auto;
|
||||||
padding: 16px 20px;
|
grid-template-rows: auto;
|
||||||
border-radius: 8px;
|
column-gap: var(--bar-logo-gap);
|
||||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
align-items: center;
|
||||||
|
margin-bottom: 18px;
|
||||||
|
padding: 22px 22px 20px;
|
||||||
|
border-radius: 12px;
|
||||||
|
/* 深蓝科技横幅:左亮右暗,贴近深色企业顶栏 */
|
||||||
|
background-color: #0a0f18;
|
||||||
|
background-image: linear-gradient(
|
||||||
|
92deg,
|
||||||
|
rgba(147, 197, 253, 0.09) 0%,
|
||||||
|
rgba(96, 165, 250, 0.04) 6%,
|
||||||
|
transparent 14%
|
||||||
|
),
|
||||||
|
linear-gradient(100deg, rgba(255, 255, 255, 0.05) 0%, transparent 12%),
|
||||||
|
linear-gradient(
|
||||||
|
110deg,
|
||||||
|
#2a4f8c 0%,
|
||||||
|
#1a3358 26%,
|
||||||
|
#121c2e 58%,
|
||||||
|
#101828 78%,
|
||||||
|
#080d14 100%
|
||||||
|
);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||||
|
box-shadow: 0 8px 28px rgba(0, 0, 0, 0.38),
|
||||||
|
inset 0 1px 0 rgba(255, 255, 255, 0.06);
|
||||||
|
|
||||||
|
.bar-pill {
|
||||||
|
color: $lt-bar-btn-text;
|
||||||
|
background: #ffffff;
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.95);
|
||||||
|
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
opacity: 1;
|
||||||
|
background: #f8fafc;
|
||||||
|
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.12);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.bar-logo {
|
||||||
|
grid-column: 1;
|
||||||
|
grid-row: 1;
|
||||||
|
align-self: center;
|
||||||
|
flex-shrink: 0;
|
||||||
|
width: var(--bar-logo-size);
|
||||||
|
height: var(--bar-logo-size);
|
||||||
|
border-radius: 16px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: #fff;
|
||||||
|
box-shadow: 0 4px 14px rgba(0, 0, 0, 0.2);
|
||||||
|
|
||||||
|
.el-icon {
|
||||||
|
font-size: 38px;
|
||||||
|
color: $lt-cyan-mid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.bar-text-block {
|
||||||
|
grid-column: 2;
|
||||||
|
grid-row: 1;
|
||||||
|
align-self: center;
|
||||||
|
min-width: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 10px;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bar-title {
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: 800;
|
||||||
|
color: #ffffff;
|
||||||
|
letter-spacing: 0.04em;
|
||||||
|
line-height: 1.2;
|
||||||
|
text-shadow: 0 1px 3px rgba(0, 0, 0, 0.45);
|
||||||
|
}
|
||||||
|
|
||||||
|
.bar-meta-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 6px 10px;
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: rgba(255, 255, 255, 0.95);
|
||||||
|
line-height: 1.4;
|
||||||
|
letter-spacing: 0.02em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bar-meta-sep {
|
||||||
|
opacity: 0.65;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bar-meta-reply {
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 16px;
|
||||||
|
color: #fff;
|
||||||
|
text-shadow: 0 0 12px rgba(255, 255, 255, 0.35);
|
||||||
|
}
|
||||||
|
|
||||||
|
.bar-actions {
|
||||||
|
grid-column: 3;
|
||||||
|
grid-row: 1;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
align-self: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bar-pill {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 6px;
|
||||||
|
padding: 10px 22px;
|
||||||
|
border-radius: 999px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #fff;
|
||||||
|
border: 1px solid $lt-cyan-mid;
|
||||||
|
background: $lt-cyan-mid;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: opacity 0.2s ease, box-shadow 0.2s ease;
|
||||||
|
|
||||||
|
.el-icon {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
opacity: 0.85;
|
||||||
|
box-shadow: 0 2px 8px rgba(64, 158, 255, 0.35);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.bar-pill-primary {
|
||||||
|
&:hover {
|
||||||
|
opacity: 0.85;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.bar-head .bar-pill-primary:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 置顶缩略区
|
||||||
|
.pinned-block {
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pinned-list {
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 10px 12px;
|
||||||
|
background: $lt-panel-soft;
|
||||||
|
border: 1px solid $lt-border-dim;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pinned-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 10px;
|
||||||
|
padding: 8px 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 4px;
|
||||||
|
transition: background 0.15s ease;
|
||||||
|
|
||||||
|
& + .pinned-row {
|
||||||
|
border-top: 1px solid $lt-border-dim;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: rgba(64, 158, 255, 0.06);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.pinned-badge {
|
||||||
|
flex-shrink: 0;
|
||||||
|
padding: 2px 8px;
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: $lt-cyan-mid;
|
||||||
|
border: 1px solid rgba(64, 158, 255, 0.4);
|
||||||
|
border-radius: 4px;
|
||||||
|
background: rgba(64, 158, 255, 0.06);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pinned-title {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: $lt-text;
|
||||||
|
line-height: 1.45;
|
||||||
|
word-break: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 置顶与普通帖之间的分界
|
||||||
|
.list-divider {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
margin: 16px 0 14px;
|
||||||
|
padding: 0 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.divider-line {
|
||||||
|
flex: 1;
|
||||||
|
height: 1px;
|
||||||
|
background: $lt-border-dim;
|
||||||
|
}
|
||||||
|
|
||||||
|
.divider-text {
|
||||||
|
flex-shrink: 0;
|
||||||
|
font-size: 12px;
|
||||||
|
color: $lt-text-muted;
|
||||||
|
letter-spacing: 0.08em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.posts-container {
|
.posts-container {
|
||||||
min-height: 400px;
|
min-height: 400px;
|
||||||
|
|
||||||
|
:deep(.el-loading-mask) {
|
||||||
|
background-color: rgba(245, 247, 250, 0.7);
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-loading-spinner .path) {
|
||||||
|
stroke: $lt-cyan-mid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.post-empty {
|
||||||
|
padding: 48px 0;
|
||||||
|
|
||||||
|
:deep(.el-empty__description) {
|
||||||
|
color: $lt-text-muted;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.loading-more {
|
.loading-more {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
color: #909399;
|
color: $lt-text-muted;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
|
|
||||||
.el-icon {
|
.el-icon {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
}
|
color: $lt-cyan-mid;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.no-more {
|
.no-more {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
color: #c0c4cc;
|
color: $lt-text-muted;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -1,147 +1,172 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-dialog v-model="dialogVisible" title="发布帖子" width="600px" :before-close="handleClose">
|
<el-dialog
|
||||||
<el-form :model="form" :rules="rules" ref="formRef" label-width="80px">
|
v-model="dialogVisible"
|
||||||
<el-form-item label="标题" prop="title">
|
class="luntan-tech-dialog"
|
||||||
<el-input v-model="form.title" placeholder="请输入帖子标题" maxlength="50" show-word-limit />
|
title="发布帖子"
|
||||||
</el-form-item>
|
width="60%"
|
||||||
|
:before-close="handleClose"
|
||||||
|
>
|
||||||
|
<div style="overflow: auto; height: 60vh">
|
||||||
|
<el-form :model="form" :rules="rules" ref="formRef" label-width="80px">
|
||||||
|
<el-form-item label="标题" prop="title">
|
||||||
|
<el-input
|
||||||
|
v-model="form.title"
|
||||||
|
placeholder="请输入帖子标题"
|
||||||
|
maxlength="50"
|
||||||
|
show-word-limit
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="内容" prop="content">
|
<el-form-item label="内容" prop="content">
|
||||||
<el-input v-model="form.content" type="textarea" :rows="6" placeholder="请输入帖子内容" maxlength="500"
|
<el-input
|
||||||
show-word-limit />
|
v-model="form.content"
|
||||||
</el-form-item>
|
type="textarea"
|
||||||
|
:rows="6"
|
||||||
|
placeholder="请输入帖子内容"
|
||||||
|
maxlength="500"
|
||||||
|
show-word-limit
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="表情">
|
<el-form-item label="表情">
|
||||||
<V3Emoji
|
<V3Emoji
|
||||||
:options-name="optionsName"
|
:options-name="optionsName"
|
||||||
@click-emoji="onEmojiClick"
|
@click-emoji="onEmojiClick"
|
||||||
:recent="true"
|
:recent="true"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="图片">
|
<el-form-item label="图片">
|
||||||
<Upload v-model="imageIds" :limit="9" :isImg="true" :isAll="true" />
|
<Upload v-model="imageIds" :limit="9" :isImg="true" :isAll="true" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
|
</div>
|
||||||
|
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<el-button @click="handleClose">取消</el-button>
|
<el-button @click="handleClose">取消</el-button>
|
||||||
<el-button type="primary" @click="handleSubmit" :loading="submitting">
|
<el-button type="primary" @click="handleSubmit" :loading="submitting">
|
||||||
发布
|
发布
|
||||||
</el-button>
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, watch } from 'vue'
|
import { ref, watch } from "vue";
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from "element-plus";
|
||||||
import V3Emoji from 'vue3-emoji'
|
import V3Emoji from "vue3-emoji";
|
||||||
import { tbGsxtXxltSave } from '@/api/tbGsxtXxltHf'
|
import { tbGsxtXxltSave } from "@/api/tbGsxtXxltHf";
|
||||||
import { getItem } from '@/utils/storage.js'
|
import { getItem } from "@/utils/storage.js";
|
||||||
import Upload from '@/components/MyComponents/Upload/index.vue'
|
import Upload from "@/components/MyComponents/Upload/index.vue";
|
||||||
|
|
||||||
const optionsName = {
|
const optionsName = {
|
||||||
'Smileys & Emotion': '笑脸&表情',
|
"Smileys & Emotion": "笑脸&表情",
|
||||||
'Food & Drink': '食物&饮料',
|
"Food & Drink": "食物&饮料",
|
||||||
'Animals & Nature': '动物&自然',
|
"Animals & Nature": "动物&自然",
|
||||||
'Travel & Places': '旅行&地点',
|
"Travel & Places": "旅行&地点",
|
||||||
'People & Body': '人物&身体',
|
"People & Body": "人物&身体",
|
||||||
Objects: '物品',
|
Objects: "物品",
|
||||||
Symbols: '符号',
|
Symbols: "符号",
|
||||||
Flags: '旗帜',
|
Flags: "旗帜",
|
||||||
Activities: '活动'
|
Activities: "活动"
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
modelValue: {
|
modelValue: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
const emit = defineEmits(['update:modelValue', 'success'])
|
const emit = defineEmits(["update:modelValue", "success"]);
|
||||||
|
|
||||||
const dialogVisible = ref(false)
|
const dialogVisible = ref(false);
|
||||||
const formRef = ref()
|
const formRef = ref();
|
||||||
const submitting = ref(false)
|
const submitting = ref(false);
|
||||||
const imageIds = ref([])
|
const imageIds = ref([]);
|
||||||
|
|
||||||
const form = ref({
|
const form = ref({
|
||||||
title: '',
|
title: "",
|
||||||
content: ''
|
content: ""
|
||||||
})
|
});
|
||||||
|
|
||||||
const rules = {
|
const rules = {
|
||||||
title: [
|
title: [{ required: true, message: "请输入标题", trigger: "blur" }],
|
||||||
{ required: true, message: '请输入标题', trigger: 'blur' }
|
content: [{ required: true, message: "请输入内容", trigger: "blur" }]
|
||||||
],
|
};
|
||||||
content: [
|
|
||||||
{ required: true, message: '请输入内容', trigger: 'blur' }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
watch(() => props.modelValue, (val) => {
|
watch(
|
||||||
dialogVisible.value = val
|
() => props.modelValue,
|
||||||
})
|
(val) => {
|
||||||
|
dialogVisible.value = val;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
watch(dialogVisible, (val) => {
|
watch(dialogVisible, (val) => {
|
||||||
emit('update:modelValue', val)
|
emit("update:modelValue", val);
|
||||||
if (!val) {
|
if (!val) {
|
||||||
resetForm()
|
resetForm();
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
const onEmojiClick = (emoji) => {
|
const onEmojiClick = (emoji) => {
|
||||||
form.value.content += emoji
|
form.value.content += emoji;
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
dialogVisible.value = false
|
dialogVisible.value = false;
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleSubmit = async () => {
|
const handleSubmit = async () => {
|
||||||
if (!formRef.value) return
|
if (!formRef.value) return;
|
||||||
|
|
||||||
await formRef.value.validate(async (valid) => {
|
await formRef.value.validate(async (valid) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
submitting.value = true
|
submitting.value = true;
|
||||||
try {
|
try {
|
||||||
const ltmasg = getItem('ltmasg')
|
const ltmasg = getItem("ltmasg");
|
||||||
|
|
||||||
const postData = {
|
const postData = {
|
||||||
title: form.value.title,
|
title: form.value.title,
|
||||||
content: form.value.content,
|
content: form.value.content,
|
||||||
tp: imageIds.value.join(','),
|
tp: imageIds.value.join(","),
|
||||||
fbrsfzh: ltmasg?.sfzh || '',
|
fbrsfzh: ltmasg?.sfzh || "",
|
||||||
fbrxm: ltmasg?.xm || '',
|
fbrxm: ltmasg?.xm || "",
|
||||||
fbrtx: ltmasg?.tx || ''
|
fbrtx: ltmasg?.tx || ""
|
||||||
}
|
};
|
||||||
|
|
||||||
await tbGsxtXxltSave(postData)
|
await tbGsxtXxltSave(postData);
|
||||||
|
|
||||||
ElMessage.success('发布成功')
|
ElMessage.success("发布成功");
|
||||||
emit('success')
|
emit("success");
|
||||||
handleClose()
|
handleClose();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('发布失败', error)
|
console.error("发布失败", error);
|
||||||
ElMessage.error('发布失败')
|
ElMessage.error("发布失败");
|
||||||
} finally {
|
} finally {
|
||||||
submitting.value = false
|
submitting.value = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
const resetForm = () => {
|
const resetForm = () => {
|
||||||
form.value = {
|
form.value = {
|
||||||
title: '',
|
title: "",
|
||||||
content: ''
|
content: ""
|
||||||
}
|
};
|
||||||
imageIds.value = []
|
imageIds.value = [];
|
||||||
formRef.value?.resetFields()
|
formRef.value?.resetFields();
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
// 样式已由Upload组件内部处理</style>
|
// Upload 等子组件样式在各自内部
|
||||||
|
::v-deep .form-item-box {
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
@import "../styles/luntan-dialog-tech.scss";
|
||||||
|
</style>
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-dialog
|
<el-dialog
|
||||||
v-model="dialogVisible"
|
v-model="dialogVisible"
|
||||||
|
class="luntan-tech-dialog"
|
||||||
title="发表回复"
|
title="发表回复"
|
||||||
width="600px"
|
width="600px"
|
||||||
:before-close="handleClose"
|
:before-close="handleClose"
|
||||||
@ -155,3 +156,7 @@ const resetForm = () => {
|
|||||||
gap: 12px;
|
gap: 12px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
@import '../styles/luntan-dialog-tech.scss';
|
||||||
|
</style>
|
||||||
|
|||||||
@ -1,49 +1,78 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="user-card">
|
<div class="user-card">
|
||||||
<div class="user-avatar">
|
<div class="user-card-head">
|
||||||
<div class="avatar-wrapper" @click="showAvatarDialog = true">
|
<div class="user-avatar">
|
||||||
<el-avatar :size="80" :src="avatarUrl">
|
<div class="avatar-wrapper" @click="showAvatarDialog = true">
|
||||||
<img src="@/assets/images/mr.png" />
|
<el-avatar :size="56" :src="avatarUrl">
|
||||||
</el-avatar>
|
<img src="@/assets/images/mr.png" />
|
||||||
<div class="avatar-overlay">
|
</el-avatar>
|
||||||
<el-icon class="upload-icon">
|
<div class="avatar-overlay">
|
||||||
<Camera />
|
<el-icon class="upload-icon">
|
||||||
</el-icon>
|
<Camera />
|
||||||
|
</el-icon>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="user-card-head-text">
|
||||||
|
<div class="name-row">
|
||||||
|
<span class="nickname">{{ userInfo.nickname || "用户信息" }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="sub-stats">内部论坛 · 已登录</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="user-info">
|
<div class="user-info">
|
||||||
<div class="info-item clickable" @click="showNicknameDialog = true">
|
<div class="info-item clickable" @click="showNicknameDialog = true">
|
||||||
<span class="label">昵称:</span>
|
<span class="label">昵称</span>
|
||||||
<span class="value">{{ userInfo.nickname || '-' }}</span>
|
<span class="value">{{ userInfo.nickname || "-" }}</span>
|
||||||
<el-icon class="edit-icon">
|
<el-icon class="edit-icon">
|
||||||
<Edit />
|
<Edit />
|
||||||
</el-icon>
|
</el-icon>
|
||||||
</div>
|
</div>
|
||||||
<div class="info-item">
|
<div class="info-item">
|
||||||
<span class="label">账号:</span>
|
<span class="label">账号</span>
|
||||||
<span class="value">{{ userInfo.account || '-' }}</span>
|
<span class="value">{{ userInfo.account || "-" }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="info-item">
|
<div class="info-item">
|
||||||
<span class="label">姓名:</span>
|
<span class="label">姓名</span>
|
||||||
<span class="value">{{ userInfo.name || '-' }}</span>
|
<span class="value">{{ userInfo.name || "-" }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="info-item">
|
<div class="info-item">
|
||||||
<span class="label">部门:</span>
|
<span class="label">部门</span>
|
||||||
<span class="value">{{ userInfo.department || '-' }}</span>
|
<span class="value">{{ userInfo.department || "-" }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 更换头像对话框 -->
|
<!-- 更换头像对话框 -->
|
||||||
<ChangeAvatar v-model="showAvatarDialog" title="更换头像" @avatarUpdated="handleAvatarUpdated" />
|
<ChangeAvatar
|
||||||
|
v-model="showAvatarDialog"
|
||||||
|
title="更换头像"
|
||||||
|
@avatarUpdated="handleAvatarUpdated"
|
||||||
|
/>
|
||||||
|
|
||||||
<!-- 编辑昵称对话框 -->
|
<!-- 编辑昵称对话框 -->
|
||||||
<el-dialog v-model="showNicknameDialog" title="编辑昵称" width="400px" center :close-on-click-modal="false">
|
<el-dialog
|
||||||
<el-form ref="nicknameFormRef" :model="nicknameForm" :rules="nicknameRules" label-width="80px">
|
v-model="showNicknameDialog"
|
||||||
|
class="luntan-tech-dialog"
|
||||||
|
title="编辑昵称"
|
||||||
|
width="400px"
|
||||||
|
center
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
>
|
||||||
|
<el-form
|
||||||
|
ref="nicknameFormRef"
|
||||||
|
:model="nicknameForm"
|
||||||
|
:rules="nicknameRules"
|
||||||
|
label-width="80px"
|
||||||
|
>
|
||||||
<el-form-item label="昵称" prop="nickname">
|
<el-form-item label="昵称" prop="nickname">
|
||||||
<el-input v-model="nicknameForm.nickname" placeholder="请输入昵称" maxlength="20" show-word-limit />
|
<el-input
|
||||||
|
v-model="nicknameForm.nickname"
|
||||||
|
placeholder="请输入昵称"
|
||||||
|
maxlength="20"
|
||||||
|
show-word-limit
|
||||||
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
@ -54,168 +83,186 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, reactive, computed, onMounted } from 'vue'
|
import { ref, reactive, computed, onMounted } from "vue";
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from "element-plus";
|
||||||
import { Camera, Edit } from '@element-plus/icons-vue'
|
import { Camera, Edit } from "@element-plus/icons-vue";
|
||||||
import { getItem, setItem, removeItem } from '@/utils/storage.js'
|
import { getItem, setItem, removeItem } from "@/utils/storage.js";
|
||||||
import { setAddress } from '@/utils/tools'
|
import { setAddress } from "@/utils/tools";
|
||||||
import { tbGsxtXxltTxTxQueryBySfzh, tbGsxtXxltTxTxSave } from '@/api/tbGsxtXxltHf.js'
|
import {
|
||||||
import ChangeAvatar from './ChangeAvatar.vue'
|
tbGsxtXxltTxTxQueryBySfzh,
|
||||||
|
tbGsxtXxltTxTxSave
|
||||||
|
} from "@/api/tbGsxtXxltHf.js";
|
||||||
|
import ChangeAvatar from "./ChangeAvatar.vue";
|
||||||
|
|
||||||
const showAvatarDialog = ref(false)
|
const showAvatarDialog = ref(false);
|
||||||
const showNicknameDialog = ref(false)
|
const showNicknameDialog = ref(false);
|
||||||
const nicknameFormRef = ref()
|
const nicknameFormRef = ref();
|
||||||
|
|
||||||
const userInfo = ref({
|
const userInfo = ref({
|
||||||
avatar: '',
|
avatar: "",
|
||||||
account: '',
|
account: "",
|
||||||
name: '',
|
name: "",
|
||||||
department: '',
|
department: "",
|
||||||
nickname: ''
|
nickname: ""
|
||||||
})
|
});
|
||||||
|
|
||||||
const nicknameForm = reactive({
|
const nicknameForm = reactive({
|
||||||
nickname: ''
|
nickname: ""
|
||||||
})
|
});
|
||||||
|
|
||||||
const nicknameRules = {
|
const nicknameRules = {
|
||||||
nickname: [
|
nickname: [
|
||||||
{ required: true, message: '请输入昵称', trigger: 'blur' },
|
{ required: true, message: "请输入昵称", trigger: "blur" },
|
||||||
{ min: 2, max: 20, message: '昵称长度在 2 到 20 个字符', trigger: 'blur' }
|
{ min: 2, max: 20, message: "昵称长度在 2 到 20 个字符", trigger: "blur" }
|
||||||
]
|
]
|
||||||
}
|
};
|
||||||
|
|
||||||
const avatarUrl = computed(() => {
|
const avatarUrl = computed(() => {
|
||||||
return userInfo.value.avatar ? setAddress(userInfo.value.avatar) : ''
|
return userInfo.value.avatar ? setAddress(userInfo.value.avatar) : "";
|
||||||
})
|
});
|
||||||
|
|
||||||
// 加载用户信息
|
// 加载用户信息
|
||||||
const loadUserInfo = async () => {
|
const loadUserInfo = async () => {
|
||||||
const sfzh = getItem('idEntityCard')
|
const sfzh = getItem("idEntityCard");
|
||||||
let ltmasg = getItem('ltmasg')
|
let ltmasg = getItem("ltmasg");
|
||||||
|
|
||||||
if (!ltmasg) {
|
if (!ltmasg) {
|
||||||
try {
|
try {
|
||||||
const res = await tbGsxtXxltTxTxQueryBySfzh({ sfzh: sfzh })
|
const res = await tbGsxtXxltTxTxQueryBySfzh({ sfzh: sfzh });
|
||||||
console.log(res);
|
console.log(res);
|
||||||
|
|
||||||
const deptId = getItem('deptId')?.[0]
|
const deptId = getItem("deptId")?.[0];
|
||||||
ltmasg = {
|
ltmasg = {
|
||||||
...res,
|
...res,
|
||||||
deptName: deptId?.deptName || ''
|
deptName: deptId?.deptName || ""
|
||||||
}
|
};
|
||||||
setItem('ltmasg', ltmasg)
|
setItem("ltmasg", ltmasg);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('加载用户信息失败:', error)
|
console.error("加载用户信息失败:", error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ltmasg) {
|
if (ltmasg) {
|
||||||
userInfo.value = {
|
userInfo.value = {
|
||||||
avatar: ltmasg.tx || '',
|
avatar: ltmasg.tx || "",
|
||||||
account: ltmasg.sfzh || '',
|
account: ltmasg.sfzh || "",
|
||||||
name: ltmasg.xm || '',
|
name: ltmasg.xm || "",
|
||||||
department: ltmasg.deptName || ltmasg.bm || '',
|
department: ltmasg.deptName || ltmasg.bm || "",
|
||||||
nickname: ltmasg.nc || ''
|
nickname: ltmasg.nc || ""
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
// 处理头像更新
|
// 处理头像更新
|
||||||
const handleAvatarUpdated = async (newAvatar) => {
|
const handleAvatarUpdated = async (newAvatar) => {
|
||||||
try {
|
try {
|
||||||
const ltmasg = getItem('ltmasg')
|
const ltmasg = getItem("ltmasg");
|
||||||
const updateData = {
|
const updateData = {
|
||||||
...ltmasg,
|
...ltmasg,
|
||||||
tx: newAvatar
|
tx: newAvatar
|
||||||
}
|
};
|
||||||
|
|
||||||
await tbGsxtXxltTxTxSave(updateData)
|
await tbGsxtXxltTxTxSave(updateData);
|
||||||
removeItem('ltmasg')
|
removeItem("ltmasg");
|
||||||
await loadUserInfo()
|
await loadUserInfo();
|
||||||
ElMessage.success('头像更新成功')
|
ElMessage.success("头像更新成功");
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('更新头像失败:', error)
|
console.error("更新头像失败:", error);
|
||||||
ElMessage.error('头像更新失败,请重试')
|
ElMessage.error("头像更新失败,请重试");
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
// 处理保存昵称
|
// 处理保存昵称
|
||||||
const handleSaveNickname = async () => {
|
const handleSaveNickname = async () => {
|
||||||
if (!nicknameFormRef.value) return
|
if (!nicknameFormRef.value) return;
|
||||||
|
|
||||||
await nicknameFormRef.value.validate(async (valid) => {
|
await nicknameFormRef.value.validate(async (valid) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
try {
|
try {
|
||||||
const ltmasg = getItem('ltmasg')
|
const ltmasg = getItem("ltmasg");
|
||||||
const updateData = {
|
const updateData = {
|
||||||
...ltmasg,
|
...ltmasg,
|
||||||
nc: nicknameForm.nickname
|
nc: nicknameForm.nickname
|
||||||
}
|
};
|
||||||
|
|
||||||
await tbGsxtXxltTxTxSave(updateData)
|
await tbGsxtXxltTxTxSave(updateData);
|
||||||
removeItem('ltmasg')
|
removeItem("ltmasg");
|
||||||
await loadUserInfo()
|
await loadUserInfo();
|
||||||
showNicknameDialog.value = false
|
showNicknameDialog.value = false;
|
||||||
ElMessage.success('昵称保存成功')
|
ElMessage.success("昵称保存成功");
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('保存昵称失败:', error)
|
console.error("保存昵称失败:", error);
|
||||||
ElMessage.error('昵称保存失败,请重试')
|
ElMessage.error("昵称保存失败,请重试");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
// 监听昵称对话框打开,初始化表单
|
// 监听昵称对话框打开,初始化表单
|
||||||
const openNicknameDialog = () => {
|
const openNicknameDialog = () => {
|
||||||
nicknameForm.nickname = userInfo.value.nickname
|
nicknameForm.nickname = userInfo.value.nickname;
|
||||||
}
|
};
|
||||||
|
|
||||||
// 监听对话框显示状态
|
// 监听对话框显示状态
|
||||||
const unwatchNickname = () => {
|
const unwatchNickname = () => {
|
||||||
if (showNicknameDialog.value) {
|
if (showNicknameDialog.value) {
|
||||||
openNicknameDialog()
|
openNicknameDialog();
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
loadUserInfo()
|
loadUserInfo();
|
||||||
})
|
});
|
||||||
|
|
||||||
// 监听昵称对话框
|
// 监听昵称对话框
|
||||||
const stopWatch = () => {
|
const stopWatch = () => {
|
||||||
if (showNicknameDialog.value) {
|
if (showNicknameDialog.value) {
|
||||||
nicknameForm.nickname = userInfo.value.nickname
|
nicknameForm.nickname = userInfo.value.nickname;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
// 使用 watch 监听对话框状态
|
// 使用 watch 监听对话框状态
|
||||||
import { watch } from 'vue'
|
import { watch } from "vue";
|
||||||
watch(showNicknameDialog, (newVal) => {
|
watch(showNicknameDialog, (newVal) => {
|
||||||
if (newVal) {
|
if (newVal) {
|
||||||
nicknameForm.nickname = userInfo.value.nickname
|
nicknameForm.nickname = userInfo.value.nickname;
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
|
@import "../styles/luntan-tech.scss";
|
||||||
|
|
||||||
.user-card {
|
.user-card {
|
||||||
background: #fff;
|
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
padding: 24px;
|
padding: 18px 16px 16px;
|
||||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
background: linear-gradient(
|
||||||
|
135deg,
|
||||||
|
$lt-bar-blue-start 0%,
|
||||||
|
$lt-bar-blue-end 100%
|
||||||
|
);
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.22);
|
||||||
|
box-shadow: 0 4px 18px lt-blue(0.22);
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-card-head {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 14px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
padding-bottom: 14px;
|
||||||
|
border-bottom: 1px solid rgba(255, 255, 255, 0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.user-avatar {
|
.user-avatar {
|
||||||
display: flex;
|
flex-shrink: 0;
|
||||||
justify-content: center;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
|
|
||||||
.avatar-wrapper {
|
.avatar-wrapper {
|
||||||
position: relative;
|
position: relative;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
border: 2px solid rgba(255, 255, 255, 0.5);
|
||||||
|
|
||||||
&:hover .avatar-overlay {
|
&:hover .avatar-overlay {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
@ -227,7 +274,7 @@ watch(showNicknameDialog, (newVal) => {
|
|||||||
left: 0;
|
left: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background: rgba(0, 0, 0, 0.5);
|
background: rgba(0, 0, 0, 0.55);
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -236,19 +283,41 @@ watch(showNicknameDialog, (newVal) => {
|
|||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
|
|
||||||
.upload-icon {
|
.upload-icon {
|
||||||
font-size: 24px;
|
font-size: 22px;
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.user-card-head-text {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.name-row {
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nickname {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #ffffff;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sub-stats {
|
||||||
|
font-size: 12px;
|
||||||
|
color: rgba(255, 255, 255, 0.82);
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
.user-info {
|
.user-info {
|
||||||
.info-item {
|
.info-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: flex-start;
|
||||||
margin-bottom: 12px;
|
margin-bottom: 10px;
|
||||||
font-size: 14px;
|
font-size: 13px;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
&:last-child {
|
&:last-child {
|
||||||
@ -257,14 +326,14 @@ watch(showNicknameDialog, (newVal) => {
|
|||||||
|
|
||||||
&.clickable {
|
&.clickable {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
padding: 4px 8px;
|
padding: 6px 8px;
|
||||||
margin-left: -8px;
|
margin-left: -8px;
|
||||||
margin-right: -8px;
|
margin-right: -8px;
|
||||||
border-radius: 4px;
|
border-radius: 6px;
|
||||||
transition: background-color 0.3s ease;
|
transition: background-color 0.2s ease;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: #f5f7fa;
|
background-color: rgba(255, 255, 255, 0.12);
|
||||||
|
|
||||||
.edit-icon {
|
.edit-icon {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
@ -273,23 +342,28 @@ watch(showNicknameDialog, (newVal) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.label {
|
.label {
|
||||||
color: #909399;
|
color: rgba(255, 255, 255, 0.72);
|
||||||
min-width: 50px;
|
min-width: 40px;
|
||||||
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.value {
|
.value {
|
||||||
color: #303133;
|
color: #ffffff;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
}
|
}
|
||||||
|
|
||||||
.edit-icon {
|
.edit-icon {
|
||||||
margin-left: 8px;
|
margin-left: 6px;
|
||||||
color: #409eff;
|
color: rgba(255, 255, 255, 0.95);
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transition: opacity 0.3s ease;
|
transition: opacity 0.2s ease;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
@import "../styles/luntan-dialog-tech.scss";
|
||||||
|
</style>
|
||||||
|
|||||||
@ -1,82 +1,304 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="luntan-container">
|
<div class="luntan-container">
|
||||||
<!-- 列表页 -->
|
<!-- 列表页:主列帖子 + 右侧信息栏 -->
|
||||||
<template v-if="!showDetail">
|
<template v-if="!showDetail">
|
||||||
<div class="luntan-left">
|
<div class="luntan-main">
|
||||||
<UserCard />
|
|
||||||
</div>
|
|
||||||
<div class="luntan-center">
|
|
||||||
<PostList @openDetail="handleOpenDetail" />
|
<PostList @openDetail="handleOpenDetail" />
|
||||||
</div>
|
</div>
|
||||||
<div class="luntan-right">
|
<aside class="luntan-sidebar">
|
||||||
<!-- 右侧留白区域,可以后续添加其他内容 -->
|
<UserCard />
|
||||||
</div>
|
<div class="hot-news-card" v-loading="hotLoading">
|
||||||
|
<div class="hot-news-head">
|
||||||
|
<span class="hot-news-title">热度消息</span>
|
||||||
|
<span class="hot-news-badge">HOT</span>
|
||||||
|
</div>
|
||||||
|
<ul class="hot-news-list">
|
||||||
|
<li
|
||||||
|
v-for="(item, index) in hotList"
|
||||||
|
:key="item.id"
|
||||||
|
class="hot-news-item"
|
||||||
|
@click="handleOpenDetail(item)"
|
||||||
|
>
|
||||||
|
<span class="hot-rank" :class="{ 'is-top': index < 3 }">{{
|
||||||
|
index + 1
|
||||||
|
}}</span>
|
||||||
|
<span class="hot-item-title">{{ item.lineTitle }}</span>
|
||||||
|
</li>
|
||||||
|
<li
|
||||||
|
v-if="!hotLoading && hotList.length === 0"
|
||||||
|
class="hot-news-empty"
|
||||||
|
>
|
||||||
|
暂无热度内容
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</aside>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- 详情页 -->
|
<!-- 详情页 -->
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<div class="luntan-left"></div>
|
<div class="luntan-detail-wrap">
|
||||||
<div class="luntan-detail">
|
<div class="luntan-detail">
|
||||||
<PostDetail :post-id="currentPostId" @back="handleBack" />
|
<PostDetail :post-id="currentPostId" @back="handleBack" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="luntan-right"></div>
|
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref } from 'vue'
|
import { ref, computed, onMounted } from "vue";
|
||||||
import UserCard from './components/UserCard.vue'
|
import UserCard from "./components/UserCard.vue";
|
||||||
import PostList from './components/PostList.vue'
|
import PostList from "./components/PostList.vue";
|
||||||
import PostDetail from './components/PostDetail.vue'
|
import PostDetail from "./components/PostDetail.vue";
|
||||||
|
import { tbGsxtXxltSelectPage } from "@/api/tbGsxtXxltHf";
|
||||||
|
import { setAddress } from "@/utils/tools";
|
||||||
|
import { qcckGet } from "@/api/qcckApi.js";
|
||||||
|
const showDetail = ref(false);
|
||||||
|
const currentPostId = ref(null);
|
||||||
|
|
||||||
const showDetail = ref(false)
|
const hotList = ref([]);
|
||||||
const currentPostId = ref(null)
|
const hotLoading = ref(false);
|
||||||
|
|
||||||
|
function lineTitleFromRecord(item) {
|
||||||
|
const tit = (item.title || "").trim();
|
||||||
|
if (tit) {
|
||||||
|
return tit.length > 40 ? `${tit.slice(0, 40)}…` : tit;
|
||||||
|
}
|
||||||
|
const t = (item.content || "").trim();
|
||||||
|
if (!t) return "无标题";
|
||||||
|
const idx = t.indexOf("\n");
|
||||||
|
const first = idx === -1 ? t : t.slice(0, idx).trim();
|
||||||
|
const line = first || t.slice(0, 60);
|
||||||
|
return line.length > 40 ? `${line.slice(0, 40)}…` : line;
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapHotPost(item) {
|
||||||
|
return {
|
||||||
|
id: item.id,
|
||||||
|
lineTitle: lineTitleFromRecord(item),
|
||||||
|
userName: item.fbrxm || "匿名用户",
|
||||||
|
userAvatar: item.fbrtx ? setAddress(item.fbrtx) : "",
|
||||||
|
userTag: item.userTag || "",
|
||||||
|
publishTime: item.time || "",
|
||||||
|
content: item.content || "",
|
||||||
|
images: item.tp ? item.tp.split(",").map((img) => setAddress(img)) : [],
|
||||||
|
commentCount: item.hfsl || 0,
|
||||||
|
likeCount: item.likeCount || 0,
|
||||||
|
isPremium: item.sfzd === 1,
|
||||||
|
isLiked: false,
|
||||||
|
ssbm: item.ssbm,
|
||||||
|
rawData: item
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadHotNews = () => {
|
||||||
|
hotLoading.value = true;
|
||||||
|
qcckGet({}, "/mosty-gsxt/tbGsxtXxlt/hotList")
|
||||||
|
.then((res) => {
|
||||||
|
console.log(res);
|
||||||
|
hotList.value = res.map(mapHotPost);
|
||||||
|
hotLoading.value = false;
|
||||||
|
})
|
||||||
|
.catch((err) => {})
|
||||||
|
.finally(() => {
|
||||||
|
hotLoading.value = false;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
loadHotNews();
|
||||||
|
});
|
||||||
|
|
||||||
const handleOpenDetail = (post) => {
|
const handleOpenDetail = (post) => {
|
||||||
currentPostId.value = post.id
|
currentPostId.value = post.id;
|
||||||
showDetail.value = true
|
showDetail.value = true;
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleBack = () => {
|
const handleBack = () => {
|
||||||
showDetail.value = false
|
showDetail.value = false;
|
||||||
currentPostId.value = null
|
currentPostId.value = null;
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
|
@import "./styles/luntan-tech.scss";
|
||||||
|
|
||||||
.luntan-container {
|
.luntan-container {
|
||||||
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 20px;
|
gap: 24px;
|
||||||
padding: 20px;
|
padding: 20px 24px;
|
||||||
background-color: #f5f7fa;
|
box-sizing: border-box;
|
||||||
min-height: calc(100vh - 60px);
|
/* 固定可视高度 + 隐藏溢出,让主列在内部滚动(flex 子项需 min-height:0) */
|
||||||
|
height: calc(100vh - 60px);
|
||||||
max-height: calc(100vh - 60px);
|
max-height: calc(100vh - 60px);
|
||||||
|
min-height: 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
background: #ffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.luntan-left {
|
.luntan-main {
|
||||||
width: 240px;
|
position: relative;
|
||||||
flex-shrink: 0;
|
z-index: 1;
|
||||||
}
|
|
||||||
|
|
||||||
.luntan-center {
|
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
min-height: 0;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.luntan-right {
|
.luntan-sidebar {
|
||||||
width: 240px;
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
width: 400px;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
|
min-height: 0;
|
||||||
|
align-self: stretch;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 16px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hot-news-card {
|
||||||
|
position: relative;
|
||||||
|
flex: 0 1 auto;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
border-radius: 12px;
|
||||||
|
background: #ffffff;
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.08);
|
||||||
|
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
:deep(.el-loading-mask) {
|
||||||
|
background-color: rgba(245, 247, 250, 0.7);
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-loading-spinner .path) {
|
||||||
|
stroke: #409eff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.hot-news-head {
|
||||||
|
flex-shrink: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 10px;
|
||||||
|
padding: 16px 18px 14px;
|
||||||
|
border-bottom: 1px solid rgba(0, 0, 0, 0.06);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hot-news-title {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #1a1a1a;
|
||||||
|
letter-spacing: 0.06em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hot-news-badge {
|
||||||
|
flex-shrink: 0;
|
||||||
|
padding: 3px 10px;
|
||||||
|
font-size: 10px;
|
||||||
|
font-weight: 800;
|
||||||
|
letter-spacing: 0.12em;
|
||||||
|
color: #fff;
|
||||||
|
border-radius: 4px;
|
||||||
|
background: linear-gradient(180deg, #ff7a3c 0%, #ff5722 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hot-news-list {
|
||||||
|
margin: 0;
|
||||||
|
padding: 8px 12px 12px;
|
||||||
|
list-style: none;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hot-news-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 12px;
|
||||||
|
padding: 12px 8px;
|
||||||
|
border-radius: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.15s ease;
|
||||||
|
|
||||||
|
& + .hot-news-item {
|
||||||
|
border-top: 1px solid rgba(0, 0, 0, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: rgba(64, 158, 255, 0.08);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.hot-rank {
|
||||||
|
flex-shrink: 0;
|
||||||
|
width: 22px;
|
||||||
|
height: 22px;
|
||||||
|
line-height: 22px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: #4b5563;
|
||||||
|
border-radius: 4px;
|
||||||
|
background: #f3f4f6;
|
||||||
|
border: 1px solid #e5e7eb;
|
||||||
|
|
||||||
|
&.is-top {
|
||||||
|
color: #fff;
|
||||||
|
background: linear-gradient(180deg, #ff7a3c 0%, #ff5722 100%);
|
||||||
|
border-color: rgba(255, 87, 34, 0.4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.hot-item-title {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
font-size: 13px;
|
||||||
|
line-height: 1.55;
|
||||||
|
color: $lt-text;
|
||||||
|
font-weight: 500;
|
||||||
|
word-break: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hot-news-item:hover .hot-item-title {
|
||||||
|
color: $lt-bar-blue-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hot-news-empty {
|
||||||
|
padding: 28px 12px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 13px;
|
||||||
|
color: $lt-text-muted;
|
||||||
|
list-style: none;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.luntan-detail-wrap {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
display: flex;
|
||||||
|
min-height: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.luntan-detail {
|
.luntan-detail {
|
||||||
height: 83vh;
|
height: 83vh;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
background: #fff;
|
border-radius: 4px;
|
||||||
border-radius: 8px;
|
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
|
background: #ffffff;
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.08);
|
||||||
|
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<!-- 非 scoped:el-image-viewer 通过 Teleport 挂到 body,需全局选择器 -->
|
||||||
|
<style lang="scss">
|
||||||
|
@import "./styles/luntan-tech.scss";
|
||||||
|
</style>
|
||||||
|
|||||||
104
src/views/backOfficeSystem/luntan/styles/luntan-dialog-tech.scss
Normal file
104
src/views/backOfficeSystem/luntan/styles/luntan-dialog-tech.scss
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
@import "./luntan-tech.scss";
|
||||||
|
@import "./luntan-v3emoji-tech.scss";
|
||||||
|
|
||||||
|
.luntan-tech-dialog.el-dialog {
|
||||||
|
background: rgba(8, 20, 48, 0.98) !important;
|
||||||
|
border: 1px solid $lt-border;
|
||||||
|
border-radius: 4px;
|
||||||
|
box-shadow: $lt-glow-strong, 0 16px 48px rgba(0, 0, 0, 0.55);
|
||||||
|
}
|
||||||
|
|
||||||
|
.luntan-tech-dialog .el-dialog__header {
|
||||||
|
border-bottom: 1px solid $lt-border-dim;
|
||||||
|
padding: 14px 18px;
|
||||||
|
margin: 0;
|
||||||
|
background: rgba(8, 20, 48, 0.98) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.luntan-tech-dialog .el-dialog__title {
|
||||||
|
color: $lt-text;
|
||||||
|
font-weight: 600;
|
||||||
|
letter-spacing: 0.06em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.luntan-tech-dialog .el-dialog__headerbtn .el-dialog__close {
|
||||||
|
color: $lt-text-muted;
|
||||||
|
}
|
||||||
|
|
||||||
|
.luntan-tech-dialog .el-dialog__headerbtn:hover .el-dialog__close {
|
||||||
|
color: $lt-cyan;
|
||||||
|
}
|
||||||
|
|
||||||
|
.luntan-tech-dialog .el-dialog__body {
|
||||||
|
padding: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.luntan-tech-dialog .el-dialog__footer {
|
||||||
|
border-top: 1px solid $lt-border-dim;
|
||||||
|
padding: 12px 18px;
|
||||||
|
background: rgba(8, 20, 48, 0.98) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.luntan-tech-dialog .el-form-item__label {
|
||||||
|
color: $lt-text-muted;
|
||||||
|
}
|
||||||
|
|
||||||
|
.luntan-tech-dialog .el-input__wrapper {
|
||||||
|
background: rgba(10, 28, 58, 0.85) !important;
|
||||||
|
box-shadow: 0 0 0 1px rgba(0, 227, 255, 0.28) inset !important;
|
||||||
|
border-radius: 4px;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
box-shadow: 0 0 0 1px rgba(0, 227, 255, 0.4) inset !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-focus {
|
||||||
|
box-shadow: 0 0 0 1px rgba(0, 227, 255, 0.55) inset,
|
||||||
|
0 0 14px rgba(0, 163, 255, 0.22) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.luntan-tech-dialog .el-input__inner {
|
||||||
|
color: $lt-text-dim;
|
||||||
|
}
|
||||||
|
|
||||||
|
.luntan-tech-dialog .el-input__count,
|
||||||
|
.luntan-tech-dialog .el-input__count .el-input__count-inner {
|
||||||
|
background: transparent !important;
|
||||||
|
color: $lt-text-muted;
|
||||||
|
}
|
||||||
|
|
||||||
|
.luntan-tech-dialog .el-textarea__inner {
|
||||||
|
background: rgba(10, 28, 58, 0.9) !important;
|
||||||
|
color: $lt-text-dim;
|
||||||
|
border: 1px solid rgba(0, 227, 255, 0.3);
|
||||||
|
border-radius: 4px;
|
||||||
|
box-shadow: inset 0 0 20px rgba(20, 80, 140, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.luntan-tech-dialog .el-button--default {
|
||||||
|
background: rgba(15, 40, 75, 0.65);
|
||||||
|
border-color: rgba(0, 163, 255, 0.35);
|
||||||
|
color: $lt-text-dim;
|
||||||
|
}
|
||||||
|
|
||||||
|
.luntan-tech-dialog .el-button--primary {
|
||||||
|
background: linear-gradient(180deg, #00a3ff 0%, #0066bb 100%);
|
||||||
|
border-color: rgba(0, 227, 255, 0.5);
|
||||||
|
box-shadow: 0 0 16px rgba(0, 163, 255, 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.luntan-tech-dialog .el-upload--picture-card {
|
||||||
|
background: rgba(10, 28, 58, 0.75) !important;
|
||||||
|
border-color: rgba(0, 227, 255, 0.35) !important;
|
||||||
|
|
||||||
|
.el-icon {
|
||||||
|
color: $lt-cyan;
|
||||||
|
font-size: 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border-color: rgba(0, 227, 255, 0.55) !important;
|
||||||
|
box-shadow: 0 0 14px rgba(0, 163, 255, 0.25);
|
||||||
|
}
|
||||||
|
}
|
||||||
115
src/views/backOfficeSystem/luntan/styles/luntan-tech.scss
Normal file
115
src/views/backOfficeSystem/luntan/styles/luntan-tech.scss
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
// 论坛模块 — 白色清新主题变量
|
||||||
|
$lt-bg: #f5f7fa;
|
||||||
|
$lt-bg-soft: #ffffff;
|
||||||
|
$lt-cyan: #4a9eff;
|
||||||
|
$lt-cyan-mid: #409eff;
|
||||||
|
$lt-panel: #ffffff;
|
||||||
|
$lt-panel-soft: #f8fafc;
|
||||||
|
$lt-border: rgba(0, 0, 0, 0.08);
|
||||||
|
$lt-border-dim: rgba(0, 0, 0, 0.04);
|
||||||
|
$lt-text: #333333;
|
||||||
|
$lt-text-dim: #666666;
|
||||||
|
$lt-text-muted: #999999;
|
||||||
|
$lt-glow: 0 1px 4px rgba(0, 0, 0, 0.06);
|
||||||
|
$lt-glow-strong: 0 2px 12px rgba(0, 0, 0, 0.08);
|
||||||
|
// 顶栏:与浅色页面、白字/白按钮协调的蓝色
|
||||||
|
$lt-bar-blue-start: #3d7dd6;
|
||||||
|
$lt-bar-blue-end: #2563eb;
|
||||||
|
$lt-bar-btn-text: #1d4ed8;
|
||||||
|
|
||||||
|
// 主题蓝 rgba(与顶栏渐变一致,便于详情页等复用)
|
||||||
|
@function lt-blue($alpha) {
|
||||||
|
@return rgba(37, 99, 235, $alpha);
|
||||||
|
}
|
||||||
|
|
||||||
|
@function lt-blue-light($alpha) {
|
||||||
|
@return rgba(61, 125, 214, $alpha);
|
||||||
|
}
|
||||||
|
|
||||||
|
@mixin lt-panel-frame {
|
||||||
|
background: $lt-panel;
|
||||||
|
border: 1px solid $lt-border;
|
||||||
|
box-shadow: $lt-glow;
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@mixin lt-panel-soft-bg {
|
||||||
|
background: $lt-panel-soft;
|
||||||
|
border: 1px solid $lt-border-dim;
|
||||||
|
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.05);
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@mixin lt-corner-brackets {
|
||||||
|
position: relative;
|
||||||
|
&::before,
|
||||||
|
&::after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
border-color: $lt-cyan-mid;
|
||||||
|
border-style: solid;
|
||||||
|
pointer-events: none;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
&::before {
|
||||||
|
top: -1px;
|
||||||
|
left: -1px;
|
||||||
|
border-width: 2px 0 0 2px;
|
||||||
|
box-shadow: -1px -1px 6px rgba(64, 158, 255, 0.2);
|
||||||
|
}
|
||||||
|
&::after {
|
||||||
|
bottom: -1px;
|
||||||
|
right: -1px;
|
||||||
|
border-width: 0 2px 2px 0;
|
||||||
|
box-shadow: 1px 1px 6px rgba(64, 158, 255, 0.2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// el-image-viewer 全屏预览覆盖
|
||||||
|
.el-image-viewer__wrapper {
|
||||||
|
background: rgba(0, 0, 0, 0.85) !important;
|
||||||
|
|
||||||
|
.el-image-viewer__mask {
|
||||||
|
background: rgba(0, 0, 0, 0.6) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-image-viewer__btn {
|
||||||
|
color: #fff;
|
||||||
|
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||||
|
background: rgba(80, 80, 80, 0.7);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: rgba(100, 100, 100, 0.85);
|
||||||
|
border-color: rgba(255, 255, 255, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.el-image-viewer__close {
|
||||||
|
top: 24px;
|
||||||
|
right: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.el-image-viewer__prev {
|
||||||
|
left: 24px;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.el-image-viewer__next {
|
||||||
|
right: 24px;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-image-viewer__canvas {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-icon {
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,64 @@
|
|||||||
|
@import './luntan-tech.scss';
|
||||||
|
|
||||||
|
// vue3-emoji(dist/style.css)默认浅色/白底,与论坛科技风统一
|
||||||
|
@mixin lt-v3-emoji-vars {
|
||||||
|
--V3Emoji-backgroundColor: rgba(10, 28, 58, 0.96);
|
||||||
|
--V3Emoji-hoverColor: rgba(0, 100, 160, 0.22);
|
||||||
|
--V3Emoji-activeColor: rgba(0, 130, 200, 0.3);
|
||||||
|
--V3Emoji-fontColor: #{$lt-text};
|
||||||
|
--V3Emoji-borderColor: #{rgba(0, 227, 255, 0.38)};
|
||||||
|
--V3Emoji-borderFocusColor: #{$lt-cyan};
|
||||||
|
--V3Emoji-shadowColor: rgba(0, 40, 90, 0.45);
|
||||||
|
}
|
||||||
|
|
||||||
|
.luntan-tech-dialog,
|
||||||
|
.comment-list .reply-input-box,
|
||||||
|
.luntan-tech-dialog .emoji-row {
|
||||||
|
@include lt-v3-emoji-vars;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 组件内未使用 CSS 变量的原生 input / textarea(仍为白底)
|
||||||
|
.luntan-tech-dialog [class*='emojiInput'] input,
|
||||||
|
.comment-list .reply-input-box [class*='emojiInput'] input {
|
||||||
|
background: rgba(10, 28, 58, 0.92) !important;
|
||||||
|
color: $lt-text-dim !important;
|
||||||
|
border-color: rgba(0, 227, 255, 0.35) !important;
|
||||||
|
box-shadow: inset 0 0 12px rgba(0, 50, 100, 0.25) !important;
|
||||||
|
|
||||||
|
&::placeholder {
|
||||||
|
color: $lt-text-muted;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.luntan-tech-dialog [class*='emojiTextarea'] textarea,
|
||||||
|
.comment-list .reply-input-box [class*='emojiTextarea'] textarea {
|
||||||
|
background: rgba(10, 28, 58, 0.92) !important;
|
||||||
|
color: $lt-text-dim !important;
|
||||||
|
border-color: rgba(0, 227, 255, 0.35) !important;
|
||||||
|
box-shadow: inset 0 0 12px rgba(0, 50, 100, 0.25) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.luntan-tech-dialog [class*='emojiContainerOpenBtn'],
|
||||||
|
.luntan-tech-dialog [class*='emojiTextareaOpenBtn'],
|
||||||
|
.comment-list .reply-input-box [class*='emojiContainerOpenBtn'],
|
||||||
|
.comment-list .reply-input-box [class*='emojiTextareaOpenBtn'] {
|
||||||
|
color: $lt-cyan !important;
|
||||||
|
filter: drop-shadow(0 0 6px rgba(0, 227, 255, 0.35));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 表情面板可能 teleport / 挂到 body,需单独写选择器
|
||||||
|
[class*='V3Emoji-vue'][class*='__pollup___'],
|
||||||
|
[class*='PollUp-vue'][class*='__pollup___'] {
|
||||||
|
@include lt-v3-emoji-vars;
|
||||||
|
}
|
||||||
|
|
||||||
|
[id='EmojiItem'],
|
||||||
|
[id*='EmojiItem'] {
|
||||||
|
::-webkit-scrollbar-thumb {
|
||||||
|
background-color: rgba(0, 163, 255, 0.45) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-track {
|
||||||
|
background: rgba(8, 20, 48, 0.88) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user