Compare commits
146 Commits
28d7d0e8f0
...
main
Author | SHA1 | Date | |
---|---|---|---|
71487ac647 | |||
2b06febd8e | |||
42e9bd894c | |||
820d543f4a | |||
50ff873463 | |||
a5c48d796c | |||
058b870b35 | |||
951ff3cba2 | |||
24351e4f7d | |||
33a5f56d83 | |||
81b2319acc | |||
b3b30026c9 | |||
1c3a25f527 | |||
bcbf0be923 | |||
78c589bf3c | |||
4f4530bc2a | |||
cd4b85c587 | |||
326d0f0d13 | |||
73fc5e2a00 | |||
a961f32d93 | |||
1e1cbdf6f1 | |||
1dc72750f6 | |||
18e569cdd0 | |||
3b30b2b834 | |||
03d2e9f459 | |||
2eb2a41b06 | |||
3d439b62e6 | |||
63442217fc | |||
b6e8df30ff | |||
e453742024 | |||
6396f9c13c | |||
3870addd51 | |||
677f2c4a3b | |||
7d809e52d2 | |||
36d23fcbdb | |||
3c1c42a8c5 | |||
6d106674bd | |||
33ceb7a85a | |||
8ea67fd810 | |||
a334d9f61e | |||
08ba25b66a | |||
fdab1188c0 | |||
cf8651fb14 | |||
49ae691b37 | |||
211b947c3c | |||
fdf75c11d2 | |||
b8f943ca79 | |||
83d732d805 | |||
c1abd76205 | |||
2ab7f59898 | |||
a6b918f762 | |||
32de231f1b | |||
057cd0fda6 | |||
1074049a6b | |||
671e33492d | |||
465876a5cc | |||
8b92e91215 | |||
f4bd352162 | |||
fbd2431f63 | |||
72a2e174c1 | |||
874b4a5994 | |||
5ccbc7f3d4 | |||
ce8eee2380 | |||
e447346af5 | |||
92c3c00b98 | |||
20cb6743cd | |||
e1c84d9b27 | |||
cacb2218cd | |||
fcc7c7dc68 | |||
3f4fa2dd0e | |||
26a946daae | |||
b470f5946b | |||
6367754737 | |||
ba54ca1efb | |||
f80a0e5539 | |||
a03780b352 | |||
7407a43c85 | |||
726bae2652 | |||
596760a707 | |||
122208d9cb | |||
e2c18bf8df | |||
b98625f344 | |||
3019295319 | |||
91cadd297c | |||
896590f35c | |||
186f647473 | |||
dfae83dae9 | |||
ee12595e1f | |||
b6818d430e | |||
f01d911476 | |||
9b9b2e6e8f | |||
0f5f6c27d2 | |||
498caf263d | |||
a94687d5fa | |||
42cb2cb268 | |||
3b6e0d6912 | |||
26b52c0175 | |||
6ff3f78b75 | |||
b288168070 | |||
39ae9755db | |||
c7c239e1ee | |||
b30a8b4a33 | |||
446304ae1b | |||
694ad9a54c | |||
e940744dd8 | |||
09a47e5369 | |||
6a2b4e12c5 | |||
dc43ddd3c5 | |||
f6d433fd65 | |||
bfc6504e2d | |||
813e5a9c97 | |||
d32f7fe5bc | |||
cd4f8a95d2 | |||
7c9b3152f8 | |||
15e23797ac | |||
bf1b90c578 | |||
c438006604 | |||
342754ca20 | |||
0fe250f0fd | |||
f65adab730 | |||
9039840986 | |||
9cb8877486 | |||
d3031e0aee | |||
193cc06752 | |||
69bee283a8 | |||
f5d605fc23 | |||
f8559da65b | |||
a903362712 | |||
2f443e33bd | |||
529089b73c | |||
a487cf59a1 | |||
b90aa5371a | |||
e07beea359 | |||
5e9638fba3 | |||
d0d3da243c | |||
b2880cd82c | |||
5f6f37a166 | |||
be93c68817 | |||
7705b46451 | |||
df1e33c9bf | |||
f3e0a1823e | |||
3346582af9 | |||
e5ca357876 | |||
f6390c9002 | |||
a825e90ec4 | |||
e0ae89616b |
4
.gitignore
vendored
@ -1,6 +1,8 @@
|
||||
.DS_Store
|
||||
node_modules
|
||||
/dist
|
||||
# dist/
|
||||
# build/
|
||||
gsxt/
|
||||
|
||||
# local env files
|
||||
.env.local
|
||||
|
20632
package-lock.json
generated
@ -15,6 +15,8 @@
|
||||
"@fullcalendar/list": "^5.9.0",
|
||||
"@fullcalendar/timegrid": "^5.9.0",
|
||||
"@fullcalendar/vue3": "^5.9.0",
|
||||
"@paddlejs-models/ocr": "^1.1.2",
|
||||
"@paddlejs-models/ocrdet": "^0.0.3",
|
||||
"@types/video.js": "^7.3.42",
|
||||
"@wangeditor/editor": "^5.1.23",
|
||||
"@wangeditor/editor-for-vue": "^5.1.12",
|
||||
@ -24,12 +26,15 @@
|
||||
"echarts-gl": "^2.0.9",
|
||||
"el-table-infinite-scroll": "^3.0.6",
|
||||
"element-plus": "2.0.2",
|
||||
"file-saver": "^2.0.5",
|
||||
"gifler": "^0.1.0",
|
||||
"image-compressor.js": "^1.1.4",
|
||||
"lodash": "^4.17.21",
|
||||
"mitt": "^3.0.0",
|
||||
"moment": "^2.30.1",
|
||||
"ol": "^6.14.1",
|
||||
"pinia": "^3.0.1",
|
||||
"tesseract.js": "^6.0.1",
|
||||
"vue": "^3.2.8",
|
||||
"vue-router": "^4.0.11",
|
||||
"vuex": "^4.0.2",
|
||||
|
@ -20,8 +20,8 @@
|
||||
<%= htmlWebpackPlugin.options.title %>
|
||||
</title>
|
||||
|
||||
<!-- 地图 -->
|
||||
<script type="text/javascript" src="./pgis/eliMapboxgl.min.js"></script>
|
||||
<!-- 地图 -->
|
||||
<script type="text/javascript" src="./pgis/eliMapboxgl.min.js"></script>
|
||||
|
||||
<!-- 视频 -->
|
||||
<script src="./static/js/vconsole.min.js"></script>
|
||||
@ -31,26 +31,34 @@
|
||||
<script src="./static/js/antd.min.js"></script>
|
||||
<script src="./static/js/antd-with-locales.min.js"></script>
|
||||
|
||||
<!-- 文本提取 -->
|
||||
<script src="./textPdf/pdf.min.js"></script>
|
||||
<!-- 引入mammoth.js处理Word文件 -->
|
||||
<script src="./textPdf/mammoth.browser.min.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<noscript>
|
||||
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work
|
||||
properly without JavaScript enabled. Please enable it to
|
||||
continue.</strong>
|
||||
</noscript>
|
||||
<!-- 语音- 视频 提取 -->
|
||||
<script src="./textVideo/recorder-core.js" charset="UTF-8"></script>
|
||||
<script src="./textVideo/wav.js" charset="UTF-8"></script>
|
||||
<script src="./textVideo/pcm.js" charset="UTF-8"></script>
|
||||
<noscript><strong></strong> </noscript>
|
||||
|
||||
<div id="app"></div>
|
||||
<script>
|
||||
document.documentElement.addEventListener(
|
||||
"touchmove",
|
||||
var imgIsLoad = false
|
||||
var videoText = ''
|
||||
// 初始化PDF.js
|
||||
pdfjsLib.GlobalWorkerOptions.workerSrc = "./textPdf/pdf.worker.min.js";
|
||||
|
||||
document.documentElement.addEventListener("touchmove",
|
||||
function (event) {
|
||||
if (event.touches.length > 1) {
|
||||
event.preventDefault();
|
||||
}
|
||||
},
|
||||
false
|
||||
);
|
||||
if (event.touches.length > 1) event.preventDefault();
|
||||
}, false);
|
||||
</script>
|
||||
|
||||
<script src="./textVideo/wsconnecter.js" charset="utf-8"></script>
|
||||
<script src="./textVideo/textVideo.js" charset="utf-8"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
BIN
public/ocr_v2_det_new/chunk_1.dat
Normal file
10846
public/ocr_v2_det_new/model.json
Normal file
BIN
public/ocr_v2_rec_320/chunk_1.dat
Normal file
BIN
public/ocr_v2_rec_320/chunk_2.dat
Normal file
42769
public/ocr_v2_rec_320/model.json
Normal file
18
public/textPdf/mammoth.browser.min.js
vendored
Normal file
22
public/textPdf/pdf.min.js
vendored
Normal file
22
public/textPdf/pdf.worker.min.js
vendored
Normal file
96
public/textVideo/pcm.js
Normal file
@ -0,0 +1,96 @@
|
||||
/*
|
||||
pcm编码器+编码引擎
|
||||
https://github.com/xiangyuecn/Recorder
|
||||
|
||||
编码原理:本编码器输出的pcm格式数据其实就是Recorder中的buffers原始数据(经过了重新采样),16位时为LE小端模式(Little Endian),并未经过任何编码处理
|
||||
|
||||
编码的代码和wav.js区别不大,pcm加上一个44字节wav头即成wav文件;所以要播放pcm就很简单了,直接转成wav文件来播放,已提供转换函数 Recorder.pcm2wav
|
||||
*/
|
||||
(function(){
|
||||
"use strict";
|
||||
|
||||
Recorder.prototype.enc_pcm={
|
||||
stable:true
|
||||
,testmsg:"pcm为未封装的原始音频数据,pcm数据文件无法直接播放;支持位数8位、16位(填在比特率里面),采样率取值无限制"
|
||||
};
|
||||
Recorder.prototype.pcm=function(res,True,False){
|
||||
var This=this,set=This.set
|
||||
,size=res.length
|
||||
,bitRate=set.bitRate==8?8:16;
|
||||
|
||||
var buffer=new ArrayBuffer(size*(bitRate/8));
|
||||
var data=new DataView(buffer);
|
||||
var offset=0;
|
||||
|
||||
// 写入采样数据
|
||||
if(bitRate==8) {
|
||||
for(var i=0;i<size;i++,offset++) {
|
||||
//16转8据说是雷霄骅的 https://blog.csdn.net/sevennight1989/article/details/85376149 细节比blqw的按比例的算法清晰点,虽然都有明显杂音
|
||||
var val=(res[i]>>8)+128;
|
||||
data.setInt8(offset,val,true);
|
||||
};
|
||||
}else{
|
||||
for (var i=0;i<size;i++,offset+=2){
|
||||
data.setInt16(offset,res[i],true);
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
True(new Blob([data.buffer],{type:"audio/pcm"}));
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**pcm直接转码成wav,可以直接用来播放;需同时引入wav.js
|
||||
data: {
|
||||
sampleRate:16000 pcm的采样率
|
||||
bitRate:16 pcm的位数 取值:8 或 16
|
||||
blob:blob对象
|
||||
}
|
||||
data如果直接提供的blob将默认使用16位16khz的配置,仅用于测试
|
||||
True(wavBlob,duration)
|
||||
False(msg)
|
||||
**/
|
||||
Recorder.pcm2wav=function(data,True,False){
|
||||
if(data.slice && data.type!=null){//Blob 测试用
|
||||
data={blob:data};
|
||||
};
|
||||
var sampleRate=data.sampleRate||16000,bitRate=data.bitRate||16;
|
||||
if(!data.sampleRate || !data.bitRate){
|
||||
console.warn("pcm2wav必须提供sampleRate和bitRate");
|
||||
};
|
||||
if(!Recorder.prototype.wav){
|
||||
False("pcm2wav必须先加载wav编码器wav.js");
|
||||
return;
|
||||
};
|
||||
|
||||
var reader=new FileReader();
|
||||
reader.onloadend=function(){
|
||||
var pcm;
|
||||
if(bitRate==8){
|
||||
//8位转成16位
|
||||
var u8arr=new Uint8Array(reader.result);
|
||||
pcm=new Int16Array(u8arr.length);
|
||||
for(var j=0;j<u8arr.length;j++){
|
||||
pcm[j]=(u8arr[j]-128)<<8;
|
||||
};
|
||||
}else{
|
||||
pcm=new Int16Array(reader.result);
|
||||
};
|
||||
|
||||
Recorder({
|
||||
type:"wav"
|
||||
,sampleRate:sampleRate
|
||||
,bitRate:bitRate
|
||||
}).mock(pcm,sampleRate).stop(function(wavBlob,duration){
|
||||
True(wavBlob,duration);
|
||||
},False);
|
||||
};
|
||||
reader.readAsArrayBuffer(data.blob);
|
||||
};
|
||||
|
||||
|
||||
|
||||
})();
|
1493
public/textVideo/recorder-core.js
Normal file
275
public/textVideo/textVideo.js
Normal file
@ -0,0 +1,275 @@
|
||||
/**
|
||||
* Copyright FunASR (https://github.com/alibaba-damo-academy/FunASR). All Rights
|
||||
* Reserved. MIT License (https://opensource.org/licenses/MIT)
|
||||
*/
|
||||
/* 2022-2023 by zhaoming,mali aihealthx.com */
|
||||
|
||||
|
||||
// 连接; 定义socket连接类对象与语音对象
|
||||
var wsconnecter = new WebSocketConnectMethod({ msgHandle: getJsonMessage, stateHandle: getConnState });
|
||||
var audioBlob;
|
||||
var isfilemode = true; // if it is in file mode
|
||||
// 录音; 定义录音对象,wav格式
|
||||
var rec = Recorder({
|
||||
type: "pcm",
|
||||
bitRate: 16,
|
||||
sampleRate: 16000,
|
||||
onProcess: recProcess
|
||||
});
|
||||
|
||||
var sampleBuf = new Int16Array();
|
||||
|
||||
var rec_text = ""; // for online rec asr result
|
||||
var offline_text = ""; // for offline rec asr result
|
||||
|
||||
|
||||
var file_ext = "";
|
||||
var file_sample_rate = 16000; //for wav file sample rate
|
||||
var file_data_array; // array to save file data
|
||||
var totalsend = 0;
|
||||
|
||||
addresschange();
|
||||
function addresschange() {
|
||||
var Uri = 'ws://192.168.0.232:10095';
|
||||
Uri = Uri.replace(/wss/g, "https");
|
||||
window.open(Uri, '_blank');
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
var readWavInfo = function (bytes) {
|
||||
//读取wav文件头,统一成44字节的头
|
||||
if (bytes.byteLength < 44) {
|
||||
return null;
|
||||
};
|
||||
var wavView = bytes;
|
||||
var eq = function (p, s) {
|
||||
for (var i = 0; i < s.length; i++) {
|
||||
if (wavView[p + i] != s.charCodeAt(i)) {
|
||||
return false;
|
||||
};
|
||||
};
|
||||
return true;
|
||||
};
|
||||
|
||||
if (eq(0, "RIFF") && eq(8, "WAVEfmt ")) {
|
||||
|
||||
var numCh = wavView[22];
|
||||
if (wavView[20] == 1 && (numCh == 1 || numCh == 2)) {//raw pcm 单或双声道
|
||||
var sampleRate = wavView[24] + (wavView[25] << 8) + (wavView[26] << 16) + (wavView[27] << 24);
|
||||
var bitRate = wavView[34] + (wavView[35] << 8);
|
||||
var heads = [wavView.subarray(0, 12)], headSize = 12;//head只保留必要的块
|
||||
//搜索data块的位置
|
||||
var dataPos = 0; // 44 或有更多块
|
||||
for (var i = 12, iL = wavView.length - 8; i < iL;) {
|
||||
if (wavView[i] == 100 && wavView[i + 1] == 97 && wavView[i + 2] == 116 && wavView[i + 3] == 97) {//eq(i,"data")
|
||||
heads.push(wavView.subarray(i, i + 8));
|
||||
headSize += 8;
|
||||
dataPos = i + 8; break;
|
||||
}
|
||||
var i0 = i;
|
||||
i += 4;
|
||||
i += 4 + wavView[i] + (wavView[i + 1] << 8) + (wavView[i + 2] << 16) + (wavView[i + 3] << 24);
|
||||
if (i0 == 12) {//fmt
|
||||
heads.push(wavView.subarray(i0, i));
|
||||
headSize += i - i0;
|
||||
}
|
||||
}
|
||||
if (dataPos) {
|
||||
var wavHead = new Uint8Array(headSize);
|
||||
for (var i = 0, n = 0; i < heads.length; i++) {
|
||||
wavHead.set(heads[i], n); n += heads[i].length;
|
||||
}
|
||||
return {
|
||||
sampleRate: sampleRate
|
||||
, bitRate: bitRate
|
||||
, numChannels: numCh
|
||||
, wavHead44: wavHead
|
||||
, dataPos: dataPos
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
return null;
|
||||
};
|
||||
|
||||
function upfileOnchange(files) {
|
||||
this.files = [files];
|
||||
var len = this.files.length;
|
||||
for (let i = 0; i < len; i++) {
|
||||
let fileAudio = new FileReader();
|
||||
fileAudio.readAsArrayBuffer(this.files[i]);
|
||||
file_ext = this.files[i].name.split('.').pop().toLowerCase();
|
||||
var audioblob;
|
||||
fileAudio.onload = function () {
|
||||
audioblob = fileAudio.result;
|
||||
file_data_array = audioblob;
|
||||
}
|
||||
|
||||
fileAudio.onerror = function (e) {
|
||||
console.log('error' + e);
|
||||
}
|
||||
}
|
||||
// for wav file, we get the sample rate
|
||||
if (file_ext == "wav") {
|
||||
for (let i = 0; i < len; i++) {
|
||||
let fileAudio = new FileReader();
|
||||
fileAudio.readAsArrayBuffer(this.files[i]);
|
||||
fileAudio.onload = function () {
|
||||
audioblob = new Uint8Array(fileAudio.result);
|
||||
|
||||
var info = readWavInfo(audioblob);
|
||||
file_sample_rate = info.sampleRate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function play_file() {
|
||||
var audioblob = new Blob([new Uint8Array(file_data_array)], { type: "audio/wav" });
|
||||
var audio_record = document.getElementById('audio_record');
|
||||
audio_record.src = (window.URL || webkitURL).createObjectURL(audioblob);
|
||||
audio_record.controls = true;
|
||||
}
|
||||
|
||||
function start_file_send() {
|
||||
sampleBuf = new Uint8Array(file_data_array);
|
||||
var chunk_size = 960; // for asr chunk_size [5, 10, 5]
|
||||
while (sampleBuf.length >= chunk_size) {
|
||||
sendBuf = sampleBuf.slice(0, chunk_size);
|
||||
totalsend = totalsend + sampleBuf.length;
|
||||
sampleBuf = sampleBuf.slice(chunk_size, sampleBuf.length);
|
||||
wsconnecter.wsSend(sendBuf);
|
||||
}
|
||||
stop();
|
||||
}
|
||||
|
||||
function stop() {
|
||||
var chunk_size = new Array(5, 10, 5);
|
||||
var request = {
|
||||
"chunk_size": chunk_size,
|
||||
"wav_name": "h5",
|
||||
"is_speaking": false,
|
||||
"chunk_interval": 10,
|
||||
"mode": getAsrMode(),
|
||||
};
|
||||
if (sampleBuf.length > 0) {
|
||||
wsconnecter.wsSend(sampleBuf);
|
||||
sampleBuf = new Int16Array();
|
||||
}
|
||||
wsconnecter.wsSend(JSON.stringify(request));
|
||||
// 控件状态更新
|
||||
isRec = false;
|
||||
if (isfilemode == false) {
|
||||
//wait 3s for asr result
|
||||
setTimeout(function () {
|
||||
wsconnecter.wsStop();
|
||||
}, 3000);
|
||||
rec.stop(function (blob, duration) {
|
||||
var audioBlob = Recorder.pcm2wav(data = { sampleRate: 16000, bitRate: 16, blob: blob },
|
||||
function (theblob, duration) {
|
||||
console.log(theblob);
|
||||
var audio_record = document.getElementById('audio_record');
|
||||
audio_record.src = (window.URL || webkitURL).createObjectURL(theblob);
|
||||
audio_record.controls = true;
|
||||
}, function (msg) {
|
||||
console.log(msg);
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
|
||||
}, function (errMsg) {
|
||||
console.log("errMsg: " + errMsg);
|
||||
});
|
||||
}
|
||||
// 停止连接
|
||||
}
|
||||
|
||||
function getAsrMode() {
|
||||
return 'offline';
|
||||
}
|
||||
function getHotwords() {
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
function handleWithTimestamp(tmptext, tmptime) {
|
||||
|
||||
if (tmptime == null || tmptime == "undefined" || tmptext.length <= 0) {
|
||||
return tmptext;
|
||||
}
|
||||
tmptext = tmptext.replace(/。|?|,|、|\?|\.|\ /g, ","); // in case there are a lot of "。"
|
||||
var words = tmptext.split(","); // split to chinese sentence or english words
|
||||
var jsontime = JSON.parse(tmptime); //JSON.parse(tmptime.replace(/\]\]\[\[/g, "],[")); // in case there are a lot segments by VAD
|
||||
var char_index = 0; // index for timestamp
|
||||
var text_withtime = "";
|
||||
for (var i = 0; i < words.length; i++) {
|
||||
if (words[i] == "undefined" || words[i].length <= 0) {
|
||||
continue;
|
||||
}
|
||||
if (/^[a-zA-Z]+$/.test(words[i])) { // if it is english
|
||||
text_withtime = text_withtime + jsontime[char_index][0] / 1000 + ":" + words[i] + "\n";
|
||||
char_index = char_index + 1; //for english, timestamp unit is about a word
|
||||
}
|
||||
else {
|
||||
text_withtime = text_withtime + jsontime[char_index][0] / 1000 + ":" + words[i] + "\n";
|
||||
char_index = char_index + words[i].length; //for chinese, timestamp unit is about a char
|
||||
}
|
||||
}
|
||||
return text_withtime;
|
||||
|
||||
|
||||
}
|
||||
// 语音识别结果; 对jsonMsg数据解析,将识别结果附加到编辑框中
|
||||
function getJsonMessage(jsonMsg) {
|
||||
var rectxt = "" + JSON.parse(jsonMsg.data)['text'];
|
||||
var asrmodel = JSON.parse(jsonMsg.data)['mode'];
|
||||
var is_final = JSON.parse(jsonMsg.data)['is_final'];
|
||||
var timestamp = JSON.parse(jsonMsg.data)['timestamp'];
|
||||
if (asrmodel == "2pass-offline" || asrmodel == "offline") {
|
||||
offline_text = offline_text + handleWithTimestamp(rectxt, timestamp); //rectxt; //.replace(/ +/g,"");
|
||||
rec_text = offline_text;
|
||||
} else {
|
||||
rec_text = rec_text + rectxt;
|
||||
}
|
||||
videoText = rec_text;
|
||||
if (is_final == true) {
|
||||
play_file();
|
||||
wsconnecter.wsStop();
|
||||
btnConnect.disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 连接状态响应
|
||||
function getConnState(connState) {
|
||||
if (connState === 0) start_file_send();
|
||||
}
|
||||
|
||||
// 识别启动、停止、清空操作
|
||||
function start() {
|
||||
var ret = wsconnecter.wsStart();//启动连接
|
||||
return ret == 1 ? 1 : 0;
|
||||
}
|
||||
|
||||
function recProcess(buffer, powerLevel, bufferDuration, bufferSampleRate, newBufferIdx, asyncEnd) {
|
||||
if (isRec === true) {
|
||||
var data_48k = buffer[buffer.length - 1];
|
||||
var array_48k = new Array(data_48k);
|
||||
var data_16k = Recorder.SampleData(array_48k, bufferSampleRate, 16000).data;
|
||||
sampleBuf = Int16Array.from([...sampleBuf, ...data_16k]);
|
||||
var chunk_size = 960; // for asr chunk_size [5, 10, 5]
|
||||
while (sampleBuf.length >= chunk_size) {
|
||||
sendBuf = sampleBuf.slice(0, chunk_size);
|
||||
sampleBuf = sampleBuf.slice(chunk_size, sampleBuf.length);
|
||||
wsconnecter.wsSend(sendBuf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getUseITN() {
|
||||
return false;
|
||||
}
|
86
public/textVideo/wav.js
Normal file
@ -0,0 +1,86 @@
|
||||
/*
|
||||
wav编码器+编码引擎
|
||||
https://github.com/xiangyuecn/Recorder
|
||||
|
||||
当然最佳推荐使用mp3、wav格式,代码也是优先照顾这两种格式
|
||||
浏览器支持情况
|
||||
https://developer.mozilla.org/en-US/docs/Web/HTML/Supported_media_formats
|
||||
|
||||
编码原理:给pcm数据加上一个44直接的wav头即成wav文件;pcm数据就是Recorder中的buffers原始数据(重新采样),16位时为LE小端模式(Little Endian),实质上是未经过任何编码处理
|
||||
*/
|
||||
(function(){
|
||||
"use strict";
|
||||
|
||||
Recorder.prototype.enc_wav={
|
||||
stable:true
|
||||
,testmsg:"支持位数8位、16位(填在比特率里面),采样率取值无限制"
|
||||
};
|
||||
Recorder.prototype.wav=function(res,True,False){
|
||||
var This=this,set=This.set
|
||||
,size=res.length
|
||||
,sampleRate=set.sampleRate
|
||||
,bitRate=set.bitRate==8?8:16;
|
||||
|
||||
//编码数据 https://github.com/mattdiamond/Recorderjs https://www.cnblogs.com/blqw/p/3782420.html https://www.cnblogs.com/xiaoqi/p/6993912.html
|
||||
var dataLength=size*(bitRate/8);
|
||||
var buffer=new ArrayBuffer(44+dataLength);
|
||||
var data=new DataView(buffer);
|
||||
|
||||
var offset=0;
|
||||
var writeString=function(str){
|
||||
for (var i=0;i<str.length;i++,offset++) {
|
||||
data.setUint8(offset,str.charCodeAt(i));
|
||||
};
|
||||
};
|
||||
var write16=function(v){
|
||||
data.setUint16(offset,v,true);
|
||||
offset+=2;
|
||||
};
|
||||
var write32=function(v){
|
||||
data.setUint32(offset,v,true);
|
||||
offset+=4;
|
||||
};
|
||||
|
||||
/* RIFF identifier */
|
||||
writeString('RIFF');
|
||||
/* RIFF chunk length */
|
||||
write32(36+dataLength);
|
||||
/* RIFF type */
|
||||
writeString('WAVE');
|
||||
/* format chunk identifier */
|
||||
writeString('fmt ');
|
||||
/* format chunk length */
|
||||
write32(16);
|
||||
/* sample format (raw) */
|
||||
write16(1);
|
||||
/* channel count */
|
||||
write16(1);
|
||||
/* sample rate */
|
||||
write32(sampleRate);
|
||||
/* byte rate (sample rate * block align) */
|
||||
write32(sampleRate*(bitRate/8));// *1 声道
|
||||
/* block align (channel count * bytes per sample) */
|
||||
write16(bitRate/8);// *1 声道
|
||||
/* bits per sample */
|
||||
write16(bitRate);
|
||||
/* data chunk identifier */
|
||||
writeString('data');
|
||||
/* data chunk length */
|
||||
write32(dataLength);
|
||||
// 写入采样数据
|
||||
if(bitRate==8) {
|
||||
for(var i=0;i<size;i++,offset++) {
|
||||
//16转8据说是雷霄骅的 https://blog.csdn.net/sevennight1989/article/details/85376149 细节比blqw的按比例的算法清晰点,虽然都有明显杂音
|
||||
var val=(res[i]>>8)+128;
|
||||
data.setInt8(offset,val,true);
|
||||
};
|
||||
}else{
|
||||
for (var i=0;i<size;i++,offset+=2){
|
||||
data.setInt16(offset,res[i],true);
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
True(new Blob([data.buffer],{type:"audio/wav"}));
|
||||
}
|
||||
})();
|
119
public/textVideo/wsconnecter.js
Normal file
@ -0,0 +1,119 @@
|
||||
/**
|
||||
* Copyright FunASR (https://github.com/alibaba-damo-academy/FunASR). All Rights
|
||||
* Reserved. MIT License (https://opensource.org/licenses/MIT)
|
||||
*/
|
||||
/* 2021-2023 by zhaoming,mali aihealthx.com */
|
||||
|
||||
function WebSocketConnectMethod( config ) { //定义socket连接方法类
|
||||
|
||||
|
||||
var speechSokt;
|
||||
var connKeeperID;
|
||||
|
||||
var msgHandle = config.msgHandle;
|
||||
var stateHandle = config.stateHandle;
|
||||
|
||||
this.wsStart = function () {
|
||||
var Uri = 'ws://192.168.0.232:10095'; //"wss://111.205.137.58:5821/wss/" //设置wss asr online接口地址 如 wss://X.X.X.X:port/wss/
|
||||
if(Uri.match(/wss:\S*|ws:\S*/))
|
||||
{
|
||||
console.log("Uri"+Uri);
|
||||
}
|
||||
else
|
||||
{
|
||||
alert("请检查wss地址正确性");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( 'WebSocket' in window ) {
|
||||
speechSokt = new WebSocket( Uri ); // 定义socket连接对象
|
||||
speechSokt.onopen = function(e){onOpen(e);}; // 定义响应函数
|
||||
speechSokt.onclose = function(e){
|
||||
console.log("onclose ws!");
|
||||
//speechSokt.close();
|
||||
onClose(e);
|
||||
};
|
||||
speechSokt.onmessage = function(e){onMessage(e);};
|
||||
speechSokt.onerror = function(e){onError(e);};
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
alert('当前浏览器不支持 WebSocket');
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
// 定义停止与发送函数
|
||||
this.wsStop = function () {
|
||||
if(speechSokt != undefined) {
|
||||
console.log("stop ws!");
|
||||
speechSokt.close();
|
||||
}
|
||||
};
|
||||
|
||||
this.wsSend = function ( oneData ) {
|
||||
|
||||
if(speechSokt == undefined) return;
|
||||
if ( speechSokt.readyState === 1 ) { // 0:CONNECTING, 1:OPEN, 2:CLOSING, 3:CLOSED
|
||||
|
||||
speechSokt.send( oneData );
|
||||
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
// SOCEKT连接中的消息与状态响应
|
||||
function onOpen( e ) {
|
||||
// 发送json
|
||||
var chunk_size = new Array( 5, 10, 5 );
|
||||
var request = {
|
||||
"chunk_size": chunk_size,
|
||||
"wav_name": "h5",
|
||||
"is_speaking": true,
|
||||
"chunk_interval":10,
|
||||
"itn":getUseITN(),
|
||||
"mode":getAsrMode(),
|
||||
|
||||
};
|
||||
if(isfilemode)
|
||||
{
|
||||
request.wav_format=file_ext;
|
||||
if(file_ext=="wav")
|
||||
{
|
||||
request.wav_format="PCM";
|
||||
request.audio_fs=file_sample_rate;
|
||||
}
|
||||
}
|
||||
|
||||
var hotwords=getHotwords();
|
||||
|
||||
if(hotwords!=null )
|
||||
{
|
||||
request.hotwords=hotwords;
|
||||
}
|
||||
console.log(JSON.stringify(request));
|
||||
speechSokt.send(JSON.stringify(request));
|
||||
console.log("连接成功");
|
||||
stateHandle(0);
|
||||
|
||||
}
|
||||
|
||||
function onClose( e ) {
|
||||
stateHandle(1);
|
||||
}
|
||||
|
||||
function onMessage( e ) {
|
||||
|
||||
msgHandle( e );
|
||||
}
|
||||
|
||||
function onError( e ) {
|
||||
|
||||
info_div.innerHTML="连接"+e;
|
||||
console.log(e);
|
||||
stateHandle(2);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
25
src/App.vue
@ -6,11 +6,12 @@
|
||||
</router-view>
|
||||
</template>
|
||||
<script setup>
|
||||
import { ref, nextTick, provide, onMounted } from "vue";
|
||||
import * as ocr from "@paddlejs-models/ocr";
|
||||
import { ref, nextTick, provide, onMounted,getCurrentInstance } from "vue";
|
||||
import { useStore } from "vuex";
|
||||
import { getItem } from "@/utils/storage";
|
||||
import { qcckPost, qcckGet, qcckPut, qcckDelete } from "@/api/qcckApi.js";
|
||||
import { getItem, setItem} from "@/utils/storage";
|
||||
import { generateNewStyle, writeNewStyle } from "@/utils/theme";
|
||||
const { proxy } = getCurrentInstance();
|
||||
const store = useStore();
|
||||
generateNewStyle(store.getters.mainColor).then((newStyle) => {
|
||||
writeNewStyle(newStyle);
|
||||
@ -24,9 +25,25 @@ const reload = () => {
|
||||
};
|
||||
provide("reload", reload);
|
||||
onMounted(() => {
|
||||
let dept = getItem("deptId");
|
||||
document.title = "林芝";
|
||||
// initPage()
|
||||
});
|
||||
|
||||
/**
|
||||
*@Descripttion:图片页面初始化
|
||||
*@Author: PengShuai
|
||||
*/
|
||||
const initPage = async () => {
|
||||
try {
|
||||
await ocr.init();// 模型初始化
|
||||
imgIsLoad = true;
|
||||
proxy.$message({ type: "success", message: "加载成功" });
|
||||
} catch (err) {
|
||||
proxy.$message({ type: "error", message: "加载失败,请刷新页面" });
|
||||
imgIsLoad = false;
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
<style lang="scss">
|
||||
@import "./styles/index.scss";
|
||||
|
@ -1,22 +1,17 @@
|
||||
import request from "@/utils/request";
|
||||
import axios from "axios";
|
||||
const api = "/mosty-api";
|
||||
const egisSpace = "/egis-space";
|
||||
|
||||
// 选择站口名称
|
||||
export function egisSpaceGet(fun,coords){
|
||||
let params = {
|
||||
pageNum: 1,
|
||||
pageSize: 1000,
|
||||
keyword: "",
|
||||
geometry: `{"type":"Polygon","coordinates":${JSON.stringify(coords)}}`,
|
||||
};
|
||||
params.geometry = encodeURIComponent(params.geometry)
|
||||
|
||||
let url = egisSpace + '/space/search/custom/ms-dy-intersections'
|
||||
axios.get(url,{params}).then((res) => {
|
||||
fun(res.data)
|
||||
});
|
||||
// 解析数据
|
||||
export function ParsingText(data,fun){
|
||||
axios({
|
||||
method: 'post',
|
||||
url: '/chat/completions',
|
||||
data:data,
|
||||
headers: { 'Authorization': 'Bearer sk-064b5c53131c4046883b718f2b31c050' }
|
||||
}).then( (res) => {
|
||||
fun(res)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
@ -599,7 +599,7 @@ export const selectUserDeptPage = (data = {}) => {
|
||||
///unifiedLogin
|
||||
export const unifiedLogin = (data) => {
|
||||
return request({
|
||||
url: api + `/unifiedLogin`,
|
||||
url: api + `/ssoLogin`,
|
||||
method: "POST",
|
||||
data
|
||||
});
|
||||
|
@ -3,261 +3,306 @@
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
.homeBox{
|
||||
|
||||
.homeBox {
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
|
||||
.home-aside {
|
||||
position: relative;
|
||||
width: 442px;
|
||||
top: 70px;
|
||||
height: 100%;
|
||||
height: calc(100vh - 72px);
|
||||
overflow: hidden;
|
||||
z-index: 10;
|
||||
|
||||
.asideTitle {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0 10px;
|
||||
box-sizing: border-box;
|
||||
background: linear-gradient(90deg, #124CB3 0%, rgba(18, 76, 179, 0.23) 77%, rgba(18, 76, 179, 0) 100%);
|
||||
border-radius: 0px 0px 0px 0px;
|
||||
height: 40px;
|
||||
|
||||
.title {
|
||||
font-weight: bold;
|
||||
font-size: 16px;
|
||||
color: #FFFFFF;
|
||||
margin-right: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.asideCnt {
|
||||
height: calc(100% - 40px);
|
||||
}
|
||||
|
||||
.aside-middle {
|
||||
height: calc(100%/2);
|
||||
padding: 4px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
|
||||
.homeBtn {
|
||||
height: 302px;
|
||||
width: calc(100% - 894px);
|
||||
position: absolute;
|
||||
bottom: 2px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
// 头部
|
||||
.headBox {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
.home-aside{
|
||||
position: relative;
|
||||
width: 442px;
|
||||
top: 70px;
|
||||
height: 70px;
|
||||
background: rgba(0, 0, 0, 0.8);
|
||||
z-index: 2;
|
||||
|
||||
.headBoxBg {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
height: calc(100vh - 72px);
|
||||
overflow: hidden;
|
||||
z-index: 10;
|
||||
.asideTitle{
|
||||
background: url("~@/assets/images/home_head.png") no-repeat center center;
|
||||
background-size: 100% 100%;
|
||||
height: 151px;
|
||||
}
|
||||
|
||||
.top-center {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 2%;
|
||||
transform: translateX(-50%);
|
||||
font-size: 56px;
|
||||
letter-spacing: 2px;
|
||||
font-family: "YSBTH";
|
||||
white-space: nowrap;
|
||||
background: linear-gradient(180deg, #FFFFFF 0%, #66B5FF 100%);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
text-shadow: 4px 4px 4px rgba(54, 255, 243, 0.15);
|
||||
}
|
||||
|
||||
.topBtn {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
top: 22px;
|
||||
|
||||
.topBtn-item {
|
||||
width: 190px;
|
||||
height: 38px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0 10px;
|
||||
box-sizing: border-box;
|
||||
background: linear-gradient( 90deg, #124CB3 0%, rgba(18,76,179,0.23) 77%, rgba(18,76,179,0) 100%);
|
||||
border-radius: 0px 0px 0px 0px;
|
||||
height: 40px;
|
||||
.title{
|
||||
font-weight: bold;
|
||||
font-size: 16px;
|
||||
color: #FFFFFF;
|
||||
margin-right: 20px;
|
||||
}
|
||||
}
|
||||
.asideCnt{
|
||||
height: calc(100% - 40px);
|
||||
}
|
||||
.aside-middle{
|
||||
height: calc(100%/2);
|
||||
padding: 4px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
.homeBtn{
|
||||
height: 302px;
|
||||
width: calc(100% - 894px);
|
||||
position: absolute;
|
||||
bottom: 2px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
// 头部
|
||||
.headBox {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 70px;
|
||||
background: rgba(0,0,0,0.8);
|
||||
z-index: 2;
|
||||
.headBoxBg{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: url("~@/assets/images/home_head.png") no-repeat center center;
|
||||
justify-content: center;
|
||||
background: url("~@/assets/images/home_btns.png") no-repeat center center;
|
||||
background-size: 100% 100%;
|
||||
height: 151px;
|
||||
}
|
||||
.top-center {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 2%;
|
||||
transform: translateX(-50%);
|
||||
font-size: 56px;
|
||||
letter-spacing: 2px;
|
||||
font-family: "YSBTH";
|
||||
white-space: nowrap;
|
||||
background: linear-gradient(180deg, #FFFFFF 0%, #66B5FF 100%);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
text-shadow: 4px 4px 4px rgba(54, 255, 243, 0.15);
|
||||
}
|
||||
.topBtn {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
top: 22px;
|
||||
.topBtn-item {
|
||||
width: 190px;
|
||||
height: 38px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: url("~@/assets/images/home_btns.png") no-repeat center center;
|
||||
background-size: 100% 100%;
|
||||
font-size: 18px;
|
||||
cursor: pointer;
|
||||
span {
|
||||
font-family: "YSBTH";
|
||||
margin-top: -4px;
|
||||
@include textColor(#a1d6ff, #ffffff);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
.topBtn-left {
|
||||
left: 30px;
|
||||
font-size: 12px;
|
||||
.text {
|
||||
font-size: 18px;
|
||||
cursor: pointer;
|
||||
|
||||
span {
|
||||
font-family: "YSBTH";
|
||||
color: #0bb7ff;
|
||||
}
|
||||
.tests {
|
||||
color: #0a99ff;
|
||||
}
|
||||
}
|
||||
.leftBtn-yjbtn{
|
||||
position: absolute;
|
||||
left: 360px;
|
||||
top: 20px;
|
||||
.leftBtn-item{
|
||||
width: 155px;
|
||||
height: 38px;
|
||||
line-height: 38px;
|
||||
text-align: center;
|
||||
background: url("~@/assets/images/home_btns.png") no-repeat center center;
|
||||
background-size: 100% 100%;
|
||||
font-size: 16px;
|
||||
font-family: "YSBTH";
|
||||
}
|
||||
.btms{
|
||||
margin-top: -4px;
|
||||
@include textColor(#a1d6ff, #ffffff);
|
||||
}
|
||||
}
|
||||
.yjbtnActive{
|
||||
background: url("~@/assets/images/home_btns_active.png") no-repeat center center;
|
||||
|
||||
}
|
||||
|
||||
.topBtn-left {
|
||||
left: 30px;
|
||||
font-size: 12px;
|
||||
|
||||
.text {
|
||||
font-family: "YSBTH";
|
||||
color: #0bb7ff;
|
||||
}
|
||||
|
||||
.tests {
|
||||
color: #0a99ff;
|
||||
}
|
||||
}
|
||||
|
||||
.leftBtn-yjbtn {
|
||||
position: absolute;
|
||||
left: 360px;
|
||||
top: 20px;
|
||||
|
||||
.leftBtn-item {
|
||||
width: 155px;
|
||||
height: 38px;
|
||||
line-height: 38px;
|
||||
text-align: center;
|
||||
background: url("~@/assets/images/home_btns.png") no-repeat center center;
|
||||
background-size: 100% 100%;
|
||||
.btms{
|
||||
font-size: 16px;
|
||||
font-family: "YSBTH";
|
||||
}
|
||||
|
||||
.btms {
|
||||
@include textColor(#a1d6ff, #ffffff);
|
||||
}
|
||||
}
|
||||
|
||||
.yjbtnActive {
|
||||
background: url("~@/assets/images/home_btns_active.png") no-repeat center center;
|
||||
background-size: 100% 100%;
|
||||
|
||||
.btms {
|
||||
@include textColor(#00ffff, #faff00);
|
||||
}
|
||||
}
|
||||
|
||||
.topBtn-right {
|
||||
right: 270px;
|
||||
top: 22px;
|
||||
|
||||
.topBtn-item {
|
||||
background: url("~@/assets/images/home_btns_right.png") no-repeat center center;
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
|
||||
.active-topBtn {
|
||||
background: url("~@/assets/images/home_btns_right_active.png") no-repeat center center;
|
||||
background-size: 100% 100%;
|
||||
|
||||
span {
|
||||
@include textColor(#00ffff, #faff00);
|
||||
}
|
||||
}
|
||||
.topBtn-right {
|
||||
right: 270px;
|
||||
top: 22px;
|
||||
.topBtn-item {
|
||||
background: url("~@/assets/images/home_btns_right.png") no-repeat center
|
||||
center;
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
.active-topBtn {
|
||||
background: url("~@/assets/images/home_btns_right_active.png") no-repeat
|
||||
center center;
|
||||
background-size: 100% 100%;
|
||||
span {
|
||||
@include textColor(#00ffff, #faff00);
|
||||
}
|
||||
}
|
||||
}
|
||||
.rightIcon {
|
||||
position: absolute;
|
||||
right: 20px;
|
||||
top: 22px;
|
||||
font-size: 17px;
|
||||
z-index: 9;
|
||||
span {
|
||||
color: #0bb7ff;
|
||||
cursor: pointer;
|
||||
}
|
||||
img {
|
||||
width: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 左边
|
||||
.asideL{
|
||||
position: absolute;
|
||||
box-sizing: border-box;
|
||||
left: 0px;
|
||||
.asideL-top{
|
||||
width: 100%;
|
||||
height: 141px;
|
||||
background: #052249;
|
||||
}
|
||||
.asideL-Bottom{
|
||||
height: calc(100% - 141px);
|
||||
.commom-aside{
|
||||
height: calc((100%/3) - 6px);
|
||||
margin-top: 7px;
|
||||
background: #052249;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 右边
|
||||
.asideR{
|
||||
position: absolute;
|
||||
right: 0px;
|
||||
.commom-aside-small{
|
||||
height: calc(((100% - 146px) /3) - 6px);
|
||||
background: #052249;
|
||||
margin-top: 9px;
|
||||
}
|
||||
.commom-aside-big{
|
||||
height: calc(((100% - (100% - 146px) /3)/2) - 6px);
|
||||
margin-bottom: 9px;
|
||||
background: #052249;
|
||||
}
|
||||
}
|
||||
|
||||
.home-center{
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 70px;
|
||||
transform: translateX(-50%);
|
||||
width: calc(100% - 890px);
|
||||
height: 80px;
|
||||
z-index: 9;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.home-foot-t{
|
||||
.rightIcon {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
bottom: 2px;
|
||||
transform: translateX(-50%);
|
||||
width: calc(100% - 920px);
|
||||
height: calc((100% - 141px)/3 - 32px);
|
||||
min-width: 560px;
|
||||
overflow: hidden;
|
||||
right: 20px;
|
||||
top: 22px;
|
||||
font-size: 17px;
|
||||
z-index: 9;
|
||||
background: url("~@/assets/images/right-1.png") no-repeat center center;
|
||||
background-size: 100% 100%;
|
||||
.comom-title{
|
||||
background: url("~@/assets/images/bg18.png") no-repeat center center;
|
||||
background-size: 100% 100%;
|
||||
.title{
|
||||
font-size: 22px;
|
||||
font-family: 'YSBTH';
|
||||
padding-left: 35px;
|
||||
}
|
||||
|
||||
span {
|
||||
color: #0bb7ff;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
// 公用
|
||||
.comom-title{
|
||||
background: url("~@/assets/images/bg17.png") no-repeat center center;
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
|
||||
// 左边
|
||||
.asideL {
|
||||
position: absolute;
|
||||
box-sizing: border-box;
|
||||
left: 0px;
|
||||
|
||||
.asideL-top {
|
||||
width: 100%;
|
||||
height: 35px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0 10px;
|
||||
box-sizing: border-box;
|
||||
.title{
|
||||
height: 141px;
|
||||
background: #052249;
|
||||
}
|
||||
|
||||
.asideL-Bottom {
|
||||
height: calc(100% - 141px);
|
||||
|
||||
.commom-aside {
|
||||
height: calc((100%/3) - 6px);
|
||||
margin-top: 7px;
|
||||
background: #052249;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 右边
|
||||
.asideR {
|
||||
position: absolute;
|
||||
right: 0px;
|
||||
|
||||
.commom-aside-small {
|
||||
height: calc(((100% - 146px) /3) - 6px);
|
||||
background: #052249;
|
||||
margin-top: 9px;
|
||||
}
|
||||
|
||||
.commom-aside-big {
|
||||
height: calc(((100% - (100% - 146px) /3)/2) - 6px);
|
||||
margin-bottom: 9px;
|
||||
background: #052249;
|
||||
}
|
||||
}
|
||||
|
||||
.home-center {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 70px;
|
||||
transform: translateX(-50%);
|
||||
width: calc(100% - 890px);
|
||||
z-index: 9;
|
||||
background: #052249;
|
||||
height: calc(100% - (100% - 141px) / 3 - 45px);
|
||||
|
||||
.middle-top {
|
||||
height: 80px;
|
||||
}
|
||||
|
||||
.middle-bottom {
|
||||
height: calc(100% - 90px);
|
||||
}
|
||||
}
|
||||
|
||||
.home-foot-t {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
bottom: 2px;
|
||||
transform: translateX(-50%);
|
||||
width: calc(100% - 920px);
|
||||
height: calc((100% - 141px)/3 - 32px);
|
||||
min-width: 560px;
|
||||
overflow: hidden;
|
||||
z-index: 9;
|
||||
background: url("~@/assets/images/right-1.png") no-repeat center center;
|
||||
background-size: 100% 100%;
|
||||
|
||||
.comom-title {
|
||||
background: url("~@/assets/images/bg18.png") no-repeat center center;
|
||||
background-size: 100% 100%;
|
||||
|
||||
.title {
|
||||
font-size: 22px;
|
||||
font-family: 'YSBTH';
|
||||
padding-left: 35px;
|
||||
}
|
||||
}
|
||||
.comom-cnt{
|
||||
height: calc(100% - 35px);
|
||||
padding: 4px 10px;
|
||||
box-sizing: border-box;
|
||||
background: url("~@/assets/images/bg_13.png") no-repeat center center;
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
|
||||
// 公用
|
||||
.comom-title {
|
||||
background: url("~@/assets/images/bg17.png") no-repeat center center;
|
||||
background-size: 100% 100%;
|
||||
width: 100%;
|
||||
height: 35px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0 10px;
|
||||
box-sizing: border-box;
|
||||
|
||||
.title {
|
||||
font-size: 22px;
|
||||
font-family: 'YSBTH';
|
||||
padding-left: 35px;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.comom-cnt {
|
||||
height: calc(100% - 35px);
|
||||
padding: 4px 10px;
|
||||
box-sizing: border-box;
|
||||
background: url("~@/assets/images/bg_13.png") no-repeat center center;
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
|
||||
}
|
Before Width: | Height: | Size: 540 KiB |
Before Width: | Height: | Size: 212 KiB |
Before Width: | Height: | Size: 5.4 KiB |
Before Width: | Height: | Size: 948 B |
BIN
src/assets/images/bg44.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
src/assets/images/bg46.png
Normal file
After Width: | Height: | Size: 177 KiB |
Before Width: | Height: | Size: 209 B |
Before Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 7.6 KiB |
Before Width: | Height: | Size: 7.7 KiB |
Before Width: | Height: | Size: 6.8 KiB |
Before Width: | Height: | Size: 7.0 KiB |
Before Width: | Height: | Size: 9.6 KiB |
Before Width: | Height: | Size: 3.3 KiB |
BIN
src/assets/images/car.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
src/assets/images/ddtb.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 4.0 KiB |
@ -1,4 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M16 2C10.477 2 6 6.477 6 12C6 19.5 16 30 16 30C16 30 26 19.5 26 12C26 6.477 21.523 2 16 2ZM16 16C13.791 16 12 14.209 12 12C12 9.791 13.791 8 16 8C18.209 8 20 9.791 20 12C20 14.209 18.209 16 16 16Z" fill="#00f0ff" stroke="#ffffff" stroke-width="1"/>
|
||||
</svg>
|
Before Width: | Height: | Size: 401 B |
BIN
src/assets/images/mxbg.jpg
Normal file
After Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 5.8 KiB |
Before Width: | Height: | Size: 6.8 KiB |
BIN
src/assets/images/xxxxxx.png
Normal file
After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 571 B |
Before Width: | Height: | Size: 5.8 KiB |
Before Width: | Height: | Size: 2.4 KiB |
Before Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 792 B |
Before Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 3.9 KiB |
Before Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 4.8 KiB |
Before Width: | Height: | Size: 4.2 KiB |
Before Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 6.9 KiB |
Before Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.7 KiB |
104
src/components/ChooseList/ChooseCl/addPeo.vue
Normal file
@ -0,0 +1,104 @@
|
||||
<template>
|
||||
<el-dialog v-model="showDialog" :destroy-on-close="true" title="新增车辆" @close="close" :close-on-click-modal="false">
|
||||
<FormMessage v-model="listQuery" :formList="formData" labelWidth="120px" ref="elform" :rules="rules">
|
||||
<template #bqList>
|
||||
<div class="marks pointer" @click="chooseMarksVisible = true">
|
||||
<span style="color: rgb(175 178 184);padding-left: 10px;"
|
||||
v-if="!listQuery.bqList || listQuery.bqList.length == 0">请选择标签</span>
|
||||
<span v-else>
|
||||
<el-tag @close.stop="closeTag(idx)" type="success" closable v-for="(it, idx) in listQuery.bqList"
|
||||
:key="idx">{{ it.bqMc }}</el-tag>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
</FormMessage>
|
||||
<template #footer>
|
||||
<div class="flex just-center">
|
||||
<el-button @click="close">取消</el-button>
|
||||
<el-button type="primary" @click="submitForm">确认</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<ChooseMarks v-model="chooseMarksVisible" @choosed="choosed" :roleIds="roleIds" />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import ChooseMarks from "@/components/ChooseList/ChooseMarks/index.vue";
|
||||
import FormMessage from "@/components/aboutTable/FormMessage.vue";
|
||||
import { reactive, ref, getCurrentInstance } from 'vue';
|
||||
const { proxy } = getCurrentInstance();
|
||||
const { D_BZ_XB } = proxy.$dict("D_BZ_XB"); // 获取字典数据
|
||||
const elform = ref()
|
||||
const roleIds = ref([])
|
||||
const showDialog = ref(false)
|
||||
const chooseMarksVisible = ref(false)
|
||||
const emit = defineEmits(['change'])
|
||||
const listQuery = ref({})
|
||||
const formData = ref([
|
||||
{ label: "车牌号", prop: "hphm", type: "input" },
|
||||
{ label: "车架号", prop: "clCjh", type: "input" },
|
||||
{
|
||||
label: "车辆颜色",
|
||||
prop: "clYs",
|
||||
type: "input",
|
||||
},
|
||||
{ label: "车辆所有人", prop: "clSyr", type: "input" },
|
||||
{ label: "人员身份证", prop: "clSyrsfzh", type: "input" },
|
||||
{ label: "责任单位", prop: "zrSsbmdm", depMc: 'zrSsbmmc', type: "department" },
|
||||
{ label: "管辖单位", prop: "gxSsbmdm", depMc: 'gxSsbmmc', type: "department" },
|
||||
{ label: "管控民警姓名", prop: "gkMjXm", type: "input" },
|
||||
{ label: "管控民警警号", prop: "gkMjJh", type: "input" },
|
||||
{ label: "管控原因", prop: "clLkyy", type: "textarea", width: "100%" },
|
||||
{ label: "车辆照片", prop: "fjdz", type: "upload", width: "100%" },
|
||||
])
|
||||
const rules = reactive({
|
||||
hphm: [{ required: true, message: "请输入车牌号", trigger: "blur" }],
|
||||
clCjh: [{ required: true, message: "请输入车架号", trigger: "blur" }],
|
||||
clYs: [{ required: true, message: "请输入车辆颜色", trigger: "blur" }],
|
||||
clSyr: [{ required: true, message: "请输入车辆所有人", trigger: "blur" }],
|
||||
clSyrsfzh: [{ required: true, message: "请输入人员身份证", trigger: "blur" }],
|
||||
})
|
||||
const init = () => {
|
||||
showDialog.value = true;
|
||||
}
|
||||
|
||||
// 选择标签
|
||||
const choosed = (val) => {
|
||||
listQuery.value.bqList = val.map(v => {
|
||||
return { bqZl: v.bqLb, bqId: v.id, bqLx: v.bqLx, bqLb: v.bqLb, bqMc: v.bqMc, bqDm: v.bqDm }
|
||||
});
|
||||
roleIds.value = val.map(v => v.id)
|
||||
}
|
||||
|
||||
// 删除数据
|
||||
const closeTag = (idx) => {
|
||||
listQuery.value.bqList.splice(idx, 1)
|
||||
roleIds.value.splice(idx, 1)
|
||||
}
|
||||
|
||||
const submitForm = () => {
|
||||
elform.value.submit((val) => {
|
||||
val.id = new Date().getTime()
|
||||
emit('change', val)
|
||||
showDialog.value = false;
|
||||
})
|
||||
}
|
||||
|
||||
const close = () => {
|
||||
elform.value.reset();
|
||||
listQuery.value.bqList = []
|
||||
roleIds.value = []
|
||||
showDialog.value = false;
|
||||
}
|
||||
|
||||
defineExpose({ init })
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.marks {
|
||||
width: 100%;
|
||||
min-height: 32px;
|
||||
border: 1px solid #e9e9e9;
|
||||
border-radius: 4px;
|
||||
}
|
||||
</style>
|
204
src/components/ChooseList/ChooseCl/index.vue
Normal file
@ -0,0 +1,204 @@
|
||||
<template>
|
||||
<el-dialog width="1400px" :model-value="modelValue" append-to-body @close="closed">
|
||||
<template #title>
|
||||
<span class="mr10 f16">选择布控车辆</span>
|
||||
<el-button type="primary" size="small" @click="zdyaddPerson">添加其他车辆</el-button>
|
||||
</template>
|
||||
<el-form :model="listQuery" :inline="true">
|
||||
<el-form-item label="车牌号">
|
||||
<el-input placeholder="请输入车牌号" v-model="listQuery.hphm" clearable ></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="车架号">
|
||||
<el-input placeholder="请输入车架号" v-model="listQuery.clCjh" clearable ></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="车辆所有人">
|
||||
<el-input placeholder="请输入车辆所有人" v-model="listQuery.clSyr" clearable ></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="success" @click="handleFilter">查询</el-button>
|
||||
<el-button type="info" @click="reset()"> 重置 </el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div class="tabBox" :class="props.Single ? 'tabBoxRadio' : ''" style="margin-top: 0px">
|
||||
<el-table ref="multipleUserRef" :key="keyTabel" v-loading="loading" @selection-change="handleSelectionChange" :data="tableData" border :row-key="keyid" style="width: 100%" height="450">
|
||||
<el-table-column type="selection" width="55" :reserve-selection="true"/>
|
||||
<el-table-column prop="hphm" align="center" label="车牌号"/>
|
||||
<el-table-column prop="clCjh" align="center" label="车架号"/>
|
||||
<el-table-column prop="clYs" align="center" label="车辆颜色"/>
|
||||
<el-table-column prop="clSyr" align="center" label="车辆所有人"/>
|
||||
<el-table-column prop="gxSsbmmc" align="center" label="管辖单位"/>
|
||||
<el-table-column prop="gkMjXm" align="center" label="管控民警"/>
|
||||
</el-table>
|
||||
</div>
|
||||
<div class="fenye flex just-end " :style="{ top: tableHeight + 'px' }">
|
||||
<el-pagination
|
||||
class="pagination"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
:current-page="listQuery.pageCurrent"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
:page-size="listQuery.pageSize"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="total"
|
||||
></el-pagination>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="flex just-center">
|
||||
<el-button @click="closed">取消</el-button>
|
||||
<el-button type="primary" @click="onComfirm">确认</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 自定义选添加人 -->
|
||||
<AddPeo ref="addPerson" @change="changeZdy"></AddPeo>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import AddPeo from './addPeo.vue'
|
||||
import { qcckGet} from "@/api/qcckApi.js";
|
||||
import { defineProps, ref ,getCurrentInstance, watch} from "vue";
|
||||
const { proxy } = getCurrentInstance();
|
||||
const { D_BZ_XB,D_BZ_MZ } = proxy.$dict("D_BZ_XB","D_BZ_MZ"); //获取字典数据
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: Boolean,
|
||||
default:false
|
||||
},
|
||||
LeaderType: {
|
||||
type: String,
|
||||
default: ""
|
||||
},
|
||||
//是否单选
|
||||
Single: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
roleIds: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
});
|
||||
const loading = ref(false)
|
||||
const total = ref(0);
|
||||
const listQuery = ref({
|
||||
pageCurrent: 1,
|
||||
pageSize: 20
|
||||
});
|
||||
const addPerson = ref()
|
||||
const multipleUserRef = ref(null);
|
||||
const multipleSelectionUser = ref([]);
|
||||
const tableData = ref([]);
|
||||
const emits = defineEmits(["update:modelValue", "choosed","choosedAdd"]);
|
||||
const keyTabel = ref(0)
|
||||
const keyid = (row) => {
|
||||
return row.id;
|
||||
};
|
||||
|
||||
const closed = () => {
|
||||
emits("update:modelValue", false);
|
||||
};
|
||||
const reset = () => {
|
||||
listQuery.value = { pageCurrent: 1, pageSize: 20, };
|
||||
getListData();
|
||||
};
|
||||
|
||||
|
||||
// 为用户分配角色
|
||||
const onComfirm = () => {
|
||||
const userList = multipleSelectionUser.value;
|
||||
let list = [];
|
||||
let listId = [];
|
||||
userList.forEach((val) => {
|
||||
if (listId.indexOf(val.id) == -1) {
|
||||
list.push(val);
|
||||
listId.push(val.id);
|
||||
}
|
||||
});
|
||||
emits("choosed", list);
|
||||
closed();
|
||||
};
|
||||
|
||||
// 自定义加人
|
||||
const changeZdy = (val) => {
|
||||
emits("choosedAdd", val);
|
||||
closed();
|
||||
}
|
||||
/**
|
||||
* pageSize 改变触发
|
||||
*/
|
||||
const handleSizeChange = (currentSize) => {
|
||||
listQuery.value.pageSize = currentSize;
|
||||
getListData();
|
||||
};
|
||||
/**
|
||||
* 页码改变触发
|
||||
*/
|
||||
const handleCurrentChange = (currentPage) => {
|
||||
listQuery.value.pageCurrent = currentPage;
|
||||
getListData();
|
||||
};
|
||||
const getListData = () => {
|
||||
keyTabel.value++
|
||||
const params = {...listQuery.value}
|
||||
loading.value = true;
|
||||
qcckGet(params,'/mosty-gsxt/tbGsxtZdcl/selectPage').then(res=>{
|
||||
loading.value = false;
|
||||
tableData.value = res.records || [];
|
||||
total.value = res.total;
|
||||
multipleUser();
|
||||
}).catch(()=>{
|
||||
loading.value = false;
|
||||
})
|
||||
};
|
||||
|
||||
//列表回显
|
||||
function multipleUser() {
|
||||
tableData.value.forEach((item) => {
|
||||
multipleUserRef.value.toggleRowSelection(item, false);
|
||||
if (props.roleIds.some((id) => id == item.id)) {
|
||||
multipleUserRef.value.toggleRowSelection(item, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const handleFilter = () => {
|
||||
listQuery.value.pageCurrent = 1;
|
||||
getListData();
|
||||
};
|
||||
|
||||
const handleSelectionChange = (val) => {
|
||||
if (props.Single) {
|
||||
if (val.length > 1) {
|
||||
let del_row = val.shift();
|
||||
multipleUserRef.value.toggleRowSelection(del_row, false);
|
||||
}
|
||||
multipleSelectionUser.value = val;
|
||||
} else {
|
||||
multipleSelectionUser.value = val;
|
||||
}
|
||||
};
|
||||
|
||||
const zdyaddPerson = () => {
|
||||
addPerson.value.init();
|
||||
};
|
||||
|
||||
watch(()=>props.modelValue,val=>{
|
||||
if(val) handleFilter();
|
||||
},{immediate:true})
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "@/assets/css/layout.scss";
|
||||
@import "@/assets/css/element-plus.scss";
|
||||
</style>
|
||||
<style>
|
||||
.tabBoxRadio .el-checkbox__inner {
|
||||
border-radius: 50% !important;
|
||||
}
|
||||
.tabBoxRadio .el-table__header-wrapper .el-checkbox {
|
||||
display: none;
|
||||
}
|
||||
|
||||
</style>
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
:title="titleValue"
|
||||
width="900px"
|
||||
width="1400px"
|
||||
:model-value="modelValue"
|
||||
append-to-body
|
||||
@close="closed"
|
||||
@ -17,19 +17,20 @@
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="success" @click="handleFilter">查询</el-button>
|
||||
<el-button type="info" @click="reset()"> 重置 </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
|
||||
v-loading="loading"
|
||||
ref="multipleUserRef"
|
||||
@selection-change="handleSelectionChange"
|
||||
:data="tableData"
|
||||
v-loading="loading"
|
||||
border
|
||||
:row-key="keyid"
|
||||
style="width: 100%"
|
||||
@ -43,14 +44,13 @@
|
||||
<el-table-column prop="bqMc" align="center" label="标签名称" />
|
||||
<el-table-column prop="bqDm" align="center" label="标签代码" />
|
||||
<el-table-column prop="bqDj" align="center" label="标签等级">
|
||||
<template #default="{ row }">
|
||||
<DictTag :tag="false" :value="row.bqDj" :options="D_GS_BQ_DJ" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="bqYs" align="center" label="标签颜色">
|
||||
<template #default="{ row }">
|
||||
<DictTag
|
||||
:value="row.bqYs"
|
||||
:tag="false"
|
||||
:options="props.dic.D_GS_SSYJ"
|
||||
/>
|
||||
<DictTag :value="row.bqYs" :tag="false" :options="D_GS_SSYJ" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
@ -58,11 +58,11 @@
|
||||
<div class="fenye" :style="{ top: tableHeight + 'px' }">
|
||||
<el-pagination
|
||||
class="pagination"
|
||||
@size-change="handleSizeChange"
|
||||
@pageSize-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
:current-page="listQuery.current"
|
||||
:current-page="listQuery.pageCurrent"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
:page-size="listQuery.size"
|
||||
:page-pageSize="listQuery.pageSize"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="total"
|
||||
></el-pagination>
|
||||
@ -78,28 +78,18 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { defineProps, ref, onMounted } from "vue";
|
||||
import { qcckGet } from "@/api/qcckApi.js";
|
||||
import { defineProps, ref, getCurrentInstance, watch } from "vue";
|
||||
const { proxy } = getCurrentInstance();
|
||||
const { D_GS_BQ_DJ, D_GS_SSYJ } = proxy.$dict("D_GS_BQ_DJ", "D_GS_SSYJ"); //获取字典数据
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
},
|
||||
dic: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
},
|
||||
bqDl: {
|
||||
type: String,
|
||||
default: "01"
|
||||
},
|
||||
bqLx: {
|
||||
type: String,
|
||||
default: "01"
|
||||
default: false
|
||||
},
|
||||
titleValue: {
|
||||
type: String,
|
||||
default: "选择大类"
|
||||
default: "选择标签"
|
||||
},
|
||||
LeaderType: {
|
||||
type: String,
|
||||
@ -108,35 +98,37 @@ const props = defineProps({
|
||||
//是否单选
|
||||
Single: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
default: false
|
||||
},
|
||||
roleIds: {
|
||||
type: Array,
|
||||
default: []
|
||||
}
|
||||
});
|
||||
const loading = ref(false);
|
||||
const total = ref(0);
|
||||
const listQuery = ref({
|
||||
current: 1,
|
||||
size: 20
|
||||
pageCurrent: 1,
|
||||
pageSize: 20
|
||||
});
|
||||
const loading = ref(false);
|
||||
|
||||
const keyVal = ref();
|
||||
const multipleUserRef = ref(null);
|
||||
const multipleSelectionUser = ref([]);
|
||||
const tableData = ref([]);
|
||||
const emits = defineEmits(["update:modelValue", "chooseDate"]);
|
||||
onMounted(() => {
|
||||
handleFilter();
|
||||
});
|
||||
const emits = defineEmits(["update:modelValue", "choosed"]);
|
||||
const keyid = (row) => {
|
||||
return row.id;
|
||||
};
|
||||
|
||||
const closed = () => {
|
||||
emits("update:modelValue", false);
|
||||
};
|
||||
const reset = () => {
|
||||
listQuery.value = { current: 1, size: 20 };
|
||||
getDataList();
|
||||
listQuery.value = { pageCurrent: 1, pageSize: 20 };
|
||||
getListData();
|
||||
};
|
||||
|
||||
const keyid = (row) => {
|
||||
return row.id;
|
||||
};
|
||||
// 为用户分配角色
|
||||
const onComfirm = () => {
|
||||
const userList = multipleSelectionUser.value;
|
||||
@ -148,42 +140,43 @@ const onComfirm = () => {
|
||||
listId.push(val.id);
|
||||
}
|
||||
});
|
||||
emits("chooseDate", list);
|
||||
let data = { type: props.LeaderType, userList: userList };
|
||||
emits("chooseDateLeader", data);
|
||||
emits("choosed", list);
|
||||
closed();
|
||||
};
|
||||
/**
|
||||
* pageSize 改变触发
|
||||
*/
|
||||
const handleSizeChange = (currentSize) => {
|
||||
listQuery.value.size = currentSize;
|
||||
getDataList();
|
||||
listQuery.value.pageSize = currentSize;
|
||||
getListData();
|
||||
};
|
||||
|
||||
/**
|
||||
* 页码改变触发
|
||||
*/
|
||||
const handleCurrentChange = (currentPage) => {
|
||||
listQuery.value.current = currentPage;
|
||||
getDataList();
|
||||
listQuery.value.pageCurrent = currentPage;
|
||||
getListData();
|
||||
};
|
||||
|
||||
// 查询标签组合列表
|
||||
const getDataList = () => {
|
||||
const data = listQuery.value;
|
||||
const getListData = () => {
|
||||
keyVal.value++;
|
||||
loading.value = true;
|
||||
qcckGet(data, "/mosty-gsxt/tbGsxtBqzh/selectPage").then((res) => {
|
||||
tableData.value = res?.records;
|
||||
total.value = Number(res.total);
|
||||
loading.value = false;
|
||||
multipleUser();
|
||||
});
|
||||
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;
|
||||
});
|
||||
};
|
||||
|
||||
//列表回显
|
||||
function multipleUser() {
|
||||
tableData.value.forEach((item) => {
|
||||
multipleUserRef.value.toggleRowSelection(item, false);
|
||||
if (props.roleIds.some((id) => id == item.id)) {
|
||||
multipleUserRef.value.toggleRowSelection(item, true);
|
||||
}
|
||||
@ -191,12 +184,10 @@ function multipleUser() {
|
||||
}
|
||||
|
||||
const handleFilter = () => {
|
||||
listQuery.value.current = 1;
|
||||
getDataList();
|
||||
listQuery.value.pageCurrent = 1;
|
||||
getListData();
|
||||
};
|
||||
|
||||
const multipleUserRef = ref(null);
|
||||
const multipleSelectionUser = ref([]);
|
||||
const handleSelectionChange = (val) => {
|
||||
if (props.Single) {
|
||||
if (val.length > 1) {
|
||||
@ -208,6 +199,14 @@ const handleSelectionChange = (val) => {
|
||||
multipleSelectionUser.value = val;
|
||||
}
|
||||
};
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(val) => {
|
||||
if (val) handleFilter();
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@ -221,9 +220,4 @@ const handleSelectionChange = (val) => {
|
||||
.tabBoxRadio .el-table__header-wrapper .el-checkbox {
|
||||
display: none;
|
||||
}
|
||||
:deep(.el-dialog) {
|
||||
background: #fff !important;
|
||||
border-radius: 8px !important;
|
||||
/* 其他样式 */
|
||||
}
|
||||
</style>
|
213
src/components/ChooseList/ChooseQt/index.vue
Normal file
@ -0,0 +1,213 @@
|
||||
<template>
|
||||
<el-dialog width="1400px" :model-value="modelValue" append-to-body @close="closed">
|
||||
<template #title>
|
||||
<span class="mr10 f16">选择布控群体</span>
|
||||
</template>
|
||||
<el-form :model="listQuery" :inline="true">
|
||||
<el-form-item label="群体名称">
|
||||
<el-input placeholder="请输入群体名称" v-model="listQuery.qtMc" clearable ></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="success" @click="handleFilter">查询</el-button>
|
||||
<el-button type="info" @click="reset()"> 重置 </el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div class="tabBox" :class="props.Single ? 'tabBoxRadio' : ''" style="margin-top: 0px">
|
||||
<el-table ref="multipleUserRef" v-loading="loading" :key="keyTabel" @selection-change="handleSelectionChange" :data="tableData" border :row-key="keyid" style="width: 100%" height="450">
|
||||
<el-table-column type="selection" width="55" :reserve-selection="true"/>
|
||||
<el-table-column type="expand">
|
||||
<template #default="props">
|
||||
<div class="pl20 pr10 pt10 pb10">
|
||||
<el-table :data="props.row.zdryList" >
|
||||
<el-table-column label="姓名" prop="ryXm" align="center" />
|
||||
<el-table-column prop="rySfzh" align="center" label="身份证"/>
|
||||
<el-table-column prop="ryXb" align="center" label="性别">
|
||||
<template #default="{ row }">
|
||||
<DictTag :tag="false" :value="row.ryXb" :options="D_BZ_XB" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="ryMz" align="center" label="民族">
|
||||
<template #default="{ row }">
|
||||
<DictTag :value="row.ryMz" :tag="false" :options="D_BZ_MZ" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="ryLxdh" align="center" label="手机号"/>
|
||||
<el-table-column prop="xzdXz" align="center" label="现居住址"/>
|
||||
<el-table-column prop="bqList" align="center" label="人员标签">
|
||||
<template #default="{ row }">
|
||||
<span v-if="row.bqList">
|
||||
<span v-for="(it,idx) in row.bqList" :key="idx"> {{ it.bqMc }}、</span>
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="qtMc" align="center" label="群体名称"/>
|
||||
<el-table-column prop="qtFxdj" align="center" label="风险等级">
|
||||
<template #default="{ row }">
|
||||
<DictTag :value="row.qtFxdj" :tag="false" :options="D_GS_ZDQT_FXDJ" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<div class="fenye flex just-end " :style="{ top: tableHeight + 'px' }">
|
||||
<el-pagination
|
||||
class="pagination"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
:current-page="listQuery.pageCurrent"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
:page-size="listQuery.pageSize"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="total"
|
||||
></el-pagination>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="flex just-center">
|
||||
<el-button type="primary" @click="onComfirm">确认</el-button>
|
||||
<el-button @click="closed">取消</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { qcckGet} from "@/api/qcckApi.js";
|
||||
import { defineProps, ref ,getCurrentInstance, watch} from "vue";
|
||||
const { proxy } = getCurrentInstance();
|
||||
const { D_BZ_XB,D_GS_ZDQT_FXDJ,D_BZ_MZ } = proxy.$dict("D_BZ_XB","D_GS_ZDQT_FXDJ","D_BZ_MZ"); //获取字典数据
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: Boolean,
|
||||
default:false
|
||||
},
|
||||
LeaderType: {
|
||||
type: String,
|
||||
default: ""
|
||||
},
|
||||
//是否单选
|
||||
Single: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
roleIds: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
});
|
||||
const loading = ref(false)
|
||||
const total = ref(0);
|
||||
const listQuery = ref({
|
||||
pageCurrent: 1,
|
||||
pageSize: 20
|
||||
});
|
||||
const multipleUserRef = ref(null);
|
||||
const multipleSelectionUser = ref([]);
|
||||
const tableData = ref([]);
|
||||
const emits = defineEmits(["update:modelValue", "choosed"]);
|
||||
const keyTabel = ref(0)
|
||||
const keyid = (row) => {
|
||||
return row.id;
|
||||
};
|
||||
|
||||
const closed = () => {
|
||||
emits("update:modelValue", false);
|
||||
};
|
||||
const reset = () => {
|
||||
listQuery.value = { pageCurrent: 1, pageSize: 20, };
|
||||
getListData();
|
||||
};
|
||||
|
||||
|
||||
// 为用户分配角色
|
||||
const onComfirm = () => {
|
||||
const userList = multipleSelectionUser.value;
|
||||
let list = [];
|
||||
let listId = [];
|
||||
userList.forEach((val) => {
|
||||
if (listId.indexOf(val.id) == -1) {
|
||||
list.push(val);
|
||||
listId.push(val.id);
|
||||
}
|
||||
});
|
||||
emits("choosed", list);
|
||||
closed();
|
||||
};
|
||||
|
||||
/**
|
||||
* pageSize 改变触发
|
||||
*/
|
||||
const handleSizeChange = (currentSize) => {
|
||||
listQuery.value.pageSize = currentSize;
|
||||
getListData();
|
||||
};
|
||||
/**
|
||||
* 页码改变触发
|
||||
*/
|
||||
const handleCurrentChange = (currentPage) => {
|
||||
listQuery.value.pageCurrent = currentPage;
|
||||
getListData();
|
||||
};
|
||||
const getListData = () => {
|
||||
keyTabel.value++
|
||||
loading.value = true;
|
||||
const params = {...listQuery.value}
|
||||
qcckGet(params,'/mosty-gsxt/tbGsxtZdqt/selectPage').then(res=>{
|
||||
loading.value = false;
|
||||
tableData.value = res.records || [];
|
||||
total.value = res.total;
|
||||
multipleUser();
|
||||
}).catch(()=>{
|
||||
loading.value = false;
|
||||
})
|
||||
};
|
||||
|
||||
//列表回显
|
||||
function multipleUser() {
|
||||
tableData.value.forEach((item) => {
|
||||
multipleUserRef.value.toggleRowSelection(item, false);
|
||||
if (props.roleIds.some((id) => id == item.id)) {
|
||||
multipleUserRef.value.toggleRowSelection(item, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const handleFilter = () => {
|
||||
listQuery.value.pageCurrent = 1;
|
||||
getListData();
|
||||
};
|
||||
|
||||
const handleSelectionChange = (val) => {
|
||||
if (props.Single) {
|
||||
if (val.length > 1) {
|
||||
let del_row = val.shift();
|
||||
multipleUserRef.value.toggleRowSelection(del_row, false);
|
||||
}
|
||||
multipleSelectionUser.value = val;
|
||||
} else {
|
||||
multipleSelectionUser.value = val;
|
||||
}
|
||||
};
|
||||
|
||||
watch(()=>props.modelValue,val=>{
|
||||
if(val) handleFilter();
|
||||
},{immediate:true})
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "@/assets/css/layout.scss";
|
||||
@import "@/assets/css/element-plus.scss";
|
||||
</style>
|
||||
<style>
|
||||
.tabBoxRadio .el-checkbox__inner {
|
||||
border-radius: 50% !important;
|
||||
}
|
||||
.tabBoxRadio .el-table__header-wrapper .el-checkbox {
|
||||
display: none;
|
||||
}
|
||||
|
||||
</style>
|
@ -2,8 +2,8 @@
|
||||
<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-form-item label="线索名称">
|
||||
<el-input placeholder="请输入线索名称" v-model="listQuery.xsMc" clearable ></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="success" @click="handleFilter">查询</el-button>
|
||||
@ -11,7 +11,7 @@
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div class="tabBox" :class="props.Single ? 'tabBoxRadio' : ''" style="margin-top: 0px">
|
||||
<el-table ref="multipleUserRef" :key="keyTabel" @selection-change="handleSelectionChange" :data="tableData" border :row-key="keyid" style="width: 100%" height="450">
|
||||
<el-table ref="multipleUserRef" v-loading="loading" :key="keyTabel" @selection-change="handleSelectionChange" :data="tableData" border :row-key="keyid" style="width: 100%" height="450">
|
||||
<el-table-column type="selection" width="55" :reserve-selection="true"/>
|
||||
<el-table-column prop="xsBh" align="center" label="线索编号"/>
|
||||
<el-table-column prop="xsMc" align="center" label="线索名称"/>
|
||||
@ -32,10 +32,10 @@
|
||||
<el-pagination
|
||||
class="pagination"
|
||||
@size-change="handleSizeChange"
|
||||
@pageCurrent-change="handleCurrentChange"
|
||||
:pageCurrent-page="listQuery.pageCurrent"
|
||||
@current-change="handleCurrentChange"
|
||||
:current-page="listQuery.pageCurrent"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
:page-size="listQuery.size"
|
||||
:page-size="listQuery.pageSize"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="total"
|
||||
></el-pagination>
|
||||
@ -80,6 +80,7 @@ const props = defineProps({
|
||||
default: []
|
||||
}
|
||||
});
|
||||
const loading = ref(false)
|
||||
const total = ref(0);
|
||||
const listQuery = ref({
|
||||
pageCurrent: 1,
|
||||
@ -134,11 +135,15 @@ const handleCurrentChange = (currentPage) => {
|
||||
};
|
||||
const getListData = () => {
|
||||
keyTabel.value++
|
||||
const params = {...listQuery.vlue}
|
||||
const params = {...listQuery.value}
|
||||
loading.value = true;
|
||||
qcckGet(params,'/mosty-gsxt/qbcj/selectPage').then(res=>{
|
||||
loading.value = false;
|
||||
tableData.value = res.records || [];
|
||||
total.value = res.total;
|
||||
multipleUser();
|
||||
}).catch(()=>{
|
||||
loading.value = false;
|
||||
})
|
||||
};
|
||||
|
100
src/components/ChooseList/ChooseZdr/addPeo.vue
Normal file
@ -0,0 +1,100 @@
|
||||
<template>
|
||||
<el-dialog v-model="showDialog" :destroy-on-close="true" title="新增人员" @close="close" :close-on-click-modal="false">
|
||||
<FormMessage v-model="listQuery" :formList="formData" labelWidth="120px" ref="elform" :rules="rules">
|
||||
<template #bqList>
|
||||
<div class="marks pointer" @click="chooseMarksVisible = true">
|
||||
<span style="color: rgb(175 178 184);padding-left: 10px;" v-if="!listQuery.bqList || listQuery.bqList.length == 0 ">请选择标签</span>
|
||||
<span v-else >
|
||||
<el-tag @close.stop="closeTag(idx)" type="success" closable v-for="(it,idx) in listQuery.bqList" :key="idx">{{ it.bqMc }}</el-tag >
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
</FormMessage>
|
||||
<template #footer>
|
||||
<div class="flex just-center">
|
||||
<el-button @click="close">取消</el-button>
|
||||
<el-button type="primary" @click="submitForm">确认</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
<ChooseMarks v-model="chooseMarksVisible" @choosed="choosed" :roleIds="roleIds" />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import ChooseMarks from "@/components/ChooseList/ChooseMarks/index.vue";
|
||||
import FormMessage from "@/components/aboutTable/FormMessage.vue";
|
||||
import { reactive, ref,getCurrentInstance } from 'vue';
|
||||
const { proxy } = getCurrentInstance();
|
||||
const { D_BZ_XB } = proxy.$dict("D_BZ_XB"); // 获取字典数据
|
||||
const elform = ref()
|
||||
const roleIds = ref([])
|
||||
const showDialog = ref(false)
|
||||
const chooseMarksVisible = ref(false)
|
||||
const emit = defineEmits(['change'])
|
||||
const listQuery = ref({})
|
||||
const formData = ref([
|
||||
{ label: "人员姓名", prop: "ryXm", type: "input" ,width:'45%'},
|
||||
{ label: "性别", prop: "ryXb", type: "select" ,width:'45%',options:D_BZ_XB},
|
||||
{ label: "身份证号", prop: "rySfzh", type: "input" ,width:'45%'},
|
||||
{ label: "手机号码", prop: "ryLxdh", type: "input",width:'45%' },
|
||||
{ label: "户籍地址", prop: "hjdXz", type: "input",width:'100%'},
|
||||
{ label: "户籍地派出所", prop: "hjdpcsdm",depMc:'hjdpcs', type: "department" ,width:'48%'},
|
||||
{ label: "特征描述", prop: "qtTzms", type: "input" ,width:'100%'},
|
||||
{ label: "人员标签", prop: "bqList", type: "slot" ,width:'100%'},
|
||||
{ label: "车牌号", prop: "clCph", type: "input" ,width:'45%'},
|
||||
{ label: "车架号", prop: "clCjh", type: "input" ,width:'45%'},
|
||||
{ label: "人员照片", prop: "fjZp", type: "upload" ,width:'100%'},
|
||||
])
|
||||
const rules = reactive({
|
||||
ryXm: [{ required: true, message: "请输入姓名", trigger: "blur" }],
|
||||
rySfzh: [{ required: true, message: "请输入身份证号", trigger: "blur" }],
|
||||
ryXb: [{ required: true, message: "请选择性别", trigger: "change" }],
|
||||
ryLxdh: [{ required: true, message: "请输入手机号码", trigger: "blur" }],
|
||||
hjdXz: [{ required: true, message: "请输入户籍地", trigger: "blur" }],
|
||||
xzdXz: [{ required: true, message: "请输入现居住地址", trigger: "blur" }],
|
||||
})
|
||||
const init = () =>{
|
||||
showDialog.value = true;
|
||||
}
|
||||
|
||||
// 选择标签
|
||||
const choosed = (val) => {
|
||||
listQuery.value.bqList = val.map(v=>{
|
||||
return { bqZl:v.bqLb , bqId:v.id, bqLx:v.bqLx, bqLb:v.bqLb, bqMc:v.bqMc, bqDm:v.bqDm }
|
||||
});
|
||||
roleIds.value = val.map(v=>v.id)
|
||||
}
|
||||
|
||||
// 删除数据
|
||||
const closeTag = (idx) =>{
|
||||
listQuery.value.bqList.splice(idx,1)
|
||||
roleIds.value.splice(idx,1)
|
||||
}
|
||||
|
||||
const submitForm = () =>{
|
||||
elform.value.submit((val)=>{
|
||||
val.id = new Date().getTime()
|
||||
emit('change',val)
|
||||
showDialog.value = false;
|
||||
})
|
||||
}
|
||||
|
||||
const close = () =>{
|
||||
elform.value.reset();
|
||||
listQuery.value.bqList = []
|
||||
roleIds.value = []
|
||||
showDialog.value = false;
|
||||
}
|
||||
|
||||
defineExpose({init})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
.marks{
|
||||
width: 100%;
|
||||
min-height: 32px;
|
||||
border: 1px solid #e9e9e9;
|
||||
border-radius: 4px;
|
||||
}
|
||||
</style>
|
224
src/components/ChooseList/ChooseZdr/index.vue
Normal file
@ -0,0 +1,224 @@
|
||||
<template>
|
||||
<el-dialog width="1400px" :model-value="modelValue" append-to-body @close="closed">
|
||||
<template #title>
|
||||
<span class="mr10 f16">选择布控人员</span>
|
||||
<el-button type="primary" size="small" @click="zdyaddPerson">添加其他人员</el-button>
|
||||
</template>
|
||||
<el-form :model="listQuery" :inline="true">
|
||||
<el-form-item label="人员姓名">
|
||||
<el-input placeholder="请输入人员姓名" v-model="listQuery.ryxm" clearable ></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="身份证号">
|
||||
<el-input placeholder="请输入身份证号" v-model="listQuery.sfzh" clearable ></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="手机号码">
|
||||
<el-input placeholder="请输入手机号码" v-model="listQuery.sjhm" clearable ></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="success" @click="handleFilter">查询</el-button>
|
||||
<el-button type="info" @click="reset()"> 重置 </el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div class="tabBox" :class="props.Single ? 'tabBoxRadio' : ''" style="margin-top: 0px">
|
||||
<el-table ref="multipleUserRef" :key="keyTabel" v-loading="loading" @selection-change="handleSelectionChange" :data="tableData" border :row-key="keyid" style="width: 100%" height="450">
|
||||
<el-table-column type="selection" width="55" :reserve-selection="true"/>
|
||||
<el-table-column prop="ryXm" align="center" label="姓名"/>
|
||||
<el-table-column prop="rySfzh" align="center" label="身份证"/>
|
||||
<el-table-column prop="ryXb" align="center" label="性别">
|
||||
<template #default="{ row }">
|
||||
<DictTag :tag="false" :value="row.ryXb" :options="D_BZ_XB" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="ryMz" align="center" label="民族">
|
||||
<template #default="{ row }">
|
||||
<DictTag :value="row.ryMz" :tag="false" :options="D_BZ_MZ" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="hjdXz" align="center" label="户籍地"/>
|
||||
<el-table-column prop="xzdXz" align="center" label="现居住址"/>
|
||||
<el-table-column prop="ryLxdh" align="center" label="手机号"/>
|
||||
<el-table-column prop="qtXnsf" align="center" label="虚拟身份"/>
|
||||
<el-table-column prop="clCph" align="center" label="车牌号"/>
|
||||
<el-table-column prop="clCjh" align="center" label="车架号"/>
|
||||
<el-table-column prop="qtTzms" align="center" label="特征描述"/>
|
||||
<el-table-column prop="bqList" align="center" label="人员标签">
|
||||
<template #default="{ row }">
|
||||
<span v-if="row.bqList">
|
||||
<span v-for="(it,idx) in row.bqList" :key="idx"> {{ it.bqMc }}、</span>
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<div class="fenye flex just-end " :style="{ top: tableHeight + 'px' }">
|
||||
<el-pagination
|
||||
class="pagination"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
:current-page="listQuery.pageCurrent"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
:page-size="listQuery.pageSize"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="total"
|
||||
></el-pagination>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="flex just-center">
|
||||
<el-button @click="closed">取消</el-button>
|
||||
<el-button type="primary" @click="onComfirm">确认</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 自定义选添加人 -->
|
||||
<AddPeo ref="addPerson" @change="changeZdy"></AddPeo>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import AddPeo from './addPeo.vue'
|
||||
import { qcckGet} from "@/api/qcckApi.js";
|
||||
import { defineProps, ref ,getCurrentInstance, watch} from "vue";
|
||||
const { proxy } = getCurrentInstance();
|
||||
const { D_BZ_XB,D_BZ_MZ } = proxy.$dict("D_BZ_XB","D_BZ_MZ"); //获取字典数据
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: Boolean,
|
||||
default:false
|
||||
},
|
||||
LeaderType: {
|
||||
type: String,
|
||||
default: ""
|
||||
},
|
||||
//是否单选
|
||||
Single: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
roleIds: {
|
||||
type: Array,
|
||||
default: []
|
||||
},
|
||||
});
|
||||
const loading = ref(false)
|
||||
const total = ref(0);
|
||||
const listQuery = ref({
|
||||
pageCurrent: 1,
|
||||
pageSize: 20
|
||||
});
|
||||
const addPerson = ref()
|
||||
const multipleUserRef = ref(null);
|
||||
const multipleSelectionUser = ref([]);
|
||||
const tableData = ref([]);
|
||||
const emits = defineEmits(["update:modelValue", "choosed","choosedAdd"]);
|
||||
const keyTabel = ref(0)
|
||||
const keyid = (row) => {
|
||||
return row.id;
|
||||
};
|
||||
|
||||
const closed = () => {
|
||||
emits("update:modelValue", false);
|
||||
};
|
||||
const reset = () => {
|
||||
listQuery.value = { pageCurrent: 1, pageSize: 20, };
|
||||
getListData();
|
||||
};
|
||||
|
||||
|
||||
// 为用户分配角色
|
||||
const onComfirm = () => {
|
||||
const userList = multipleSelectionUser.value;
|
||||
let list = [];
|
||||
let listId = [];
|
||||
userList.forEach((val) => {
|
||||
if (listId.indexOf(val.id) == -1) {
|
||||
list.push(val);
|
||||
listId.push(val.id);
|
||||
}
|
||||
});
|
||||
emits("choosed", list);
|
||||
closed();
|
||||
};
|
||||
|
||||
// 自定义加人
|
||||
const changeZdy = (val) => {
|
||||
emits("choosedAdd", val);
|
||||
closed();
|
||||
}
|
||||
/**
|
||||
* pageSize 改变触发
|
||||
*/
|
||||
const handleSizeChange = (currentSize) => {
|
||||
listQuery.value.pageSize = currentSize;
|
||||
getListData();
|
||||
};
|
||||
/**
|
||||
* 页码改变触发
|
||||
*/
|
||||
const handleCurrentChange = (currentPage) => {
|
||||
listQuery.value.pageCurrent = currentPage;
|
||||
getListData();
|
||||
};
|
||||
const getListData = () => {
|
||||
keyTabel.value++
|
||||
const params = {...listQuery.value}
|
||||
loading.value = true;
|
||||
qcckGet(params,'/mosty-gsxt/tbGsxtZdry/selectPage').then(res=>{
|
||||
loading.value = false;
|
||||
tableData.value = res.records || [];
|
||||
total.value = res.total;
|
||||
multipleUser();
|
||||
}).catch(()=>{
|
||||
loading.value = false;
|
||||
})
|
||||
};
|
||||
|
||||
//列表回显
|
||||
function multipleUser() {
|
||||
tableData.value.forEach((item) => {
|
||||
multipleUserRef.value.toggleRowSelection(item, false);
|
||||
if (props.roleIds.some((id) => id == item.id)) {
|
||||
multipleUserRef.value.toggleRowSelection(item, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const handleFilter = () => {
|
||||
listQuery.value.pageCurrent = 1;
|
||||
getListData();
|
||||
};
|
||||
|
||||
const handleSelectionChange = (val) => {
|
||||
if (props.Single) {
|
||||
if (val.length > 1) {
|
||||
let del_row = val.shift();
|
||||
multipleUserRef.value.toggleRowSelection(del_row, false);
|
||||
}
|
||||
multipleSelectionUser.value = val;
|
||||
} else {
|
||||
multipleSelectionUser.value = val;
|
||||
}
|
||||
};
|
||||
|
||||
const zdyaddPerson = () => {
|
||||
addPerson.value.init();
|
||||
};
|
||||
|
||||
watch(()=>props.modelValue,val=>{
|
||||
if(val) handleFilter();
|
||||
},{immediate:true})
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "@/assets/css/layout.scss";
|
||||
@import "@/assets/css/element-plus.scss";
|
||||
</style>
|
||||
<style>
|
||||
.tabBoxRadio .el-checkbox__inner {
|
||||
border-radius: 50% !important;
|
||||
}
|
||||
.tabBoxRadio .el-table__header-wrapper .el-checkbox {
|
||||
display: none;
|
||||
}
|
||||
|
||||
</style>
|
@ -8,6 +8,7 @@
|
||||
:index="index"
|
||||
:class="item.elTagType"
|
||||
@click="handleItem(item)"
|
||||
:style="{color: props.color}"
|
||||
>{{ item.label || item.zdmc }}</span>
|
||||
<el-tag
|
||||
v-else
|
||||
@ -33,6 +34,10 @@ const props = defineProps({
|
||||
type: Array,
|
||||
default: null
|
||||
},
|
||||
color:{
|
||||
type:String,
|
||||
default:'#6f6f74'
|
||||
},
|
||||
tag: false,
|
||||
value: [Number, String, Array]
|
||||
});
|
||||
|
399
src/components/ExtractionText/index.vue
Normal file
@ -0,0 +1,399 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-dialog v-model="modelValue" title="文件解析" width="1000px" :show-close="true" :center="true" :close-on-click-modal="false" :before-close="handleClose" >
|
||||
<div class="flex align-center">
|
||||
<h3>提取文件类型:</h3>
|
||||
<el-radio-group v-model="active" @change="changeRadio">
|
||||
<el-radio :label="'文件解析'">文件解析</el-radio>
|
||||
<el-radio :label="'图片解析'">图片解析</el-radio>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
<!-- 文件解析 -->
|
||||
<div v-show="active == '文件解析'">
|
||||
<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">{{ fileText }}</p>
|
||||
</div>
|
||||
|
||||
<button id="extract-btn" disabled>提取文本</button>
|
||||
|
||||
<h3>提取结果:</h3>
|
||||
<div id="result">{{ content }}</div>
|
||||
</div>
|
||||
<!-- 图片解析 -->
|
||||
<div v-show="active == '图片解析'" v-loading="loading" element-loading-text="模型加载中......">
|
||||
<div class="flex align-center just-between">
|
||||
<h1>文件文本提取工具</h1>
|
||||
<span title="刷新" class="pointer" >
|
||||
<el-icon color="#0072ff" size="30px" @click="frashJs"><RefreshRight /></el-icon>
|
||||
<el-icon color="#23c044" size="14px" v-if="hasLoad"><CircleCheckFilled /></el-icon>
|
||||
<el-icon color="#e60e0e" size="14px" v-if="!hasLoad"><CircleCloseFilled /></el-icon>
|
||||
</span>
|
||||
</div>
|
||||
<p>上传文件提取文本内容(支持 .png, .jpg )</p>
|
||||
<div class="container flex" style="height: 248px;">
|
||||
<div class="mr10">
|
||||
<el-upload :headers="headers" accept=".png,.jpg,jpeg" action="/mosty-api/mosty-base/minio/image/upload/id" :show-file-list="false" :on-success="handlerSuccess" :on-change="onHandleChange" >
|
||||
<el-button size="medium" type="primary">上传图片</el-button>
|
||||
</el-upload>
|
||||
<p id="file-info">{{ files.name || '未选择文件' }} </p>
|
||||
</div>
|
||||
<div class="box">
|
||||
<div class="imd">
|
||||
<img :src="image" v-if="image" style="width: 340px; max-height: 200px"/>
|
||||
<img :src="image" ref="imageRef" v-show="false" />
|
||||
</div>
|
||||
<div class="imd" v-show="false">
|
||||
<canvas ref="canvasRef"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<h3>提取结果:</h3>
|
||||
<div class="textModel noScollLine" v-loading="linadingImg" element-loading-text="图片解析中......">
|
||||
<p v-if="texts.length == 0">{{ alertText }}</p>
|
||||
<template v-else>
|
||||
<p v-for="(text, index) in texts" :key="index">{{ text }}</p>
|
||||
</template>
|
||||
</div>
|
||||
</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 axios from "axios";
|
||||
import * as ocr from "@paddlejs-models/ocr";
|
||||
import { drawBox } from "@/utils/ocrUtils";
|
||||
import { nextTick,reactive, ref,getCurrentInstance, watch } from "vue";
|
||||
import { useStore } from "vuex";
|
||||
const store = useStore();
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
});
|
||||
|
||||
const content = ref('请先上传文件...')
|
||||
const fileText = ref('未选择文件')
|
||||
|
||||
const { proxy } = getCurrentInstance();
|
||||
const emits = defineEmits(["update:modelValue", "change"]);
|
||||
const active = ref('文件解析')
|
||||
const hasLoad = ref(false)
|
||||
const files = ref({})
|
||||
const loading = ref(true)
|
||||
const linadingImg = ref(false)
|
||||
const image = ref('')
|
||||
const alertText = ref('请先上传文件...')
|
||||
const texts = ref([])
|
||||
const imageRef = ref()
|
||||
const canvasRef = ref()
|
||||
const textStyle = reactive({
|
||||
width: "",
|
||||
height: ""
|
||||
})
|
||||
const headers = ref({
|
||||
Authorization: store.getters.token
|
||||
});
|
||||
const fjdz = ref('') //附件地址
|
||||
const fjmc = ref('') //附件地址
|
||||
|
||||
const initDemo = () =>{
|
||||
loading.value = imgIsLoad ? false : true;
|
||||
hasLoad.value = imgIsLoad ? true : false;
|
||||
nextTick(() => {
|
||||
const fileInput = document.getElementById("file-input");
|
||||
const extractBtn = document.getElementById("extract-btn");
|
||||
let selectedFile = null;
|
||||
// 监听文件选择
|
||||
fileInput.addEventListener("change", function (e) {
|
||||
if (e.target.files.length > 0) {
|
||||
selectedFile = e.target.files[0];
|
||||
fileText.value = `已选择: ${selectedFile.name} (${( selectedFile.size / 1024 ).toFixed(2)} KB)`;
|
||||
extractBtn.disabled = false;
|
||||
fjmc.value = selectedFile.name;
|
||||
uploadFile(selectedFile); //上传附件
|
||||
} else {
|
||||
selectedFile = null;
|
||||
fileText.value = "未选择文件";
|
||||
extractBtn.disabled = true;
|
||||
}
|
||||
if (selectedFile.type == "video/mp4") {
|
||||
upfileOnchange(selectedFile);
|
||||
}
|
||||
});
|
||||
// 提取文本按钮点击事件
|
||||
extractBtn.addEventListener("click", async function () {
|
||||
if (!selectedFile) return (content.value = "请先选择文件");
|
||||
content.value = "正在处理文件...";
|
||||
try {
|
||||
let text = "";
|
||||
const fileType = selectedFile.name.split(".").pop().toLowerCase();
|
||||
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);
|
||||
} else if (["mp4", "mp3", "wav"].includes(fileType)) {
|
||||
// 处理mp4,mp3,wav文件
|
||||
await start();
|
||||
text = "数据加载有点慢,请稍等。。。。";
|
||||
setTimeout(() => {
|
||||
content.value = videoText;
|
||||
}, 2000);
|
||||
}else {
|
||||
throw new Error("不支持的文件类型");
|
||||
}
|
||||
content.value = text || "未提取到文本内容";
|
||||
} catch (error) {
|
||||
content.value = `处理失败: ${error.message}`;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
watch(()=>props.modelValue,val=>{
|
||||
if(val) initDemo();
|
||||
},{immediate:true,deep:true})
|
||||
|
||||
|
||||
|
||||
// 读取文本文件
|
||||
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 handlerSuccess = (file) =>{
|
||||
fjdz.value = file.data;
|
||||
}
|
||||
|
||||
/**@Descripttion:图片上传事件*/
|
||||
const onHandleChange = (file) => {
|
||||
fjmc.value = file.name;
|
||||
files.value = file;
|
||||
image.value = URL.createObjectURL(file.raw);
|
||||
linadingImg.value = true;
|
||||
alertText.value = '图片文件解析中。。。'
|
||||
setTimeout(() => {
|
||||
getRecognize();
|
||||
}, 600);
|
||||
|
||||
}
|
||||
// 图片解析
|
||||
const getRecognize = async () => {
|
||||
const image = imageRef.value;
|
||||
const canvas = canvasRef.value;
|
||||
const res = await ocr.recognize(image);
|
||||
const { text, points } = res;
|
||||
drawBox(points, image, canvas);
|
||||
textStyle.width = image.width - 40 + "px";
|
||||
texts.value = text;
|
||||
linadingImg.value = false;
|
||||
alertText.value = '解析失败,请选择清晰一点的图片重试!'
|
||||
}
|
||||
|
||||
// 切换标签
|
||||
const changeRadio = (val) =>{
|
||||
content.value = "请先上传文件...";
|
||||
fileText.value = "选择文件";
|
||||
files.value = {};
|
||||
alertText.value = '请先上传文件...';
|
||||
texts.value = [];
|
||||
image.value = '';
|
||||
fjmc.value = '';
|
||||
if(val == '图片解析'){
|
||||
if(!imgIsLoad) proxy.$message({ type: "error", message: "加载失败,请刷新页面" });
|
||||
}
|
||||
}
|
||||
|
||||
// 提交
|
||||
const onComfirm = () => {
|
||||
if(active.value == '文件解析'){
|
||||
if(content.value == '请先上传文件...') return proxy.$message({ type: "warning", message: "请解析文件" });
|
||||
emits("change", { text: content.value,fjdz:fjdz.value,fjmc:fjmc.value });
|
||||
}else{
|
||||
if(texts.value.length == 0) return proxy.$message({ type: "warning", message: "请解析文件" });
|
||||
emits("change", {text:texts.value.join(',\n'),fjdz:fjdz.value,fjmc:fjmc.value});
|
||||
}
|
||||
handleClose()
|
||||
};
|
||||
|
||||
// 关闭
|
||||
const handleClose = () => {
|
||||
content.value = "请先上传文件";
|
||||
fileText.value = "未选择文件";
|
||||
files.value = {}
|
||||
alertText.value = '请先上传文件...';
|
||||
texts.value = []
|
||||
image.value = ''
|
||||
active.value = '文件解析'
|
||||
emits("update:modelValue", false);
|
||||
};
|
||||
|
||||
// 上传附件
|
||||
const uploadFile = (file) =>{
|
||||
let formData = new FormData();
|
||||
formData.append("file", file);
|
||||
let token = localStorage.getItem('token');
|
||||
axios({
|
||||
method: 'post',
|
||||
url: '/mosty-api/mosty-base/minio/image/upload/id',
|
||||
data:formData,
|
||||
headers: { "Content-type": "multipart/form-data",'Authorization': token }
|
||||
}).then( (res) => {
|
||||
fjdz.value = res.data ? res.data.data : null;
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// 刷新js
|
||||
const frashJs = async () =>{
|
||||
if(!imgIsLoad){
|
||||
try {
|
||||
await ocr.init();// 模型初始化
|
||||
imgIsLoad = true;
|
||||
proxy.$message({ type: "success", message: "加载成功" });
|
||||
} catch (err) {
|
||||
proxy.$message({ type: "error", message: "加载失败,请刷新页面" });
|
||||
imgIsLoad = 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: #0072ff;
|
||||
color: white;
|
||||
padding: 10px 15px;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
font-size: 16px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
background: #0072ff;
|
||||
}
|
||||
|
||||
#result {
|
||||
margin-top: 20px;
|
||||
white-space: pre-wrap;
|
||||
background: #f9f9f9;
|
||||
padding: 15px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
height: 270px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
#file-info {
|
||||
margin: 10px 0;
|
||||
font-style: italic;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
::v-deep .el-dialog {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
|
||||
.box{
|
||||
display: flex;
|
||||
.imd{
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.textModel{
|
||||
margin-top: 20px;
|
||||
white-space: pre-wrap;
|
||||
background: #f9f9f9;
|
||||
padding: 15px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
height: 195px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
</style>
|
@ -46,11 +46,15 @@ const mMap = ref(null); //地图对象
|
||||
const mapUtil = ref(null); //地图工具对象
|
||||
const zoomTarget = ref(6);
|
||||
|
||||
// 定义组件发出的事件
|
||||
const emit = defineEmits(['mapLoaded'])
|
||||
|
||||
const props = defineProps({
|
||||
mapid: {
|
||||
type: String,
|
||||
default: "mapDiv"
|
||||
},
|
||||
|
||||
//是否显示可以切换地图底图
|
||||
isShow: {
|
||||
type: Boolean,
|
||||
@ -79,13 +83,15 @@ let map;
|
||||
let mapLayer;
|
||||
let mapLayer1;
|
||||
onMounted(() => {
|
||||
console.log("xxxxxxx");
|
||||
|
||||
emitter.on("followUp", (res) => {
|
||||
let box = document.getElementsByClassName("changeMap_box");
|
||||
if (!box) return;
|
||||
box[0].style.right = !res ? "4px" : "398px";
|
||||
box[0].style.transition = "0.5s";
|
||||
});
|
||||
|
||||
|
||||
map = new EliMap({
|
||||
id: props.mapid,
|
||||
crs: "EPSG:3857",
|
||||
@ -110,6 +116,8 @@ onMounted(() => {
|
||||
url: 'http://webrd02.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}',
|
||||
})
|
||||
zoomTarget.value = map.mapboxGLMap.getZoom();
|
||||
// 地图加载完成后发出事件
|
||||
emit('mapLoaded')
|
||||
});
|
||||
mapUtil.value = new MapUtil(map);
|
||||
|
||||
@ -253,7 +261,7 @@ const mapSetLayer = (id, source) => {
|
||||
|
||||
//获取地图绘制的数据
|
||||
const resFun = (coord, type, flag, data) => {
|
||||
|
||||
|
||||
emitter.emit("coordString", {
|
||||
coord: coord,
|
||||
type: type,
|
||||
|
359
src/components/GdMap/indexnw.vue
Normal file
@ -0,0 +1,359 @@
|
||||
<template>
|
||||
<div :id="mapid" class="map"></div>
|
||||
<div class="changeMap_box" v-if="props.isShow">
|
||||
<el-switch v-model="conditionRoute" @change="handleSwitch" active-text="打开路况" inactive-text="关闭路况"
|
||||
style="--el-switch-color: #13ce66; --el-switch-off-color: #ff4949" />
|
||||
<!-- <el-carousel type="card" height="75px" :autoplay="false" indicator-position="none" :initial-index="3" @change="onMapImageChange">
|
||||
<el-carousel-item>
|
||||
<div class="mapImageItem">
|
||||
<img :src="require('@/assets/images/slt.jpg')" alt="" />
|
||||
<div>栅格浅色</div>
|
||||
</div>
|
||||
</el-carousel-item>
|
||||
<el-carousel-item>
|
||||
<div class="mapImageItem">
|
||||
<img :src="require('@/assets/images/yxt.jpg')" alt="" />
|
||||
<div>影像图</div>
|
||||
</div>
|
||||
</el-carousel-item>
|
||||
<el-carousel-item>
|
||||
<div class="mapImageItem">
|
||||
<img :src="require('@/assets/images/yst.jpg')" alt="" />
|
||||
<div>栅格深色</div>
|
||||
</div>
|
||||
</el-carousel-item>
|
||||
<el-carousel-item>
|
||||
<div class="mapImageItem">
|
||||
<img :src="require('@/assets/images/shy.png')" alt="" />
|
||||
<div>三合一</div>
|
||||
</div>
|
||||
</el-carousel-item>
|
||||
</el-carousel> -->
|
||||
<!-- 地图缩放 -->
|
||||
<div class="zoomTargetBox">
|
||||
<el-input-number :min="7" :max="18" v-model="zoomTarget" :step="1" step-strictly @change="handleZoom"></el-input-number>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, onUnmounted, defineProps, nextTick } from "vue";
|
||||
import { MapUtil } from "./mapUtil";
|
||||
import emitter from "@/utils/eventBus.js";
|
||||
import { getItem } from "@/utils/storage";
|
||||
const conditionRoute = ref(true); //路况
|
||||
const mMap = ref(null); //地图对象
|
||||
const mapUtil = ref(null); //地图工具对象
|
||||
const zoomTarget = ref(6);
|
||||
|
||||
const props = defineProps({
|
||||
mapid: {
|
||||
type: String,
|
||||
default: "mapDiv"
|
||||
},
|
||||
//是否显示可以切换地图底图
|
||||
isShow: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
//是否显示实时路况
|
||||
isShowMvt: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
//是否显示地图层级
|
||||
isShowZoom: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
//是否显示绘制控件
|
||||
isShowDraw: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
});
|
||||
try {
|
||||
const userInfo = getItem("deptId")[0].deptCode;
|
||||
} catch (error) { }
|
||||
let map;
|
||||
let mapLayer;
|
||||
let mapLayer1;
|
||||
onMounted(() => {
|
||||
emitter.on("followUp", (res) => {
|
||||
let box = document.getElementsByClassName("changeMap_box");
|
||||
if (!box) return;
|
||||
box[0].style.right = !res ? "4px" : "398px";
|
||||
box[0].style.transition = "0.5s";
|
||||
});
|
||||
|
||||
map = new EliMap({
|
||||
id: props.mapid,
|
||||
crs: "EPSG:4490",
|
||||
style: {
|
||||
glyphs: "./fonts/{fontstack}/{range}.pbf",
|
||||
center: [94.36057012, 29.64276831],
|
||||
zoom: 15
|
||||
},
|
||||
minZoom: 7,
|
||||
maxZoom: 18,
|
||||
});
|
||||
window.map = map;
|
||||
map.mapboxGLMap.on("load", () => {
|
||||
map.addWMTSLayer(
|
||||
"/PGIS_S_TileMapServer/Maps/XZDJ_SL/EzMap"
|
||||
,
|
||||
{
|
||||
Service: "getImage",
|
||||
Type: "RGB",
|
||||
ZoomOffset: "0",
|
||||
V: "0.3",
|
||||
Zoom: "{z}",
|
||||
Row: "{y}",
|
||||
Col: "{x}"
|
||||
},
|
||||
{
|
||||
tileSize: 300
|
||||
}
|
||||
);
|
||||
zoomTarget.value = map.mapboxGLMap.getZoom();
|
||||
});
|
||||
mapUtil.value = new MapUtil(map);
|
||||
|
||||
mapUtil.value.Drawplot(); //初始化加载绘制工具
|
||||
|
||||
// 设置地图中心点及图层
|
||||
emitter.on("setMapCenter", (res) => {
|
||||
mapUtil.value.setMapCenter(res.location, res.zoomLevel);
|
||||
});
|
||||
|
||||
emitter.on("removePlot", (flag) => {
|
||||
mapUtil.value.removePlot(flag);
|
||||
});
|
||||
emitter.on("removeAll", (flag) => {
|
||||
mapUtil.value.removeAll(flag);
|
||||
});
|
||||
// 撒点
|
||||
emitter.on("addPointArea", (obj) => {
|
||||
mapUtil.value.makerSki(obj);
|
||||
});
|
||||
// 鼠标滑过提示文字的点位
|
||||
emitter.on("showPoint", (obj) => {
|
||||
mapUtil.value.showPoint(obj);
|
||||
});
|
||||
|
||||
// 清除覆盖物
|
||||
emitter.on("deletePointArea", (res) => {
|
||||
mapUtil.value.removeElement(res);
|
||||
});
|
||||
// 清除某个覆盖物的单个
|
||||
emitter.on("deletePointAreaOne", (obj) => {
|
||||
mapUtil.value.removeElementOne(obj.flag, obj.id);
|
||||
});
|
||||
|
||||
// 清除某个覆盖物的单个
|
||||
emitter.on("showSquire", (obj) => {
|
||||
mapUtil.value.zdySquire(obj);
|
||||
});
|
||||
|
||||
// 绘制图形 - 回显区域
|
||||
emitter.on("drawShape", (res) => {
|
||||
mapUtil.value.plot(res, resFun);
|
||||
});
|
||||
emitter.on("removeEara", (flag) => {
|
||||
mapUtil.value.removeEara(flag);
|
||||
});
|
||||
// 回显图形
|
||||
emitter.on("echoPlane", (res) => {
|
||||
mapUtil.value.echoPlane(res);
|
||||
});
|
||||
//移除绘制区域
|
||||
emitter.on("removeEara", (flag) => {
|
||||
mapUtil.value.removeEara(flag);
|
||||
});
|
||||
// 回显线
|
||||
emitter.on("echoLine", (res) => {
|
||||
mapUtil.value.createLine(res, res.flag);
|
||||
});
|
||||
//创建边界面(geojson)
|
||||
emitter.on("setBoundarys", (res) => {
|
||||
mapUtil.value.createBoundarys(res);
|
||||
});
|
||||
// 移除边界
|
||||
emitter.on("removeBj", (res) => {
|
||||
mapUtil.value.removeBj(res);
|
||||
});
|
||||
|
||||
// 轨迹回放
|
||||
emitter.on("drawLineAnimation", (res) => {
|
||||
mapUtil.value.displayLineAnimation(res);
|
||||
});
|
||||
|
||||
// 聚合撒点
|
||||
emitter.on("addPoint", (obj) => {
|
||||
mapUtil.value.aggregateScatteringPoint(obj);
|
||||
});
|
||||
|
||||
// 热力图显示
|
||||
emitter.on("thermodynamicChart", (res) => {
|
||||
mapUtil.value.showHeatDrawing(res);
|
||||
});
|
||||
|
||||
// 扩散圆
|
||||
emitter.on("diffusionCircle", (res) => {
|
||||
mapUtil.value.diffusionCircle(res);
|
||||
});
|
||||
|
||||
// 展示盘曲
|
||||
emitter.on("showGapText", (obj) => {
|
||||
mapUtil.value.gapText(obj);
|
||||
});
|
||||
|
||||
// 获取当前地图中心点
|
||||
emitter.on("getCurrentCenter", (res) => {
|
||||
let centerPoint = map.mapboxGLMap.getCenter();
|
||||
let coords = [centerPoint.lng, centerPoint.lat];
|
||||
emitter.emit("getcentercoord", coords);
|
||||
});
|
||||
});
|
||||
//切换地图底图
|
||||
const onMapImageChange = (val) => {
|
||||
//清除已经存在胡地图图层
|
||||
if (map.mapboxGLMap.getLayer("SGQS_ID"))
|
||||
map.mapboxGLMap.removeLayer("SGQS_ID");
|
||||
if (map.mapboxGLMap.getLayer("YX_ID")) map.mapboxGLMap.removeLayer("YX_ID");
|
||||
if (map.mapboxGLMap.getLayer("SGSG_ID"))
|
||||
map.mapboxGLMap.removeLayer("SGSG_ID");
|
||||
if (map.mapboxGLMap.getLayer("TDT_TITLE_ID"))
|
||||
map.mapboxGLMap.removeLayer("TDT_TITLE_ID");
|
||||
if (map.mapboxGLMap.getLayer("TDT_ROAD_ID"))
|
||||
map.mapboxGLMap.removeLayer("TDT_ROAD_ID");
|
||||
if (map.mapboxGLMap.getLayer("TDT_POI_ID"))
|
||||
map.mapboxGLMap.removeLayer("TDT_POI_ID");
|
||||
//设置图层
|
||||
switch (val) {
|
||||
case 0:
|
||||
mapSetLayer("SGQS_ID", "SGQS");
|
||||
break;
|
||||
case 1:
|
||||
mapSetLayer("YX_ID", "YX");
|
||||
break;
|
||||
case 2:
|
||||
mapSetLayer("SGSG_ID", "SGSG");
|
||||
break;
|
||||
case 3:
|
||||
mapSetLayer("TDT_TITLE_ID", "TDT_TITLE_SOURCES");
|
||||
mapSetLayer("TDT_ROAD_ID", "TDT_ROAD_SOURCES");
|
||||
mapSetLayer("TDT_POI_ID", "TDT_POI_SOURCES");
|
||||
break;
|
||||
}
|
||||
if (map.mapboxGLMap.getLayer("realTimeTrafficlevelOne"))
|
||||
map.mapboxGLMap.moveLayer("realTimeTrafficlevelOne");
|
||||
if (map.mapboxGLMap.getLayer("map_id")) map.mapboxGLMap.moveLayer("map_id");
|
||||
if (map.mapboxGLMap.getLayer("map_ids")) map.mapboxGLMap.moveLayer("map_ids");
|
||||
};
|
||||
|
||||
//设置图层函数
|
||||
const mapSetLayer = (id, source) => {
|
||||
map.mapboxGLMap.addLayer({ id, type: "raster", source });
|
||||
};
|
||||
|
||||
//获取地图绘制的数据
|
||||
const resFun = (coord, type, flag, data) => {
|
||||
emitter.emit("coordString", {
|
||||
coord: coord,
|
||||
type: type,
|
||||
flag: flag,
|
||||
data: data
|
||||
});
|
||||
};
|
||||
|
||||
// 地图层级
|
||||
const handleZoom = (val) => {
|
||||
map.mapboxGLMap.setZoom(val);
|
||||
};
|
||||
|
||||
// 是否打开或者关闭路况
|
||||
const handleSwitch = (val) => {
|
||||
if (val) {
|
||||
// 打开
|
||||
} else {
|
||||
// 关闭
|
||||
}
|
||||
};
|
||||
|
||||
onUnmounted(() => {
|
||||
emitter.off("removePlot");
|
||||
emitter.off("setMapCenter");
|
||||
emitter.off("addPointArea");
|
||||
emitter.off("showPoint");
|
||||
emitter.off("deletePointArea");
|
||||
emitter.off("deletePointAreaOne");
|
||||
emitter.off("drawShape");
|
||||
emitter.off("echoPlane");
|
||||
emitter.off("removeEara");
|
||||
emitter.off("echoLine");
|
||||
emitter.off("addPoint");
|
||||
emitter.off("thermodynamicChart");
|
||||
emitter.off("drawLineAnimation");
|
||||
emitter.off("aggregateScatteringPoint");
|
||||
emitter.off("hotmap");
|
||||
emitter.off("setBoundarys");
|
||||
emitter.off("diffusionCircle");
|
||||
emitter.off("SsCircle");
|
||||
emitter.off("ClearssCircle");
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.map {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: aliceblue;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
margin: auto;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.changeMap_box {
|
||||
position: absolute;
|
||||
right: 398px;
|
||||
bottom: 4px;
|
||||
z-index: 9;
|
||||
|
||||
.mapImageItem {
|
||||
border: 1px solid #08aae8;
|
||||
background: rgb(9, 26, 70);
|
||||
|
||||
&>img {
|
||||
width: 100%;
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
&>div {
|
||||
text-align: center;
|
||||
position: relative;
|
||||
top: -3px;
|
||||
}
|
||||
}
|
||||
|
||||
.zoomTargetBox {
|
||||
margin-top: 10px;
|
||||
margin-left: 23px;
|
||||
}
|
||||
|
||||
::v-deep .el-input-number__decrease,
|
||||
::v-deep .el-input-number__increase {
|
||||
background: #133362;
|
||||
color: #fff;
|
||||
border: none;
|
||||
}
|
||||
|
||||
::v-deep .el-input__inner {
|
||||
background: #0c1641;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -712,50 +712,8 @@ export function MapUtil(map) {
|
||||
// 打开详情弹窗
|
||||
MapUtil.prototype.openInfoDetail = (flag, data) => {
|
||||
switch (flag) {
|
||||
case "rx":
|
||||
emitter.emit('showJzInfo', data);
|
||||
break;
|
||||
case 'gaj':
|
||||
case 'pcs':
|
||||
case 'jwz':
|
||||
case 'xfq':
|
||||
case 'zdfkd':
|
||||
emitter.emit('showGazy', data);
|
||||
break;
|
||||
case 'kfd':
|
||||
emitter.emit("changeGroupPoint", { lx: 'kfd', xffwlx: '2', xffwid: data.kfdId });
|
||||
emitter.emit('showGazy', [data]);
|
||||
break;
|
||||
case 'sp':
|
||||
emitter.emit('showGzy', data);
|
||||
emitter.emit("showGzyInfo", data);
|
||||
break;
|
||||
case 'kk':
|
||||
emitter.emit('showGzy', data);
|
||||
break;
|
||||
case 'aj':
|
||||
case 'jqMap':
|
||||
emitter.emit('showAj', data);
|
||||
break;
|
||||
case 'yj':
|
||||
case 'yjMap':
|
||||
emitter.emit("showYjxq", data);
|
||||
break;
|
||||
case 'dzjg':
|
||||
case 'school':
|
||||
case 'hospital':
|
||||
case 'banck':
|
||||
case 'shop':
|
||||
emitter.emit("showShzy", data);
|
||||
break;
|
||||
case 'qchzc_map':
|
||||
case 'jczMap_hm':
|
||||
case 'jczMap_hhx':
|
||||
emitter.emit("showJcz", [data]);
|
||||
break;
|
||||
case 'cyryMap':
|
||||
console.log(data, '从业人员');
|
||||
emitter.emit("showCyry", [data]);
|
||||
case 'home_yj_map':
|
||||
emitter.emit("showHomeYJ", data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
125
src/components/MarkdownEdit/index.vue
Normal file
@ -0,0 +1,125 @@
|
||||
<template>
|
||||
<div style="border: 1px solid #ccc">
|
||||
<!-- 工具栏 -->
|
||||
<Toolbar style="border-bottom: 1px solid #ccc" :editor="editorRef" :defaultConfig="toolbarConfig" :mode="mode" />
|
||||
<!-- 编辑器 -->
|
||||
<Editor :style="`height: ${props.heightNumber}px; overflow-y: hidden`" v-model="editorVal" :defaultConfig="editorConfig" :mode="mode" @onCreated="handleCreated" @onChange="handChange" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { compressImage } from "@/utils/tools.js";
|
||||
import "@wangeditor/editor/dist/css/style.css";
|
||||
import { qcckPost } from "@/api/qcckApi.js";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { Editor, Toolbar } from "@wangeditor/editor-for-vue";
|
||||
import {
|
||||
ref,
|
||||
onMounted,
|
||||
shallowRef,
|
||||
onBeforeUnmount,
|
||||
defineEmits,
|
||||
defineProps,
|
||||
watch
|
||||
} from "vue";
|
||||
const props = defineProps({
|
||||
// 编辑器内容
|
||||
modelValue: {
|
||||
type: String,
|
||||
default: ""
|
||||
},
|
||||
markitVal: {
|
||||
type: String,
|
||||
default: ""
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: "请输入内容。。。。"
|
||||
},
|
||||
heightNumber: {
|
||||
type: Number,
|
||||
default: 500
|
||||
}
|
||||
});
|
||||
const editorVal = ref("");
|
||||
const editorRef = shallowRef();
|
||||
const mode = "default";
|
||||
const valueHtml = ref(""); //内容
|
||||
//工具配置
|
||||
const toolbarConfig = {
|
||||
excludeKeys: ["blockquote", "codeBlock"] //清除不必要的工具,引用和代码块
|
||||
};
|
||||
const emits = defineEmits(["update:modelValue", "changeFn"]);
|
||||
//编辑器配置
|
||||
const editorConfig = {
|
||||
withCredentials: true, //允许跨域
|
||||
placeholder: props.placeholder, //提示语
|
||||
MENU_CONF: {
|
||||
uploadImage: {
|
||||
// 自定义上传图片
|
||||
async customUpload(file, insertFn) {
|
||||
let fileBlob = await compressImage(file);
|
||||
let fileData = new File([fileBlob], fileBlob.name, {
|
||||
type: fileBlob.type
|
||||
});
|
||||
if (fileData.size > 2 * 1024 * 1024) {
|
||||
ElMessage({
|
||||
message: "图片超过2MB",
|
||||
type: "success"
|
||||
});
|
||||
} else {
|
||||
await uploadFn(fileData, insertFn);
|
||||
}
|
||||
}
|
||||
// server: "/mosty-api/mosty-base/minio/image/upload",
|
||||
// base64LimitSize: 10000 * 1024,
|
||||
},
|
||||
uploadVideo: {
|
||||
// 自定义上传视频
|
||||
async customUpload(file, insertFn) {
|
||||
await uploadFn(file, insertFn);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
watch(
|
||||
[() => props.markitVal, () => editorRef.value],
|
||||
(val) => {
|
||||
// if (val) editorRef.value = val;
|
||||
if ((val[0] && val[1]) || val[0] == "") {
|
||||
editorVal.value = val[0];
|
||||
}
|
||||
},
|
||||
{ deep: true, immediate: true }
|
||||
);
|
||||
|
||||
const uploadFn = (file, insertFn) => {
|
||||
let param = new FormData();
|
||||
param.append("file", file);
|
||||
qcckPost(param, "/mosty-base/minio/image/upload").then((res) => {
|
||||
insertFn(res);
|
||||
});
|
||||
};
|
||||
//编辑器创建成功
|
||||
const handleCreated = (editor) => {
|
||||
editorRef.value = editor;
|
||||
};
|
||||
//内容发生变化
|
||||
const handChange = (editor) => {
|
||||
// console.log(editor.getHtml(),'editor.getText()');
|
||||
// 判断是否是一个空段落,是空就传空文本
|
||||
if (editor.isEmpty()) {
|
||||
emits("changeFn", editor.getText());
|
||||
} else {
|
||||
emits("changeFn", editor.getHtml());
|
||||
}
|
||||
};
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
const editor = editorRef.value;
|
||||
if (editor) editor.destroy();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
</style>
|
@ -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$/);
|
||||
|
@ -1,187 +0,0 @@
|
||||
<template>
|
||||
<el-dialog :title="titleValue" width="1400px" :model-value="modelValue" append-to-body @close="closed">
|
||||
<div>
|
||||
<el-form :model="listQuery" class="mosty-from-wrap" :inline="true">
|
||||
<el-form-item label="标签名称">
|
||||
<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' : ''" style="margin-top: 0px">
|
||||
<el-table ref="multipleUserRef" :key="keyTabel" @selection-change="handleSelectionChange" :data="tableData" border :row-key="keyid" style="width: 100%" height="450">
|
||||
<el-table-column type="selection" width="55" :reserve-selection="true"/>
|
||||
<el-table-column prop="bqMc" align="center" label="标签名称"/>
|
||||
<el-table-column prop="bqDm" align="center" label="标签代码"/>
|
||||
<el-table-column prop="bqDj" align="center" label="标签等级">
|
||||
<template #default="{ row }">
|
||||
<DictTag :tag="false" :value="row.bqDj" :options="D_GS_BQ_DJ" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="bqYs" align="center" label="标签颜色">
|
||||
<template #default="{ row }">
|
||||
<DictTag :value="row.bqYs" :tag="false" :options="D_GS_SSYJ" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<div class="fenye" :style="{ top: tableHeight + 'px' }">
|
||||
<el-pagination
|
||||
class="pagination"
|
||||
@size-change="handleSizeChange"
|
||||
@pageCurrent-change="handleCurrentChange"
|
||||
:pageCurrent-page="listQuery.pageCurrent"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
:page-size="listQuery.size"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="total"
|
||||
></el-pagination>
|
||||
</div>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="closed">取消</el-button>
|
||||
<el-button type="primary" @click="onComfirm">确认</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { qcckGet} from "@/api/qcckApi.js";
|
||||
import { defineProps, ref ,getCurrentInstance, watch} from "vue";
|
||||
const { proxy } = getCurrentInstance();
|
||||
const { D_GS_BQ_DJ,D_GS_SSYJ } = proxy.$dict("D_GS_BQ_DJ","D_GS_SSYJ"); //获取字典数据
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: Boolean,
|
||||
default:false
|
||||
},
|
||||
titleValue: {
|
||||
type: String,
|
||||
default: "选择标签"
|
||||
},
|
||||
LeaderType: {
|
||||
type: String,
|
||||
default: ""
|
||||
},
|
||||
//是否单选
|
||||
Single: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
roleIds: {
|
||||
type: Array,
|
||||
default: []
|
||||
}
|
||||
});
|
||||
const total = ref(0);
|
||||
const listQuery = ref({
|
||||
pageCurrent: 1,
|
||||
pageSize: 20
|
||||
});
|
||||
|
||||
const multipleUserRef = ref(null);
|
||||
const multipleSelectionUser = ref([]);
|
||||
const tableData = ref([]);
|
||||
const emits = defineEmits(["update:modelValue", "choosed"]);
|
||||
const keyTabel = ref(0)
|
||||
const keyid = (row) => {
|
||||
return row.id;
|
||||
};
|
||||
|
||||
const closed = () => {
|
||||
emits("update:modelValue", false);
|
||||
};
|
||||
const reset = () => {
|
||||
listQuery.value = { pageCurrent: 1, pageSize: 20, };
|
||||
getListData();
|
||||
};
|
||||
|
||||
|
||||
// 为用户分配角色
|
||||
const onComfirm = () => {
|
||||
const userList = multipleSelectionUser.value;
|
||||
let list = [];
|
||||
let listId = [];
|
||||
userList.forEach((val) => {
|
||||
if (listId.indexOf(val.id) == -1) {
|
||||
list.push(val);
|
||||
listId.push(val.id);
|
||||
}
|
||||
});
|
||||
emits("choosed", list);
|
||||
closed();
|
||||
};
|
||||
/**
|
||||
* pageSize 改变触发
|
||||
*/
|
||||
const handleSizeChange = (currentSize) => {
|
||||
listQuery.value.pageSize = currentSize;
|
||||
getListData();
|
||||
};
|
||||
/**
|
||||
* 页码改变触发
|
||||
*/
|
||||
const handleCurrentChange = (currentPage) => {
|
||||
listQuery.value.pageCurrent = currentPage;
|
||||
getListData();
|
||||
};
|
||||
const getListData = () => {
|
||||
keyTabel.value++
|
||||
const params = {bqLb:'02',...listQuery.vlue}
|
||||
qcckGet(params,'/mosty-gsxt/tbGsxtBqgl/selectPage').then(res=>{
|
||||
tableData.value = res.records || [];
|
||||
total.value = res.total;
|
||||
multipleUser();
|
||||
})
|
||||
};
|
||||
|
||||
//列表回显
|
||||
function multipleUser() {
|
||||
tableData.value.forEach((item) => {
|
||||
multipleUserRef.value.toggleRowSelection(item, false);
|
||||
if (props.roleIds.some((id) => id == item.id)) {
|
||||
multipleUserRef.value.toggleRowSelection(item, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const handleFilter = () => {
|
||||
listQuery.value.pageCurrent = 1;
|
||||
getListData();
|
||||
};
|
||||
|
||||
const handleSelectionChange = (val) => {
|
||||
if (props.Single) {
|
||||
if (val.length > 1) {
|
||||
let del_row = val.shift();
|
||||
multipleUserRef.value.toggleRowSelection(del_row, false);
|
||||
}
|
||||
multipleSelectionUser.value = val;
|
||||
} else {
|
||||
multipleSelectionUser.value = val;
|
||||
}
|
||||
};
|
||||
|
||||
watch(()=>props.modelValue,val=>{
|
||||
if(val) handleFilter();
|
||||
},{immediate:true})
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "@/assets/css/layout.scss";
|
||||
@import "@/assets/css/element-plus.scss";
|
||||
</style>
|
||||
<style>
|
||||
.tabBoxRadio .el-checkbox__inner {
|
||||
border-radius: 50% !important;
|
||||
}
|
||||
.tabBoxRadio .el-table__header-wrapper .el-checkbox {
|
||||
display: none;
|
||||
}
|
||||
|
||||
</style>
|
@ -1,18 +1,31 @@
|
||||
<template>
|
||||
<div class="form-item-box" :style="{ width: width }">
|
||||
<el-date-picker style="width:100%" v-model="modelValue" type="date" v-bind="$attrs" @change="onInput" :placeholder="placeholder" value-format="YYYY-MM-DD"/>
|
||||
<el-date-picker
|
||||
style="width:100%"
|
||||
v-model="localModelValue"
|
||||
:type="props.type"
|
||||
v-bind="$attrs"
|
||||
@change="onInput"
|
||||
:placeholder="placeholder"
|
||||
:value-format="props.format"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { COMPONENT_WIDTH } from "@/constant";
|
||||
import { ref, defineProps, defineEmits, defineExpose } from "vue";
|
||||
import { ref, defineProps, defineEmits, defineExpose, computed } from "vue";
|
||||
|
||||
const props = defineProps({
|
||||
//获取组件传值
|
||||
placeholder: {
|
||||
default: "请填写",
|
||||
type: String
|
||||
},
|
||||
format:{
|
||||
default: "YYYY-MM-DD",
|
||||
type: String
|
||||
},
|
||||
modelValue: {
|
||||
default: "",
|
||||
type: String
|
||||
@ -21,12 +34,21 @@ const props = defineProps({
|
||||
default: COMPONENT_WIDTH,
|
||||
type: String
|
||||
},
|
||||
|
||||
type: {
|
||||
default: "date",
|
||||
type: String
|
||||
}
|
||||
});
|
||||
|
||||
const emits = defineEmits(["update:modelValue"]);
|
||||
|
||||
// 使用计算属性处理双向绑定
|
||||
const localModelValue = computed({
|
||||
get: () => props.modelValue,
|
||||
set: (value) => emits("update:modelValue", value)
|
||||
});
|
||||
|
||||
const onInput = (e) => {
|
||||
emits("update:modelValue", e);
|
||||
};
|
||||
</script>
|
||||
|
||||
</script>
|
@ -20,6 +20,7 @@ import { COMPONENT_WIDTH } from "@/constant";
|
||||
import { qcckPost, qcckGet, qcckFlvGet } from "@/api/qcckApi.js";
|
||||
import { ref, defineProps, defineEmits, defineExpose, computed, onMounted, watch } from "vue";
|
||||
import { selectDeptPage } from "@/api/user-manage";
|
||||
import { tr } from "element-plus/es/locale.mjs";
|
||||
const props = defineProps({
|
||||
//获取组件传值
|
||||
placeholder: {
|
||||
@ -41,9 +42,13 @@ const props = defineProps({
|
||||
width: {
|
||||
default: COMPONENT_WIDTH,
|
||||
type: String
|
||||
},
|
||||
isAll:{
|
||||
default: false,
|
||||
type: Boolean
|
||||
}
|
||||
});
|
||||
const modelShow = ref(false);
|
||||
const firstLoad = ref(true)
|
||||
const oldmodelValue = ref([]);
|
||||
const listQuery = ref({
|
||||
deptname: "",
|
||||
@ -61,7 +66,12 @@ const endProps = {
|
||||
lazy: true,
|
||||
lazyLoad(node, resolve) {
|
||||
listQuery.value.parentid = node.data.id;
|
||||
selectDeptPage(listQuery.value).then((res) => {
|
||||
let params = { ...listQuery.value };
|
||||
if(props.isAll && firstLoad.value) {
|
||||
params.parentid = 1;
|
||||
firstLoad.value = false;
|
||||
}
|
||||
selectDeptPage(params).then((res) => {
|
||||
depList.value = depList.value.concat(res)
|
||||
//处理部门是否包含下级
|
||||
for (let i = 0; i < res.length; i++) {
|
||||
@ -73,7 +83,9 @@ const endProps = {
|
||||
};
|
||||
const tableData = ref([]);
|
||||
const getSysMenuTree = async () => {
|
||||
const res = await selectDeptPage(listQuery.value);
|
||||
let params = { ...listQuery.value }
|
||||
if(props.isAll) params.parentid = 1;
|
||||
const res = await selectDeptPage(params);
|
||||
tableData.value = res;
|
||||
depList.value = res
|
||||
};
|
||||
|
@ -1,287 +0,0 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-dialog
|
||||
:title="titleValue"
|
||||
width="1400px"
|
||||
:model-value="modelValue"
|
||||
@close="closed"
|
||||
>
|
||||
<el-form :model="listQuery" :inline="true">
|
||||
<el-form-item label="所属部门">
|
||||
<MOSTY.Department width="100%" clearable v-model="listQuery.ssbmdm" />
|
||||
</el-form-item>
|
||||
<el-form-item label="圈层名称">
|
||||
<el-input
|
||||
v-model="listQuery.qcmc"
|
||||
placeholder="请输入圈层名称"
|
||||
clearable
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-button type="success" @click="handleFilter">查询</el-button>
|
||||
<el-button type="info" @click="reset()"> 重置 </el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div class="tabBox" style="margin-top: 0px" v-if="modelValue">
|
||||
<el-table
|
||||
ref="multipleUserRef"
|
||||
@selection-change="handleSelectionChange"
|
||||
:data="tableData"
|
||||
border
|
||||
style="width: 100%"
|
||||
:row-key="keyid"
|
||||
height="450"
|
||||
>
|
||||
<el-table-column
|
||||
type="selection"
|
||||
width="55"
|
||||
:reserve-selection="true"
|
||||
v-if="props.multiple"
|
||||
/>
|
||||
<el-table-column width="55" #default="{ row }" v-else>
|
||||
<el-radio v-model="ridioIndex" :label="row.id"></el-radio>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
label="序号"
|
||||
type="index"
|
||||
align="center"
|
||||
sortable
|
||||
width="80"
|
||||
/>
|
||||
<el-table-column
|
||||
sortable
|
||||
prop="ssbm"
|
||||
label="所属部门"
|
||||
show-overflow-tooltip
|
||||
align="center"
|
||||
></el-table-column>
|
||||
<el-table-column
|
||||
sortable
|
||||
prop="qcmc"
|
||||
show-overflow-tooltip
|
||||
label="圈层名称"
|
||||
align="center"
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
sortable
|
||||
prop="qclx"
|
||||
show-overflow-tooltip
|
||||
label="圈层类型"
|
||||
align="center"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<dict-tag :options="D_BZ_QCLX" :value="row.qclx" :tag="false" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
sortable
|
||||
prop="qcjb"
|
||||
show-overflow-tooltip
|
||||
label="圈层等级"
|
||||
align="center"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<dict-tag :options="D_BZ_QCDJ" :value="row.qcjb" :tag="false" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<div class="fenye" :style="{ top: tableHeight + 'px' }">
|
||||
<el-pagination
|
||||
class="pagination"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
:current-page="listQuery.pageCurrent"
|
||||
:page-sizes="[2, 5, 10, 20]"
|
||||
:page-size="listQuery.pageSize"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="total"
|
||||
></el-pagination>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="closed">取消</el-button>
|
||||
<el-button type="primary" @click="onComfirm">确认</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import * as rule from "@/utils/rules.js";
|
||||
import * as MOSTY from "@/components/MyComponents/index";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { qcckGet, qcckPost } from "@/api/qcckApi.js";
|
||||
import {
|
||||
defineProps,
|
||||
watch,
|
||||
ref,
|
||||
onMounted,
|
||||
nextTick,
|
||||
getCurrentInstance
|
||||
} from "vue";
|
||||
const { proxy } = getCurrentInstance();
|
||||
const { D_BZ_QCLX, D_BZ_QCDJ } = proxy.$dict("D_BZ_QCLX", "D_BZ_QCDJ");
|
||||
const props = defineProps({
|
||||
//是否显示
|
||||
modelValue: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
},
|
||||
//标题
|
||||
titleValue: {
|
||||
type: String,
|
||||
default: "选择圈层"
|
||||
},
|
||||
//是否多选
|
||||
multiple: {
|
||||
default: true,
|
||||
type: Boolean
|
||||
},
|
||||
//已经选中得数据回显
|
||||
data: {
|
||||
type: Array,
|
||||
default: []
|
||||
}
|
||||
});
|
||||
const keyid = (row) => {
|
||||
return row.id;
|
||||
};
|
||||
const total = ref(0);
|
||||
const ridioIndex = ref(null);
|
||||
const listQuery = ref({
|
||||
pageCurrent: 1,
|
||||
pageSize: 20,
|
||||
qcmc: "",
|
||||
ssbmdm: ""
|
||||
});
|
||||
const form = ref({});
|
||||
const tableData = ref([]);
|
||||
const emits = defineEmits(["close", "choosedQc"]);
|
||||
const closed = () => {
|
||||
emits("close", false);
|
||||
};
|
||||
const reset = () => {
|
||||
listQuery.value = {
|
||||
pageCurrent: 1,
|
||||
pageSize: 20,
|
||||
qcmc: "",
|
||||
ssbmdm: ""
|
||||
};
|
||||
getListData();
|
||||
};
|
||||
//确认选中
|
||||
const onComfirm = () => {
|
||||
if (props.multiple) {
|
||||
//多选
|
||||
const List = JSON.parse(JSON.stringify(multipleSelectionUser.value));
|
||||
if (List.length === 0) {
|
||||
proxy.$message.warning("请选择圈层");
|
||||
return;
|
||||
}
|
||||
emits("choosedQc", List);
|
||||
} else {
|
||||
//单选
|
||||
if (![ridioIndex.value][0]) {
|
||||
proxy.$message.warning("请选择圈层");
|
||||
return;
|
||||
}
|
||||
const info = tableData.value.find((item) => {
|
||||
return item.id === ridioIndex.value;
|
||||
});
|
||||
emits("choosedQc", [info]);
|
||||
}
|
||||
closed();
|
||||
};
|
||||
onMounted(() => {
|
||||
getListData();
|
||||
});
|
||||
/**
|
||||
* pageSize 改变触发
|
||||
*/
|
||||
const handleSizeChange = (currentSize) => {
|
||||
listQuery.value.pageSize = currentSize;
|
||||
getListData();
|
||||
};
|
||||
|
||||
/**
|
||||
* 页码改变触发
|
||||
*/
|
||||
const handleCurrentChange = (currentPage) => {
|
||||
listQuery.value.pageSize = currentPage;
|
||||
getListData();
|
||||
};
|
||||
//圈层数据
|
||||
const getListData = async () => {
|
||||
qcckGet(listQuery.value, "/mosty-jcgl/qc/selectQcList").then((res) => {
|
||||
tableData.value = res?.records;
|
||||
multipleUser(props.data, tableData.value);
|
||||
total.value = Number(res.total);
|
||||
});
|
||||
};
|
||||
const handleFilter = () => {
|
||||
listQuery.value.pageCurrent = 1;
|
||||
getListData();
|
||||
};
|
||||
|
||||
const multipleUserRef = ref(null); //表单
|
||||
//多选选中的数据
|
||||
const multipleSelectionUser = ref([]);
|
||||
const handleSelectionChange = (val) => {
|
||||
multipleSelectionUser.value = val;
|
||||
};
|
||||
//回显
|
||||
function multipleUser(row, list) {
|
||||
if (row) {
|
||||
if (props.multiple) {
|
||||
row.forEach((item) => {
|
||||
list.forEach((select) => {
|
||||
if (item.id == select.id) {
|
||||
if (multipleUserRef.value) {
|
||||
multipleUserRef.value.toggleRowSelection(select, true);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(val) => {
|
||||
if (val === true) {
|
||||
handleFilter();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.data,
|
||||
(val) => {
|
||||
if (multipleUserRef.value) multipleUser(val, tableData.value);
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "@/assets/css/layout.scss";
|
||||
@import "@/assets/css/element-plus.scss";
|
||||
::v-deep .el-form--inline {
|
||||
padding-left: 0 !important;
|
||||
}
|
||||
::v-deep .el-radio__label {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
<style lang="scss">
|
||||
.el-dialog {
|
||||
// --el-dialog-bg-color: #fff !important;
|
||||
}
|
||||
// .el-dialog__title {
|
||||
// color: #fff !important;
|
||||
// }
|
||||
</style>
|
@ -1,23 +1,11 @@
|
||||
<template>
|
||||
<div class="form-item-box" :class="props.showBtn?'showBtn-upload':''" :style="{ width: width }">
|
||||
<el-upload
|
||||
v-bind="$attrs"
|
||||
:headers="headers"
|
||||
:multiple="false"
|
||||
class="avatar-uploader"
|
||||
:limit="props.limit"
|
||||
:action="actionUrl"
|
||||
:list-type=" props.showBtn ? '' :'picture-card'"
|
||||
:file-list="fileList"
|
||||
show-file-list
|
||||
:on-exceed="handleExceed"
|
||||
:on-success="handlerSuccess"
|
||||
:before-upload="beforeImgUpload"
|
||||
>
|
||||
|
||||
<div class="form-item-box" :class="props.showBtn ? 'showBtn-upload' : ''" :style="{ width: width }">
|
||||
<el-upload v-bind="$attrs" :headers="headers" :multiple="false" class="avatar-uploader" :limit="props.limit"
|
||||
:action="actionUrl" :list-type="props.showBtn ? '' : 'picture-card'" :file-list="fileList" show-file-list
|
||||
:on-exceed="handleExceed" :on-success="handlerSuccess" :before-upload="beforeImgUpload">
|
||||
<template #default>
|
||||
<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 #file="{ file }" v-if="!props.showBtn">
|
||||
<div v-if="props.isImg">
|
||||
@ -26,42 +14,22 @@
|
||||
<span class="el-upload-list__item-preview" @click="handlePictureCardPreview(file)">
|
||||
<el-icon> <zoom-in /></el-icon>
|
||||
</span>
|
||||
<span
|
||||
v-if="!disabled"
|
||||
class="el-upload-list__item-delete"
|
||||
@click="handleRemove(file, fileList)"
|
||||
>
|
||||
<el-icon>
|
||||
<Delete />
|
||||
</el-icon>
|
||||
<span v-if="!disabled" class="el-upload-list__item-delete" @click="handleRemove(file, fileList)">
|
||||
<el-icon><Delete /></el-icon>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div v-else>
|
||||
<div class="file-wrap">
|
||||
<span>
|
||||
<svg-icon :icon="getSuffix(file.name)" />
|
||||
</span>
|
||||
<span><svg-icon :icon="getSuffix(file.name)" /></span>
|
||||
<span class="file-name">{{ file.name }}</span>
|
||||
</div>
|
||||
<span class="el-upload-list__item-actions">
|
||||
<span
|
||||
v-if="!disabled"
|
||||
class="el-upload-list__item-delete"
|
||||
@click="handleDownload(file)"
|
||||
>
|
||||
<el-icon>
|
||||
<Download />
|
||||
</el-icon>
|
||||
<span v-if="!disabled" class="el-upload-list__item-delete" @click="handleDownload(file)">
|
||||
<el-icon><Download /></el-icon>
|
||||
</span>
|
||||
<span
|
||||
v-if="!disabled"
|
||||
class="el-upload-list__item-delete"
|
||||
@click="handleRemove(file, fileList)"
|
||||
>
|
||||
<el-icon>
|
||||
<Delete />
|
||||
</el-icon>
|
||||
<span v-if="!disabled" class="el-upload-list__item-delete" @click="handleRemove(file, fileList)">
|
||||
<el-icon><Delete /></el-icon>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
@ -75,14 +43,7 @@
|
||||
|
||||
<script setup>
|
||||
import { COMPONENT_WIDTH } from "@/constant";
|
||||
import {
|
||||
ref,
|
||||
defineProps,
|
||||
defineEmits,
|
||||
computed,
|
||||
watch,
|
||||
onMounted
|
||||
} from "vue";
|
||||
import { ref, defineProps, defineEmits, computed, watch, onMounted } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { useStore } from "vuex";
|
||||
const props = defineProps({
|
||||
@ -103,17 +64,25 @@ const props = defineProps({
|
||||
default: COMPONENT_WIDTH,
|
||||
type: String
|
||||
},
|
||||
showBtn:{
|
||||
type:Boolean,
|
||||
default:false
|
||||
showBtn: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
isAll: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
});
|
||||
|
||||
const actionUrl = computed(() =>
|
||||
props.isImg
|
||||
? "/mosty-api/mosty-base/minio/image/upload/id"
|
||||
: "/mosty-api/mosty-base/minio/file/upload"
|
||||
);
|
||||
const actionUrl = computed(() => {
|
||||
if (props.isAll) {
|
||||
return "/mosty-api/mosty-base/minio/image/upload/id";
|
||||
} else {
|
||||
return props.isImg
|
||||
? "/mosty-api/mosty-base/minio/image/upload/id"
|
||||
: "/mosty-api/mosty-base/minio/file/upload";
|
||||
}
|
||||
});
|
||||
|
||||
const emits = defineEmits(["update:modelValue", "handleChange"]);
|
||||
|
||||
@ -174,8 +143,6 @@ const getSuffix = (fileName) => {
|
||||
//否则返回other
|
||||
return "OTHER";
|
||||
};
|
||||
|
||||
const imageUrl = ref("");
|
||||
const store = useStore();
|
||||
const dialogImageUrl = ref("");
|
||||
const dialogVisible = ref(false);
|
||||
@ -184,23 +151,44 @@ const headers = ref({
|
||||
Authorization: store.getters.token
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
if (props.modelValue) {
|
||||
fileList.value = props.modelValue.map((el) => {
|
||||
return {
|
||||
url: `/mosty-api/mosty-base/minio/image/download/` + el
|
||||
};
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const fileList = ref([]);
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(val) => {
|
||||
let arr = val ? val : [];
|
||||
if (arr && arr.length > 0) {
|
||||
if (!props.sfUrl) {
|
||||
fileList.value = arr.map((el) => {
|
||||
if (Object.prototype.toString.call(el) === "[object Object]") {
|
||||
return {
|
||||
url: `/mosty-api/mosty-base/minio/image/download/` + el,
|
||||
name: el.name
|
||||
};
|
||||
} else {
|
||||
return { url: `/mosty-api/mosty-base/minio/image/download/` + el };
|
||||
}
|
||||
});
|
||||
} else {
|
||||
fileList.value = arr.map((el) => {
|
||||
if (Object.prototype.toString.call(el) === "[object Object]") {
|
||||
return { url: el, name: el.name };
|
||||
} else {
|
||||
return { url: el };
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
const handlerSuccess = (res, file) => {
|
||||
file.url = `/mosty-api/mosty-base/minio/image/download/` + res.data;
|
||||
fileList.value.push(file);
|
||||
props.modelValue.push(res.data);
|
||||
let arr = props.modelValue ? props.modelValue : [];
|
||||
arr.push(res.data);
|
||||
emits("update:modelValue", arr);
|
||||
emits("handleChange", props.modelValue);
|
||||
emits("update:modelValue", props.modelValue);
|
||||
};
|
||||
|
||||
const handleExceed = (files, fileList) => {
|
||||
@ -225,9 +213,6 @@ const beforeImgUpload = (file) => {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
const handleAvatarSuccess = (res, file) => {
|
||||
imageUrl.value = URL.createObjectURL(file.raw);
|
||||
};
|
||||
//查询图片
|
||||
const handlePictureCardPreview = (file) => {
|
||||
dialogImageUrl.value = file.url;
|
||||
@ -245,6 +230,7 @@ const handleRemove = (file) => {
|
||||
emits("handleChange", props.modelValue);
|
||||
emits("update:modelValue", props.modelValue);
|
||||
};
|
||||
const propsModelValue = ref();
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
@ -16,7 +16,6 @@ import StationSelect from "./StationSelect/index.vue";
|
||||
import Provinces from "./Provinces2/index.vue";
|
||||
import MarkdownEdit from "./MarkdownEdit/index.vue";
|
||||
import FileUpload from "./FileUpload/index.vue";
|
||||
import RichOnly from "./RichOnly/index.vue";
|
||||
import Date from "./Date/index.vue";
|
||||
import Empty from "./Empty/index.vue";
|
||||
export {
|
||||
@ -38,7 +37,6 @@ export {
|
||||
Provinces,
|
||||
MarkdownEdit,
|
||||
FileUpload,
|
||||
RichOnly,
|
||||
Date,
|
||||
Empty
|
||||
};
|
||||
|
@ -29,10 +29,7 @@
|
||||
:header-cell-class-name="() => 'myTableHeadBgColorDark'"
|
||||
:highlight-current-row="getConfiger.showSelectType === 'radio'"
|
||||
:row-style="{
|
||||
height:
|
||||
getConfiger.rowHeight === 'auto'
|
||||
? getConfiger.rowHeight
|
||||
: getConfiger.rowHeight + 'px'
|
||||
height: getConfiger.rowHeight === 'auto' ? getConfiger.rowHeight : getConfiger.rowHeight + 'px'
|
||||
}"
|
||||
>
|
||||
<el-table-column
|
||||
|
@ -1,161 +1,57 @@
|
||||
<template>
|
||||
<el-form
|
||||
ref="elform"
|
||||
:model="listQuery"
|
||||
:label-width="props.labelWidth"
|
||||
:rules="props.rules"
|
||||
:inline="props.inline"
|
||||
label-position="right"
|
||||
>
|
||||
<el-form-item
|
||||
v-for="(item,idx) in props.formList"
|
||||
:style="item.width && { width: item.width }"
|
||||
:prop="item.prop"
|
||||
:label="item.label"
|
||||
:label-width="item.labelWidth"
|
||||
:key="idx"
|
||||
>
|
||||
<el-form ref="elform" :model="listQuery" :label-width="props.labelWidth" :rules="props.rules" :inline="props.inline"
|
||||
label-position="right" :disabled="props.disabled">
|
||||
<el-form-item v-for="(item, idx) in props.formList" :style="item.width && { width: item.width }" :prop="item.prop"
|
||||
:label="item.label" :label-width="item.labelWidth" :key="idx">
|
||||
<!-- input表单 input-->
|
||||
<MOSTY.Other
|
||||
v-if="item.type == 'input'"
|
||||
width="100%"
|
||||
clearable
|
||||
v-model="listQuery[item.prop]"
|
||||
:placeholder="`请输入${item.label}`"
|
||||
:disabled="item.disabled"
|
||||
/>
|
||||
<el-input
|
||||
v-model="listQuery[item.prop]"
|
||||
v-else-if="item.type == 'textarea'"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
:placeholder="`请输入${item.label}`"
|
||||
:disabled="item.disabled"
|
||||
/>
|
||||
<MOSTY.Other v-if="item.type == 'input'" width="100%" clearable v-model="listQuery[item.prop]"
|
||||
:placeholder="`请输入${item.label}`" :disabled="item.disabled" />
|
||||
<el-input v-model="listQuery[item.prop]" v-else-if="item.type == 'textarea'" type="textarea" :rows="3"
|
||||
:placeholder="`请输入${item.label}`" :disabled="item.disabled" />
|
||||
<!-- 数值 inputNumber-->
|
||||
<el-input
|
||||
type="number"
|
||||
v-model="listQuery[item.prop]"
|
||||
v-else-if="item.type == 'inputNumber'"
|
||||
:placeholder="`请输入${item.label}`"
|
||||
:disabled="item.disabled"
|
||||
/>
|
||||
<el-input type="number" v-model="listQuery[item.prop]" v-else-if="item.type == 'inputNumber'"
|
||||
:placeholder="`请输入${item.label}`" :disabled="item.disabled" />
|
||||
<!-- 数值 number-->
|
||||
<el-input-number
|
||||
v-model="listQuery[item.prop]"
|
||||
v-else-if="item.type == 'number'"
|
||||
style="width: 100%"
|
||||
:min="item.min || 0"
|
||||
:max="item.max || 1000"
|
||||
:disabled="item.disabled"
|
||||
/>
|
||||
<el-input-number v-model="listQuery[item.prop]" v-else-if="item.type == 'number'" style="width: 100%"
|
||||
:min="item.min || 0" :max="item.max || 1000" :disabled="item.disabled" />
|
||||
<!--选择 select-->
|
||||
<MOSTY.Select
|
||||
v-else-if="item.type == 'select'"
|
||||
filterable
|
||||
:multiple="item.multiple"
|
||||
v-model="listQuery[item.prop]"
|
||||
:dictEnum="item.options"
|
||||
width="100%"
|
||||
clearable
|
||||
:placeholder="`请选择${item.label}`"
|
||||
:disabled="item.disabled"
|
||||
/>
|
||||
<MOSTY.Select v-else-if="item.type == 'select'" filterable :multiple="item.multiple"
|
||||
v-model="listQuery[item.prop]" :dictEnum="item.options" width="100%" clearable :placeholder="`请选择${item.label}`"
|
||||
:disabled="item.disabled" />
|
||||
<!-- 部门department -->
|
||||
<template v-else-if="item.type === 'department'">
|
||||
<MOSTY.Department style="width: 100%;" clearable v-model="listQuery[item.prop]" />
|
||||
<MOSTY.Department style="width: 100%;" clearable :isAll="item.isAll" @getDepValue="getdep($event, item.depMc)"
|
||||
v-model="listQuery[item.prop]" :placeholder="listQuery[item.depMc] ? listQuery[item.depMc] : '请选择'" />
|
||||
</template>
|
||||
|
||||
<!-- 上传 upload -->
|
||||
<MOSTY.Upload
|
||||
v-else-if="item.type == 'upload'"
|
||||
width="100%"
|
||||
v-model="listQuery[item.prop]"
|
||||
:isImg="item.isImg"
|
||||
:disabled="item.disabled"
|
||||
/>
|
||||
<MOSTY.Upload v-else-if="item.type == 'upload'" width="100%" v-model="listQuery[item.prop]" :isImg="item.isImg"
|
||||
:disabled="item.disabled" />
|
||||
<!--选择checkbox -->
|
||||
<MOSTY.CheckBox
|
||||
v-else-if="item.type == 'checkbox'"
|
||||
width="100%"
|
||||
clearable
|
||||
v-model="listQuery[item.prop]"
|
||||
:checkList="item.options"
|
||||
:placeholder="`请选择${item.label}`"
|
||||
:disabled="item.disabled"
|
||||
/>
|
||||
<MOSTY.CheckBox v-else-if="item.type == 'checkbox'" width="100%" clearable v-model="listQuery[item.prop]"
|
||||
:checkList="item.options" :placeholder="`请选择${item.label}`" :disabled="item.disabled" />
|
||||
|
||||
<!-- 单选radio -->
|
||||
<el-radio-group
|
||||
v-model="listQuery[item.prop]"
|
||||
v-else-if="item.type == 'radio'"
|
||||
:disabled="item.disabled"
|
||||
>
|
||||
<el-radio
|
||||
v-for="obj in item.options"
|
||||
:key="obj.value"
|
||||
:label="obj.value"
|
||||
>{{ obj.label }}</el-radio
|
||||
>
|
||||
<el-radio-group v-model="listQuery[item.prop]" v-else-if="item.type == 'radio'" :disabled="item.disabled">
|
||||
<el-radio v-for="obj in item.options" :key="obj.value" :label="obj.value">{{ obj.label }}</el-radio>
|
||||
</el-radio-group>
|
||||
|
||||
<!-- 时间选择 -->
|
||||
<el-time-picker
|
||||
v-else-if="item.type == 'time'"
|
||||
v-model="listQuery[item.prop]"
|
||||
placeholder="选择时间"
|
||||
style="width: 100%"
|
||||
:disabled="item.disabled"
|
||||
/>
|
||||
<el-date-picker
|
||||
v-else-if="item.type == 'date'"
|
||||
v-model="listQuery[item.prop]"
|
||||
type="date"
|
||||
value-format="YYYY-MM-DD"
|
||||
placeholder="请选择日期"
|
||||
style="width: 100%"
|
||||
:disabled="item.disabled"
|
||||
/>
|
||||
<el-date-picker
|
||||
v-else-if="item.type == 'datetime'"
|
||||
v-model="listQuery[item.prop]"
|
||||
type="datetime"
|
||||
value-format="YYYY-MM-DD HH:mm:ss"
|
||||
placeholder="请选择时间"
|
||||
style="width: 100%"
|
||||
:disabled="item.disabled"
|
||||
/>
|
||||
<el-date-picker
|
||||
v-else-if="item.type == 'datetimerange'"
|
||||
v-model="listQuery[item.prop]"
|
||||
type="datetimerange"
|
||||
:shortcuts="shortcuts"
|
||||
range-separator="To"
|
||||
value-format="YYYY-MM-DD HH:mm:ss"
|
||||
start-placeholder="选择开始时间"
|
||||
end-placeholder="选择结束时间"
|
||||
style="width: 100%"
|
||||
:disabled="item.disabled"
|
||||
/>
|
||||
<el-date-picker
|
||||
v-else-if="item.type == 'daterange'"
|
||||
v-model="listQuery[item.prop]"
|
||||
type="daterange"
|
||||
range-separator="To"
|
||||
value-format="YYYY-MM-DD"
|
||||
start-placeholder="选择开始日期"
|
||||
end-placeholder="选择开始日期"
|
||||
style="width: 100%"
|
||||
:disabled="item.disabled"
|
||||
/>
|
||||
<el-time-picker v-else-if="item.type == 'time'" v-model="listQuery[item.prop]" placeholder="选择时间"
|
||||
style="width: 100%" :disabled="item.disabled" />
|
||||
<el-date-picker v-else-if="item.type == 'date'" v-model="listQuery[item.prop]" type="date"
|
||||
value-format="YYYY-MM-DD" placeholder="请选择日期" style="width: 100%" :disabled="item.disabled" />
|
||||
<el-date-picker v-else-if="item.type == 'datetime'" v-model="listQuery[item.prop]" type="datetime"
|
||||
value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择时间" style="width: 100%" :disabled="item.disabled" />
|
||||
<el-date-picker v-else-if="item.type == 'datetimerange'" v-model="listQuery[item.prop]" type="datetimerange"
|
||||
:shortcuts="shortcuts" range-separator="To" value-format="YYYY-MM-DD HH:mm:ss" start-placeholder="选择开始时间"
|
||||
end-placeholder="选择结束时间" style="width: 100%" :disabled="item.disabled" />
|
||||
<el-date-picker v-else-if="item.type == 'daterange'" v-model="listQuery[item.prop]" type="daterange"
|
||||
range-separator="To" value-format="YYYY-MM-DD" start-placeholder="选择开始日期" end-placeholder="选择开始日期"
|
||||
style="width: 100%" :disabled="item.disabled" />
|
||||
|
||||
<el-switch
|
||||
v-else-if="item.type == 'switch'"
|
||||
v-model="listQuery[item.prop]"
|
||||
class="ml-2"
|
||||
:disabled="item.disabled"
|
||||
style="--el-switch-on-color: #13ce66; --el-switch-off-color: #ff4949"
|
||||
/>
|
||||
<el-switch v-else-if="item.type == 'switch'" v-model="listQuery[item.prop]" class="ml-2" :disabled="item.disabled"
|
||||
style="--el-switch-on-color: #13ce66; --el-switch-off-color: #ff4949" />
|
||||
|
||||
<template v-else-if="item.type === 'slot'">
|
||||
<slot :name="item.prop"></slot>
|
||||
@ -165,7 +61,7 @@
|
||||
</template>
|
||||
<script setup>
|
||||
import * as MOSTY from "@/components/MyComponents/index";
|
||||
import { ref, defineProps, defineEmits, defineExpose, watch } from "vue";
|
||||
import { ref, defineProps, defineEmits, defineExpose, watch, watchEffect } from "vue";
|
||||
const props = defineProps({
|
||||
//循环的值
|
||||
formList: {
|
||||
@ -184,9 +80,13 @@ const props = defineProps({
|
||||
type: Object,
|
||||
default: {}
|
||||
},
|
||||
inline:{
|
||||
type:Boolean,
|
||||
default:true
|
||||
inline: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
});
|
||||
const elform = ref();
|
||||
@ -200,28 +100,32 @@ const submit = (resfun) => {
|
||||
});
|
||||
};
|
||||
|
||||
const reset = () =>{
|
||||
const getdep = (e, val) => {
|
||||
if (val) listQuery.value[val] = e ? e.orgName : '';
|
||||
}
|
||||
const reset = () => {
|
||||
elform.value.resetFields()
|
||||
}
|
||||
|
||||
watch(
|
||||
() => listQuery.value,
|
||||
(newVal) => {
|
||||
// 修改这里的watch逻辑,避免无限循环
|
||||
let isUpdatingFromProps = false;
|
||||
|
||||
watch(() => listQuery.value, (newVal) => {
|
||||
if (newVal && !isUpdatingFromProps) {
|
||||
emits("update:modelValue", newVal);
|
||||
},
|
||||
{ immediate: true, deep: true }
|
||||
);
|
||||
}
|
||||
}, { deep: true });
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(newVal) => {
|
||||
// 只有在新值确实变化时才更新(避免空值覆盖)
|
||||
if (newVal && Object.keys(newVal).length > 0) {
|
||||
listQuery.value = { ...newVal };
|
||||
}
|
||||
},
|
||||
{ immediate: true, deep: true }
|
||||
);
|
||||
watch(() => props.modelValue, (newVal) => {
|
||||
// 只有在新值确实变化时才更新(避免空值覆盖)
|
||||
if (newVal && Object.keys(newVal).length > 0) {
|
||||
isUpdatingFromProps = true;
|
||||
listQuery.value = { ...newVal };
|
||||
setTimeout(() => {
|
||||
isUpdatingFromProps = false;
|
||||
}, 0);
|
||||
}
|
||||
}, { immediate: true, deep: true });
|
||||
|
||||
defineExpose({ submit,reset });
|
||||
defineExpose({ submit, reset });
|
||||
</script>
|
||||
|
@ -1,12 +1,10 @@
|
||||
<template>
|
||||
<div style="width: 100%">
|
||||
<div style="width: 100%" :class="getConfiger.showSelectType === 'radio' ? 'tabBoxRadio' : ''">
|
||||
<!-- hasChildren要在tableData中定义表示当前行有没有下一级 children要在tableData中定义表示下一级的数据-->
|
||||
<el-table
|
||||
ref="multipleTableRef"
|
||||
:data="tableData"
|
||||
@selection-change="handleSelectionChange"
|
||||
@current-change="handleCurrentChange"
|
||||
@row-click="singleElection"
|
||||
:row-key="getConfiger.rowKey"
|
||||
:border="getConfiger.border"
|
||||
:default-expand-all="getConfiger.defaultExpandAll"
|
||||
@ -21,23 +19,7 @@
|
||||
:highlight-current-row="getConfiger.showSelectType === 'radio'"
|
||||
:row-style="{ height: getConfiger.rowHeight === 'auto' ? getConfiger.rowHeight : getConfiger.rowHeight + 'px'}"
|
||||
>
|
||||
<el-table-column
|
||||
type="selection"
|
||||
width="55"
|
||||
v-if="getConfiger.showSelectType === 'checkBox'"
|
||||
/>
|
||||
<el-table-column
|
||||
width="55"
|
||||
v-else-if="getConfiger.showSelectType === 'radio'"
|
||||
#default="{ row }"
|
||||
>
|
||||
<el-radio
|
||||
class="radio"
|
||||
v-model="getConfiger.radioChoose"
|
||||
:label="row[getConfiger.rowKey]"
|
||||
> </el-radio
|
||||
>
|
||||
</el-table-column>
|
||||
<el-table-column type="selection" width="55" />
|
||||
<el-table-column
|
||||
type="index"
|
||||
label="序号"
|
||||
@ -148,19 +130,16 @@ onMounted(() => {
|
||||
});
|
||||
// 可选的时候选择的数据
|
||||
const handleSelectionChange = (val) => {
|
||||
emit("chooseData", val);
|
||||
};
|
||||
// 单选的时候选择的数据
|
||||
const handleCurrentChange = (val) => {
|
||||
currentRow.value = val;
|
||||
emit("chooseData", val);
|
||||
};
|
||||
const singleElection = (val) => {
|
||||
if (getConfiger.showSelectType === "radio") {
|
||||
getConfiger.radioChoose = val[getConfiger.rowKey];
|
||||
if(getConfiger.showSelectType === 'radio' && val.length > 1){
|
||||
let del_row = val.shift();
|
||||
multipleTableRef.value.toggleRowSelection(del_row, false);
|
||||
currentRow.value = val;
|
||||
emit("chooseData", val);
|
||||
}else{
|
||||
emit("chooseData", val);
|
||||
}
|
||||
};
|
||||
|
||||
// 懒加载数据的方法
|
||||
const load = (date, treeNode, resolve) => {
|
||||
setTimeout(() => {
|
||||
@ -184,25 +163,14 @@ const load = (date, treeNode, resolve) => {
|
||||
function setDefaultChoose() {
|
||||
nextTick(() => {
|
||||
// 多选的默认选中
|
||||
if (
|
||||
props.tableConfiger.defaultSelectKeys?.length > 0 &&
|
||||
props.tableConfiger.showSelectType === "checkBox"
|
||||
) {
|
||||
if ( props.tableConfiger.defaultSelectKeys?.length > 0 && props.tableConfiger.showSelectType === "checkBox" ) {
|
||||
props.tableData.forEach((item) => {
|
||||
if (
|
||||
props.tableConfiger.defaultSelectKeys.findIndex(
|
||||
(v) => v === item[props.tableConfiger.rowKey]
|
||||
) > -1
|
||||
) {
|
||||
if ( props.tableConfiger.defaultSelectKeys.findIndex( (v) => v === item[props.tableConfiger.rowKey] ) > -1) {
|
||||
multipleTableRef.value.toggleRowSelection(item, true);
|
||||
}
|
||||
});
|
||||
// 单选的默认选中
|
||||
} else if (
|
||||
props.tableConfiger.defaultSelectKeys &&
|
||||
props.tableConfiger.defaultSelectKeys?.length > 0 &&
|
||||
props.tableConfiger.showSelectType === "radio"
|
||||
) {
|
||||
} else if ( props.tableConfiger.defaultSelectKeys && props.tableConfiger.defaultSelectKeys?.length > 0 && props.tableConfiger.showSelectType === "radio" ) {
|
||||
getConfiger.radioChoose = props.tableConfiger.defaultSelectKeys[0];
|
||||
}
|
||||
});
|
||||
@ -212,3 +180,12 @@ function setDefaultChoose() {
|
||||
<style lang = "scss">
|
||||
|
||||
</style>
|
||||
<style>
|
||||
.tabBoxRadio .el-checkbox__inner {
|
||||
border-radius: 50% !important;
|
||||
}
|
||||
.tabBoxRadio .el-table__header-wrapper .el-checkbox {
|
||||
display: none;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
@ -9,12 +9,7 @@
|
||||
<template>
|
||||
<div class="fenye" :style="{ top: tableHeight+10 + 'px' }">
|
||||
<el-pagination
|
||||
:current-page="
|
||||
pageData.configer.currentPage ||
|
||||
pageData.configer.pageNo ||
|
||||
pageData.configer.current ||
|
||||
pageData.configer.pageCurrent ||
|
||||
pageData.configer.pageNum"
|
||||
:current-page=" pageData.configer.currentPage || pageData.configer.pageNo || pageData.configer.current || pageData.configer.pageCurrent || pageData.configer.pageNum"
|
||||
:page-size="pageData.configer.pageSize || pageData.configer.size"
|
||||
:page-sizes="pageSizeArr"
|
||||
:small="small"
|
||||
|
@ -63,10 +63,18 @@
|
||||
value-format="YYYY-MM-DD"
|
||||
>
|
||||
</el-date-picker>
|
||||
<el-date-picker
|
||||
v-else-if="item.showType === 'datetime'"
|
||||
v-model="searchObj[item.prop]"
|
||||
type="datetime"
|
||||
:placeholder="item.placeholder"
|
||||
value-format="YYYY-MM-DD HH:mm:ss"
|
||||
>
|
||||
</el-date-picker>
|
||||
|
||||
<!-- checkbox -->
|
||||
<template v-else-if="item.showType === 'department'">
|
||||
<MOSTY.Department clearable v-model="item.ssbmdm" />
|
||||
<MOSTY.Department clearable v-model="searchObj[item.prop]" />
|
||||
</template>
|
||||
<!-- checkbox -->
|
||||
<template v-else-if="item.showType === 'checkbox'">
|
||||
@ -117,7 +125,6 @@
|
||||
<!-- 级联选择 -->
|
||||
<el-cascader
|
||||
v-else-if="item.showType === 'cascader'"
|
||||
@change="changeca"
|
||||
v-model="searchObj[item.prop]"
|
||||
:props="item.props"
|
||||
:show-all-levels="item.showAllLevels"
|
||||
@ -143,11 +150,8 @@
|
||||
import {
|
||||
ref,
|
||||
reactive,
|
||||
watch,
|
||||
watchEffect,
|
||||
nextTick,
|
||||
getCurrentInstance,
|
||||
toRefs
|
||||
} from "vue";
|
||||
import * as MOSTY from "@/components/MyComponents/index";
|
||||
const { proxy } = getCurrentInstance();
|
||||
@ -175,6 +179,12 @@ const props = defineProps({
|
||||
defaultVal: "",
|
||||
label: "输入"
|
||||
},
|
||||
{
|
||||
showType: "department",
|
||||
prop: "deptKey",
|
||||
defaultVal: "",
|
||||
label: "输入"
|
||||
},
|
||||
{
|
||||
showType: "daterange",
|
||||
prop: "daterangeKey",
|
||||
@ -207,9 +217,6 @@ const props = defineProps({
|
||||
{
|
||||
showType: "radio",
|
||||
defaultVal: ""
|
||||
// prop: "cascaderKey",
|
||||
// label: "级联选择",
|
||||
// checkStrictly: false //点击任意选中
|
||||
},
|
||||
{
|
||||
showType: "defaultTime",
|
||||
@ -229,16 +236,9 @@ const props = defineProps({
|
||||
}
|
||||
});
|
||||
let loadingPage = ref(false);
|
||||
const isShowDate = ref(false);
|
||||
const emit = defineEmits(["submit", "reset"]);
|
||||
let searchObj = reactive({});
|
||||
const timeConfig = reactive({
|
||||
//时间字典筛选和自定义日期组件相关数据
|
||||
typeValue: "01", //时间字典类型默认
|
||||
timeArry: [] //时间筛选自定义默认值
|
||||
});
|
||||
//全所或自定义选择按钮
|
||||
const slectType = ref("qs");
|
||||
|
||||
// select 的一些默认配置
|
||||
const selectDefault = {
|
||||
clearable: true, // 是否可以清空
|
||||
@ -354,53 +354,6 @@ const dateShortcuts = [
|
||||
}
|
||||
}
|
||||
];
|
||||
//自定义时间选择 item 配置项 value 选中的值
|
||||
const screenSelect = (item, value) => {
|
||||
if (value == "08") {
|
||||
searchObj[item.prop] = value;
|
||||
isShowDate.value = true;
|
||||
} else {
|
||||
timeConfig.typeValue = value;
|
||||
searchObj[item.prop] = value;
|
||||
submit();
|
||||
}
|
||||
};
|
||||
//自定义时间确定时间
|
||||
const chooseDateOk = (item) => {
|
||||
timeConfig.typeValue = "08";
|
||||
if (timeConfig.timeArry && timeConfig.timeArry.length) {
|
||||
//选择了时间
|
||||
searchObj[item.propStart] = timeConfig.timeArry[0];
|
||||
searchObj[item.propEnd] = timeConfig.timeArry[1];
|
||||
} else {
|
||||
//清空了时间
|
||||
searchObj[item.prop] = "01";
|
||||
timeConfig.typeValue = "01";
|
||||
}
|
||||
isShowDate.value = false;
|
||||
submit();
|
||||
};
|
||||
//全所-部门选择回调
|
||||
const organizatioHland = (val) => {
|
||||
let item = getArr.find((item) => item.showType == "qsOrZdy");
|
||||
searchObj[item.propBm] = val?.data?.orgCode || "";
|
||||
if (!val || val == "") {
|
||||
//清空了部门选择后清空责任区ID
|
||||
slectType.value = "qs";
|
||||
delete searchObj[item.propZrq];
|
||||
}
|
||||
submit();
|
||||
};
|
||||
//全所-责任区回调
|
||||
const zrqHland = (val) => {
|
||||
let item = getArr.find((item) => item.showType == "qsOrZdy");
|
||||
searchObj[item.propZrq] = val || ""; //责任区选择
|
||||
submit();
|
||||
};
|
||||
//自定义时间取消事件
|
||||
const popoverCancel = (item) => {
|
||||
isShowDate.value = false;
|
||||
};
|
||||
// 设置不可选的日期
|
||||
const disabledDate = (time) => {
|
||||
return time.getTime() > Date.now();
|
||||
@ -505,10 +458,6 @@ const cascaderLazyProps = reactive({
|
||||
resolve(options);
|
||||
}
|
||||
});
|
||||
// 级联框选择
|
||||
function changeca(v) {
|
||||
console.log("vvvv", v);
|
||||
}
|
||||
// 获取到传过来的参数
|
||||
let getArr = reactive([]);
|
||||
const submit = () => {
|
||||
@ -521,25 +470,22 @@ const reset = () => {
|
||||
emit("submit", searchObj);
|
||||
emit("reset", false);
|
||||
};
|
||||
let dataOptions = reactive([]); //时间字典筛选
|
||||
watchEffect(() => {
|
||||
loadingPage.value = true;
|
||||
getArr = JSON.parse(JSON.stringify(props.searchArr));
|
||||
getArr = getArr.map((item) => {
|
||||
let arr = JSON.parse(JSON.stringify(props.searchArr));
|
||||
getArr = arr.map((item) => {
|
||||
switch (item.showType) {
|
||||
case "select":
|
||||
item = { ...selectDefault, ...item };
|
||||
item.options = reactive(item.options);
|
||||
getOptions[item.prop] = item.options;
|
||||
break;
|
||||
case "input":
|
||||
item = { ...inputDefault, ...item };
|
||||
case "input":
|
||||
item = { ...inputDefault, ...item };
|
||||
break;
|
||||
case "daterange":
|
||||
item = { ...daterangeDefault, ...item };
|
||||
if (item.defaultShortcuts) {
|
||||
item.shortcuts = shortcuts;
|
||||
}
|
||||
if (item.defaultShortcuts) item.shortcuts = shortcuts;
|
||||
break;
|
||||
case "date":
|
||||
item = { ...defaultDate, ...item };
|
||||
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<el-dialog v-model="showDialog" :destroy-on-close="true" :title="title+'人员'" @close="close" :close-on-click-modal="false">
|
||||
<el-dialog v-model="modelValue" :destroy-on-close="true" :title="title+'人员'" @close="close" :close-on-click-modal="false">
|
||||
<FormMessage v-model="listQuery" :formList="formData" labelWidth="120px" ref="elform" :rules="rules">
|
||||
<template #bqList>
|
||||
<div class="marks pointer" @click="chooseMarksVisible = true">
|
||||
@ -21,7 +21,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import ChooseMarks from "@/components/MyComponents/ChooseMarks/index.vue";
|
||||
import ChooseMarks from "@/components/ChooseList/ChooseMarks/index.vue";
|
||||
import FormMessage from "@/components/aboutTable/FormMessage.vue";
|
||||
import { reactive, ref } from 'vue';
|
||||
const props = defineProps({
|
||||
@ -29,11 +29,14 @@ const props = defineProps({
|
||||
type:Object,
|
||||
default:{}
|
||||
},
|
||||
modelValue:{
|
||||
type:Boolean,
|
||||
default:false
|
||||
}
|
||||
})
|
||||
const chooseMarksVisible = ref(false)
|
||||
const roleIds = ref([])
|
||||
const elform = ref()
|
||||
const showDialog = ref(false)
|
||||
const emit = defineEmits(['change'])
|
||||
const listQuery = ref({})
|
||||
const formData = ref([
|
||||
@ -41,7 +44,7 @@ const formData = ref([
|
||||
{ label: "性别", prop: "xb", type: "select",options:props.dic.D_BZ_XB ,width:'48%'},
|
||||
{ label: "身份证号", prop: "sfzh", type: "input" ,width:'48%'},
|
||||
{ label: "户籍地", prop: "hjdz", type: "input",width:'48%' },
|
||||
{ label: "户籍地派出所", prop: "hjdpcsdm", type: "department" ,width:'48%'},
|
||||
{ label: "户籍地派出所", prop: "hjdpcsdm",depMc:'hjdpcs', type: "department" ,width:'48%'},
|
||||
{ label: "标签", prop: "bqList", type: "slot",width:'100%' },
|
||||
{ label: "是否挑头人", prop: "sfttr", type: "select",options:props.dic.D_BZ_SF ,width:'48%'},
|
||||
{ label: "是否响应人", prop: "sfxyr", type: "select" ,options:props.dic.D_BZ_SF,width:'48%' },
|
||||
@ -60,7 +63,6 @@ const order = ref(null)
|
||||
const init = (type,row,index) =>{
|
||||
title.value = type == 'add' ? '新增' :'编辑';
|
||||
order.value = index;
|
||||
showDialog.value = true;
|
||||
if(row) listQuery.value = {...row};
|
||||
}
|
||||
|
||||
@ -82,13 +84,13 @@ const submitForm = () =>{
|
||||
elform.value.submit((val)=>{
|
||||
let obj = { data:val,type:title.value ,index:order.value}
|
||||
emit('change',obj)
|
||||
showDialog.value = false;
|
||||
emit('update:modelValue',false)
|
||||
})
|
||||
}
|
||||
|
||||
const close = () =>{
|
||||
elform.value.reset();
|
||||
showDialog.value = false;
|
||||
emit('update:modelValue',false)
|
||||
}
|
||||
|
||||
defineExpose({init})
|
@ -1,35 +1,17 @@
|
||||
<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>
|
||||
</div>
|
||||
<div>仅支持扩展名:.xls , xlsx</div>
|
||||
<div>仅支持扩展名:.xls , xlsx</div>
|
||||
</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();
|
||||
@ -60,30 +41,30 @@ const filesList = ref({});
|
||||
const baseUrl = ref('')//上传地址
|
||||
const modelUrl = ref('')//下载模板地址
|
||||
watch(()=>props.lx,(val)=>{
|
||||
switch (val) {
|
||||
case 'policeF':
|
||||
baseUrl.value = '/mosty-api/mosty-jcgl/tbJcglXfll/importData'
|
||||
modelUrl.value = '/mosty-api/mosty-jcgl/tbJcglXfll/importTemplate'
|
||||
break;
|
||||
case 'car':
|
||||
baseUrl.value = '/mosty-api/mosty-jcgl/tpJcglXfcl/importData'
|
||||
modelUrl.value = '/mosty-api/mosty-jcgl/tpJcglXfcl/importTemplate'
|
||||
break;
|
||||
case 'jyqx':
|
||||
baseUrl.value = '/mosty-api/mosty-jcgl/tpJcglJyqx/importData'
|
||||
modelUrl.value = '/mosty-api/mosty-jcgl/tpJcglJyqx/importTemplate'
|
||||
break;
|
||||
case 'znzb':
|
||||
baseUrl.value = '/mosty-api/mosty-jcgl/tpjcglZnzb/importData'
|
||||
modelUrl.value = '/mosty-api/mosty-jcgl/tpjcglZnzb/importTemplate'
|
||||
break;
|
||||
case 'fjnr':
|
||||
baseUrl.value = '/mosty-api/mosty-gsxt/tbGsxtRqfjNr/importFxnr'
|
||||
// modelUrl.value = '/mosty-api/mosty-jcgl/tpjcglZnzb/importTemplate'
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
switch (val) {
|
||||
case 'policeF':
|
||||
baseUrl.value = '/mosty-api/mosty-jcgl/tbJcglXfll/importData'
|
||||
modelUrl.value = '/mosty-api/mosty-jcgl/tbJcglXfll/importTemplate'
|
||||
break;
|
||||
case 'car':
|
||||
baseUrl.value = '/mosty-api/mosty-jcgl/tpJcglXfcl/importData'
|
||||
modelUrl.value = '/mosty-api/mosty-jcgl/tpJcglXfcl/importTemplate'
|
||||
break;
|
||||
case 'jyqx':
|
||||
baseUrl.value = '/mosty-api/mosty-jcgl/tpJcglJyqx/importData'
|
||||
modelUrl.value = '/mosty-api/mosty-jcgl/tpJcglJyqx/importTemplate'
|
||||
break;
|
||||
case 'znzb':
|
||||
baseUrl.value = '/mosty-api/mosty-jcgl/tpjcglZnzb/importData'
|
||||
modelUrl.value = '/mosty-api/mosty-jcgl/tpjcglZnzb/importTemplate'
|
||||
break;
|
||||
case 'fjnr':
|
||||
baseUrl.value = '/mosty-api/mosty-gsxt/tbGsxtRqfjNr/importFxnr'
|
||||
// modelUrl.value = '/mosty-api/mosty-jcgl/tpjcglZnzb/importTemplate'
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
},{
|
||||
immediate:true
|
||||
|
114
src/components/ypModel/index.vue
Normal file
@ -0,0 +1,114 @@
|
||||
<template>
|
||||
<el-dialog v-model="modelValue" center width="1000px" :destroy-on-close="true" title="报告模板" @close="close" :close-on-click-modal="false">
|
||||
<div class="cntBox">
|
||||
<!-- 工具栏 -->
|
||||
<Toolbar style="border-bottom: 1px solid #ccc" :editor="editorRef" :defaultConfig="toolbarConfig" :mode="mode" />
|
||||
<!-- 编辑器 -->
|
||||
<Editor :style="`height: ${props.heightNumber}px; overflow-y: hidden`" v-model="textContent" :defaultConfig="editorConfig" :mode="mode" @onCreated="handleCreated" @onChange="handChange" />
|
||||
</div>
|
||||
<template #footer>
|
||||
<el-button type="primary">暂存</el-button>
|
||||
<el-button type="primary">下载</el-button>
|
||||
<el-button type="primary" @click="close">取消</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { compressImage } from "@/utils/tools.js";
|
||||
import "@wangeditor/editor/dist/css/style.css";
|
||||
import { qcckPost } from "@/api/qcckApi.js";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { Editor, Toolbar } from "@wangeditor/editor-for-vue";
|
||||
import { ref, shallowRef, onBeforeUnmount, defineEmits, defineProps, watch } from "vue";
|
||||
const props = defineProps({
|
||||
modelValue:{
|
||||
type:Boolean,
|
||||
default:false
|
||||
},
|
||||
// 编辑器内容
|
||||
textContent: {
|
||||
type: String,
|
||||
default: ""
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: "请输入内容。。。。"
|
||||
},
|
||||
heightNumber: {
|
||||
type: Number,
|
||||
default: 448
|
||||
}
|
||||
});
|
||||
const editorRef = shallowRef();
|
||||
const mode = "default";
|
||||
//工具配置
|
||||
const toolbarConfig = {
|
||||
excludeKeys: ["blockquote", "codeBlock"] //清除不必要的工具,引用和代码块
|
||||
};
|
||||
const emits = defineEmits(["update:textContent", "changeFn"]);
|
||||
//编辑器配置
|
||||
const editorConfig = {
|
||||
withCredentials: true, //允许跨域
|
||||
placeholder: props.placeholder, //提示语
|
||||
MENU_CONF: {
|
||||
uploadImage: {
|
||||
// 自定义上传图片
|
||||
async customUpload(file, insertFn) {
|
||||
let fileBlob = await compressImage(file);
|
||||
let fileData = new File([fileBlob], fileBlob.name, { type: fileBlob.type });
|
||||
if (fileData.size > 2 * 1024 * 1024) {
|
||||
ElMessage({ message: "图片超过2MB", type: "success" });
|
||||
} else {
|
||||
await uploadFn(fileData, insertFn);
|
||||
}
|
||||
}
|
||||
},
|
||||
uploadVideo: {
|
||||
// 自定义上传视频
|
||||
async customUpload(file, insertFn) {
|
||||
await uploadFn(file, insertFn);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const uploadFn = (file, insertFn) => {
|
||||
let param = new FormData();
|
||||
param.append("file", file);
|
||||
qcckPost(param, "/mosty-base/minio/image/upload").then((res) => {
|
||||
insertFn(res);
|
||||
});
|
||||
};
|
||||
//编辑器创建成功
|
||||
const handleCreated = (editor) => {
|
||||
editorRef.value = editor;
|
||||
};
|
||||
//内容发生变化
|
||||
const handChange = (editor) => {
|
||||
console.log(editor.getHtml(),'====editor.getHtml()');
|
||||
// 判断是否是一个空段落,是空就传空文本
|
||||
if (editor.isEmpty()) {
|
||||
emits("changeFn", editor.getText());
|
||||
} else {
|
||||
emits("changeFn", editor.getHtml());
|
||||
}
|
||||
};
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
const editor = editorRef.value;
|
||||
if (editor) editor.destroy();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.cntBox{
|
||||
height: 60vh;
|
||||
padding: 8px;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
overflow-y: auto;
|
||||
border: 1px dashed #e9e9e9;
|
||||
}
|
||||
|
||||
</style>
|