This commit is contained in:
2025-07-16 18:33:13 +08:00
parent e2c18bf8df
commit 122208d9cb
8 changed files with 617 additions and 179 deletions

View File

@ -1,18 +1,46 @@
<template>
<el-dialog :title="titleValue" width="1400px" :model-value="modelValue" append-to-body @close="closed">
<el-dialog
:title="titleValue"
width="1400px"
:model-value="modelValue"
append-to-body
@close="closed"
>
<div>
<el-form :model="listQuery" class="mosty-from-wrap" :inline="true">
<el-form-item label="标签名称">
<el-input placeholder="请输入标签名称" v-model="listQuery.bqMc" clearable ></el-input>
<el-input
placeholder="请输入标签名称"
v-model="listQuery.bqMc"
clearable
></el-input>
</el-form-item>
<el-form-item>
<el-button type="success" @click="handleFilter">查询</el-button>
<el-button type="info" @click="reset"> 重置 </el-button>
</el-form-item>
</el-form>
<div class="tabBox" :class="props.Single ? 'tabBoxRadio' : ''" :key="keyVal" style="margin-top: 0px">
<el-table ref="multipleUserRef" @selection-change="handleSelectionChange" :data="tableData" v-loading="loading" border :row-key="keyid" style="width: 100%" height="450">
<el-table-column type="selection" width="55" :reserve-selection="true"/>
<div
class="tabBox"
:class="props.Single ? 'tabBoxRadio' : ''"
:key="keyVal"
style="margin-top: 0px"
>
<el-table
ref="multipleUserRef"
@selection-change="handleSelectionChange"
:data="tableData"
v-loading="loading"
border
:row-key="keyid"
style="width: 100%"
height="450"
>
<el-table-column
type="selection"
width="55"
:reserve-selection="true"
/>
<el-table-column prop="bqMc" align="center" label="标签名称" />
<el-table-column prop="bqDm" align="center" label="标签代码" />
<el-table-column prop="bqDj" align="center" label="标签等级">
@ -77,14 +105,14 @@ const props = defineProps({
default: []
}
});
const loading = ref(false)
const loading = ref(false);
const total = ref(0);
const listQuery = ref({
pages: 1,
size: 20
});
const keyVal = ref()
const keyVal = ref();
const multipleUserRef = ref(null);
const multipleSelectionUser = ref([]);
const tableData = ref([]);
@ -97,11 +125,10 @@ const closed = () => {
emits("update:modelValue", false);
};
const reset = () => {
listQuery.value = { pages: 1, size: 20, };
listQuery.value = { pages: 1, size: 20 };
getListData();
};
// 为用户分配角色
const onComfirm = () => {
const userList = multipleSelectionUser.value;
@ -133,15 +160,17 @@ const handleCurrentChange = (currentPage) => {
const getListData = () => {
keyVal.value++;
loading.value = true;
const params = { ...listQuery.value, bqLb:'02',}
qcckGet(params,'/mosty-gsxt/tbGsxtBqgl/selectPage').then(res=>{
const params = { ...listQuery.value, bqLb: "02" };
qcckGet(params, "/mosty-gsxt/tbGsxtBqgl/selectPage")
.then((res) => {
loading.value = false;
tableData.value = res.records || [];
total.value = res.total;
multipleUser();
}).catch(()=>{
loading.value = false;
})
.catch(() => {
loading.value = false;
});
};
//列表回显
@ -171,10 +200,13 @@ const handleSelectionChange = (val) => {
}
};
watch(()=>props.modelValue,val=>{
watch(
() => props.modelValue,
(val) => {
if (val) handleFilter();
},{immediate:true})
},
{ immediate: true }
);
</script>
<style lang="scss" scoped>
@ -188,5 +220,4 @@ watch(()=>props.modelValue,val=>{
.tabBoxRadio .el-table__header-wrapper .el-checkbox {
display: none;
}
</style>

View File

@ -1,8 +1,15 @@
<template>
<!--选择图标-->
<div class="form-item-box choose-icon-zj" :style="{ width: width }">
<el-autocomplete v-bind="$attrs" v-model="modelValue" :fetch-suggestions="querySearch"
popper-class="choose-icon-zj-autocomplete" :placeholder="placeholder" @change="onInput" @select="handleSelect">
<el-autocomplete
v-bind="$attrs"
v-model="modelValue"
:fetch-suggestions="querySearch"
popper-class="choose-icon-zj-autocomplete"
:placeholder="placeholder"
@change="onInput"
@select="handleSelect"
>
<template #prefix>
<SvgIcon :icon="modelValue"></SvgIcon>
</template>
@ -57,8 +64,7 @@ const handleSelect = (item) => {
emits("update:modelValue", item.value);
};
const handleIconClick = (ev) => {
};
const handleIconClick = (ev) => {};
const loadAll = () => {
const svgRequire = require.context("@/icons/svg", false, /\.svg$/);

View File

@ -0,0 +1,238 @@
<template>
<div>
<el-dialog
v-model="modelValue"
title="文件解析"
width="1000px"
:show-close="true"
:center="true"
:close-on-click-modal="false"
:before-close="handleClose"
>
<h1>文件文本提取工具</h1>
<p>上传文件提取文本内容支持 .txt, .pdf, .docx, mp4 , mp3, wav</p>
<div class="container">
<input
type="file"
id="file-input"
accept=".txt,.pdf,.docx,'.mp4','.mp3','.wav'"
/>
<button @click="chooseFile">选择文件</button>
<p id="file-info">未选择文件</p>
</div>
<button id="extract-btn" disabled>提取文本</button>
<h3>提取结果</h3>
<div id="result">请先上传文件...</div>
<template #footer>
<el-button @click="handleClose">取消</el-button>
<el-button type="primary" @click="onComfirm">确认</el-button>
</template>
</el-dialog>
</div>
</template>
<script setup>
import { nextTick, onMounted, ref } from "vue";
const props = defineProps({
modelValue: {
type: Boolean,
default: false
}
});
const emits = defineEmits(["update:modelValue", "change"]);
onMounted(() => {
nextTick(() => {
const fileInput = document.getElementById("file-input");
const fileInfo = document.getElementById("file-info");
const extractBtn = document.getElementById("extract-btn");
const resultDiv = document.getElementById("result");
let selectedFile = null;
// 监听文件选择
fileInput.addEventListener("change", function (e) {
if (e.target.files.length > 0) {
selectedFile = e.target.files[0];
fileInfo.textContent = `已选择: ${selectedFile.name} (${(
selectedFile.size / 1024
).toFixed(2)} KB)`;
extractBtn.disabled = false;
} else {
selectedFile = null;
fileInfo.textContent = "未选择文件";
extractBtn.disabled = true;
}
if (selectedFile.type == "video/mp4") {
upfileOnchange(selectedFile);
}
});
// 提取文本按钮点击事件
extractBtn.addEventListener("click", async function () {
if (!selectedFile) return (resultDiv.textContent = "请先选择文件");
resultDiv.textContent = "正在处理文件...";
try {
let text = "";
const fileType = selectedFile.name.split(".").pop().toLowerCase();
console.log(selectedFile);
if (fileType === "txt") {
// 处理文本文件
text = await readTextFile(selectedFile);
} else if (fileType === "pdf") {
// 处理PDF文件
text = await extractTextFromPDF(selectedFile);
} else if (fileType === "docx") {
// 处理Word文件
text = await extractTextFromDocx(selectedFile);
console.log(text, "===word");
} else if (["mp4", "mp3", "wav"].includes(fileType)) {
// 处理mp4,mp3,wav文件
await start();
text = "数据加载有点慢,请稍等。。。。";
setTimeout(() => {
resultDiv.textContent = videoText;
}, 2000);
} else {
throw new Error("不支持的文件类型");
}
resultDiv.textContent = text || "未提取到文本内容";
} catch (error) {
resultDiv.textContent = `处理失败: ${error.message}`;
console.error(error);
}
});
});
});
// 读取文本文件
function readTextFile(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = (e) => resolve(e.target.result);
reader.onerror = (e) => reject(new Error("文件读取失败"));
reader.readAsText(file);
});
}
// 提取PDF文本
async function extractTextFromPDF(file) {
return new Promise((resolve, reject) => {
const fileReader = new FileReader();
fileReader.onload = async function () {
try {
const typedArray = new Uint8Array(this.result);
const pdf = await pdfjsLib.getDocument(typedArray).promise;
let fullText = "";
for (let i = 1; i <= pdf.numPages; i++) {
const page = await pdf.getPage(i);
const textContent = await page.getTextContent();
const text = textContent.items.map((item) => item.str).join(" ");
fullText += text + "\n\n";
}
resolve(fullText);
} catch (error) {
reject(error);
}
};
fileReader.onerror = reject;
fileReader.readAsArrayBuffer(file);
});
}
// 提取Word文档文本
async function extractTextFromDocx(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = function (event) {
const arrayBuffer = event.target.result;
mammoth
.extractRawText({ arrayBuffer: arrayBuffer })
.then(function (result) {
resolve(result.value);
})
.catch(function (error) {
reject(error);
});
};
reader.onerror = reject;
reader.readAsArrayBuffer(file);
});
}
const onComfirm = () => {
const resultDiv = document.getElementById("result");
let obj = {
text: resultDiv.textContent
};
emits("change", obj);
};
// 关闭
const handleClose = () => {
const resultDiv = document.getElementById("result");
resultDiv.textContent = "请先上传文件";
const fileInfo = document.getElementById("file-info");
fileInfo.textContent = "未选择文件";
emits("update:modelValue", false);
};
const chooseFile = () => {
document.getElementById("file-input").click();
};
</script>
<style lang="scss" scoped>
.container {
border: 2px dashed #ccc;
padding: 20px;
text-align: center;
margin-bottom: 20px;
}
#file-input {
display: none;
}
button {
background: #4caf50;
color: white;
padding: 10px 15px;
border: none;
cursor: pointer;
font-size: 16px;
border-radius: 4px;
}
button:hover {
background: #45a049;
}
#result {
margin-top: 20px;
white-space: pre-wrap;
background: #f9f9f9;
padding: 15px;
border: 1px solid #ddd;
border-radius: 4px;
height: 320px;
overflow-y: auto;
}
#file-info {
margin: 10px 0;
font-style: italic;
color: #666;
}
::v-deep .el-dialog {
margin-top: 10px;
}
</style>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,24 +1,8 @@
<template>
<div class="exportBox">
<el-dialog
v-model="show"
title="导入文件"
width="400px"
:show-close="true"
:center="true"
:before-close="handleClose"
>
<el-dialog v-model="show" title="导入文件" width="400px" :show-close="true" :center="true" :before-close="handleClose">
<div class="uplodBox">
<el-upload
action="#"
drag
:on-success="handleSuccess"
:on-change="handleChange"
:show-file-list="true"
:file-list="fileDate"
accept=".xls,.xlsx"
:auto-upload="false"
>
<el-upload action="#" drag :on-success="handleSuccess" :on-change="handleChange" :show-file-list="true" :file-list="fileDate" accept=".xls,.xlsx" :auto-upload="false">
<el-icon class="el-icon-upload" size="100"><upload-filled /></el-icon>
<div class="el-upload-text">
拖动或者点击上传或者<span @click.stop="downloadModel" class="model">下载模板</span>
@ -27,9 +11,7 @@
</el-upload>
</div>
<div class="check">
<el-checkbox true-label="true" false-label="false" v-model="isSelect"
>是否替换已存在的数据</el-checkbox
>
<el-checkbox true-label="true" false-label="false" v-model="isSelect">是否替换已存在的数据</el-checkbox>
</div>
<div class="foot">
<el-button @click="handleClose">取消</el-button>
@ -42,7 +24,6 @@
<script setup>
import axios from "axios";
import { ElMessage } from "element-plus";
import { qcckPost, qcckGet } from "@/api/qcckApi.js";
import { useStore } from "vuex";
import { ref, defineProps, defineEmits, watch } from "vue";
const store = useStore();

View File

@ -2,7 +2,11 @@
<div class="statistical-analysis">
<!-- 左侧树形菜单 -->
<div class="left-menu">
<CheckBox :data="checkData" customClass="all" @changeData="changeData"></CheckBox>
<CheckBox
:data="checkData"
customClass="all"
@changeData="changeData"
></CheckBox>
</div>
<!-- 右侧内容区 -->
<div class="right-content">
@ -11,8 +15,13 @@
<PageTitle title="发掘内容" style="color: #333">
<el-button type="primary" size="small" @click="handleData('add', '')">
<el-icon style="vertical-align: middle"><CirclePlus /></el-icon>
<span style="vertical-align: middle" @click="handleData('add', '')" >新增</span>
<span style="vertical-align: middle" @click="handleData('add', '')"
>新增</span
>
</el-button>
<!-- <el-button type="primary" size="small" @click="showText = true">
<span style="vertical-align: middle">导入内容</span>
</el-button> -->
<el-button type="primary" size="small" @click="isImport = true">
<span style="vertical-align: middle">导入内容</span>
</el-button>
@ -35,9 +44,21 @@
</template>
<!-- 操作 -->
<template #controls="{ row }">
<el-link size="small" type="success" @click="handleData('edit', row)">编辑</el-link>
<el-link size="small" type="primary" @click="handleData('info', row)">查看</el-link>
<el-link size="small" type="danger" @click="deleteRow([row.id])">删除</el-link>
<el-link
size="small"
type="success"
@click="handleData('edit', row)"
>编辑</el-link
>
<el-link
size="small"
type="primary"
@click="handleData('info', row)"
>查看</el-link
>
<el-link size="small" type="danger" @click="deleteRow([row.id])"
>删除</el-link
>
</template>
</MyTable>
<div class="ww100 flex just-center mt8">
@ -45,9 +66,20 @@
</div>
</div>
<div class="tableCnt mb10 pl10 pr10">
<PageTitle title="模型智能识别/LP解析结果" style="color: #333" ></PageTitle>
<PageTitle
title="模型智能识别/LP解析结果"
style="color: #333"
></PageTitle>
<div ref="searchBox" class="mb8">
<el-button :type="it == '批量删除' ? 'danger':'primary'" size="small" v-for="it in btnsList" :key="it" @click="chooseType(it)"> {{ it }} </el-button>
<el-button
:type="it == '批量删除' ? 'danger' : 'primary'"
size="small"
v-for="it in btnsList"
:key="it"
@click="chooseType(it)"
>
{{ it }}
</el-button>
</div>
<div>
<MyTable
@ -61,7 +93,9 @@
>
<template #bqList="{ row }">
<div v-if="row.bqList">
<el-tag v-for="(it,idx) in row.bqList" :key="idx">{{ it.bqMc }}</el-tag>
<el-tag v-for="(it, idx) in row.bqList" :key="idx"
>{{ it.bqMc }}</el-tag
>
</div>
</template>
<template #fxDj="{ row }">
@ -89,8 +123,15 @@
</template>
<!-- 操作 -->
<template #controls="{ row }">
<el-link size="small" type="danger" @click="deleteRowBottom(row.id)">删除</el-link>
<el-link size="small" type="primary" @click="viewDetails(row)">查看</el-link>
<el-link
size="small"
type="danger"
@click="deleteRowBottom(row.id)"
>删除</el-link
>
<el-link size="small" type="primary" @click="viewDetails(row)"
>查看</el-link
>
</template>
</MyTable>
<Pages
@ -99,20 +140,40 @@
:tableHeight="pageData.tableHeight2"
:pageConfiger="{
...pageData.pageConfiger,
total: pageData.total }"></Pages>
total: pageData.total
}"
></Pages>
</div>
</div>
</div>
<!-- 弹窗智能分析 -->
<IntelligentParsing :tableData="pageData.tableData" ref="IntelligentParsingRef" @upadate="getModelList" />
<IntelligentParsing
:tableData="pageData.tableData"
ref="IntelligentParsingRef"
@upadate="getModelList"
/>
<addForm ref="addFormDiloag" @onSearch="onSearch" />
<Model v-model="isShow" :type="chooselx" :ids="ids" @change="getModelList" :dic="{D_GS_RQFJ_FXDJ}"></Model>
<Export :show="isImport" lx="fjnr" @closeImport="isImport = false" @handleImport="getList" />
<Model
v-model="isShow"
:type="chooselx"
:ids="ids"
@change="getModelList"
:dic="{ D_GS_RQFJ_FXDJ }"
></Model>
<Export
:show="isImport"
lx="fjnr"
@closeImport="isImport = false"
@handleImport="getList"
/>
<!-- 文字解析 -->
<TextExtraction v-model="showText"></TextExtraction>
</div>
</template>
<script setup>
import { download } from "@/utils/request";
import TextExtraction from "@/components/TextExtraction/index.vue";
import Export from "@/components/export/index.vue";
import CheckBox from "@/components/checkBox/index.vue";
import PageTitle from "@/components/aboutTable/PageTitle.vue";
@ -126,22 +187,47 @@ import { ElMessage } from "element-plus";
import { qcckGet, qcckDelete } from "@/api/qcckApi.js";
import { reactive, ref, onMounted, getCurrentInstance } from "vue";
const { proxy } = getCurrentInstance();
const { D_GS_RQFJ_LX, D_GS_RQFJ_FXDJ, D_BZ_SF, D_GS_RQFJ_FXLB } = proxy.$dict('D_GS_RQFJ_FXDJ',"D_GS_RQFJ_LX","D_GS_RQFJ_FXDJ","D_BZ_SF","D_GS_RQFJ_FXLB"); //获取字典数据
const { D_GS_RQFJ_LX, D_GS_RQFJ_FXDJ, D_BZ_SF, D_GS_RQFJ_FXLB } = proxy.$dict(
"D_GS_RQFJ_FXDJ",
"D_GS_RQFJ_LX",
"D_GS_RQFJ_FXDJ",
"D_BZ_SF",
"D_GS_RQFJ_FXLB"
); //获取字典数据
const showText = ref(false);
const searchConfiger = ref([
{ label: "管辖部门", prop: "ssbm", placeholder: "请选择管辖部门", showType: "department" },
{ label: "是否关注", prop: "sfgz", placeholder: "请选择是否关注", showType: "select", options:D_BZ_SF },
{
label: "管辖部门",
prop: "ssbm",
placeholder: "请选择管辖部门",
showType: "department"
},
{
label: "是否关注",
prop: "sfgz",
placeholder: "请选择是否关注",
showType: "select",
options: D_BZ_SF
}
]);
const isImport = ref(false)
const isImport = ref(false);
const checkData = reactive({
hasChoose: ["警情"],
list: ["警情","人力情报","线索","民警处置文本", "交通事故"],
list: ["警情", "人力情报", "线索", "民警处置文本", "交通事故"]
});
const btnsList = reactive(['级别变更','警种变更','指定分配','添加标签','导出','批量删除'])
const btnsList = reactive([
"级别变更",
"警种变更",
"指定分配",
"添加标签",
"导出",
"批量删除"
]);
const chooselx = ref('')
const isShow = ref(false)
const idsTop = ref([])
const ids = ref([])
const chooselx = ref("");
const isShow = ref(false);
const idsTop = ref([]);
const ids = ref([]);
const addFormDiloag = ref();
const IntelligentParsingRef = ref();
@ -183,12 +269,42 @@ const pageData = reactive({
{ label: "管辖单位", prop: "gxDwDm", showOverflowTooltip: true },
{ label: "管控民警", prop: "gxMj", showOverflowTooltip: true },
{ label: "责任部门", prop: "ssbm", showOverflowTooltip: true },
{ label: "标签", prop: "bqList",showOverflowTooltip:true, showSolt: true },
{ label: "风险等级", prop: "fxDj",showOverflowTooltip:true, showSolt: true },
{ label: "风险类别", prop: "fxLb",showOverflowTooltip:true, showSolt: true },
{ label: "是否关注", prop: "sfGz",showOverflowTooltip:true, showSolt: true },
{ label: "是否转布控人员", prop: "sfZbkry",showOverflowTooltip:true, showSolt: true },
{ label: "是否转重点人员", prop: "sfZzdry",showOverflowTooltip:true, showSolt: true }
{
label: "标签",
prop: "bqList",
showOverflowTooltip: true,
showSolt: true
},
{
label: "风险等级",
prop: "fxDj",
showOverflowTooltip: true,
showSolt: true
},
{
label: "风险类别",
prop: "fxLb",
showOverflowTooltip: true,
showSolt: true
},
{
label: "是否关注",
prop: "sfGz",
showOverflowTooltip: true,
showSolt: true
},
{
label: "是否转布控人员",
prop: "sfZbkry",
showOverflowTooltip: true,
showSolt: true
},
{
label: "是否转重点人员",
prop: "sfZzdry",
showOverflowTooltip: true,
showSolt: true
}
]
});
@ -213,10 +329,12 @@ const getList = () => {
pageData.tableConfiger.loading = true;
let data = { ...queryFrom.value };
let url = "/mosty-gsxt/tbGsxtRqfjNr/selectPage";
qcckGet(data, url).then((res) => {
qcckGet(data, url)
.then((res) => {
pageData.tableData = res.records || [];
pageData.tableConfiger.loading = false;
}).catch(() => {
})
.catch(() => {
pageData.tableConfiger.loading = false;
});
};
@ -225,14 +343,16 @@ const getList = () => {
const getModelList = () => {
let data = { ...pageData.pageConfiger };
pageData.tableConfiger0.loading = true;
qcckGet(data, "/mosty-gsxt/tbGsxtRqfjRy/selectPage").then((res) => {
qcckGet(data, "/mosty-gsxt/tbGsxtRqfjRy/selectPage")
.then((res) => {
pageData.tableConfiger0.loading = false;
pageData.tableData2 = res.records || [];
pageData.total = res.total;
ids.value = []
}).catch(()=>{
pageData.tableConfiger0.loading = false;
ids.value = [];
})
.catch(() => {
pageData.tableConfiger0.loading = false;
});
};
//新增- 编辑
const handleData = (type, row) => {
@ -243,64 +363,65 @@ const intelligent = () => {
IntelligentParsingRef.value.init();
};
// 选择数据
const chooseDataTop = (val) => {
if(Array.isArray(val)) idsTop.value = val.map(item=>item.id);
}
if (Array.isArray(val)) idsTop.value = val.map((item) => item.id);
};
//删除操作
const deleteRow = (ids) => {
proxy.$confirm("确定要删除", "警告", { type: "warning" }).then(() => {
ids.forEach(id=>{
ids.forEach((id) => {
qcckGet({}, "/mosty-gsxt/tbGsxtRqfjNr/closeById/" + id).then((res) => {
ElMessage.success("删除成功");
getList();
})
})
})
});
});
});
};
const deleteRowBottom = (id) => {
proxy.$confirm("确定要删除", "警告", { type: "warning" }).then(() => {
qcckDelete({}, "/mosty-gsxt/tbGsxtRqfjRy/" + id).then((res) => {
ElMessage.success("删除成功");
getModelList();
})
})
});
});
};
// 选择数据
const chooseDataBottom = (val) => {
if(Array.isArray(val)) ids.value = val.map(item=>item.id);
}
if (Array.isArray(val)) ids.value = val.map((item) => item.id);
};
const chooseType = (val) => {
chooselx.value = val;
switch (val) {
case '级别变更':
case '警种变更':
case '指定分配':
case '添加标签':
case "级别变更":
case "警种变更":
case "指定分配":
case "添加标签":
if (ids.value.length == 0) return ElMessage.warning("请选择对应的数据");
isShow.value = true;
break;
case '导出':
case "导出":
// download("/mosty-api/mosty-gsxt/tbGsxtRqfjRy/exportRyfjFxjg", {"bkBt":"1"},`模型智能识别/LP解析结果_${new Date().getTime()}.xlsx`);
break;
case '批量删除':
if(ids.value.length == 0) return ElMessage.warning("请选择对应删除的数据");
ids.value.forEach(id=>{
case "批量删除":
if (ids.value.length == 0)
return ElMessage.warning("请选择对应删除的数据");
ids.value.forEach((id) => {
deleteRowBottom(id);
})
});
break;
}
}
};
const tabHeightFn = () => {
pageData.tableHeight2 = window.innerHeight - searchBox.value.offsetHeight - 650;
window.onresize = function () { tabHeightFn(); };
pageData.tableHeight2 =
window.innerHeight - searchBox.value.offsetHeight - 650;
window.onresize = function () {
tabHeightFn();
};
};
onMounted(() => {
@ -346,7 +467,6 @@ onMounted(() => {
.all {
width: calc(100% - 4px);
}
}
.right-content {
float: left;