7 Commits

338 changed files with 29870 additions and 32022 deletions

View File

@@ -8,7 +8,7 @@ steps:
- name: build-package
image: node:18.19.0
image: node:16.20.0
volumes:
- name: cache
path: /drone/src/node_modules
@@ -23,17 +23,11 @@ steps:
- cp docker.sh /app/build/$DRONE_REPO_NAME/
- cp nginx.conf /app/build/$DRONE_REPO_NAME/
- npm -v
- node -v
- mkdir -p ./node_modules
- export NODE_MODULES_PATH=`pwd`/node_modules
- npm config set registry https://registry.npmmirror.com
- set NODE_OPTIONS=--openssl-legacy-provider
- npm install --legacy-peer-deps
- npm install patch-package
- npx patch-package
# - npm info unplugin-icons
- npm list package-manager-detector
# - npm install unplugin-icons@latest @antfu/install-pkg@latest package-manager-detector@latest
# - npm config set registry https://registry.npmmirror.com
#- set NODE_OPTIONS=--openssl-legacy-provider
# - npm install
- npm run build
- ls /app/build/$DRONE_REPO_NAME/
- echo $NODE_MODULES_PATH
@@ -41,7 +35,7 @@ steps:
- name: build-docker-prod # 制作docker镜像
image: 10.7.127.190:38080/docker/docker # 使用官方docker镜像
image: docker # 使用官方docker镜像
volumes: # 将容器内目录挂载到宿主机
- name: docker
path: /var/run/docker.sock # 挂载宿主机的docker

View File

@@ -1,11 +1,9 @@
FROM 10.7.127.190:38080/nginx:latest
FROM nginx
RUN rm -rf /etc/nginx/conf.d/default.conf
RUN rm -rf /etc/nginx/nginx.conf
COPY default.conf /etc/nginx/conf.d
COPY nginx.conf /etc/nginx/
#COPY mosr.feashow.cn_chain.crt /etc/nginx/
#COPY private.key /etc/nginx/
#RUN useradd -b /home/clay -m -s /bin/bash clay
#RUN chmod a+xr -R /home/clay && chown clay:clay -R /home/clay

View File

@@ -1,2 +1,2 @@
# 科技创新项目管理平台
# <EFBFBD><EFBFBD><EFBFBD>й<EFBFBD><EFBFBD><EFBFBD>ƽ̨

View File

@@ -4,7 +4,7 @@
<meta charset="UTF-8">
<link rel="icon" href="/favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>科技创新项目管理平台</title>
<!-- <title>科研管理平台</title>-->
</head>
<body>
<div id="app"></div>

View File

@@ -1,72 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIG3DCCBMSgAwIBAgIQDzIS+rldpl8FKv9qt1IuQDANBgkqhkiG9w0BAQsFADBb
MQswCQYDVQQGEwJDTjElMCMGA1UEChMcVHJ1c3RBc2lhIFRlY2hub2xvZ2llcywg
SW5jLjElMCMGA1UEAxMcVHJ1c3RBc2lhIERWIFRMUyBSU0EgQ0EgMjAyNTAeFw0y
NTAzMTkwMDAwMDBaFw0yNTA2MTcyMzU5NTlaMBoxGDAWBgNVBAMTD21vc3IuZmVh
c2hvdy5jbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK92bSayd6Wo
wFJz+ldX8QEgQiUjEPyQB0rV+Op9/eZSmpC6y+DuS/CddOPaXs+t1fV9L2kQ1yWD
Byc7cZK2PnzGb8+Uh9BR3UtVaCxISGqxjvt2V1lIwXbBDOUjtkVVlchhGR+BrNzP
YGyMLhgdBDxhKK4ogBNOx23AzCpTGFsU7sL996qwYo2rhIE8UuYcw3deS4RtfMUx
zt58wn1s+9kki6Qti7dLw3Bg0eCXop+7/FC09fg5Nh3EygMlZvLyvNOFig+o/Fk3
6ibp2N56yFLEfe+WNj4xPCad/3Cevh5BIgTsSAPBh6J5Jk4IXoL8PuCSc96d79Bg
SVGNGhRuCgcCAwEAAaOCAtswggLXMB8GA1UdIwQYMBaAFLQSKKW0wB2fKXFpPNkR
lkp1aVDAMB0GA1UdDgQWBBTL9/e/QUue1NxlPXspxQ/RzXhzxTAaBgNVHREEEzAR
gg9tb3NyLmZlYXNob3cuY24wPgYDVR0gBDcwNTAzBgZngQwBAgEwKTAnBggrBgEF
BQcCARYbaHR0cDovL3d3dy5kaWdpY2VydC5jb20vQ1BTMA4GA1UdDwEB/wQEAwIF
oDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIweQYIKwYBBQUHAQEEbTBr
MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQwYIKwYBBQUH
MAKGN2h0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9UcnVzdEFzaWFEVlRMU1JT
QUNBMjAyNS5jcnQwDAYDVR0TAQH/BAIwADCCAX8GCisGAQQB1nkCBAIEggFvBIIB
awFpAHYATnWjJ1yaEMM4W2zU3z9S6x3w4I4bjWnAsfpksWKaOd8AAAGVrKDPywAA
BAMARzBFAiAJkC1pvmPIhgdAkRoyPCItM4oRM5Bb8OI3zVzNvdNTkQIhAN1Fq4mU
GJYrJkOmwvJ2Mb5upB50Ic8C7KatpMdKEFM7AHYAfVkeEuF4KnscYWd8Xv340Idc
FKBOlZ65Ay/ZDowuebgAAAGVrKDQBwAABAMARzBFAiAT9jfX08uN94aIeK84IySz
jUPDa1MSWjJKsA3XusY3GAIhAJ9PvGtFx9+UM9YNNT7BZUq6hhVvhYWhlf+d0qpy
uEl9AHcAzxFW7tUufK/zh1vZaS6b6RpxZ0qwF+ysAdJbd87MOwgAAAGVrKDP+AAA
BAMASDBGAiEA0c9dt1JwyAMzQtv7UsPaKEJ5sp6HDaSWe5BGIYWsYrcCIQDjS6L1
9TF6SpcEWHH6bl952VQb6Xvt1JmmKUNX6iK2xTANBgkqhkiG9w0BAQsFAAOCAgEA
0E2VWQjWgEBz968xq2cpYGv2Enfs2TWpynuoPTwY83V7h2ejNbpjgyW1gT/kQkxa
G5k4jpkVmNMaj3CAvK4IA5jOPh6dhzBG35Qc0PwRm0eovcUdUNUd0g4EOv82p2s1
ab1SWNYoxGdS+y+LHhfFZ7CoVcSvBz+LHBlPTVTkLA0SWLA0fhS3pl5oGIilMtSM
znCUUuMBtMQBv7sFX2gDEYwxGaMn3lpoqBGkpx4UBc51z/U3+X9zLqu6n/GpLC72
+qz6QtQVm0Np8gcjul0ebQqAPwDG4U+9jYEmdwVHZ0iUKgyZPECPU+TTtHx0TFS3
B5JXy8vbGJBqpwq6hMnu/SFm+GY3iPk7N0Aj5+9QNcl2FTF8k/nCoK3MuY71ZmxR
E1NY6Hl5KpKzBqc7JG4iqQxJ0dD9Racn4wegGDlX0Vr2U+ohHYeETNJXOX+JT4tc
1PBdfiywbX+FCdE2ZPehWa6dt4fnPBC/9lSywrzOWLNt9z1a/Mh73N5F6ndaXq1p
v/N3Q0qnXpW1RZa6Baqlfvk2vqhraRbT9YH5Y+f51DhtVB6fbELO/pJr1H5kh0XI
CczHkGTGD7xZloNfTMLP2AVguIXJ0EASAAMw/MBRWvSd4He2lLHvujEqTXsTISgv
v+/5bZP8qBk3/oEgdLjlmqWY1sesBH84tiMZcxCkPNM=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIFnjCCBIagAwIBAgIQCSYyO0lk42hGFRLe8aXVLDANBgkqhkiG9w0BAQsFADBh
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH
MjAeFw0yNTAxMDgwMDAwMDBaFw0zNTAxMDcyMzU5NTlaMFsxCzAJBgNVBAYTAkNO
MSUwIwYDVQQKExxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMSUwIwYDVQQD
ExxUcnVzdEFzaWEgRFYgVExTIFJTQSBDQSAyMDI1MIICIjANBgkqhkiG9w0BAQEF
AAOCAg8AMIICCgKCAgEA0fuEmuBIsN6ZZVq+gRobMorOGIilTCIfQrxNpR8FUZ9R
/GfbiekbiIKphQXEZ7N1uBnn6tXUuZ32zl6jPkZpHzN/Bmgk1BWSIzVc0npMzrWq
/hrbk5+KddXJdsNpeG1+Q8lc8uVMBrztnxaPb7Rh7yQCsMrcO4hgVaqLJWkVvEfW
ULtoCHQnNaj4IroG6VxQf1oArQ8bPbwpI02lieSahRa78FQuXdoGVeQcrkhtVjZs
ON98vq5fPWZX2LFv7e5J6P9IHbzvOl8yyQjv+2/IOwhNSkaXX3bI+//bqF9XW/p7
+gsUmHiK5YsvLjmXcvDmoDEGrXMzgX31Zl2nJ+umpRbLjwP8rxYIUsKoEwEdFoto
Aid59UEBJyw/GibwXQ5xTyKD/N6C8SFkr1+myOo4oe1UB+YgvRu6qSxIABo5kYdX
FodLP4IgoVJdeUFs1Usa6bxYEO6EgMf5lCWt9hGZszvXYZwvyZGq3ogNXM7eKyi2
20WzJXYMmi9TYFq2Fa95aZe4wki6YhDhhOO1g0sjITGVaB73G+JOCI9yJhv6+REN
D40ZpboUHE8JNgMVWbG1isAMVCXqiADgXtuC+tmJWPEH9cR6OuJLEpwOzPfgAbnn
2MRu7Tsdr8jPjTPbD0FxblX1ydW3RG30vwLF5lkTTRkHG9epMgpPMdYP7nY/08MC
AwEAAaOCAVYwggFSMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFLQSKKW0
wB2fKXFpPNkRlkp1aVDAMB8GA1UdIwQYMBaAFE4iVCAYlebjbuYP+vq5Eu0GF485
MA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw
dgYIKwYBBQUHAQEEajBoMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2Vy
dC5jb20wQAYIKwYBBQUHMAKGNGh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9E
aWdpQ2VydEdsb2JhbFJvb3RHMi5jcnQwQgYDVR0fBDswOTA3oDWgM4YxaHR0cDov
L2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0R2xvYmFsUm9vdEcyLmNybDARBgNV
HSAECjAIMAYGBFUdIAAwDQYJKoZIhvcNAQELBQADggEBAJ4a3svh316GY2+Z7EYx
mBIsOwjJSnyoEfzx2T699ctLLrvuzS79Mg3pPjxSLlUgyM8UzrFc5tgVU3dZ1sFQ
I4RM+ysJdvIAX/7Yx1QbooVdKhkdi9X7QN7yVkjqwM3fY3WfQkRTzhIkM7mYIQbR
r+y2Vkju61BLqh7OCRpPMiudjEpP1kEtRyGs2g0aQpEIqKBzxgitCXSayO1hoO6/
71ts801OzYlqYW9OQQQ2GCJyFbD6XHDjdpn+bWUxTKWaMY0qedSCbHE3Kl2QEF0C
ynZ7SbC03yR+gKZQDeTXrNP1kk5Qhe7jSXgw+nhbspe0q/M1ZcNCz+sPxeOwdCcC
gJE=
-----END CERTIFICATE-----

View File

@@ -25,7 +25,6 @@ http {
keepalive_timeout 65;
server {
listen 80;
listen [::]:80;
@@ -40,7 +39,6 @@ http {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
client_max_body_size 30m;
}
location / {

11348
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -7,20 +7,13 @@
"build": "vite build",
"preview": "vite preview"
},
"overrides": {
"package-manager-detector": "1.0.0",
"@iconify/utils": "2.2.1"
},
"dependencies": {
"@antv/g6": "^3.5.7",
"@tinymce/tinymce-vue": "^4.0.7",
"axios": "^1.4.0",
"d3": "^7.8.5",
"docx-preview": "^0.3.2",
"echarts": "^5.4.2",
"element-plus": "^2.6.0",
"file-saver": "^2.0.5",
"highlight.js": "9.18.5",
"jquery": "^3.6.0",
"js-cookie": "^3.0.5",
@@ -37,11 +30,7 @@
"vue-codemirror": "^6.1.1",
"vue-json-viewer": "^3.0.4",
"vue-router": "^4.1.6",
"vue3-pdf-app": "^1.0.3",
"vue3-print-nb": "^0.1.4",
"vuedraggable": "^4.1.0",
"xlsx": "^0.18.5",
"xlsx-style-vite": "^0.0.2"
"vuedraggable": "^4.1.0"
},
"devDependencies": {
"@codemirror/lang-java": "^6.0.1",

View File

@@ -1,28 +0,0 @@
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCvdm0msnelqMBS
c/pXV/EBIEIlIxD8kAdK1fjqff3mUpqQusvg7kvwnXTj2l7PrdX1fS9pENclgwcn
O3GStj58xm/PlIfQUd1LVWgsSEhqsY77dldZSMF2wQzlI7ZFVZXIYRkfgazcz2Bs
jC4YHQQ8YSiuKIATTsdtwMwqUxhbFO7C/feqsGKNq4SBPFLmHMN3XkuEbXzFMc7e
fMJ9bPvZJIukLYu3S8NwYNHgl6Kfu/xQtPX4OTYdxMoDJWby8rzThYoPqPxZN+om
6djeeshSxH3vljY+MTwmnf9wnr4eQSIE7EgDwYeieSZOCF6C/D7gknPene/QYElR
jRoUbgoHAgMBAAECggEABmJQMV6/9LKRoM5gduoXtjtGvNQsS4wv/7yOTHXeFZG+
1vI89cel0rDf7mRlG7hO9xohbfizY0WDrp0+kiB4YJDVw587W8yGuTV3z1in7d3c
/nA9WF3J0DjQ78tfV+F3zC0gPWG5+OTAtOJa0PzJSSsd0Exf8JPmtKsVopqYYcPv
RL2uP+NfcsxIEPz7rBBqiTGbOgsoKIpVZWiV6dmGOHLnI3ktWE8GXyIFv0VO6kp2
fk/Z2uU9rfS9Qc9NijVdZ5AejdSh70iWNdiVMTSXZ69XLQCiY1h/376mraAPZTC1
T0fYAtaOdyRrYLIW3yuznZa6hz351+t4TjJHQGjAUQKBgQDe8FS3yM85Ve3qlNaV
pzjpjkv8cn8u43Hyk88owNACxkvzUXx15YE+AGjjycVO5rbyC1mtdE2MKX8cd5T/
cA75RoSDxBTR7xi9eqBzJpQ7hm2rTaZSkHhu4P9KsthgQFFYQB6EkZgYczLOs/OV
UmPMuKwL7HcwuRf00jjAOoJPdwKBgQDJe7R4PS0VBAWnh3lC9R/NEbEoFQ6LUwPh
Qgmgj6LRB/1NgaC7ekDCSyfFlTtpnRDD+WqCrZDiB1ZZehyUObvr0Y0Cb4Y77Fjh
lPVG0kfcKUldMpJIfeex0LPBwYHC62Y0ztNQmtgTldDjX04b4gAEgpUReHVTJtDr
6S1wRPVd8QKBgHIL0+roqUmVcc5NMbEBCJZCGxEbqYBdDg+gGZupdz/UHUpt5xOQ
wprrLr1InM0OLYyIzelz06/eEo6HhgteUeqnbmbRyizS+X8E2kvN8oq47CVz5Z/b
FCD0rOSTtSkX/gT9WB9NM9deJyGi4PsEWNWDq0+2OgsMxPqTCEEeLUdlAoGAHNmB
tdXMpr20sZBMZLIEo7Bs1XhuZLS2UYLLLhpjDds/AeIVycJvk2J/h2Me5rh+thD4
l02S+Upjqtw5S2AY8GNI9ZhSeDIXZ/WUSVfCwluHDbk4CPk+O8/ObWfv1KEwOU+E
In6JggRprKTw4j0yE3M/NQkyg32DXMQ+pVy6ZYECgYEAmW/+vm3X2NMj8yjr0Io2
P3F/9EHPkrGHNC3Qj6Q2mFus6oDe6NwOQg5Su0fFC77spHFi1g/MlGUxbzoxjVxH
1wQmwCHBJuJ97H9MOJ9K2v88/pkvfFGthkTLpbcJLqX57WVEVnVKBMNhpLrlp+0r
T3tV8tN010INwiQkaoqCsuw=
-----END PRIVATE KEY-----

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 750 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 736 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 743 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 733 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -1,211 +0,0 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>axupimgs</title>
<meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1.0, maximum-scale=1.0"/>
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
<meta name="format-detection" content="telephone=no">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<style>
html,body{height:100%;margin:0;padding:0;background:#fff;}
ul{margin:0;padding:0;list-style:none;}
#wrap{padding:10px;}
#topbar{padding:10px 0;border-bottom:1px solid #ccc;text-align:right;}
#topbar button {margin:0;margin-left:5px;outline:none;padding: 4px 16px;box-sizing: border-box;
display:inline-block;border:none;border-radius:3px;text-align:center;cursor:pointer;
font-size:14px;line-height:1.5;background-color:#f0f0f0;color:#223;
}
#topbar button.primary{background-color:#3d97d4;color:#fff;}
#topbar button:hover{background-color:#207ab7;color:#fff;}
#topbar button.removeall{float:left}
#file_list {display:grid;grid-gap:10px;grid-template-columns:repeat(auto-fill,minmax(160px,1fr));padding-top:10px;}
#file_list:empty:after{content:'可以直接拖拽文件到这里';color:#777;font-size:0.8em;}
#file_list li{position:relative;display:block;vertical-align:top;padding:5px 5px;border-radius:5px;}
#file_list li.up-over {}
#file_list li.up-now {}
#file_list li.up-now:after{content:'';position:absolute;top:0;left:0;display:block;width:100%;height:100%;background:rgba(255,255,255,0.8) url(loading.gif) center center no-repeat;border-radius:5px;z-index:999;}
#file_list li:hover{background-color:#ddd;}
#file_list li .picbox {display:flex;flex:0 0 auto;justify-content:center;overflow:hidden;position:relative;width:100%;padding-top:100%;align-items:center;}
#file_list li .picbox img {display:block;max-width:100%;max-height:100%;position:absolute;
top:50%;left:50%;transform:translateX(-50%) translateY(-50%);}
#file_list li.up-over .picbox:after{content:url('data:image/svg+xml;%20charset=utf8,%3Csvg%20viewBox%3D%220%200%201024%201024%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M512%200C229.376%200%200%20229.376%200%20512s229.376%20512%20512%20512%20512-229.376%20512-512S794.624%200%20512%200z%22%20fill%3D%22%234AC711%22%3E%3C%2Fpath%3E%3Cpath%20d%3D%22M855.552%20394.752l-358.4%20358.4a50.9952%2050.9952%200%200%201-72.192%200l-204.8-204.8c-18.944-19.968-18.944-51.2%200-71.168a50.5344%2050.5344%200%200%201%2072.192-1.024L460.8%20644.608l322.048-322.048c19.968-18.944%2051.2-18.944%2071.168%200%2020.48%2019.456%2020.992%2051.712%201.536%2072.192z%22%20fill%3D%22%23FFFFFF%22%3E%3C%2Fpath%3E%3C%2Fsvg%3E');position:absolute;bottom:2px;right:2px;z-index:9;}
#file_list li .tools {display:none;position:absolute;bottom:5px;right:5px;z-index:99;}
#file_list li:hover .tools {display:block;}
#file_list li .tools .remove{cursor:pointer;}
#file_list li .tools .remove:after{content:url('data:image/svg+xml;%20charset=utf8,%3Csvg%20width=%2224%22%20height=%2224%22%20viewBox=%220%200%2024%2024%22%20xmlns=%22http://www.w3.org/2000/svg%22%3E%3Cpath%20d=%22M17%206h3a1%201%200%200%201%200%202h-1v11a3%203%200%200%201-3%203H8a3%203%200%200%201-3-3V8H4a1%201%200%201%201%200-2h3V5a3%203%200%200%201%203-3h4a3%203%200%200%201%203%203v1zm-2%200V5a1%201%200%200%200-1-1h-4a1%201%200%200%200-1%201v1h6zm2%202H7v11a1%201%200%200%200%201%201h8a1%201%200%200%200%201-1V8zm-8%203a1%201%200%200%201%202%200v6a1%201%200%200%201-2%200v-6zm4%200a1%201%200%200%201%202%200v6a1%201%200%200%201-2%200v-6z%22%3E%3C/path%3E%3C/svg%3E');}
#file_list li .namebox {font-size:14px;line-height:20px;max-height:40px;overflow:hidden;padding:5px 10px;text-align:center;display:flex;justify-content:center;align-items:flex-start;}
#file_list li .namebox span{word-break:break-all;vertical-align:top;}
</style>
</head>
<body>
<div id="wrap">
<div id="topbar"><button class="addfile primary">+ 添加文件</button><button class="removeall">清空列表</button></div>
<ul id="file_list"></ul>
</div>
<script>
var editor=parent.tinymce.activeEditor;
var axupimgs=parent.axupimgs;
axupimgs.res = []; //存放本地文件的数组
var blobInfo = {file:null}
blobInfo.blob = function(){return this.file;}
var upload_handler = axupimgs.images_upload_handler;
var upload_base_path = axupimgs.images_upload_base_path;
//为列表添加排序
function reSort(){
document.querySelectorAll('#file_list li').forEach((el,i)=>{
el.setAttribute('data-num',i);
});
}
function addList(files){
var files_sum = files.length;
var vDom = document.createDocumentFragment();
for(let i=0;i<files_sum;i++){
let file = files[i];
let blobUrl = window.URL.createObjectURL(file)
axupimgs.res.push({file:file,blobUrl:blobUrl,url:''});
let li = document.createElement('li');
li.setAttribute('class','up-no');
li.setAttribute('data-time',file.lastModified);
li.innerHTML='<div class="picbox"><img src="'+blobUrl+'"></div><div class="namebox"><span>'+file.name+'</span></div><div class="tools"><a class="remove"></a></div>';
vDom.appendChild(li);
}
document.querySelector('#file_list').appendChild(vDom);
if(axupimgs.res.length>0){
document.querySelectorAll('#file_list li.up-no').forEach((el,i)=>{
el.classList ? el.classList.add('up-now') : el.className+=' up-now';
});
upAllFiles(0);
}
//reSort();
}
//清空列表
document.querySelector('#topbar .removeall').addEventListener('click',()=>{
axupimgs.res=[]
document.querySelectorAll('#file_list li').forEach((el,i)=>{
el.parentNode.removeChild(el)
});
});
//拖拽添加
document.addEventListener('dragover', (e)=>{
e.stopPropagation();
e.preventDefault();
e.dataTransfer.dropEffect = 'copy';
});
document.addEventListener('drop', (e)=>{
e.stopPropagation();
e.preventDefault();
if(!e.dataTransfer.files){return false;}
var dropfiles = e.dataTransfer.files;
if(!(dropfiles.length>0)){return false;}
var exts=axupimgs.axupimgs_filetype.replace(/(\s)+/g,'').toLowerCase().split(',');
var files=[];
for( let file of dropfiles ){
ext = file.name.split('.');
ext = '.'+ext[ext.length-1];
for(let s of exts){
if(s==ext){
files.push(file);
break;
}
}
}
if(files.length>0){ addList(files) }
});
//添加文件
document.querySelector('#topbar .addfile').addEventListener('click',()=>{
var input = document.createElement('input');
input.setAttribute('type', 'file');
input.setAttribute('multiple', 'multiple');
input.setAttribute('accept', axupimgs.axupimgs_filetype);
input.click();
input.onchange = function() {
var files = this.files;
addList(files);
}
});
var file_i = 0;
function upAllFiles(n){
var len = axupimgs.res.length;
file_i = n;
if(len == n){
file_i=0;
// document.querySelector('#topbar .upall').innerText='全部上传';
return true;
}
if( axupimgs.res[n].url!='' ){
n++;
upAllFiles(n)
}else{
blobInfo.file=axupimgs.res[n].file;
upload_handler(blobInfo,function(url,name){
if(upload_base_path){
if(upload_base_path.slice(-1)=='/' && url.substr(0,1)=='/' ){
url = upload_base_path + url.slice(1);
}else if(upload_base_path.slice(-1)!='/' && url.substr(0,1)!='/' ){
url = upload_base_path + '/' + url;
}else{
url = upload_base_path + url;
}
}
axupimgs.res[file_i].url = url;
// filename = url.split('/').pop();
filename = name
var li = document.querySelectorAll('#file_list li')[file_i];
li.setAttribute('class','up-over');
li.querySelector('.namebox span').innerText = filename;
n++
upAllFiles(n);
},function(err){
// document.querySelector('#topbar .upall').innerText='全部上传';
// document.querySelectorAll('#file_list li.up-now').forEach((el,i)=>{
// el.setAttribute('class','up-no');
// });
// alert(err);
});
}
}
//
// document.querySelector('#topbar .upall').addEventListener('click',(e)=>{
// if(e.target.innerText!='全部上传'){return false;}
// if(axupimgs.res.length>0){
// document.querySelectorAll('#file_list li.up-no').forEach((el,i)=>{
// el.classList ? el.classList.add('up-now') : el.className+=' up-now';
// });
// e.target.innerText='上传中...';
// upAllFiles(0);
// }
// });
var observ_flist = new MutationObserver( (muList,observe)=>{
if(muList[0].addedNodes.length>0){
muList[0].addedNodes.forEach((el)=>{
el.querySelector('.remove').addEventListener('click',(e)=>{
var li = e.target.parentNode.parentNode;
var n = li.getAttribute('data-num');
var el = document.querySelectorAll('#file_list li')[n];
el.parentNode.removeChild(el);
axupimgs.res.splice(n,1);
});
});
}
reSort();
});
observ_flist.observe(document.querySelector('#file_list'),{childList:true});
</script>
</body>
</html>

View File

@@ -8,6 +8,5 @@ window.addEventListener('beforeunload', e=>beforeunload(e))
const beforeunload = (()=>{
const permisstionStore = usePermisstionStroe()
permisstionStore.setIsLoadRoutes(true)
permisstionStore.setIsSuccessReq()
})
</script>

View File

@@ -1,36 +0,0 @@
import request from '@/utils/request.js'
export const getArticle = (params) => {
return request({
url: '/workflow/mosr/article/list',
method: "get",
params
});
};
export const getArticleDetail = (articleId) => {
return request({
url: `/workflow/mosr/article/${articleId}`,
method: "get"
});
};
export const addArticle= (data) => {
return request({
url: '/workflow/mosr/article/add',
method: "post",
data
});
};
export const editArticle= (data) => {
return request({
url: '/workflow/mosr/article/update',
method: "post",
data
});
};
export const deleteArticle = (articleIds) => {
return request({
url: `/workflow/mosr/article/${articleIds}`,
method: "delete"
});
};

View File

@@ -1,31 +1,9 @@
import request from "@/utils/request.js";
export const initPassword=(data)=>{
export const modifyUser=(data)=>{
return request({
url:'/admin/mosr/user/init/password',
method:'post',
url:'/admin/user',
method:'put',
data
})
}
export const editPassword=(data)=>{
return request({
url:'/admin/mosr/user/update/password',
method:'post',
data
})
}
export const getAgentInfo=()=>{
return request({
url:'/admin/mosr/user/self/approval/agent',
method:'get'
})
}
export const editAgentInfo=(data)=>{
return request({
url:'/admin/mosr/user/self/approval/agent',
method:'post',
data
})
}
}

View File

@@ -0,0 +1,61 @@
import request from '@/utils/request.js'
// 请求数据源适配器list
export const getDataAdapterList = (params) => {
return request({
url: '/custom/query/query/adapter',
method: 'get',
params
})
}
//获取到option列表
export const getDataAdapterOpt = () => {
return request({
url: '/custom/query/query/adapter/option',
method: 'get',
})
}
// 获取数据源适配器详情
export const getDataAdapterDetails = (dataAdapterId) => {
return request({
url: '/custom/query/query/adapter/' + dataAdapterId,
method: 'get'
})
}
// 新增数据源适配器
export const addDataAdapter = (data) => {
return request({
url: '/custom/query/query/adapter',
method: 'post',
data
})
}
//模拟执行适配器函数
export const executeAdapterMockData = (data) => {
return request({
url: '/custom/query/query/adapter/mock/execute',
method: 'post',
data
})
}
// 修改数据源适配器
export const editDataAdapter = (data) => {
return request({
url: '/custom/query/query/adapter',
method: 'put',
data
})
}
// 删除数据源适配器
export const delDataAdapter =(dataAdapterId) => {
return request({
url: '/custom/query/query/adapter/' + dataAdapterId,
method: 'delete'
})
}

View File

@@ -0,0 +1,66 @@
import request from '@/utils/request.js'
// 请求数据源管理list
export const getDataSourceManageList = (params) => {
return request({
url: '/custom/query/datasource',
method: 'get',
params
})
}
//获取到option列表
export const getDataSourceManageOpt = () => {
return request({
url: '/custom/query/datasource/option',
method: 'get',
})
}
// 获取数据源管理详情
export const getDataSourceManageDetails = (queryDataSourceId) => {
return request({
url: '/custom/query/datasource/' + queryDataSourceId,
method: 'get'
})
}
// 获取数据源管理详情
export const getDataSourceType = () => {
return request({
url: '/custom/query/datasource/option/type',
method: 'get'
})
}
// 获取校验规则option
export const getDataSourceOption = () => {
return request({
url: '/custom/query/datasource/option',
method: 'get'
})
}
// 新增数据源管理
export const addDataSourceManage = (data) => {
return request({
url: '/custom/query/datasource',
method: 'post',
data
})
}
// 修改数据源管理
export const editDataSourceManage = (data) => {
return request({
url: '/custom/query/datasource',
method: 'put',
data
})
}
// 删除数据源管理
export const delDataSourceManage =(queryDataSourceId) => {
return request({
url: '/custom/query/datasource/' + queryDataSourceId,
method: 'delete'
})
}

View File

@@ -0,0 +1,36 @@
import request from '@/utils/request.js'
export const getEchartsList = (params) => {
return request({
url: '/custom/query/echarts',
method: 'get',
params
})
}
export const getEchartsDetails = (echartsId) => {
return request({
url: '/custom/query/echarts/' + echartsId,
method: 'get'
})
}
export const addEcharts = (data) => {
return request({
url: '/custom/query/echarts',
method: 'post',
data
})
}
export const editEcharts = (data) => {
return request({
url: '/custom/query/echarts',
method: 'put',
data
})
}
export const delEcharts=(echartsIdList) => {
return request({
url: '/custom/query/echarts/' + echartsIdList,
method: 'delete'
})
}

View File

@@ -0,0 +1,22 @@
import request from '@/utils/request.js'
// 获取查询页面信息
export const getPageInfo = (queryId, params) => {
return request({
url: '/custom/query/page/' + queryId,
method: 'get',
params: params
})
}
// 获取到页面数据
export const getPageData = (params, data) => {
return request({
url: '/custom/query/page/data',
method: 'post',
params: params,
data: data
})
}

View File

@@ -0,0 +1,37 @@
import request from '@/utils/request.js'
export const getSqlInfo = (queryId) => {
return request({
url: '/custom/query/sql/search/' + queryId,
method: 'get'
})
}
export const previewSql= (data,pageInfo) => {
return request({
url:'/custom/query/sql/search/preview' ,
method: 'put',
data,
params:pageInfo
})
}
export const saveSqlQueryParams = (data) => {
return request({
url: '/custom/query/sql/search',
method: 'post',
data
})
}
export const sqlToLine = (data) => {
return request({
url: '/custom/query/sql/search/publish',
method: 'post',
data
})
}
export const sqlDownLine = (queryId) => {
return request({
url: '/custom/query/sql/search/cancel/'+queryId,
method: 'put'
})
}

View File

@@ -0,0 +1,42 @@
import request from '@/utils/request.js'
// 获取Sql List
export const getSqlList = (params) => {
return request({
url: '/custom/query/sql/uni',
method: 'get',
params
})
}
// 获取Sql详情
export const getSqlDetails = (sqlId) => {
return request({
url: '/custom/query/sql/uni/' + sqlId,
method: 'get'
})
}
// 新增Sql
export const addSql = (data) => {
return request({
url: '/custom/query/sql/uni',
method: 'post',
data
})
}
// 修改Sql
export const editSql = (data) => {
return request({
url: '/custom/query/sql/uni',
method: 'put',
data
})
}
// 删除Sql
export const delSql =(idList) => {
return request({
url: '/custom/query/sql/uni/' + idList,
method: 'delete'
})
}

View File

@@ -0,0 +1,70 @@
import request from '@/utils/request.js'
//获取表格维护列表
export const getTableInfo = (params) => {
return request({
url: '/custom/query/table',
method: 'get',
params
})
}
export const getDynamicTableList = (params) => {
return request({
url: '/custom/query/dynamic/table',
method: 'get',
params
})
}
//根据数据源获取到表格option信息
export const getAssociationTableOption = (datasourceId) => {
return request({
url: '/custom/query/table/option/' + datasourceId,
method: 'get'
})
}
//获取表格字段option信息
export const getAssociationFieldOption = (tableId) => {
return request({
url: '/custom/query/table/column/option/' + tableId,
method: 'get'
})
}
// 获取详细信息
export const getTableDetails = (tableId) => {
return request({
url: '/custom/query/table/' + tableId,
method: 'get'
})
}
// 导入表信息
export const addTableInfo= (data) => {
return request({
url: '/custom/query/table/import',
method: 'post',
data
})
}
// 修改自定义查询表格维护
export const editTable = (data) => {
return request({
url: '/custom/query/table',
method: 'put',
data
})
}
// 同步数据库
export const syncDatabase = (tableId) => {
return request({
url: '/custom/query/table/sync/'+ tableId,
method: 'put'
})
}
// 删除自定义查询表格维护
export const delTable=(tableId) => {
return request({
url: '/custom/query/table/' + tableId,
method: 'delete'
})
}

View File

@@ -0,0 +1,47 @@
import request from '@/utils/request.js'
// 获取topo拖拽数据信息
export const getTopoDragInfo = (queryId) => {
return request({
url: '/custom/query/topo/search/' + queryId,
method: 'get'
})
}
export const saveTopo = (data) => {
return request({
url: '/custom/query/topo/search',
method: 'post',
data
})
}
export const previewTopo = (data,pageInfo) => {
return request({
url: '/custom/query/topo/search/preview',
method: 'post',
data,
params:pageInfo,
})
}
export const previewTopologyData = (data,pageInfo) => {
return request({
url: '/custom/query/topo/search/preview/data',
method: 'post',
data,
params:pageInfo,
})
}
export const topoToLine = (data) => {
return request({
url: '/custom/query/topo/search/publish',
method: 'post',
data
})
}
export const topoDownLine = (queryId) => {
return request({
url: '/custom/query/topo/search/cancel/'+queryId,
method: 'put'
})
}

View File

@@ -0,0 +1,42 @@
import request from '@/utils/request.js'
// 获取topoList
export const getTopoList = (params) => {
return request({
url: '/custom/query/topo/uni',
method: 'get',
params
})
}
// 获取topo详情
export const getTopoDetails = (topoId) => {
return request({
url: '/custom/query/topo/uni/' + topoId,
method: 'get'
})
}
// 新增topo
export const addTopo = (data) => {
return request({
url: '/custom/query/topo/uni',
method: 'post',
data
})
}
// 修改topo
export const editTopo = (data) => {
return request({
url: '/custom/query/topo/uni',
method: 'put',
data
})
}
// 删除topo
export const delTopo =(idList) => {
return request({
url: '/custom/query/topo/uni/' + idList,
method: 'delete'
})
}

View File

@@ -1,107 +0,0 @@
import request from '@/utils/request.js'
import axios from "axios";
import {getToken} from "@/utils/auth";
export const addAllocation = (data) => {
return request({
url:'/workflow/mosr/cost/allocation',
method: "post",
data
});
};
export const addShare = (data) => {
return request({
url:'/workflow/mosr/cost/share',
method: "post",
data
});
};
export const getAllocationDetail = (allocationId) => {
return request({
url: `/workflow/mosr/cost/allocation/info/${allocationId}`,
method: "get"
});
};
export const getAllocationDetails = (allocationId) => {
return request({
url: `/workflow/mosr/cost/allocation/usr/detail/${allocationId}`,
method: "get"
});
};
export const getAllocationSummaryDetails = (params) => {
return request({
url: '/workflow/mosr/cost/allocation/collect',
method: "get",
params:params
});
};
export const getAllocationProcess = () => {
return request({
url: '/workflow/mosr/cost/allocation/process',
method: "get"
});
};
export const getAllocationDetailList = (params) => {
return request({
url: '/workflow/mosr/cost/allocation/usr',
method: "get",
params:params
});
};
export const getResearchUser = () => {
return request({
url: '/admin/mosr/user/research',
method: "get"
});
};
export const getProjectOption = () => {
return request({
url: '/workflow/mosr/project/implementation/in/implementation/option',
method: "get"
});
};
export const editAllocation = (data) => {
return request({
url: '/workflow/mosr/cost/allocation/edit',
method: "post",
data
});
};
export const applyCcSend = (data) => {
return request({
url: '/workflow/mosr/cc/send',
method: "post",
data
});
};
export const deleteAllocation = (id) => {
return request({
url: `/workflow/mosr/cost/allocation/${id}`,
method: "delete"
});
};
export const shareExportExcel = (allocationId) => {
return axios.get(
`${import.meta.env.VITE_BASE_URL}/workflow/mosr/cost/allocation/collect/${allocationId}`,
{
responseType: 'blob',
headers: {
Authorization: getToken()
}
}
);
};
export const shareDetailExport= (data) => {
return axios.post(
`${import.meta.env.VITE_BASE_URL}/workflow/mosr/cost/share/export`,
data, {
responseType: 'blob',
headers: {
Authorization: getToken()
}
}
);
};

View File

@@ -1,31 +1,8 @@
import request from '@/utils/request.js'
export const getHomeTaskInfo = () => {
export const getHomeInfo = () => {
return request({
url: '/workflow/mosr/process/task',
method: "get"
});
};
//获取已办数据
export const getDoneTaskInfo = () => {
return request({
url: '/workflow/mosr/process/task/about',
method: "get"
});
};
//获取专项资金饼图数据
export const getSpecialFundChart = () => {
return request({
url: '/workflow/home/page/statistic',
method: "get"
});
};
//获取首页四个统计数量
export const getHomeStatistics = () => {
return request({
url: '/workflow/mosr/process/task/statistics',
method: "get"
});
};

View File

@@ -7,7 +7,6 @@ export const getCodeImg = () => {
})
}
export const login = (data) => {
return request({
url: '/auth/login',
@@ -15,12 +14,6 @@ export const login = (data) => {
data
})
}
export const switchAccount = (userId) => {
return request({
url: `/auth/switch/account/${userId}`,
method: 'post',
})
}
export const getUserInfo = () => {
return request({
@@ -28,9 +21,3 @@ export const getUserInfo = () => {
method: 'get',
})
}
export const getAuthInfo = () => {
return request({
url: '/admin/mosr/user/detail/info',
method: 'get',
})
}

View File

@@ -1,7 +1,4 @@
import request from '@/utils/request.js'
import axios from "axios";
import {getToken} from "@/utils/auth";
//需求征集
export const getDemandInfo = (param) => {
return request({
@@ -10,12 +7,6 @@ export const getDemandInfo = (param) => {
params: param
});
};
export const filterRequirementName = (requirementName) => {
return request({
url: `/workflow/mosr/requirement/match/${requirementName}`,
method: "get"
});
};
export const getWorkflowInfo = () => {
return request({
url: '/workflow/mosr/requirement/process',
@@ -91,38 +82,3 @@ export const deleteDemand = (id) => {
method: "delete"
});
};
export const getRequirementStatePerm = () => {
return request({
url: '/workflow/mosr/requirement/prem/state',
method: "get"
});
};
export const downloadTemplate = (type) => {
return request({
url: '/workflow/mosr/attachment/download/template',
method: "get",
responseType:'blob',
params:{
type:type
}
});
};
export const downloadTemplateZip = (typeList) => {
return axios.get(
`${import.meta.env.VITE_BASE_URL}/workflow/mosr/attachment/download/pack?typeList=${typeList}`,
{
responseType: 'blob',
headers: {
Authorization: getToken()
},
}
);
// return request({
// url: '/workflow/mosr/attachment/download/pack',
// method: "get",
// responseType:'blob',
// params:{
// typeList:typeList
// }
// });
};

View File

@@ -1,123 +0,0 @@
import request from '@/utils/request'
export const fileUp = (url, data) => {
return request({
url,
method: 'post',
data,
headers: {
'Content-Type': 'multipart/form-data'
}
})
}
export const requirementReported = (data) => {
return request({
url: '/workflow/mosr/requirement/reported',
method: "post",
data: data
});
};
//需求汇总-征集名称关键词匹配
export const getRequirementName = (requirementName) => {
return request({
url: `/workflow/mosr/requirement/collect/project/match/${requirementName}`,
method: "get"
});
};
//需求汇总-项目名称关键词匹配
export const getProjectName = (projectName) => {
return request({
url: `workflow/mosr/requirement/collect`,
method: "get",
params:{
projectName:projectName
}
});
};
//获取需求上报 流程信息
export const getProcessInfo = (specialFund) => {
return request({
url: `/workflow/mosr/requirement/collect/process/${specialFund}`,
method: "get"
});
};
export const getDetail = (projectId) => {
return request({
url: `/workflow/mosr/requirement/collect/info/${projectId}`,
method: "get"
});
};
export const resubmitReported = (data) => {
return request({
url: '/workflow/mosr/requirement/collect/resubmit',
method: "post",
data: data
});
};
export const getCollectAttachment = (params) => {
return request({
url: '/workflow/mosr/requirement/collect/attachments',
method: "get",
params:params
});
};
export const uploadCollectAttachment= (data) => {
return request({
url: '/workflow/mosr/requirement/collect/upload',
method: "post",
data: data
});
};
// 年度计划
export const addPlan= (data) => {
return request({
url: '/workflow/annual/plan',
method: "post",
data: data
});
};
export const editPlan= (data) => {
return request({
url: '/workflow/annual/plan',
method: "put",
data: data
});
};
export const getPlan= (annualPlanId) => {
return request({
url: `/workflow/annual/plan/info/${annualPlanId}`,
method: "get"
});
};
export const deletePlan= (annualPlanId) => {
return request({
url: `/workflow/annual/plan/${annualPlanId}`,
method: "delete"
});
};
export const approvePlan= (data) => {
return request({
url: '/workflow/annual/plan/approve',
method: "post",
data: data
});
};
export const getProjectOption = () => {
return request({
url: '/workflow/mosr/requirement/master',
method: "get"
});
};
export const getRequirementOption = () => {
return request({
url: '/workflow/mosr/requirement/option',
method: "get"
});
};

View File

@@ -1,38 +0,0 @@
import request from '@/utils/request.js'
export const searchFileList = (params) => {
return request({
url: `/workflow/mosr/attachment/list`,
method: "get",
params: params
});
};
export const searchAllFileList = (params) => {
return request({
url: '/workflow/mosr/attachment/all',
method: "get",
params: params
});
};
export const uploadFileList = (data) => {
return request({
url: '/workflow/mosr/attachment/upload',
method: "post",
data: data
});
};
export const searchImplementationFileList = (params) => {
return request({
url: '/workflow/mosr/attachment/implementation/list',
method: "get",
params: params
});
};
export const switchAttachmentState = (data) => {
return request({
url: '/workflow/mosr/project/filing/attachment/switch',
method: "post",
data
});
};

View File

@@ -1,240 +1,86 @@
import request from '@/utils/request.js'
import axios from "axios";
import {getToken} from "@/utils/auth";
//项目立项
export const getApplyProcess = (projectId) => {
return request({
url: `/workflow/mosr/project/approval/initiation/process/${projectId}`,
method: "get"
});
};
export const filterProjectName = (projectName,targetState) => {
return request({
url: `/workflow/mosr/project/approval/match/${projectName}/${targetState}`,
method: "get"
});
return request({
url: `/workflow/mosr/project/approval/initiation/process/${projectId}`,
method: "get"
});
};
export const projectApply = (data) => {
return request({
url: '/workflow/mosr/project/approval/initiation/apply',
method: "post",
data: data
});
return request({
url: '/workflow/mosr/project/approval/initiation/apply',
method: "post",
data: data
});
};
export const getApplyDetail = (ProjectId) => {
return request({
url: `/workflow/mosr/project/approval/info/${ProjectId}`,
method: "get"
});
return request({
url: `/workflow/mosr/project/approval/info/${ProjectId}`,
method: "get"
});
};
export const resubmitApply = (data) => {
return request({
url: '/workflow/mosr/project/approval/initiation/resubmit',
method: "post",
data: data
});
};
export const getInitiationAttachment = (params) => {
return request({
url: '/workflow/mosr/project/approval/attachments',
method: "get",
params: params
});
return request({
url: '/workflow/mosr/project/approval/initiation/resubmit',
method: "post",
data: data
});
};
//项目实施
export const getCheckDetail = (projectId) => {
return request({
url: `/workflow/mosr/project/implementation/info/${projectId}`,
method: "get"
});
return request({
url: `/workflow/mosr/project/implementation/info/${projectId}`,
method: "get"
});
};
export const resubmitCheck = (data) => {
return request({
url: '/workflow/mosr/project/implementation/resubmit',
method: "post",
data: data
});
return request({
url: '/workflow/mosr/project/implementation/resubmit',
method: "post",
data: data
});
};
export const projectCheck = (data) => {
return request({
url: '/workflow/mosr/project/implementation/initiation/check',
method: "post",
data: data
});
return request({
url: '/workflow/mosr/project/implementation/initiation/check',
method: "post",
data: data
});
};
export const getProjectCheckProcess = (projectId) => {
return request({
url: `/workflow/mosr/project/implementation/process/${projectId}`,
method: "get"
});
};
export const addLedger = (data) => {
return request({
url: '/workflow/mosr/expense/ledger',
method: "post",
data: data
});
};
export const getTags = (projectId) => {
return request({
url: `/workflow/mosr/attachment/option/${projectId}`,
method: "get"
});
};
export const getTagList = (projectId) => {
return request({
url: `/workflow/mosr/file/tag/list`,
method: "get",
params:{
projectId: projectId
}
});
};
export const addTag = (data) => {
return request({
url: '/workflow/mosr/file/tag/add',
method: "post",
data:data
});
};
export const updateTag = (data) => {
return request({
url: '/workflow/mosr/file/tag/update',
method: "post",
data:data
});
};
export const delTag = (tageId) => {
return request({
url: `/workflow/mosr/file/tag/${tageId}`,
method: "delete"
});
};
export const getPhaseProcess = () => {
return request({
url: '/workflow/phase/change/process',
method: "get"
});
};
export const submitPhaseChange = (data) => {
return request({
url: '/workflow/phase/change',
method: "post",
data: data
});
};
export const getPhaseDetail = (projectId) => {
return request({
url: `/workflow/phase/change/info/${projectId}`,
method: "get"
});
};
export const getPhaseForm = (projectId) => {
return request({
url: `/workflow/phase/change/from/${projectId}`,
method: "get"
});
};
export const resubmitPhaseForm = (data) => {
return request({
url: '/workflow/phase/change/resubmit',
method: "post",
data: data
});
return request({
url: `/workflow/mosr/project/implementation/process/${projectId}`,
method: "get"
});
};
//项目归档
export const getConclusionDetail = (ProjectId) => {
return request({
url: `/workflow/mosr/project/filing/info/${ProjectId}`,
method: "get"
});
return request({
url: `/workflow/mosr/project/filing/info/${ProjectId}`,
method: "get"
});
};
export const resubmitConclusion = (data) => {
return request({
url: '/workflow/mosr/project/filing/resubmit',
method: "post",
data: data
});
return request({
url: '/workflow/mosr/project/filing/resubmit',
method: "post",
data: data
});
};
export const projectConclusion = (data) => {
return request({
url: '/workflow/mosr/project/filing/project/entry',
method: "post",
data: data
});
return request({
url: '/workflow/mosr/project/filing/project/entry',
method: "post",
data: data
});
};
export const getProjectConclusionProcess = () => {
return request({
url: '/workflow/mosr/project/filing/process',
method: "get"
});
};
//获取前置流程
export const getPreProcess = () => {
return request({
url: '/workflow/details/pre/process',
method: "get"
});
};
export const updateLedger = (data) => {
return request({
url: '/workflow/mosr/expense/ledger/replenishment',
method: "post",
data: data
});
};
export const searchUpdateLedgerData = (projectId) => {
return request({
url: `/workflow/mosr/expense/ledger/${projectId}`,
method: "get"
});
};
//
// export const searchUpdateLedgerData = (projectId) => {
// return request({
// url: '/workflow/mosr/expense/ledger/import',
// method: "get"
// });
// };
export const exportExcel = (data) => {
return axios.post(
`${import.meta.env.VITE_BASE_URL}/workflow/mosr/project/implementation/export`,
data, {
responseType: 'blob',
headers: {
Authorization: getToken()
}
}
);
};
//台账模板下载
export const ledgerTemplateDownload = () => {
return axios.get(
`${import.meta.env.VITE_BASE_URL}/workflow/mosr/project/implementation/download/template`,
{
responseType: 'blob',
headers: {
Authorization: getToken()
}
}
);
};
//费用明细模板下载
export const costTemplateDownload = () => {
return axios.get(
`${import.meta.env.VITE_BASE_URL}/workflow/mosr/rd/expense/download/template`,
{
responseType: 'blob',
headers: {
Authorization: getToken()
}
}
);
return request({
url: '/workflow/mosr/project/filing/process',
method: "get"
});
};

View File

@@ -1,36 +0,0 @@
import request from '@/utils/request.js'
export const getResearchFundChart = (year) => {
return request({
url: '/workflow/mosr/rd/home',
method: 'get',
params: {year:year}
})
}
export const getResearchFundDetail = (rdFundId) => {
return request({
url: `/workflow/mosr/rd/${rdFundId}`,
method: "get"
});
};
export const addResearchFund= (data) => {
return request({
url: '/workflow/mosr/rd/add',
method: "post",
data
});
};
export const editResearchFund= (data) => {
return request({
url: '/workflow/mosr/rd/update',
method: "post",
data
});
};
export const deleteResearchFund = (rdFundIds) => {
return request({
url: `/workflow/mosr/rd/${rdFundIds}`,
method: "delete"
});
};

View File

@@ -1,46 +0,0 @@
import request from '@/utils/request.js'
export const getFundDetail = (specialFundId) => {
return request({
url: `/workflow/mosr/special/fund/from/${specialFundId}`,
method: "get"
});
};
export const getFundDetailProcess = (specialFundId) => {
return request({
url: `/workflow/mosr/special/fund/info/${specialFundId}`,
method: "get"
});
};
export const getFundOption = () => {
return request({
url: '/workflow/mosr/special/fund/option',
method: "get"
});
};
export const getFundProcess = (specialFundId) => {
return request({
url: '/workflow/mosr/special/fund/process',
method: "get"
});
};
export const addFund= (data) => {
return request({
url: '/workflow/mosr/special/fund',
method: "post",
data
});
};
export const resubmitFund= (data) => {
return request({
url: '/workflow/mosr/special/fund/resubmit',
method: "post",
data
});
};
export const deleteFund = (id) => {
return request({
url: `/workflow/mosr/special/fund/${id}`,
method: "delete"
});
};

View File

@@ -14,17 +14,3 @@ export const getDepartmentList=(params)=>{
params
})
}
export const getCompanyDetail=(companyId)=>{
return request({
url:`/admin/mosr/sub/company/info/${companyId}`,
method:'get'
})
}
export const setCompanyLeader=(data)=>{
return request({
url:'/admin/mosr/sub/company/leader',
method:'post',
data:data
})
}

View File

@@ -18,13 +18,6 @@ export const getConfigDetails = (configId) => {
method: 'get'
})
}
// 获取参数配置表详情
export const getConfigByKey = (configKey) => {
return request({
url: '/admin/config/key/' + configKey,
method: 'get'
})
}
// 新增参数配置表
export const addConfig = (data) => {

View File

@@ -49,10 +49,3 @@ export const delDictType =(dictTypeId) => {
method: 'delete'
})
}
//字典刷新缓存
export const refreshDict =() => {
return request({
url: 'admin/dict/type/refresh',
method: 'post'
})
}

View File

@@ -50,4 +50,4 @@ export const getMenuOptRole = (roleId) => {
url: '/admin/menu/option/role/'+roleId,
method: 'get'
})
}
}

View File

@@ -15,18 +15,6 @@ export const getSubCompOpt = () => {
method: 'get'
})
}
export const getUserAccount = () => {
return request({
url: `/admin/mosr/user/account/list`,
method: 'get'
})
}
export const judgeIsSameRole = (userId) => {
return request({
url: `/admin/mosr/user/company/same/${userId}`,
method: 'get'
})
}
// 查询角色信息
export const getRolesOpt = () => {
@@ -44,13 +32,6 @@ export const getJobOpt = () => {
})
}
export const getMosrUserList = (params) => {
return request({
url: '/admin/mosr/user',
method: 'get',
params
})
}
export const getUserList = (params) => {
return request({
url: '/admin/user',
@@ -68,9 +49,9 @@ export const getUserDetail = (userId) => {
// 操作
export const operate = (data, type) => {
// console.log(type ,'type');
if (data.userId && type !== '0') return editUser(data)
else if (type == '0') return editUserOA(data)
console.log(type ,'type');
if(data.userId && type !== '0') return editUser(data)
else if(type == '0') return editUserOA(data)
return addUser(data)
}
@@ -198,54 +179,3 @@ export const unbindAllUserByPost = (postId) => {
}
})
}
export const bindAccount = (data) => {
return request({
url: '/admin/mosr/user/bind/account',
method: 'post',
data
})
}
export const getBindAccount = (userId) => {
return request({
url: `/admin/mosr/user/bind/account/info/${userId}`,
method: 'get'
})
}
export const checkMatrix = (userId) => {
return request({
url: `/admin/mosr/user/matrix?userId=` + userId,
method: 'get'
})
}
export const getAgentInfo=(userId)=>{
return request({
url: `/admin/mosr/user/approval/agent/${userId}`,
method:'get'
})
}
export const editAgentInfo=(data)=>{
return request({
url:'/admin/mosr/user/approval/agent',
method:'post',
data
})
}
export const addWhiteUser=(data)=>{
return request({
url:'/admin/approve/white',
method:'post',
data
})
}
export const delWhiteUser=(data)=>{
return request({
url:'/admin/approve/white',
method:'delete',
data
})
}

View File

@@ -68,11 +68,4 @@ export function getTypeOption() {
})
}
export function getFromPerm(processKey) {
return request({
url: "/workflow/process/definition/from/perm/"+processKey,
method: "get",
})
}

View File

@@ -5,7 +5,6 @@ export function getUserTree(type,chooseId){
return request({
url:`/admin/user/choose/${type}/${chooseId}`,
method:'get'
})
}
@@ -23,25 +22,10 @@ export function getDepartmentTree() {
method: 'get'
})
}
export function getMosrUser(params) {
export function getMosrDept(params) {
return request({
url: '/admin/mosr/user/choose',
method: 'get',
params:params
})
}
export function getOrganizationStructure(params) {
return request({
url: '/admin/organizational/structure/choose',
method: 'get',
params:params
})
}
export function getOrganizationStructureTree(params) {
return request({
url: '/admin/organizational/structure/tree',
method: 'get',
params: params
})
}

View File

@@ -1,77 +0,0 @@
tinymce.PluginManager.add('axupimgs', function (editor, url) {
var pluginName = '多图片上传';
window.axupimgs = {}; //扔外部公共变量,也可以扔一个自定义的位置
const baseURL = import.meta.env.VITE_BASE_URL
// var baseURL=tinymce.baseURL;
var iframe1 = '/upfiles.html';
console.log('editor',editor)
axupimgs.images_upload_handler = editor.getParam('images_upload_handler_not_loading', undefined, 'function');
axupimgs.images_upload_base_path = editor.getParam('images_upload_base_path', '', 'string');
axupimgs.axupimgs_filetype = editor.getParam('axupimgs_filetype', '.png,.gif,.jpg,.jpeg', 'string');
axupimgs.res = [];
var openDialog = function () {
return editor.windowManager.openUrl({
title: pluginName,
size: 'large',
url: iframe1,
buttons: [
{
type: 'cancel',
text: 'Close'
},
{
type: 'custom',
text: 'Save',
name: 'save',
primary: true
},
],
onAction: function (api, details) {
switch (details.name) {
case 'save':
var html = '';
var imgs = axupimgs.res;
var len = imgs.length;
for (let i = 0; i < len; i++) {
if (imgs[i].url) {
html += '<img src="' + imgs[i].url + '" />';
}
}
editor.insertContent(html);
axupimgs.res = [];
api.close();
break;
default:
break;
}
}
});
};
editor.ui.registry.getAll().icons.axupimgs || editor.ui.registry.addIcon('axupimgs', '<svg viewBox="0 0 1280 1024" xmlns="http://www.w3.org/2000/svg" width="24" height="24"><path d="M1126.2,779.8V87.6c0-24-22.6-86.9-83.5-86.9H83.5C14.7,0.7,0,63.7,0,87.7v692c0,36.2,29.2,89.7,83.5,89.7l959.3-1.3c51.7,0,83.5-42.5,83.5-88.3zm-1044,4V86.3h961.6V783.7H82.2v0.1z" fill="#53565A"/><path d="M603,461.6L521.1,366.3,313,629.8,227.2,546.8,102.4,716.8H972.8v-170L768.2,235.2,603.1,461.6zM284.6,358.4a105.4,105.4,0,0,0,73.5-30c19.5-19.1,30.3-45,30.2-71.8,0-56.8-45.9-103-102.4-103-56.6,0-102.4,46.1-102.4,103C183.4,313.5,228,358.4,284.6,358.4z" fill="#9598A0"/><path d="M1197.7,153.6l-0.3,669.3s13.5,113.9-67.4,113.9H153.6c0,24.1,23.9,87.2,83.5,87.2h959.3c58.3,0,83.6-49.5,83.6-89.9V240.8c-0.1-41.8-44.9-87.2-82.3-87.2z" fill="#53565A"/></svg>');
editor.ui.registry.addButton('axupimgs', {
icon: 'axupimgs',
tooltip: pluginName,
onAction: function () {
openDialog();
}
});
editor.ui.registry.addMenuItem('axupimgs', {
icon: 'axupimgs',
text: '图片批量上传...',
onAction: function () {
openDialog();
}
});
return {
getMetadata: function () {
return {
name: pluginName,
url: "http://tinymce.ax-z.cn/more-plugins/axupimgs.php",
};
}
};
});

View File

@@ -1,75 +0,0 @@
tinymce.PluginManager.add('axupimgs', function(editor, url) {
var pluginName='Ax多图片上传';
window.axupimgs={}; //扔外部公共变量,也可以扔一个自定义的位置
var baseURL=tinymce.baseURL;
var iframe1 = baseURL+'/plugins/axupimgs/upfiles.html';
axupimgs.images_upload_handler = editor.getParam('images_upload_handler', undefined, 'function');
axupimgs.images_upload_base_path = editor.getParam('images_upload_base_path', '', 'string');
axupimgs.axupimgs_filetype = editor.getParam('axupimgs_filetype', '.png,.gif,.jpg,.jpeg', 'string');
axupimgs.res=[];
var openDialog = function() {
return editor.windowManager.openUrl({
title: pluginName,
size: 'large',
url:iframe1,
buttons: [
{
type: 'cancel',
text: 'Close'
},
{
type: 'custom',
text: 'Save',
name: 'save',
primary: true
},
],
onAction: function (api, details) {
switch (details.name) {
case 'save':
var html = '';
var imgs = axupimgs.res;
var len = imgs.length;
for(let i=0;i<len;i++){
if( imgs[i].url ){
html += '<img src="'+imgs[i].url+'" />';
}
}
editor.insertContent(html);
axupimgs.res=[];
api.close();
break;
default:
break;
}
}
});
};
editor.ui.registry.getAll().icons.axupimgs || editor.ui.registry.addIcon('axupimgs','<svg viewBox="0 0 1280 1024" xmlns="http://www.w3.org/2000/svg" width="24" height="24"><path d="M1126.2,779.8V87.6c0-24-22.6-86.9-83.5-86.9H83.5C14.7,0.7,0,63.7,0,87.7v692c0,36.2,29.2,89.7,83.5,89.7l959.3-1.3c51.7,0,83.5-42.5,83.5-88.3zm-1044,4V86.3h961.6V783.7H82.2v0.1z" fill="#53565A"/><path d="M603,461.6L521.1,366.3,313,629.8,227.2,546.8,102.4,716.8H972.8v-170L768.2,235.2,603.1,461.6zM284.6,358.4a105.4,105.4,0,0,0,73.5-30c19.5-19.1,30.3-45,30.2-71.8,0-56.8-45.9-103-102.4-103-56.6,0-102.4,46.1-102.4,103C183.4,313.5,228,358.4,284.6,358.4z" fill="#9598A0"/><path d="M1197.7,153.6l-0.3,669.3s13.5,113.9-67.4,113.9H153.6c0,24.1,23.9,87.2,83.5,87.2h959.3c58.3,0,83.6-49.5,83.6-89.9V240.8c-0.1-41.8-44.9-87.2-82.3-87.2z" fill="#53565A"/></svg>');
editor.ui.registry.addButton('axupimgs', {
icon: 'axupimgs',
tooltip: pluginName,
onAction: function() {
openDialog();
}
});
editor.ui.registry.addMenuItem('axupimgs', {
icon: 'axupimgs',
text: '图片批量上传...',
onAction: function() {
openDialog();
}
});
return {
getMetadata: function() {
return {
name: pluginName,
url: "http://tinymce.ax-z.cn/more-plugins/axupimgs.php",
};
}
};
});

Binary file not shown.

Before

Width:  |  Height:  |  Size: 750 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 736 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 743 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 733 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 183 KiB

View File

@@ -60,7 +60,7 @@ html, body, #app, .el-container, .el-aside, .el-main {
top: 0;
bottom: 0;
left: 0;
//z-index: 1001;
z-index: 1001;
}
.el-dialog {
@@ -374,21 +374,20 @@ html, body, #app, .el-container, .el-aside, .el-main {
left: 200px;
}
//.el-overlay-dialog {
// left: 200px !important;
//}
//放大缩小按钮上外边距
.scale {
margin-top: 10px;
//z-index: 666;
//position: static;
z-index: 666;
position: static;
//top: -20px;
}
.el-overlay-dialog {
left: 200px !important;
}
.el-overlay-dialog::-webkit-scrollbar, .scrollbar-dict::-webkit-scrollbar {
width: 6px;
height: 6px;
}
// 滚动条轨道
@@ -406,9 +405,7 @@ html, body, #app, .el-container, .el-aside, .el-main {
.nowrap {
white-space: pre
}
.el-empty__description {
margin-top: 0!important;
}
//SvgIcon组件的样式
.home-icon {
width: 4em;
@@ -418,13 +415,7 @@ html, body, #app, .el-container, .el-aside, .el-main {
overflow: hidden;
margin-right: 5px;
}
.oran-icon{
width: 1em;
height: 1em;
margin-right: 4px;
vertical-align: -0.21em;
}
.svg-icon {
width: 1.2em;
height: 1.2em;
@@ -474,16 +465,7 @@ html, body, #app, .el-container, .el-aside, .el-main {
width: 1.8em;
height: 1.7em;
}
.home-time{
width: 1.4em;
height: 1.4em;
margin-right: 5px;
}
.file-svg{
width: 1.4em;
height: 1.4em;
fill: #BEA266;
}
.middle-icon {
width: 1.4em;
height: 1.4em;
@@ -563,37 +545,7 @@ html, body, #app, .el-container, .el-aside, .el-main {
// 操作页面底部按钮
.oper-page-btn {
position: fixed;
top: 135px;
bottom: 15px;
right: 15px;
z-index: 5;
}
.approval-record {
//padding-top: 10px;
padding-bottom: 30px;
position: relative;
.approval-title {
display: flex;
align-items: center;
//justify-content: space-between;
.diagram {
display: flex;
align-items: center;
float: right;
.base-title {
margin-left: 10px;
margin-right: 10px;
}
//.el-switch {
// margin-left: 15px;
//}
}
}
.process {
position: relative;
}
}

View File

@@ -2,7 +2,7 @@
border-radius: 10px;
}
.logo {
height: 65px;
height: 106px;
background-color: #BEA266;
color: #ffffff;
font-weight: bold;
@@ -10,13 +10,6 @@
display: flex;
justify-content: center;
align-items: center;
box-sizing: border-box;
padding: 10px;
& > img {
object-fit: scale-down;
width: 100%;
height: 40px;
}
}
.port-link{
display: block;

View File

@@ -1 +0,0 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1717294999406" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="10473" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><path d="M721.7 259.8h140l-196-196v140c0 31 25 56 56 56z" fill="#2c2c2c" p-id="10474"></path><path d="M469.7 749.8c0-146.7 119.3-266 266-266 45.6 0 88.5 11.5 126 31.8V301.8h-140c-54 0-98-44-98-98v-140h-490c-30.9 0-56 25.1-56 56v784c0 30.9 25.1 56 56 56H573c-62.7-48.7-103.3-124.6-103.3-210z m-252-426.5h308c15.5 0 28 12.5 28 28s-12.5 28-28 28h-308c-15.5 0-28-12.5-28-28s12.5-28 28-28z m98 424.1h-98c-15.5 0-28-12.5-28-28s12.5-28 28-28h98c15.5 0 28 12.5 28 28s-12.6 28-28 28z m56-184h-154c-15.5 0-28-12.5-28-28s12.5-28 28-28h154c15.5 0 28 12.5 28 28s-12.6 28-28 28z" fill="#2c2c2c" p-id="10475"></path><path d="M735.7 539.8c-116 0-210 94-210 210s94 210 210 210 210-94 210-210-94.1-210-210-210z m69.1 163.5c12.9 0 23.3 10.5 23.3 23.4 0 12.9-10.4 23.3-23.3 23.3h-46.6v23.3h46.6c12.9 0 23.3 10.4 23.3 23.3s-10.4 23.3-23.3 23.3h-46.6v46.7c0 12.9-10.4 23.3-23.3 23.3s-23.3-10.4-23.3-23.3v-46.7H665c-12.9 0-23.3-10.4-23.3-23.3s10.4-23.3 23.3-23.3h46.6V750H665c-12.9 0-23.3-10.4-23.3-23.3s10.4-23.3 23.3-23.3h37.3l-53.9-53.8c-9.1-9.1-9.1-23.9 0-33 9.1-9.1 23.9-9.1 33 0l53.4 53.3 55.5-53.6c9.2-8.9 24-8.7 33 0.6 9 9.2 8.7 24-0.6 33l-55.5 53.3h37.6z" fill="#2c2c2c" p-id="10476"></path></svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -1 +0,0 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1717295020643" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="11515" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><path d="M683.604677 560.04317c-28.140302-46.866394-27.62866-47.68502-27.62866-47.685021s-97.007295 27.219346-115.017088-65.797142h-56.178275s-15.451584 93.118817-114.607775 65.592486c-28.651944 47.787349-29.675227 49.219946-29.675227 49.322274 0 0 77.564905 54.234036 0 127.808134l30.08454 49.526931s85.648846-36.940542 113.68682 63.955232h56.894573s17.805136-92.811832 114.198462-65.387829c27.424003-46.866394 27.833317-47.275707 27.833316-47.275707s-72.755471-62.829619 0.409314-130.059358zM511.590687 690.102528c-36.224243 0-65.592485-29.368242-65.592486-65.592485 0-36.224243 29.368242-65.592485 65.592486-65.592485 36.224243 0 65.592485 29.368242 65.592485 65.592485 0 36.224243-29.368242 65.592485-65.592485 65.592485z" fill="#2c2c2c" p-id="11516"></path><path d="M716.554412 255.718597c7.674628-12.791046 14.939942-25.684421 21.898271-38.168482 7.674628-14.121315 13.098031-24.865794 16.065554-31.210153C818.780454 77.462576 755.848506-1.22794 631.92885 35.81493c-12.381733 4.297792-30.903168 10.232837-52.903768 16.27021-13.405016 3.683821-26.912361 6.856001-40.522034 9.618867-15.349256 3.376836-31.005496 5.321075-46.764065 5.730389-11.767763 0-25.991406-1.534926-42.261617-4.40012-32.540422-6.242031-64.466873-15.04227-95.677026-26.093734C228.141101 0 166.437094 76.541621 230.187669 188.386529c2.455881 5.321075 8.80024 17.907465 17.805136 34.280004 9.107225 16.577196 18.930748 33.25672 29.265914 49.833917C116.296193 366.540222 9.874688 533.233137 9.874688 729.089637c0 47.889677 6.242031 95.063056 18.419106 140.701509 1.432597 9.925852 5.116419 22.409913 10.335166 34.075347l1.22794 3.479165 7.879285 22.61457h5.730388c30.596183 42.568602 83.090637 66.820426 146.431898 66.820426h625.32867c92.607175 0 159.836914-51.47117 170.888378-131.389628 11.870091-44.512841 17.702808-90.355951 17.60048-136.301389 0-209.159189-120.747477-386.187269-297.161587-473.37104zM930.727691 852.395323c-6.958329 48.810633-44.717498 77.564905-105.50055 77.564905H199.898471c-48.094334 0-82.476666-18.521435-98.030579-48.810633l-1.330268-2.353552-0.204657-0.818627c-3.274508-7.060658-5.423404-14.632957-6.651344-22.307585-11.153792-41.340662-16.884181-83.909264-16.98651-126.682522 0-183.372439 106.626162-337.78595 263.08624-414.327571l34.791646-16.884181-21.898271-31.824123c-23.637854-34.586989-44.717498-70.811232-63.341261-108.365744-34.893974-61.397022-22.716898-76.439292 43.591885-56.996902 9.925852 3.683821 29.368242 10.02818 52.699111 16.372539 17.907465 4.911762 35.303288 9.004897 51.880484 11.870091 19.851704 3.581493 37.963825 5.525732 54.131707 5.525732 17.293495 0 37.247527-2.455881 59.964425-6.958329 14.4283-2.865194 29.675227-6.549016 45.126811-10.846807 18.82842-5.116419 37.452183-10.846807 55.871291-17.293495 64.262216-19.135405 77.360248-3.069851 42.67093 55.564305-3.888478 7.879285-8.80024 17.702808-15.963226 30.698511-11.870091 21.898271-25.172779 44.512841-39.601079 66.615769L617.398221 286.519436l37.963826 15.144599C825.94344 369.507745 946.690916 533.130808 946.690916 728.987309c0 41.954632-5.525732 83.295293-15.963225 123.408014z m0 0" fill="#2c2c2c" p-id="11517"></path></svg>

Before

Width:  |  Height:  |  Size: 3.4 KiB

View File

@@ -1 +0,0 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1717294973537" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="9231" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><path d="M736.3 722.8c-15.9 0-31.5-0.6-46.6-1.8-5.4 19-12.7 37.8-23.7 54.3-9.1 18-21.6 33.8-36.2 47.9 32 5.6 68.5 8.8 106.5 8.8 119.6 0 223.7-31.2 223.7-72.8v-93.6c-46.8 31.2-124.8 57.2-223.7 57.2zM192.5 201.1c7.7 5.2 15.5 10.4 20.7 18.1 7.7 5.2 12.9 12.9 18.1 20.7 2.6 5.2 7.7 10.3 10.4 15.5 5.2 5.2 7.7 10.3 10.3 15.5 2.6 5.2 7.7 12.9 10.3 18.1h173.3c2.6-5.2 7.7-10.3 10.4-18.1 2.6-5.2 5.2-10.3 10.3-15.5 2.6-2.6 5.2-5.2 7.7-10.4 5.2-7.7 10.3-15.5 15.5-20.7 5.2-7.7 12.9-12.9 23.2-20.7 5.2-2.6 10.3-5.2 12.9-10.3 2.6-5.2 5.2-7.7 5.2-12.9s0-7.7-2.6-12.9-5.2-7.7-10.3-10.3c-5.2-2.6-10.3-2.6-12.9-2.6-2.6 0-7.7 2.6-10.4 2.6-2.6 0-7.7 2.6-10.3 5.2-2.6 2.6-7.7 2.6-12.9 2.6s-10.3 0-12.9-2.6c-2.6-2.6-7.7-5.2-10.4-7.7-2.6-2.6-5.2-5.2-10.3-7.7-2.6-2.6-7.7-5.2-12.9-7.7-10.3-5.2-20.7-5.2-25.9-2.6-7.7 2.6-12.9 7.7-20.7 12.9-5.2 5.2-10.3 10.4-12.9 10.4-2.6 0-2.6 2.6-5.2 2.6-2.6-2.6-5.2-2.6-10.3-5.2-2.6-2.6-5.2-2.6-7.7-5.2l-7.7-7.7c-2.6-2.6-10.3-5.2-18.1-7.7-7.7-2.6-15.5 0-23.2 5.2-10.3 5.2-15.5 10.3-20.7 15.5-5.2 5.2-10.3 7.7-18.1 7.7h-15.5c-2.6-2.6-7.7-2.6-12.9-5.2s-10.3-2.6-15.5-2.6c-5.2 0-10.3 0-12.9 2.6-7.7 5.2-10.4 12.9-7.7 23.2 2.2 7.6 7.4 12.7 12.6 17.9z m447.6 393.2c-5.2-28.4-10.3-51.7-20.7-72.4-10.3-20.7-23.2-38.8-36.2-54.3-12.9-15.5-28.4-28.4-41.4-41.4-15.5-12.9-31-25.9-41.4-38.8-10.4-12.9-23.2-23.2-31.1-31.1-10.3-10.3-18.1-20.7-25.9-28.4H257.1c-5.2 10.3-15.5 20.7-23.2 31.1-7.7 10.3-18.1 20.7-28.4 31-10.3 10.3-25.9 23.2-38.8 36.2-15.5 15.5-31 31-46.6 49.1-15.5 18.1-25.9 38.8-36.2 59.5-10.4 20.7-15.5 43.9-18.1 69.8-2.6 25.9-2.6 51.8 2.6 77.6 5.2 23.2 12.9 49.1 28.4 72.4 12.9 23.2 31 46.6 56.9 67.3s51.7 36.2 85.3 49.1c33.7 13 72.6 18.2 116.5 18.2 41.4 0 80.2-5.2 113.8-15.5 33.6-10.4 62.1-25.9 85.3-43.9 23.2-18.1 43.9-38.8 56.9-64.6 15.5-23.2 23.2-51.7 28.4-77.6 2.7-33.8 5.3-64.9 0.2-93.3zM430.5 697.8c15.5 0 23.2 5.2 23.2 18.1 0 5.2 0 10.3-5.2 12.9-2.6 2.6-7.7 2.6-12.9 2.6h-56.9v15.5c0 5.2-2.6 10.3-5.2 15.5-5.2 5.2-10.3 7.7-15.5 5.2-7.7 0-12.9-2.6-15.5-5.2-5.2-2.6-7.7-7.7-7.7-15.5v-15.5h-59.5c-5.2 0-10.3-2.6-12.9-5.2-2.6-2.6-5.2-7.7-5.2-10.3 0-5.2 2.6-7.7 5.2-12.9 2.6-2.6 7.7-5.2 12.9-5.2h57v-28.4h-56.9c-5.2 0-10.3-2.6-12.9-5.2-2.6-2.6-5.2-7.7-5.2-10.4 0-2.6 2.6-7.7 5.2-12.9 2.6-2.6 7.7-5.2 12.9-5.2h56.9v-18.1L303.7 589c-7.7-7.7-12.9-15.5-20.7-20.7l-10.4-12.8c-2.6-2.6-5.2-7.7-7.7-12.9s0-12.9 2.6-18.1c5.2-5.2 10.3-7.7 18.1-5.2 7.7 2.6 12.9 5.2 18.1 10.3 2.6 2.6 5.2 7.7 10.3 12.9l41.4 41.4c10.3-7.7 18.1-15.5 25.9-23.2 7.7-5.2 12.9-12.9 20.7-18.1s10.3-10.3 12.9-12.9c5.2-5.2 10.3-7.7 15.5-7.7s10.4 2.6 15.5 7.7c7.7 7.7 5.2 18.1-7.7 28.4l-15.5 15.6-46.6 46.6v12.9h54.3c7.7 0 12.9 2.6 18.1 5.2 5.2 2.6 5.2 7.7 5.2 12.9s-2.6 10.3-5.2 12.9c-2.6 2.6-7.7 5.2-15.5 5.2h-54.3v28.4h51.8zM736.3 556.4c-16.3 0-31.9-0.6-46.9-1.7 2.8 11.2 5.1 23.1 7.5 36 4.7 25.9 3.4 53.9 1.1 83.9 12.3 1 25.1 1.5 38.2 1.5 119.6 0 208.1-41.6 223.7-83.2v-93.6c-46.7 36.3-124.7 57.1-223.6 57.1zM736.3 337.9c-72.8 3.2-139.7 17.9-181 39.5 10.2 10.5 22.8 21 35.4 31.5 14 14 30.7 28 44.7 44.7 12.6 15 25 32.5 35.5 52 20.4 2.5 42.3 3.9 65.4 3.9 119.6 0 208.1-41.6 223.7-83.2 0-46.8-98.8-88.4-223.7-88.4z" fill="#2c2c2c" p-id="9232"></path></svg>

Before

Width:  |  Height:  |  Size: 3.4 KiB

View File

@@ -1 +0,0 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1717295344332" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="22536" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><path d="M0 307.2h66.56l79.36 94.72H870.4L947.2 307.2h76.8v512c0 112.64-92.16 204.8-204.8 204.8H204.8c-112.64 0-204.8-92.16-204.8-204.8V307.2z m340.48 325.12V563.2c0-17.92-15.36-33.28-33.28-33.28s-33.28 15.36-33.28 33.28v102.4c0 17.92 15.36 33.28 33.28 33.28h427.52c17.92 0 33.28-15.36 33.28-33.28v-102.4c0-17.92-15.36-33.28-33.28-33.28s-33.28 15.36-33.28 33.28v69.12H340.48zM102.4 204.8h819.2v69.12L852.48 358.4h-680.96L102.4 273.92V204.8z m0-204.8h819.2v69.12L852.48 153.6h-680.96L102.4 69.12V0z" fill="#3B3B47" p-id="22537"></path></svg>

Before

Width:  |  Height:  |  Size: 865 B

View File

@@ -1 +0,0 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1726060385019" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8147" data-spm-anchor-id="a313x.search_index.0.i14.42e13a81ABrE1q" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><path d="M514 514m-448 0a448 448 0 1 0 896 0 448 448 0 1 0-896 0Z" fill="#bfbfbf" p-id="8148" data-spm-anchor-id="a313x.search_index.0.i9.42e13a81ABrE1q" class=""></path><path d="M542 543.4h-56v-310c0-16.6 13.4-30 30-30 14.4 0 26 11.6 26 26v314z" fill="#ffffff" p-id="8149" data-spm-anchor-id="a313x.search_index.0.i10.42e13a81ABrE1q" class="selected"></path><path d="M809.4 515.7v-4c0-14.4-11.6-26-26-26h-284v56h284c14.4 0 26-11.6 26-26z" fill="#ffffff" p-id="8150" data-spm-anchor-id="a313x.search_index.0.i8.42e13a81ABrE1q" class=""></path></svg>

Before

Width:  |  Height:  |  Size: 934 B

View File

@@ -1 +0,0 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1717296104869" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6006" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><path d="M554.965333 101.248l406.954667 373.034667a34.133333 34.133333 0 0 1-23.04 59.306666l-40.277333-0.042666v298.666666a85.333333 85.333333 0 0 1-85.333334 85.333334h-597.333333a85.333333 85.333333 0 0 1-85.333333-85.333334v-298.666666h-40.234667a34.133333 34.133333 0 0 1-23.04-59.264l406.912-373.034667a59.733333 59.733333 0 0 1 80.725333 0zM312.448 591.36a42.666667 42.666667 0 0 0 0 60.330667 279.978667 279.978667 0 0 0 395.946667 0 42.666667 42.666667 0 0 0-60.330667-60.330667 194.645333 194.645333 0 0 1-275.242667 0 42.666667 42.666667 0 0 0-60.373333 0z" fill="#2c2c2c" p-id="6007"></path></svg>

Before

Width:  |  Height:  |  Size: 933 B

6
src/assets/svg/home1.svg Normal file
View File

@@ -0,0 +1,6 @@
<svg width="71" height="68" viewBox="0 0 71 68" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Group 229">
<ellipse id="Ellipse 12" cx="35.3747" cy="33.663" rx="35.3747" ry="33.663" fill="#87C3ED"/>
<path id="Subtract" fill-rule="evenodd" clip-rule="evenodd" d="M23.3174 21.8325C23.3174 20.7279 24.2128 19.8325 25.3174 19.8325H28.485V23.3688C28.485 23.9211 28.9327 24.3688 29.485 24.3688H32.7358C33.288 24.3688 33.7358 23.9211 33.7358 23.3688V19.8325H45.4049C46.5094 19.8325 47.4049 20.7279 47.4049 21.8325V44.741C47.4049 45.8456 46.5094 46.741 45.4049 46.741H25.3174C24.2128 46.741 23.3174 45.8456 23.3174 44.741V21.8325ZM32.7358 19.8325H29.485V23.3688L32.7358 23.3688V19.8325ZM28.876 29.1297H39.9933V28.1297H28.876V29.1297ZM41.8462 34.4079H28.876V33.4079H41.8462V34.4079ZM41.8462 39.6862H28.876V38.6862H41.8462V39.6862Z" fill="#0043C5"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 860 B

6
src/assets/svg/home2.svg Normal file
View File

@@ -0,0 +1,6 @@
<svg width="71" height="68" viewBox="0 0 71 68" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Group 230">
<ellipse id="Ellipse 13" cx="35.3747" cy="33.663" rx="35.3747" ry="33.663" fill="#B487ED"/>
<path id="Subtract" fill-rule="evenodd" clip-rule="evenodd" d="M41.1045 20.8325C41.1045 20.2802 40.6568 19.8325 40.1045 19.8325H26.1016C24.997 19.8325 24.1016 20.7279 24.1016 21.8325V44.741C24.1016 45.8456 24.997 46.741 26.1016 46.741H46.189C47.2936 46.741 48.189 45.8456 48.189 44.741V27.5596C48.189 27.0073 47.7413 26.5596 47.189 26.5596H42.1045C41.5522 26.5596 41.1045 26.1118 41.1045 25.5596V20.8325ZM43.9383 31.0958H31.1861V30.0958H43.9383V31.0958ZM35.4369 23.0234H39.6876V22.0234H35.4369V23.0234ZM43.9383 36.4777H31.1861V35.4777H43.9383V36.4777ZM31.1861 41.8593H43.9383V40.8593H31.1861V41.8593Z" fill="#8600C5"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 838 B

6
src/assets/svg/home3.svg Normal file
View File

@@ -0,0 +1,6 @@
<svg width="71" height="68" viewBox="0 0 71 68" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Group 231">
<ellipse id="Ellipse 14" cx="35.3747" cy="33.663" rx="35.3747" ry="33.663" fill="#FDCB9D"/>
<path id="Subtract" fill-rule="evenodd" clip-rule="evenodd" d="M54.4044 32.614C54.4044 40.4161 46.1575 46.741 35.9845 46.741C32.9189 46.741 30.0281 46.1666 27.4852 45.1505C27.3501 45.3211 27.1528 45.4524 26.9047 45.5078L19.6131 47.1386C18.844 47.3106 18.1654 46.6256 18.393 45.9072L20.2692 39.9868C18.5537 37.8406 17.5647 35.3159 17.5647 32.614C17.5647 24.8119 25.8115 18.4871 35.9845 18.4871C46.1575 18.4871 54.4044 24.8119 54.4044 32.614ZM28.1916 34.6321C29.3654 34.6321 30.317 33.7286 30.317 32.614C30.317 31.4994 29.3654 30.5958 28.1916 30.5958C27.0178 30.5958 26.0662 31.4994 26.0662 32.614C26.0662 33.7286 27.0178 34.6321 28.1916 34.6321ZM38.8184 32.614C38.8184 33.7286 37.8669 34.6321 36.6931 34.6321C35.5193 34.6321 34.5677 33.7286 34.5677 32.614C34.5677 31.4994 35.5193 30.5958 36.6931 30.5958C37.8669 30.5958 38.8184 31.4994 38.8184 32.614ZM45.1945 34.6321C46.3683 34.6321 47.3198 33.7286 47.3198 32.614C47.3198 31.4994 46.3683 30.5958 45.1945 30.5958C44.0207 30.5958 43.0691 31.4994 43.0691 32.614C43.0691 33.7286 44.0207 34.6321 45.1945 34.6321Z" fill="#F47D0E"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

6
src/assets/svg/home4.svg Normal file
View File

@@ -0,0 +1,6 @@
<svg width="71" height="68" viewBox="0 0 71 68" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="Group 232">
<ellipse id="Ellipse 19" cx="35.3747" cy="33.663" rx="35.3747" ry="33.663" fill="#87EDBC"/>
<path id="Subtract" fill-rule="evenodd" clip-rule="evenodd" d="M18.7023 20.134C18.1358 20.4872 17.7588 21.1158 17.7588 21.8325V42.0502C17.7588 43.1547 18.6542 44.0502 19.7588 44.0502H48.3477C49.4523 44.0502 50.3477 43.1547 50.3477 42.0502V21.8325C50.3477 21.1082 49.9627 20.4738 49.3861 20.1229L49.9153 20.9221L35.7553 30.2976C34.9339 30.8415 33.8697 30.8523 33.0374 30.3252L18.1997 20.9276L18.7023 20.134ZM18.7605 20.0991L33.5725 29.4804C34.0718 29.7966 34.7104 29.7902 35.2032 29.4638L49.3465 20.0993C49.0526 19.9296 48.7115 19.8325 48.3477 19.8325H19.7588C19.3952 19.8325 19.0543 19.9295 18.7605 20.0991Z" fill="#01A054"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 845 B

View File

@@ -1 +0,0 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1717295325359" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="21461" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><path d="M854.016 889.514667l-41.642667-43.690667c10.922667-11.605333 25.941333-18.432 41.642667-18.432 32.768 0 59.392-27.989333 59.392-62.122667V144.725333c0-34.133333-26.624-62.122667-59.392-62.122666H263.509333c-32.768 0-59.392 27.989333-59.392 62.122666v5.461334c0 17.066667-6.826667 32.768-17.066666 43.690666L145.408 150.186667v-5.461334C145.408 75.776 197.973333 20.48 263.509333 20.48h591.189334c65.536 0 118.101333 55.296 118.101333 124.245333v620.544c-0.682667 68.949333-53.248 124.245333-118.784 124.245334zM86.016 268.970667v620.544c0 34.133333 26.624 62.122667 59.392 62.122666h591.189333c32.768 0 59.392-27.989333 59.392-62.122666V268.970667c0-34.133333-26.624-62.122667-59.392-62.122667H145.408c-32.768 0-59.392 27.989333-59.392 62.122667z m649.898667-124.245334c65.536 0 118.101333 55.296 118.101333 124.245334v620.544c0 68.266667-53.248 124.245333-118.101333 124.245333H145.408c-65.536 0-118.101333-55.296-118.101333-124.245333V268.970667c0-68.266667 53.248-124.245333 118.101333-124.245334h590.506667z" p-id="21462" fill="#2c2c2c"></path><path d="M735.914667 1024H145.408c-70.997333 0-128.341333-60.074667-128.341333-134.485333V268.970667c0-70.314667 52.565333-129.024 118.784-133.802667 4.096-69.632 60.074667-124.928 127.658666-124.928h591.189334c70.997333 0 128.341333 60.074667 128.341333 134.485333v620.544c0 70.314667-52.565333 129.024-118.784 133.802667-4.778667 70.314667-60.757333 124.928-128.341333 124.928zM135.850667 154.965333c-55.296 4.778667-98.986667 53.930667-98.986667 113.322667v620.544c0 62.805333 48.469333 114.005333 107.861333 114.005333h591.189334c58.026667 0 105.813333-49.152 107.861333-109.909333L805.546667 853.333333v36.181334c0 39.594667-31.402667 72.362667-69.632 72.362666H145.408c-38.229333 0-69.632-32.768-69.632-72.362666V268.970667c0-39.594667 31.402667-72.362667 69.632-72.362667h30.72l-40.277333-41.642667z m9.557333 62.122667c-26.624 0-49.152 23.210667-49.152 51.882667v620.544c0 28.672 21.845333 51.882667 49.152 51.882666h591.189333c26.624 0 49.152-23.210667 49.152-51.882666V268.970667c0-28.672-21.845333-51.882667-49.152-51.882667H145.408z m718.848 619.861333v41.642667c54.613333-5.461333 97.621333-53.930667 97.621333-113.322667V144.725333c0-62.805333-48.469333-114.005333-107.861333-114.005333H263.509333c-55.978667 0-102.4 45.738667-107.178666 103.765333h38.912c4.778667-34.816 33.450667-62.122667 68.949333-62.122666h591.189333c38.229333 0 69.632 32.768 69.632 72.362666v620.544c-1.365333 36.181333-27.306667 66.901333-60.757333 71.68z m-36.864 9.557334l17.066667 17.749333v-25.258667c-6.826667 1.365333-12.288 4.096-17.066667 7.509334zM197.973333 196.608h537.941334c38.229333 0 69.632 32.768 69.632 72.362667v569.344c10.24-10.922667 23.893333-17.749333 38.912-20.48V268.970667c0-62.805333-48.469333-114.005333-107.861334-114.005334H214.357333c-0.682667 15.018667-6.826667 30.037333-16.384 41.642667z m17.749334-62.122667h520.874666c70.997333 0 128.341333 60.074667 128.341334 134.485334v547.498666c21.845333-4.778667 38.912-25.941333 38.912-50.517333v-621.226667c0-28.672-21.845333-51.882667-49.152-51.882666H263.509333c-23.893333 0-43.690667 17.749333-47.786666 41.642666z m-51.882667 20.48l21.845333 23.210667c4.096-6.826667 6.826667-15.018667 7.509334-23.210667H163.84z" fill="#2c2c2c" p-id="21463"></path><path d="M162.474667 289.450667h372.736c17.066667 0 30.72 13.653333 30.72 30.72s-13.653333 30.72-30.72 30.72H162.474667c-17.066667 0-30.72-13.653333-30.72-30.72s13.653333-30.72 30.72-30.72z m559.104 62.122666c-17.066667 0-30.72-13.653333-30.72-30.72s13.653333-30.72 30.72-30.72 30.72 13.653333 30.72 30.72-13.653333 30.72-30.72 30.72zM69.632 434.176h744.789333v62.122667H69.632v-62.122667z" p-id="21464" fill="#2c2c2c"></path><path d="M824.661333 506.538667H59.392V423.936h765.269333v82.602667z m-744.789333-20.48h724.309333v-41.642667H79.872v41.642667z m641.706667-124.245334c-22.528 0-40.96-18.432-40.96-40.96s18.432-40.96 40.96-40.96 40.96 18.432 40.96 40.96-18.432 40.96-40.96 40.96z m0-62.122666c-11.605333 0-20.48 9.557333-20.48 20.48 0 11.605333 9.557333 20.48 20.48 20.48 11.605333 0 20.48-9.557333 20.48-20.48 0-11.605333-8.874667-20.48-20.48-20.48zM535.210667 361.813333H162.474667c-22.528 0-40.96-18.432-40.96-40.96s18.432-40.96 40.96-40.96h372.736c22.528 0 40.96 18.432 40.96 40.96s-18.432 40.96-40.96 40.96z m-372.736-62.122666c-11.605333 0-20.48 9.557333-20.48 20.48 0 11.605333 9.557333 20.48 20.48 20.48h372.736c11.605333 0 20.48-9.557333 20.48-20.48 0-11.605333-9.557333-20.48-20.48-20.48H162.474667z" fill="#2c2c2c" p-id="21465"></path></svg>

Before

Width:  |  Height:  |  Size: 4.7 KiB

View File

@@ -1 +0,0 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1717295270657" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="16717" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><path d="M419.84 952.32c-10.24 0-15.36 0-25.6-5.12l-225.28-61.44c-46.08-15.36-76.8-61.44-61.44-107.52l168.96-640C286.72 92.16 337.92 61.44 384 76.8l230.4 56.32c46.08 10.24 76.8 61.44 61.44 107.52L506.88 885.76c-5.12 25.6-20.48 40.96-40.96 56.32-15.36 5.12-30.72 10.24-46.08 10.24z m-56.32-803.84h-5.12s-5.12 5.12-5.12 10.24l-174.08 640c0 5.12 0 15.36 10.24 15.36l225.28 61.44h10.24s5.12-5.12 5.12-10.24l174.08-640c0-5.12 0-15.36-10.24-15.36l-230.4-61.44c5.12 0 0 0 0 0z" p-id="16718"></path><path d="M604.16 168.96l-225.28-56.32c-25.6-10.24-56.32 5.12-61.44 35.84l-174.08 640c-5.12 25.6 10.24 56.32 35.84 61.44l225.28 61.44c25.6 5.12 56.32-10.24 61.44-35.84l174.08-640c5.12-30.72-10.24-56.32-35.84-66.56z m-128 348.16c-5.12 15.36-20.48 30.72-35.84 30.72h-10.24l-92.16-25.6c-20.48-5.12-35.84-25.6-25.6-51.2 5.12-15.36 20.48-30.72 35.84-30.72h10.24l92.16 25.6c20.48 10.24 30.72 30.72 25.6 51.2zM512 404.48c-5.12 15.36-20.48 25.6-35.84 25.6h-10.24l-97.28-25.6c-20.48-5.12-30.72-25.6-25.6-46.08 5.12-15.36 20.48-30.72 40.96-30.72h10.24l92.16 25.6c20.48 5.12 30.72 25.6 25.6 51.2z m240.64 532.48c-20.48 0-40.96-15.36-40.96-40.96V215.04c0-20.48 15.36-40.96 40.96-40.96s40.96 15.36 40.96 40.96V896c-5.12 25.6-20.48 40.96-40.96 40.96z m87.04-10.24c-5.12 0-15.36-5.12-15.36-15.36V209.92c0-5.12 5.12-15.36 15.36-15.36s15.36 5.12 15.36 15.36v701.44c-5.12 10.24-10.24 15.36-15.36 15.36z m40.96 0c-5.12 0-15.36-5.12-15.36-15.36V209.92c0-5.12 5.12-15.36 15.36-15.36S896 199.68 896 209.92v701.44c0 10.24-5.12 15.36-15.36 15.36z" p-id="16719"></path></svg>

Before

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -1 +0,0 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1720946136639" class="icon" viewBox="0 0 1025 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4221" xmlns:xlink="http://www.w3.org/1999/xlink" width="128.125" height="128"><path d="M992.090881 443.129l-388.66-404.16C579.320881 13.934 546.998881 0.023 512.424881 0.023s-66.896 13.776-91.006 38.946L32.889881 443.129c-40.138 41.728-34.972 77.759-28.348 92.86 4.769 10.731 20.665 40.005 66.63 40.005l56.961 0 0 310.902c0 70.604 50.736 137.104 122.797 137.104l165.454 0L416.383881 694.949c0-35.236-5.298-54.974 30.733-54.974l130.745 0c36.031 0 30.733 19.605 30.733 54.974L608.594881 1024l165.321 0c72.063 0 122.797-66.499 122.797-137.104L896.712881 575.994l56.961 0c45.966 0 61.862-29.407 66.63-40.005C1026.927881 520.888 1032.094881 484.856 992.090881 443.129L992.090881 443.129zM953.676881 512.013 832.601881 512.013l0 374.884c0 35.237-22.784 72.99-58.815 72.99L672.446881 959.887 672.446881 694.949c0-70.604-22.652-118.956-94.717-118.956L446.985881 575.993c-72.063 0-94.717 48.352-94.717 118.956l0 265.069L250.929881 960.018c-36.031 0-58.816-37.754-58.816-72.99L192.113881 512.145 71.038881 512.145c-1.191 0-2.118-4.371-3.047-4.503 2.253-3.843 6.094-13.646 12.452-20.269l388.66-403.895c11.525-12.187 27.95-19.473 43.848-19.34 15.895-0.132 31.262 7.285 42.919 19.34L944.398881 487.24c6.358 6.623 10.199 16.426 12.32 20.269-0.796 0.132-1.856 4.503-3.047 4.503L953.676881 512.013z" fill="#909399" p-id="4222"></path></svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -1 +0,0 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1717295208831" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="15626" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><path d="M179.28 124.787c21.504 0 35.84 14.357 35.84 35.86 0 21.505-14.336 35.86-35.84 35.86-21.524 0-35.86-14.355-35.86-35.86 0-21.503 14.336-35.86 35.86-35.86z m0 358.541c21.504 0 35.84 14.356 35.84 35.86 0 21.524-14.336 35.86-35.84 35.86-21.524 0-35.86-14.336-35.86-35.86 0-21.504 14.336-35.86 35.86-35.86z m0 358.56h143.4c21.525 0 35.86 14.337 35.86 35.84 0 21.525-14.335 35.86-35.86 35.86H179.3c-21.524 0-35.86-14.335-35.86-35.86 0-21.503 14.336-35.84 35.86-35.84z" fill="#2c2c2c" p-id="15627"></path><path d="M888.41 318.163H125.832c-55.678 0.341-85.073-26.102-84.731-81.76V103.745c0.34-55.677 20.82-87.843 76.498-88.204h293.728s6.927-0.261 14.557 0c15.32 0.562 19.195 10.561 19.355 18.512 0.362 17.267 0 8.634 0 26.905 0 2.149-0.803 21.223-22.327 21.745-13.653 0.341-278.187 1.285-278.187 1.285-26.764 0.341-34.133 13.694-34.514 34.495v96.637c0 25.179 7.57 34.656 34.534 34.515h724.691c29.676 0.16 34.676-22.367 34.515-34.535v-96.597c0.924-11.344-4.819-35.58-34.515-35.78 0 0-465.177 0.823-478.77 0-17.83-1.064-22.387-8.071-22.428-20.68-0.06-17.69-0.662-8.574 0-26.183 0.382-9.939-2.61-19.737 22.609-20.28 6.224-0.16 11.284 0 11.284 0H883.21c55.657 0.342 89.59 45.98 89.931 101.658v119.186c0.342 55.657-29.113 82.12-84.73 81.759z m0 351.372H125.832c-55.678 0.342-85.073-26.102-84.731-81.759V455.118c0.34-55.678 20.82-87.843 76.498-88.205h293.728s6.927-0.26 14.557 0c15.32 0.562 19.195 10.562 19.355 18.513 0.362 17.267 0 8.633 0 26.905 0 2.148-0.803 21.223-22.327 21.745-13.653 0.34-278.187 1.285-278.187 1.285-26.764 0.341-34.133 13.693-34.514 34.494v96.638c0 25.178 7.57 34.655 34.534 34.515h724.691c29.676 0.16 34.676-22.368 34.515-34.535v-96.618c0.924-11.344-4.819-35.579-34.515-35.78 0 0-465.177 0.824-478.77 0-17.83-1.064-22.387-8.07-22.428-20.68-0.06-17.69-0.662-8.574 0-26.182 0.382-9.94-2.61-19.738 22.609-20.28 6.224-0.16 11.284 0 11.284 0H883.21c55.657 0.342 89.59 45.98 89.931 101.657v119.186c0.342 55.657-29.113 82.12-84.73 81.76z m0 351.373H125.832c-55.678 0.341-85.073-26.102-84.731-81.76V806.49c0.34-55.677 20.82-87.843 76.498-88.204h293.728s6.927-0.261 14.557 0c15.32 0.562 19.195 10.561 19.355 18.512 0.362 17.268 0 8.634 0 26.905 0 2.149-0.803 21.223-22.327 21.745-13.653 0.341-278.187 1.285-278.187 1.285-26.764 0.342-34.133 13.694-34.514 34.495v96.637c0 25.179 7.57 34.656 34.534 34.515h724.691c29.676 0.16 34.676-22.367 34.515-34.535v-96.617c0.924-11.344-4.819-35.58-34.515-35.78 0 0-465.177 0.823-478.77 0-17.83-1.064-22.387-8.071-22.428-20.68-0.06-17.69-0.662-8.574 0-26.183 0.382-9.939-2.61-19.737 22.609-20.28 6.224-0.16 11.284 0 11.284 0H883.21c55.657 0.342 89.59 45.98 89.931 101.658v119.186c0.342 55.657-29.113 82.12-84.73 81.759z" fill="#2c2c2c" p-id="15628"></path></svg>

Before

Width:  |  Height:  |  Size: 3.0 KiB

View File

@@ -1 +0,0 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1717295421269" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="23541" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><path d="M918.112262 0.279019H282.088283c-57.896458 0-105.050681 43.805995-105.050681 97.656676v53.013624H60.965668C27.762398 150.949319 0.837057 177.874659 0.837057 211.077929v752.653951c0 33.20327 26.925341 60.12861 60.128611 60.12861h736.889373c33.20327 0 60.12861-26.925341 60.12861-60.12861v-33.900817h60.26812c57.896458 0 105.050681-43.805995 105.050681-97.656676V97.935695c-0.13951-53.850681-47.293733-97.656676-105.19019-97.656676zM734.378202 343.751499c0 20.089373-16.183106 36.27248-36.27248 36.272479h-417.133515c-20.089373 0-36.27248-16.183106-36.272479-36.272479s16.183106-36.27248 36.272479-36.27248h417.133515c20.089373 0 36.27248 16.183106 36.27248 36.27248z m0 251.814714c0 20.089373-16.183106 36.27248-36.27248 36.272479h-417.133515c-20.089373 0-36.27248-16.183106-36.272479-36.272479s16.183106-36.27248 36.272479-36.27248h417.133515c20.089373 0 36.27248 16.183106 36.27248 36.27248zM146.345504 879.607629c-20.089373 0-36.27248-16.183106-36.272479-36.272479s16.183106-36.27248 36.272479-36.27248 36.27248 16.183106 36.27248 36.27248c0 19.949864-16.183106 36.27248-36.27248 36.272479z m0-247.768937c-20.089373 0-36.27248-16.183106-36.272479-36.272479s16.183106-36.27248 36.272479-36.27248 36.27248 16.183106 36.27248 36.27248-16.183106 36.27248-36.27248 36.272479z m0-251.814714c-20.089373 0-36.27248-16.183106-36.272479-36.272479s16.183106-36.27248 36.272479-36.27248 36.27248 16.183106 36.27248 36.27248c0 19.949864-16.183106 36.27248-36.27248 36.272479z m551.760218 499.583651h-417.133515c-20.089373 0-36.27248-16.183106-36.272479-36.272479s16.183106-36.27248 36.272479-36.27248h417.133515c20.089373 0 36.27248 16.183106 36.27248 36.27248 0 19.949864-16.183106 36.27248-36.27248 36.272479z m252.512262-47.572752c0 13.671935-14.92752 25.111717-32.505722 25.111717h-60.26812V210.93842c0-33.20327-26.925341-60.12861-60.128611-60.128611H249.582561v-53.013624c0-13.671935 14.92752-25.111717 32.505722-25.111716H917.972752c17.578202 0 32.505722 11.579292 32.505722 25.111716v734.238692z" p-id="23542"></path></svg>

Before

Width:  |  Height:  |  Size: 2.3 KiB

View File

@@ -1 +0,0 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1717295441926" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="24673" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><path d="M834.021053 560.505263l-56.589474-56.589474c-10.778947-10.778947-26.947368-10.778947-37.726316 0l-245.221052 245.221053c-8.084211 40.421053-13.473684 80.842105-21.557895 118.568421 40.421053-5.389474 80.842105-13.473684 121.263158-21.557895l245.221052-245.221052c8.084211-8.084211 10.778947-21.557895 5.389474-29.642105-5.389474 0-8.084211-5.389474-10.778947-10.778948zM747.789474 673.684211c-10.778947 5.389474-24.252632 5.389474-32.336842-2.694737l-40.421053-40.421053c-5.389474-5.389474-8.084211-16.168421-8.084211-24.252632 2.694737-10.778947 8.084211-18.863158 18.863158-21.557894 10.778947-2.694737 18.863158 0 26.947369 5.389473l37.726316 37.726316c5.389474 5.389474 8.084211 8.084211 8.08421 16.168421 2.694737 10.778947-2.694737 21.557895-10.778947 29.642106z m59.28421-61.978948c-5.389474 8.084211-16.168421 10.778947-26.947368 10.778948-5.389474 0-10.778947-2.694737-16.168421-8.084211L726.231579 576.673684c-2.694737-2.694737-5.389474-8.084211-8.084211-13.473684-2.694737-13.473684 8.084211-29.642105 21.557895-32.336842 8.084211-2.694737 16.168421 0 24.252632 5.389474l32.336842 32.336842 10.778947 10.778947c8.084211 13.473684 8.084211 24.252632 0 32.336842z" p-id="24674"></path><path d="M993.010526 102.4c-5.389474-18.863158-13.473684-37.726316-24.252631-51.2C949.894737 26.947368 925.642105 10.778947 896 2.694737c-10.778947 0-21.557895-2.694737-32.336842-2.694737H146.863158C79.494737 8.084211 28.294737 61.978947 25.6 129.347368v762.610527c2.694737 64.673684 48.505263 118.568421 113.178947 129.347368 5.389474 2.694737 13.473684 2.694737 21.557895 2.694737h706.021053c8.084211 0 16.168421 0 21.557894-2.694737 53.894737-10.778947 97.010526-53.894737 107.789474-107.789474 2.694737-13.473684 2.694737-26.947368 2.694737-43.115789v-727.578947c-2.694737-13.473684-2.694737-26.947368-5.389474-40.421053zM243.873684 223.663158h530.863158c10.778947 0 18.863158 5.389474 24.252632 13.473684 2.694737 5.389474 5.389474 10.778947 5.389473 13.473684 0 13.473684-13.473684 26.947368-26.947368 26.947369H246.568421c-13.473684 0-26.947368-13.473684-26.947368-26.947369s10.778947-26.947368 24.252631-26.947368z m-18.863158 231.747368c5.389474-5.389474 8.084211-8.084211 16.168421-10.778947h296.421053c5.389474 0 10.778947 2.694737 16.168421 5.389474 13.473684 8.084211 16.168421 26.947368 8.084211 37.726315-5.389474 8.084211-13.473684 10.778947-24.252632 10.778948H246.568421c-5.389474 0-10.778947-2.694737-16.168421-5.389474-13.473684-8.084211-16.168421-26.947368-5.389474-37.726316z m164.378948 245.221053c-5.389474 8.084211-13.473684 13.473684-21.557895 13.473684H241.178947c-8.084211 0-16.168421-8.084211-18.863158-13.473684-2.694737-5.389474-2.694737-13.473684-2.694736-18.863158 2.694737-10.778947 13.473684-18.863158 24.252631-21.557895h121.263158c5.389474 0 8.084211 0 13.473684 2.694737 10.778947 8.084211 16.168421 24.252632 10.778948 37.726316z m487.747368-59.284211l-250.610526 250.610527c-5.389474 5.389474-13.473684 8.084211-21.557895 8.08421l-161.68421 26.947369c-13.473684 2.694737-26.947368-5.389474-29.642106-18.863158v-13.473684l29.642106-164.378948c0-5.389474 2.694737-10.778947 5.389473-13.473684 59.284211-59.284211 118.568421-118.568421 177.852632-180.547368l53.894737-53.894737c10.778947-13.473684 24.252632-24.252632 37.726315-32.336842 8.084211-5.389474 18.863158-8.084211 26.947369-8.084211 24.252632-2.694737 48.505263 5.389474 67.368421 21.557895l61.978947 61.978947c10.778947 10.778947 18.863158 21.557895 21.557895 35.031579 8.084211 32.336842 0 61.978947-18.863158 80.842105z" p-id="24675"></path></svg>

Before

Width:  |  Height:  |  Size: 3.8 KiB

View File

@@ -1 +0,0 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1726897356959" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4330" xmlns:xlink="http://www.w3.org/1999/xlink" width="256" height="256"><path d="M26.293 1022.219c-14.41 0-26.122-11.652-26.122-26.006 0-14.41 11.712-26.182 26.122-26.182h818.455c69.64 0 126.306-58.5 126.306-130.379l-0.174-679.348c0-14.525 11.654-26.236 26.009-26.236 14.41 0 26.178 11.711 26.178 26.236l0.115 679.348c0 100.699-80.03 182.566-178.434 182.566H26.293z" fill="#2c2c2c" p-id="4331"></path><path d="M679.977 873.811c-14.41 0-26.063-11.654-26.063-26.006V674.537c0-14.352 11.653-26.006 26.063-26.006s26.124 11.654 26.124 26.006v173.268c0 14.351-11.714 26.006-26.124 26.006zM504.759 873.811c-14.354 0-26.009-11.654-26.009-26.006v-186.76c0-14.352 11.655-26.006 26.009-26.006 14.41 0 26.065 11.654 26.065 26.006v186.76c0 14.351-11.655 26.006-26.065 26.006zM336.313 873.811c-14.41 0-26.122-11.654-26.122-26.006v-92.26c0-14.412 11.712-26.123 26.122-26.123 14.354 0 25.894 11.711 25.894 26.123v92.26c0 14.351-11.54 26.006-25.894 26.006zM174.357 873.811c-14.354 0-26.009-11.654-26.009-26.006v-85.658c0-14.352 11.655-25.949 26.009-25.949 14.41 0 26.178 11.598 26.178 25.949v85.658c0 14.351-11.767 26.006-26.178 26.006zM50.637 873.811c-14.354 0-26.01-11.654-26.01-26.006v-85.658c0-14.352 11.655-25.949 26.01-25.949 14.41 0 26.121 11.598 26.121 25.949v85.658c0 14.351-11.711 26.006-26.121 26.006zM848.652 873.754c-14.41 0-26.124-11.598-26.124-25.949V573.379c0-14.354 11.714-26.006 26.124-26.006 14.352 0 26.007 11.652 26.007 26.006v274.426c0 14.351-11.655 25.949-26.007 25.949zM26.121 675.111C11.711 675.111 0 663.514 0 649.219c0-14.41 11.711-26.121 26.121-26.121h289.696l169.65-186.988c5.053-5.453 12.172-8.555 19.406-8.555 4.132 0 8.209 1.033 12.169 3.041l142.667 77.391 168.503-212.135c4.65-6.313 12.573-10.217 20.782-10.217 12.287 1.436 20.555 7.348 24.229 16.648 3.331 8.783 1.722 18.717-4.134 25.951l-182.05 229.299c-5.111 6.201-12.458 9.76-20.381 9.76-4.42 0-8.67-1.09-12.517-3.271L510.385 486.4 346.59 666.729c-4.648 5.283-11.768 8.383-19.289 8.383H26.121zM245.316 381.566c-10.333 0-18.716-8.439-18.716-18.715v-57.697h-62.578c-10.276 0-18.716-8.439-18.716-18.717 0-10.334 8.439-18.658 18.716-18.658h62.637v-38.064h-62.637c-10.22 0-18.659-8.439-18.659-18.715 0-10.221 8.439-18.604 18.659-18.604h66.884l-63.21-58.846c-5.109-4.592-7.291-11.369-5.741-17.854 1.379-6.717 6.258-12 12.688-13.896 1.551-0.112 3.042-0.112 4.362-0.112 7.234 0 10.967 1.662 13.896 4.535l51.842 47.994 45.986-47.307c3.445-3.673 8.268-5.625 13.32-5.625 4.878 0 9.588 1.837 12.975 5.28 3.674 3.446 5.626 8.097 5.74 12.976 0.057 4.996-1.78 9.818-5.282 13.436l-57.983 59.418h60.912c10.218 0 18.657 8.383 18.657 18.604 0 10.275-8.439 18.715-18.657 18.715h-56.436v38.064h56.436c10.218 0 18.657 8.324 18.657 18.658 0 10.277-8.439 18.717-18.657 18.717h-56.436v57.697c0.001 10.277-8.382 18.716-18.659 18.716z" fill="#2c2c2c" p-id="4332"></path><path d="M241.699 476.182c-61.602 0-121.94-25.145-165.517-68.721C16.648 348.27-6.89 261.291 14.696 180.229c21.586-80.896 85.313-144.619 166.32-166.38 19.808-5.282 40.015-7.866 60.455-7.866 62.176 0 122.858 25.262 166.606 69.411 67.459 67.284 87.438 167.755 50.866 255.882-36.341 87.955-121.482 144.906-216.785 144.906h-0.459z m0.46-432.193c-108.853 0-197.379 88.528-197.379 197.382 0 108.965 88.526 197.494 197.379 197.494 108.909 0 197.438-88.529 197.438-197.494 0-108.853-88.529-197.382-197.438-197.382z" fill="#2c2c2c" p-id="4333"></path></svg>

Before

Width:  |  Height:  |  Size: 3.5 KiB

View File

@@ -1 +0,0 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1717295133873" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="12684" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><path d="M568.917333 852.48h-277.703111a27.306667 27.306667 0 0 1-27.306666-27.221333 27.335111 27.335111 0 0 1 27.306666-27.278223h71.111111l99.555556-99.356444 0.824889-0.739556a27.818667 27.818667 0 0 1 3.925333-2.986666H158.606222a53.020444 53.020444 0 0 1-52.963555-52.963556V245.703111a53.020444 53.020444 0 0 1 52.963555-52.963555h659.911111a53.191111 53.191111 0 0 1 53.048889 52.963555v266.268445h-259.982222a42.666667 42.666667 0 0 0-42.666667 42.666666v140.060445H495.786667a20.906667 20.906667 0 0 1 4.664889 3.754666 4.835556 4.835556 0 0 1 1.109333 1.194667l67.384889 67.470222v85.333334z m-114.887111-349.866667v52.849778h52.878222V502.613333h79.274667v-52.849777h-79.274667v-26.396445h79.274667v-52.878222h-54.044444l41.728-42.012445-37.262223-37.262222-55.978666 55.978667-56.064-55.978667-37.546667 37.262222 42.012445 42.012445h-54.044445v52.878222h79.274667v26.396445h-79.274667v52.849777z" p-id="12685" fill="#2c2c2c"></path><path d="M909.482667 583.765333A43.150222 43.150222 0 0 0 866.161778 540.444444h-225.479111a43.150222 43.150222 0 0 0-43.320889 43.320889v226.247111A43.150222 43.150222 0 0 0 640.682667 853.333333h226.247111a43.150222 43.150222 0 0 0 43.320889-43.320889z m-81.464889 104.049778v0.369778a19.484444 19.484444 0 0 1-26.652445 0l-34.446222-33.336889v138.496a18.887111 18.887111 0 0 1-37.774222-0.369778v-139.235555l-35.157333 35.185777a18.602667 18.602667 0 0 1-25.912889-26.652444l65.422222-65.422222a18.488889 18.488889 0 0 1 12.970667-5.176889 19.000889 19.000889 0 0 1 12.600888 4.807111c0.369778 0.739556 1.109333 1.109333 1.479112 1.479111a0.369778 0.369778 0 0 0 0.369777 0.369778l0.369778 0.369778 66.275556 63.687111 0.369777 0.369778a17.664 17.664 0 0 1 0.085334 25.059555z" p-id="12686" fill="#2c2c2c"></path></svg>

Before

Width:  |  Height:  |  Size: 2.0 KiB

View File

@@ -1 +0,0 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1717295457045" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="25716" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><path d="M170.666667 34.133333h659.911111c34.133333 0 68.266667 17.066667 96.711111 39.822223 22.755556 22.755556 34.133333 51.2 34.133333 85.333333V534.755556c-5.688889 11.377778-22.755556 17.066667-34.133333 11.377777-45.511111-22.755556-91.022222-28.444444-142.222222-28.444444-39.822222 0-79.644444 11.377778-119.466667 34.133333-56.888889 34.133333-102.4 85.333333-125.155556 147.911111-22.755556 68.266667-22.755556 142.222222 5.688889 210.488889 5.688889 17.066667 11.377778 28.444444 22.755556 39.822222l5.688889 5.688889c5.688889 5.688889 5.688889 17.066667 0 22.755556-5.688889 5.688889-11.377778 11.377778-22.755556 11.377778H170.666667c-34.133333 0-62.577778-11.377778-85.333334-39.822223-22.755556-22.755556-39.822222-56.888889-34.133333-91.022222V153.6c0-28.444444 5.688889-51.2 22.755556-73.955556 17.066667-28.444444 51.2-51.2 85.333333-56.888888 0 11.377778 5.688889 11.377778 11.377778 11.377777z m73.955555 210.488889c-11.377778 0-17.066667 11.377778-17.066666 17.066667 0 5.688889 0 17.066667 5.688888 22.755555 5.688889 5.688889 11.377778 5.688889 17.066667 5.688889h506.311111c11.377778-5.688889 17.066667-17.066667 17.066667-28.444444s-11.377778-22.755556-22.755556-22.755556H250.311111c0 5.688889-5.688889 5.688889-5.688889 5.688889m5.688889 204.8c-5.688889 0-11.377778 5.688889-17.066667 11.377778-5.688889 11.377778-5.688889 22.755556 0 28.444444 5.688889 5.688889 11.377778 11.377778 17.066667 11.377778h273.066667c5.688889 0 17.066667-5.688889 22.755555-11.377778 5.688889-5.688889 5.688889-17.066667 0-28.444444-5.688889-5.688889-11.377778-11.377778-22.755555-11.377778H250.311111z" fill="#2c2c2c" p-id="25717"></path><path d="M625.777778 989.866667c-11.377778-5.688889-28.444444-11.377778-45.511111-17.066667 17.066667-39.822222 28.444444-73.955556 39.822222-113.777778l45.511111 17.066667c-11.377778 45.511111-22.755556 85.333333-39.822222 113.777778z m5.688889-159.288889v-170.666667h79.644444l-34.133333-51.2 56.888889-17.066667c17.066667 17.066667 28.444444 39.822222 45.511111 62.577778l-17.066667 5.688889h62.577778c17.066667-28.444444 34.133333-51.2 39.822222-68.266667l56.888889 17.066667c-11.377778 17.066667-22.755556 34.133333-39.822222 51.2h79.644444v170.666667h-159.288889c5.688889 5.688889 22.755556 28.444444 51.2 62.577778l-45.511111 34.133333c-17.066667-28.444444-34.133333-51.2-51.2-68.266667l39.822222-28.444444h-164.977777z m56.888889-125.155556v73.955556h216.177777v-73.955556h-216.177777z m56.888888 307.2c-22.755556 0-34.133333-5.688889-45.511111-17.066666-11.377778-11.377778-17.066667-28.444444-17.066666-51.2v-85.333334h51.2v73.955556c0 22.755556 11.377778 34.133333 34.133333 28.444444h56.888889c11.377778 0 22.755556 0 28.444444-5.688889 5.688889-5.688889 11.377778-11.377778 11.377778-17.066666 0-11.377778 5.688889-22.755556 5.688889-39.822223l51.2 17.066667c-5.688889 28.444444-11.377778 45.511111-11.377778 56.888889-5.688889 17.066667-11.377778 22.755556-22.755555 34.133333-11.377778 5.688889-28.444444 11.377778-45.511111 11.377778h-96.711112z m216.177778-34.133333c-22.755556-39.822222-39.822222-73.955556-56.888889-102.4l45.511111-22.755556c22.755556 39.822222 45.511111 73.955556 62.577778 102.4l-51.2 22.755556z" fill="#2c2c2c" p-id="25718"></path></svg>

Before

Width:  |  Height:  |  Size: 3.5 KiB

View File

@@ -1,486 +1,145 @@
<template>
<el-form :model="formData" ref="applyForm" :rules="rules" :label-position="labelPosition" :style="{marginLeft: label==='项目验收附件'?'25px': label==='项目立项附件'?'25px':'5px'}">
<el-form :model="formData" ref="applyForm" label-width="auto" :rules="rules">
<el-row>
<!-- <el-col :span="24">-->
<!-- <el-form-item :label="label" prop="attachment" >-->
<!-- <template v-if="preview">-->
<!-- <file-upload @getFile="getAttachment" :multiple="false"-->
<!-- :disabled="singleFileArray?.length>0?true:false" title="如需修改需求申请书附件,请先删除文件再上传!"/>-->
<!-- <fvTable style="width: 100%;max-height: 80px;" height="80" v-if="singleFileArray?.length>0"-->
<!-- :tableConfig="editSingleTableConfig"-->
<!-- :data="singleFileArray" :isSettingCol="false" :pagination="false">-->
<!-- </fvTable>-->
<!-- </template>-->
<!-- <template v-else-if="!preview">-->
<!-- <file-upload @getFile="getAttachment" :multiple="false"-->
<!-- :disabled="isSingleFile"/>-->
<!-- <fvTable style="width: 100%;max-height: 80px;" v-if="showSingleTable" height="80"-->
<!-- :tableConfig="singleTableConfig"-->
<!-- :data="_singleFileValue" :isSettingCol="false" :pagination="false">-->
<!-- </fvTable>-->
<!-- </template>-->
<!-- </el-form-item>-->
<!-- </el-col>-->
<el-col :span="24">
<el-form-item :label="label" prop="" :required="label!='项目归档附件'">
<file-upload @getFile="getOtherFile"/>
<el-button color="#DED0B2" v-if="templateDownloadBtnShow" @click="handleImportTemplateDownload"
style="margin-left: 10px">模板下载
</el-button>
<fvTable style="width: 100%;" :height="label=='项目立项附件'?'160':'160'" :scrollbar-always-on="true" :style="{maxHeight:label=='项目立项附件'?'160px':'160px',height:label=='项目立项附件'?'160px':'160px'}" v-if="showTable" :tableConfig="tableConfig"
:data="allFileList" :isSettingCol="false" :pagination="false">
<template #empty>
<el-empty :image-size="55" description="暂无数据" style="padding: 0"/>
</template>
</fvTable>
<el-form-item :label="label" prop="attachment">
<template v-if="preview&&JSON.stringify(singleFile) !== '{}'&&JSON.stringify(singleFile)!=='null'">
<el-button type="primary" link @click="handleDownload(singleFile)" style="font-size: 18px">
{{ singleFile?.originalFileName }}
</el-button>
<el-button type="danger" link @click="deleteOtherFile(singleFile,1)">删除</el-button>
</template>
<template v-else-if="!preview||JSON.stringify(singleFile) === '{}'||singleFile==null">
<file-upload @getFile="getAttachment" :showFileList="showFileList" :maxSize="0" @delete="deleteAttachment"/>
</template>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="其他文件">
<el-card style="width: 100%">
<file-upload @getFile="getOtherFile"/>
<fvTable style="width: 100%;max-height: 250px;height: 250px" v-if="showTable" :tableConfig="tableConfig"
:data="allFileList" :isSettingCol="false" :pagination="false">
<template #empty>
<el-empty :image-size="90" description="暂无数据" style="padding: 0"/>
</template>
</fvTable>
</el-card>
</el-form-item>
</el-col>
</el-row>
</el-form>
<file-preview ref="filePreviewRef" v-if="filePreviewShow" :fileName="filePreviewParam.fileName"
:fileUrl="filePreviewParam.fileUrl"
:fileType="filePreviewParam.fileType"/>
</template>
<script setup lang="jsx">
import FileUpload from '@/components/FileUpload.vue'
import {deleteFile, downloadFile, downloadTemplate, downloadTemplateZip} from "@/api/project-demand";
import {ElMessageBox, ElNotification} from "element-plus";
import {deleteFile, downloadFile} from "../api/project-demand";
import {ElMessage, ElMessageBox, ElNotification} from "element-plus";
const emit = defineEmits(["getAttachment", "getOtherFile"])
const formData = ref({})
const tableConfig = reactive({
columns: [
{
prop: 'index',
type: 'index',
label: '序号',
align: 'center',
width: '80',
},
{
prop: 'originalFileName',
label: '文件名',
align: 'center',
},
{
prop: 'tag',
label: '标签',
align: 'center'
},
{
prop: 'size',
label: '文件大小',
align: 'center',
currentRender: ({row, index}) => (parseInt(row.size / 1024) + 'KB')
},
// {
// prop: 'oper',
// label: '操作',
// align: 'center',
// showOverflowTooltip: false,
// currentRender: ({row, index}) => {
// return (
// <div>
// <el-button type="primary" link onClick={() => handleDownload(row)}>下载</el-button>
// <el-button type="primary" size="large" link onClick={() => deleteOtherFile(row)}>删除</el-button>
// </div>
// )
// }
// }
]
})
const rules = reactive({
attachment: [{required: true, message: '请上传附件', trigger: ['blur', 'change']}],
})
const applyForm = ref()
const singleFile = ref()
const allFileList = ref([])
const props = defineProps({
showFileList: {
type: Boolean,
default: false
},
label: {
}, label: {
type: String,
default: '项目附件'
},
showTable: {
}, showTable: {
type: Boolean,
default: true
}, preview: {
type: Boolean,
default: false
},
showSingleTable: {
type: Boolean,
default: false
},
preview: {
type: Boolean,
default: false
},
//是否显示模板下载按钮
templateDownloadBtnShow: {
type: Boolean,
default: false
},
//模板下载时的文件名
templateName: {
type: String,
default: ''
},
singleList: {
}, otherFileList: {
type: Array,
default: []
},
otherFileList: {
}, formData: {
type: Array,
default: []
},
formData: {
type: Object,
default: {}
},
labelPosition: {
type: String,
default: ''
},
tag: {
type: String,
default: ''
}
})
const emit = defineEmits(["getAttachment", "getOtherFile", "update:singleList"])
const baseTableConf = reactive(
[
{
prop: 'index',
type: 'index',
label: '序号',
align: 'center',
width: '80',
},
{
prop: 'originalFileName',
label: '文件名',
align: 'center',
width: 400,
currentRender: ({row, index}) => (
<div style="color: #2a99ff;cursor: pointer;"
onClick={() => clickToPreview(row)}>{row.originalFileName}</div>)
},
{
prop: 'tag',
label: '标签',
align: 'center',
// currentRender: ({row, index}) => (
// <el-input placeholder={row.tag} onClick={() => {}}></el-input>)
},
{
prop: 'size',
label: '文件大小',
align: 'center',
currentRender: ({row, index}) => (parseInt(row.size / 1024) + 'KB')
},
]
)
const tableConfig = reactive({
columns: [
...baseTableConf,
{
prop: 'oper',
label: '操作',
align: 'center',
showOverflowTooltip: false,
currentRender: ({row, index}) => {
let btn = []
btn.push({label: '下载', func: () => handleDownload(row), type: 'primary'})
// if (row.newFile) {
// btn.push({label: '删除', func: () => handleDelete(row), type: 'primary'})
// }
return (
<div style={{width: '100%'}}>
{
btn.map(item => (
<el-button
type={item.type}
onClick={() => item.func()}
link
>
{item.label}
</el-button>
))
}
{
row.newFile || props.preview || !props.preview ?
<popover-delete name={row.originalFileName} type={'文件'} btnType={'danger'}
// perm={['']}
onDelete={() => handleDelete(row)}/>
: ''
}
</div>
)
}
}
]
})
const singleTableConfig = reactive({
columns: [
...baseTableConf,
{
prop: 'oper',
label: '操作',
align: 'center',
showOverflowTooltip: false,
currentRender: ({row, index}) => {
let btn = []
btn.push({label: '下载', func: () => handleDownload(row), type: 'primary'})
// if (row.newFile) {
// btn.push({label: '删除', func: () => handleDelete(row), type: 'primary'})
// }
return (
<div style={{width: '100%'}}>
{
btn.map(item => (
<el-button
type={item.type}
onClick={() => item.func()}
link
>
{item.label}
</el-button>
))
}
{
row.newFile || props.preview || !props.preview ?
<popover-delete name={row.originalFileName} type={'文件'} btnType={'danger'}
// perm={['']}
onDelete={() => handleSingleDelete(row)}/>
: ''
}
</div>
)
}
}
]
})
const editSingleTableConfig = reactive({
columns: [
...baseTableConf,
{
prop: 'oper',
label: '操作',
align: 'center',
showOverflowTooltip: false,
currentRender: ({row, index}) => {
let btn = []
btn.push({label: '下载', func: () => handleDownload(row), type: 'primary'})
// if (row.newFile) {
// btn.push({label: '删除', func: () => handleDelete(row), type: 'primary'})
// }
return (
<div style={{width: '100%'}}>
{
btn.map(item => (
<el-button
type={item.type}
onClick={() => item.func()}
link
>
{item.label}
</el-button>
))
}
{
row.newFile || props.preview || !props.preview ?
<popover-delete name={row.originalFileName} type={'文件'} btnType={'danger'}
// perm={['']}
onDelete={() => deleteSingleFile(row, 1)}/>
: ''
}
</div>
)
}
}
]
})
const singleFileArray = ref([])
const rules = reactive({
// attachment: [{required: true, message: '请上传附件', trigger: ['blur', 'change']}],
})
const applyForm = ref()
const singleFile = ref({})
const isSingleFile = ref(false)
const isHaveOneFile = ref(false)
const allFileList = ref([])
if (localStorage.getItem('singleFile')) {
singleFileArray.value.push(JSON.parse(localStorage.getItem('singleFile')))
singleFile.value = JSON.parse(localStorage.getItem('singleFile'))
}
const filePreviewParam = ref({
fileUrl: '',
fileName: '',
fileType: 'pdf'
})
const filePreviewRef = ref()
const filePreviewShow = ref(false)
const _singleFileValue = computed({
get() {
return props.singleList;
},
set(value) {
emit('update:singleList', value)
}
})
const _otherFileListValue = computed({
get() {
return props.otherFileList;
},
set(value) {
emit('update:otherFileList', value)
}
})
if (_otherFileListValue.value && _otherFileListValue.value.length > 0) {
isHaveOneFile.value = true
_otherFileListValue.value.forEach(item => {
allFileList.value.push(item)
})
}
// watch(() => props.showSingleTable, (newVal) => {
// props.showSingleTable = newVal
// }, {deep: true})
watch(() => props.formData.fileList, (newVal) => {
if (props.preview) {
newVal?.forEach(item => {
isHaveOneFile.value = true
allFileList.value.push(item)
})
}
}, {immediate: true})
watch(() => props.formData.singleFile, (newVal) => {
props.formData.singleFile = newVal
if (newVal != null) {
singleFileArray.value.push(newVal)
} else {
singleFileArray.value = []
}
singleFile.value = newVal
}, {immediate: true})
// watch(() => props.otherFileList, (newVal) => {
// props.otherFileList=newVal
// if (props.preview) {
// console.log('newotherFileList', newVal,props.preview,props.formData.fileList)
// if (props.formData.fileList === null || props.formData.fileList?.length === 0) {
// allFileList.value = newVal
// } else {
// console.log('props.otherFileList',props.otherFileList)
// // props.otherFileList?.forEach(item => {
// // allFileList.value.push(item)
// // })
// }
// } else {
// allFileList.value = newVal
// }
// }, {deep: true})
watch(() => props.showTable, (newVal) => {
props.showTable = newVal
}, {deep: true})
// watch(() => props.singleList, (newVal) => {
// console.log('singleFile', newVal)
// singleFileList.value = newVal
// }, {deep: true})
watch(() => isSingleFile.value, (newVal) => {
isSingleFile.value = newVal
}, {deep: true})
watch(() => isHaveOneFile.value, (newVal) => {
isHaveOneFile.value = newVal
}, {deep: true})
// watch(() => singleFile.value, (newVal) => {
// singleFile.value = newVal
// }, {deep: true})
const handleImportTemplateDownload = async () => {
console.info("🚀 ~method:handleImportTemplateDownload -----", props.tag)
let templateType = ''
let templateTypeList = ''
let isZip = false
if (props.tag === '需求上报') {
templateType = '2'
isZip = false
} else if (props.tag === '项目立项') {
templateTypeList = '5,6'
isZip = true
} else if (props.tag === '项目验收') {
templateType = '7'
isZip = false
} else if (props.tag === '阶段变更') {
templateTypeList = '8,9'
isZip = true
}
let res = ''
if (isZip) {
res = await downloadTemplateZip(templateTypeList)
let fileName = props.templateName +'.zip'
const blob = new Blob([res.data])
let a = document.createElement('a')
a.href = URL.createObjectURL(blob)
a.download = fileName
a.click()
} else {
res = await downloadTemplate(templateType)
const blob = new Blob([res])
let a = document.createElement('a')
a.href = URL.createObjectURL(blob)
a.download = props.templateName + ".docx"
a.click()
}
}
const clickToPreview = (row) => {
filePreviewShow.value = false
console.log('clickToPreview', row, row.fileType)
filePreviewParam.value = {
fileUrl: row.url,
fileName: row.originalFileName,
fileType: row.fileType
}
nextTick(() => {
filePreviewShow.value = true
watch(() => props.otherFileList, (newVal) => {
newVal.forEach(item => {
allFileList.value.push(item)
})
// filePreviewRef.value.show()
}
const handleDelete = (row, type) => {
// deleteFile(row.fileId).then(res => {
// ElNotification({
// title: '提示',
// message: res.msg,
// type: res.code === 1000 ? 'success' : 'error'
// })
// if (res.code === 1000) {
if (type === 'single') {
_singleFileValue.value.splice(_singleFileValue.value.findIndex((item) => item.fileId === row.fileId), 1);
isSingleFile.value = false
} else {
allFileList.value.splice(allFileList.value.findIndex((item) => item.fileId === row.fileId), 1);
isHaveOneFile.value = !(allFileList.value && allFileList.value?.length == 0);
console.log('allFileList.value',allFileList.value)
if (localStorage.getItem('collectData')) {
let collectData = JSON.parse(localStorage.getItem('collectData'))
collectData.fileList = allFileList.value
localStorage.setItem('collectData', JSON.stringify(collectData))
}
if (localStorage.getItem('otherFileList')) {
localStorage.setItem('otherFileList', JSON.stringify(allFileList.value))
}
}
// }
// });
}
const handleSingleDelete = (row) => {
handleDelete(row, 'single')
}
}, {deep: true})
watch(() => props.formData.fileList, (newVal) => {
if (props.preview) {
newVal.forEach(item => {
allFileList.value.push(item)
})
}
}, {deep: true})
watch(() => props.formData.singleFile, (newVal) => {
// singleFile.value = {}
singleFile.value = newVal
}, {deep: true})
const getAttachment = (val) => {
isSingleFile.value = true
emit('getAttachment', val)
}
const compositeParam = (item) => {
return {
fileId: item.id,
size: item.size,
originalFileName: item.originalFilename,
fileType: item.fileType,
url: item.url,
newFile: true,
tag: props.tag
}
}
const getOtherFile = (val) => {
if (props.preview) {
allFileList.value.push(compositeParam(val))
} else {
allFileList.value = _otherFileListValue.value
}
isHaveOneFile.value = true
emit('getOtherFile', val)
}
const deleteAttachment = (val) => {
deleteFile(val).then(res => {
if (res.code === 1000) {
ElNotification({
title: '提示',
message: "删除成功",
type: 'success'
})
isSingleFile.value = false
singleFile.value = null
singleFileArray.value = []
ElMessage.success("删除成功");
}
});
}
const deleteSingleFile = (row, type) => {
ElMessageBox.confirm(`确认删除名称为${row.originalFileName}的文件吗?`, '系统提示', {
const deleteOtherFile = (row, type) => {
ElMessageBox.confirm(`确认删除名称为${row.originalFileName}的表格吗?`, '系统提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
@@ -492,12 +151,10 @@ const deleteSingleFile = (row, type) => {
type: res.code === 1000 ? 'success' : 'error'
})
if (res.code === 1000) {
isSingleFile.value = false
if (type === 1) {
singleFile.value = null
singleFileArray.value = []
singleFile.value = {}
} else {
props.otherFileList.splice(props.otherFileList.findIndex((item) => item.fileId === row.fileId), 1);
props.otherFileList.splice(props.otherFileList.findIndex((item) => item.id === row.fileId), 1);
}
}
});
@@ -526,29 +183,10 @@ defineExpose({
return applyForm.value.clearValidate()
},
allFileList,
singleFile,
isSingleFile,
isHaveOneFile,
singleFile
})
</script>
<style lang="scss" scoped>
:deep(.el-table--fit ) {
height: 160px !important;
}
:deep(.el-table__header) {
.is-leaf:first-child {
.cell {
margin-left: -22px !important;
}
}
}
<style scoped>
:deep(.el-table__body) {
.el-table__cell:first-child {
.cell {
margin-left: -11px !important;
}
}
}
</style>

View File

@@ -1,110 +0,0 @@
<template>
<el-button color="#DED0B2" style="float: right;margin: 0 10px 10px 0" @click="exportExcelHandler">导出</el-button>
<el-table ref="table" :data="tableData" style="width: 100%;height: 479px" :show-summary="true" border
:summary-method="getSummaries" v-loading="loading" :header-cell-style="{background:'#f5f7fa'}">
<el-table-column type="index" label="序号" align="center" width="60"/>
<el-table-column prop="projectName" label="项目名称" align="center"/>
<el-table-column prop="projectCost" label="费用性质" align="center">
<template #default="scope">
<div v-if="scope.row.projectCost !== null">
<Tag dictType="project_cost" :value="scope.row.projectCost"/>
</div>
<div v-else>--</div>
</template>
</el-table-column>
<el-table-column prop="researchStage" label="研发阶段" align="center">
<template #default="scope">
<div v-if="scope.row.researchStage !== null && scope.row.researchStage !== null && scope.row.researchStage !== undefined">
<el-tag effect="plain">{{scope.row.researchStage==1?'开发阶段':'研究阶段'}}</el-tag>
</div>
<div v-else>--</div>
</template>
</el-table-column>
<el-table-column prop="afterTax" label="分摊金额" align="center">
<template #default="scope">
<div v-if="scope.row.afterTax !== null">
<!-- {{ toThousands(scope.row.afterTax) }}-->
{{ scope.row.afterTax }}
</div>
</template>
</el-table-column>
</el-table>
<!-- <Tag dictType="research_stage" :value="scope.row.researchStage"/>-->
</template>
<script setup>
import {getAllocationSummaryDetails} from "@/api/expense-manage";
import {shareExportExcel} from "@/api/expense-manage";
const props = defineProps({
allocationName :{
type: String,
default: ''
}
})
const tableData = ref()
const loading = ref(false)
const table = ref()
const route = useRoute()
const getSummaries = (param) => {
const {columns, data} = param
const sums = []
columns.forEach((column, index) => {
if (index === 0) {
sums[index] = '小计'
} else if (index === 4) {
const values = data.map((item) => Number(item[column.property]))
if (!values.every((value) => Number.isNaN(value))) {
sums[index] = `${values.reduce((prev, curr) => {
const value = Number(curr)
if (!Number.isNaN(value)) {
return prev + curr
} else {
return prev
}
}, 0)}`
sums[index] = parseFloat(sums[index]).toFixed(2)
// sums[index] = toThousands(sums[index])
} else {
sums[index] = '-'
}
}
})
return sums
}
// const exportTable = () => {
// const $e = table.value.$el
// let $table = $e.querySelector('.el-table__fixed')
// if (!$table) {
// $table = $e
// }
// exportExcel($table, (5 + (Object.keys(tableData.value[0]).length - 5) * 5), "四川省国有资产经营投资管理有限责任公司科技创新项目费用分摊表", 2)
// }
const exportExcelHandler = () => {
shareExportExcel(route.query.id).then(res => {
let fileName = `科技创新项目费用分摊表-${props.allocationName}.zip`
const blob = new Blob([res.data])
let a = document.createElement('a')
a.href = URL.createObjectURL(blob)
a.download = fileName
a.click()
})
}
const init = () => {
loading.value = true
let params = {
allocationId: route.query.id
}
getAllocationSummaryDetails(params).then(res => {
tableData.value = res.data
loading.value = false
})
}
init()
</script>
<style scoped>
</style>

View File

@@ -1,73 +1,51 @@
<template>
<div v-loading="loading">
<baseTitle v-if="type!='phase'" :title="getTagName(type)+getTitleInfo(data.taskId)"></baseTitle>
<fvForm :schema="schema" @getInstance="(e)=>form = e" style="margin-left: 15px"></fvForm>
<el-form :model="formData" label-width="auto" style="margin-top: -15px">
<file-component :title="getTagName(type)+'附件'" :tag="getTagName(type)" :isOpenPrint="isOpenPrint"
v-model:value="formData.fileList" :processViewer="processViewer"
:file-list-show="fileListShow"/>
</el-form>
<div v-if="data.taskId">
<baseTitle title="审核意见"></baseTitle>
<el-form-item prop="_value">
<el-input
v-model="_value"
:rows="3"
type="textarea"
placeholder="请输入审核意见"
/>
<div v-loading="loading">
<fvForm :schema="schema" @getInstance="(e)=>form = e"></fvForm>
<!-- <AttachmentUpload></AttachmentUpload> -->
<el-form :model="formData" label-width="auto">
<el-form-item label="其他文件">
<el-table :data="formData.fileList" style="width: 100%">
<el-table-column label="序号" type="index" width="80"></el-table-column>
<el-table-column label="文件名称" prop="originalFileName"></el-table-column>
<el-table-column label="标签" prop="tag"></el-table-column>
<el-table-column label="文件大小" prop="size">
<template #default="{row}">
{{ parseInt(row.size / 1024) + 'KB' }}
</template>
</el-table-column>
</el-table>
</el-form-item>
</div>
</el-form>
<div class="approval-record">
<div class="approval-title" style="margin-top: -15px">
<baseTitle title="审批记录"></baseTitle>
<div class="diagram">
<div class="base-title">流程图</div>
<el-switch
v-model="changeDiagram"
style="--el-switch-on-color:#BEA266 ; --el-switch-off-color:#cecdcd"
/>
<div class="process">
<operation-render v-if="processViewer" :operation-list="data.operationList"
:state="data.state"/>
<process-diagram-viewer v-if="processViewer" :id-name="type"/>
</div>
<el-button color="#DED0B2" style="margin-left: 10px"
@click="handleCarbonCopy()">立即抄送
</el-button>
</div>
<div class="process">
<operation-render v-if="processViewer && data.operationList && data.operationList.length > 0&&!changeDiagram"
:operation-list="data.operationList"
:state="data.state"/>
<process-diagram-viewer v-if="processViewer&&changeDiagram" :id-name="idName?idName:type"/>
</div>
</div>
<user-picker :multiple="true" ref="carbonCopyUserRef" title="请选择抄送人员"
v-model:value="carbonCopyUserList" @ok="carbonCopyUserPickerOk"
@cancelOrClear="carbonCopyUserPickerOk"/>
<file-preview ref="filePreviewRef" :fullscreen="fullscreen" v-if="filePreviewShow"
:fileName="filePreviewParam.fileName" :fileUrl="filePreviewParam.fileUrl"
:fileType="filePreviewParam.fileType"/>
<!-- <Opinion: v-if="data.taskId" :formData="formData" :taskId="formData.taskId"></Opinion:>-->
</div>
</template>
<script setup lang="jsx">
import { computed, markRaw, reactive, ref, watchEffect } from 'vue';
import AttachmentUpload from '../AttachmentUpload.vue';
import OperationRender from '@/views/workflow/common/OperationRender.vue'
import ProcessDiagramViewer from '@/views/workflow/common/ProcessDiagramViewer.vue';
import {ElLoading, ElNotification} from 'element-plus';
import {downloadFile} from "@/api/project-demand";
import {searchImplementationFileList} from "@/api/project-manage/attachment";
import {getTags} from "@/api/project-manage";
import {applyCcSend} from "@/api/expense-manage";
import UserPicker from "@/views/workflow/process/common/UserPicker.vue";
import Opinion from './Opinion.vue';
import fvTable from '@/fvcomponents/fvTable/index.vue'
import { ElLoading } from 'element-plus';
import {deleteFile, downloadFile} from "@/api/project-demand";
const changeDiagram = ref(false)
const props = defineProps({
formData: {
type: Object,
default: {}
},
data: {
type: Object,
default: {}
type: Array,
default: []
},
processViewer: {
type: Boolean,
@@ -77,579 +55,122 @@ const props = defineProps({
type: Array,
default: []
},
basicData: {
type: Object,
default: {}
},
fileListShow: {
type: String,
default: 'READ'
},
preProcessShow: {
type: String,
default: 'READ'
},
// approval 立项, execute 实施, 归档 archivist
type: {
type: String,
default: 'approval'
},
loading: {
}, loading: {
type: Boolean,
default: false
},
//是否开始打印
isOpenPrint: {
type: Boolean,
default: false
},
value: {
type: String,
default: ''
},
idName: {
type: String,
default: ''
}
})
watch(() => props.loading, (newVal) => {
props.loading = newVal
}, {deep: true})
const form = ref()
const carbonCopyUserList = ref([])
const carbonCopyUserRef = ref()
const editSingleTableConfig = reactive({
columns: [
{
prop: 'index',
type: 'index',
label: '序号',
align: 'center',
width: 85,
},
{
prop: 'originalFileName',
label: '文件名',
align: 'center',
width: 400,
currentRender: ({row, index}) => (
<div style="color: #2a99ff;cursor: pointer;" onClick={() => clickToPreview(row)}>{row.originalFileName}</div>)
},
{
prop: 'tag',
label: '标签',
align: 'center'
},
{
prop: 'size',
label: '文件大小',
align: 'center',
width: 150,
currentRender: ({row, index}) => (parseInt(row.size / 1024) + 'KB')
},
{
prop: 'oper',
label: '操作',
align: 'center',
showOverflowTooltip: false,
currentRender: ({row, index}) => {
let btn = []
btn.push({label: '下载', func: () => handleDownload(row), type: 'primary'})
// if (row.newFile) {
// btn.push({label: '删除', func: () => handleDelete(row), type: 'primary'})
// }
return (
<div style={{width: '100%'}}>
{
btn.map(item => (
<el-button
type={item.type}
onClick={() => item.func()}
link>
{item.label}
</el-button>
))
}
{
row.newFile ? <popover-delete name={row.originalFileName} type={'文件'} btnType={'danger'}
onDelete={() => handleDelete(row)}/>
: ''
}
</div>
)
}
}
]
const localData = reactive({
fileList: props.formData.fileList,
singleFile: props.formData.singleFile
})
let preProcess = {
label: '前置流程',
prop: 'preProcess',
colProps: {
span: 24
},
labelWidth: 'left',
component: () => (
<div>
{
props.formData.preProcess ? props.formData.preProcess.map((item, index) => {
return <span><a target="_blank" style={{color: '#409EFF', cursor: 'pointer'}}
href={props.formData.preProcessBaseUrl + item.requestId}>{item.requestName} {index != (props.formData.preProcess.length - 1) ?
<span></span> : ''}</a></span>
}) : <span>{'--'}</span>
}
</div>
)
}
const schema = computed(() => {
const schema = computed(()=>{
let arr
if (props.type == 'approval') {
if(props.type == 'approval') {
arr = [
{
label: '项目负责人',
prop: 'projectChargePerson',
colProps: {
span: 6
},
labelWidth: 'left',
component: () => (
<div>
{
props.formData.projectChargePerson ?
<span>{props.formData.projectChargePerson.name} </span>
: <span>{'--'}</span>
}
</div>
)
},
{
label: '项目成员',
prop: 'projectPersonList',
colProps: {
span: 6
},
labelWidth: 'left',
component: () => (
<div>
{
props.formData.projectPersonList ? props.formData.projectPersonList.map((item, index) => {
return <span>{item.name}
<span>{index != props.formData.projectPersonList?.length - 1 ? '' : ''}</span></span>
}) : <span>{'--'}</span>
}
</div>
)
},
{
label: '部门分管领导',
prop: 'optionalChargeLeadership',
colProps: {
span: 6
},
labelWidth: 'left',
component: () => (
<div>
{
props.formData.optionalChargeLeadership?.length > 0 ? props.formData.optionalChargeLeadership.map(item => {
return <span>{item.name} </span>
}) : <span>{'--'}</span>
}
</div>
)
},
]
if (props.preProcessShow == 'EDIT') {
preProcess = {
label: '前置流程',
prop: 'preProcess',
colProps: {
span: 24
},
labelWidth: 'left',
component: () => (
<div>
{
<select-pre-process formData={props.formData} basicData={props.basicData}/>
}
</div>
)
}
}
arr.push(preProcess)
// arr.push({
// label: '项目立项附件',
// prop: 'singleFile',
// colProps: {
// span: 24
// },
// labelWidth: 'left',
// component: () => {
// let singleFileArray = [props.formData.singleFile]
// return props.formData.singleFile ? <fvTable style="width: 100%;max-height: 80px;" height="80"
// tableConfig={editSingleTableConfig}
// data={singleFileArray} isSettingCol={false} pagination={false}>
// </fvTable>
// : <span>--</span>
// }
// })
} else if (props.type == 'execute') {
arr = [
{
label: '实际专利(项)',
prop: 'actualNewPatent',
colProps: {
span: 6
},
labelWidth: 'left',
component: () => (
<div>
{
props.formData.actualNewPatent ? props.formData.actualNewPatent :props.formData.actualNewPatent==0?0: <span>{'--'}</span>
}
</div>
)
}
},
{
label: '实际软件著作权(项)',
prop: 'actualSoftwareCopyright',
colProps: {
span: 6
},
labelWidth: 'left',
component: () => (
<div>
{
props.formData.actualSoftwareCopyright ? props.formData.actualSoftwareCopyright : props.formData.actualSoftwareCopyright==0?0: <span>{'--'}</span>
}
</div>
)
},
{
label: '实际技术标准(项)',
prop: 'actualTechnicalNorms',
colProps: {
span: 6
},
labelWidth: 'left',
component: () => (
<div>
{
props.formData.actualTechnicalNorms ? props.formData.actualTechnicalNorms : props.formData.actualTechnicalNorms==0?0:<span>{'--'}</span>
}
</div>
)
},
{
label: '实际新产品(项)',
prop: 'actualNewProduct',
colProps: {
span: 6
},
labelWidth: 'left',
component: () => (
<div>
{
props.formData.actualNewProduct ? props.formData.actualNewProduct : props.formData.actualNewProduct==0?0:<span>{'--'}</span>
}
</div>
)
},
{
label: '实际新工艺(项)',
prop: 'actualNewProcess',
colProps: {
span: 6
},
labelWidth: 'left',
component: () => (
<div>
{
props.formData.actualNewProcess ? props.formData.actualNewProcess : props.formData.actualNewProcess==0?0: <span>{'--'}</span>
}
</div>
)
},
{
label: '实际新装置(项)',
prop: 'actualNewDevice',
colProps: {
span: 6
},
labelWidth: 'left',
component: () => (
<div>
{
props.formData.actualNewDevice ? props.formData.actualNewDevice :props.formData.actualNewDevice==0?0: <span>{'--'}</span>
}
</div>
)
},
{
label: '实际新材料(项)',
prop: 'actualNewMaterials',
colProps: {
span: 6
},
labelWidth: 'left',
component: () => (
<div>
{
props.formData.actualNewMaterials ? props.formData.actualNewMaterials : props.formData.actualNewMaterials==0?0: <span>{'--'}</span>
}
</div>
)
},
{
label: '实际计算机软件(项)',
prop: 'actualComputerSoftware',
colProps: {
span: 6
},
labelWidth: 'left',
component: () => (
<div>
{
props.formData.actualComputerSoftware ? props.formData.actualComputerSoftware : props.formData.actualComputerSoftware==0?0:<span>{'--'}</span>
}
</div>
)
},
{
label: '实际论文论著(项)',
prop: 'actualThesis',
colProps: {
span: 6
},
labelWidth: 'left',
component: () => (
<div>
{
props.formData.actualThesis ? props.formData.actualThesis : props.formData.actualThesis==0?0:<span>{'--'}</span>
}
</div>
)
},
{
label: '实际研究报告(项)',
prop: 'actualResearchReport',
colProps: {
span: 6
},
labelWidth: 'left',
component: () => (
<div>
{
props.formData.actualResearchReport ? props.formData.actualResearchReport : props.formData.actualResearchReport==0?0: <span>{'--'}</span>
}
</div>
)
},
{
label: '实际商标(项)',
prop: 'actualTrademark',
colProps: {
span: 6
},
labelWidth: 'left',
component: () => (
<div>
{
props.formData.actualTrademark ? props.formData.actualTrademark :props.formData.actualTrademark==0?0: <span>{'--'}</span>
}
</div>
)
},
{
label: '实际其他(项)',
prop: 'actualOther',
label: '项目立项附件',
prop: 'singleFile',
colProps: {
span: 24
},
labelWidth: 'left',
component: () => (
<div style="white-space: pre-wrap;">
{
props.formData.actualOther ? props.formData.actualOther : props.formData.actualOther==0?0: <span>{'--'}</span>
}
</div>
component: ()=>(
<div>
{
props.formData.singleFile?.originalFileName ?
<span
style={{color: '#409EFF', cursor: 'pointer'}}
onClick={()=>handleDownload(props.formData.singleFile)}
>
{props.formData.singleFile?.originalFileName}
</span> :
<span>{'--'}</span>
}
</div>
)
},
{
label: '部门分管领导',
prop: 'optionalChargeLeadership',
colProps: {
span: 24
},
labelWidth: 'left',
component: () => (
<div>
{
props.formData.optionalChargeLeadership?.length > 0 ? props.formData.optionalChargeLeadership.map(item => {
return <span>{item.name} </span>
}) : <span>{'--'}</span>
}
</div>
)
}
]
if (props.preProcessShow == 'EDIT') {
preProcess = {
} else if(props.type == 'execute') {
arr = [
{
label: '前置流程',
prop: 'preProcess',
colProps: {
span: 24
}
},
{
label: '项目验收附件',
prop: 'singleFile',
colProps: {
span: 24
},
labelWidth: 'left',
component: () => (
component: ()=>(
<div>
{
<select-pre-process formData={props.formData} basicData={props.basicData}/>
props.formData.singleFile?.originalFileName ?
<span
style={{color: '#409EFF', cursor: 'pointer'}}
onClick={()=>handleDownload(props.formData.singleFile)}
>
{props.formData.singleFile?.originalFileName}
</span> :
<span>{'--'}</span>
}
</div>
)
}
}
arr.push(preProcess)
// arr.push(
// {
// label: '项目验收附件',
// prop: 'singleFile',
// colProps: {
// span: 24
// },
// labelWidth: 'left',
// component: () => {
// let singleFileArray = [props.formData.singleFile]
// return props.formData.singleFile ? <fvTable style="width: 100%;max-height: 80px;" height="80"
// tableConfig={editSingleTableConfig}
// data={singleFileArray} isSettingCol={false} pagination={false}>
// </fvTable>
// : <span>--</span>
// }
// })
} else if (props.type == 'archivist') {
arr = [
// {
// label: '项目归档附件',
// prop: 'singleFile',
// colProps: {
// span: 24
// },
// labelWidth: 'left',
// component: () => {
// let singleFileArray = [props.formData.singleFile]
// return props.formData.singleFile ? <fvTable style="width: 100%;max-height: 80px;" height="80"
// tableConfig={editSingleTableConfig}
// data={singleFileArray} isSettingCol={false} pagination={false}>
// </fvTable>
// : <span>--</span>
// }
// },
},
]
} else if (props.type == 'phase') {
} else {
arr = [
// {
// label: '阶段变更附件',
// prop: 'singleFile',
// colProps: {
// span: 24
// },
// labelWidth: 'left',
// component: () => {
// let singleFileArray = [props.formData.singleFile]
// return props.formData.singleFile ? <fvTable style="width: 100%;max-height: 80px;" height="80"
// tableConfig={editSingleTableConfig}
// data={singleFileArray} isSettingCol={false} pagination={false}>
// </fvTable>
// : <span>--</span>
// }
// },
{
label: '项目归档附件',
prop: 'singleFile',
colProps: {
span: 24
},
component: ()=>(
<div>
{
props.formData.singleFile?.originalFileName ?
<span
style={{color: '#409EFF', cursor: 'pointer'}}
onClick={()=>handleDownload(props.formData.singleFile)}
>
{props.formData.singleFile?.originalFileName}
</span> :
<span>{'--'}</span>
}
</div>
)
},
]
}
return arr
})
const filePreviewParam = ref({
fileUrl: '',
fileName: '',
fileType: ''
})
const filePreviewShow = ref(false)
const route = useRoute()
const emit = defineEmits(['update:value', 'ccSend'])
const _value = computed({
get() {
return props.value;
},
set(val) {
emit("update:value", val);
}
})
const handleCarbonCopy = () => {
carbonCopyUserRef.value.showUserPicker()
}
const carbonCopyUserPickerOk = (userList) => {
carbonCopyUserList.value = userList.map(item => item.id)
console.log('localFormData.value', props.data)
console.log("🚀 ~ file:'carbonCopyUserList.value ", carbonCopyUserList.value)
addUser()
}
const addUser = async () => {
const res = await applyCcSend({
instanceId: props.data.processInstanceId,
// message:props.data.remark,
projectId: route.query.projectId,
state: route.query.step,
userIds: carbonCopyUserList.value
})
console.log('res', res)
if (res.code === 1000) {
ElNotification({
title: '提示',
message: '抄送成功',
type: 'success'
})
emit('ccSend')
} else {
ElNotification({
title: '提示',
message: res.msg,
type: 'error'
})
}
}
const clickToPreview = (row) => {
filePreviewShow.value = false
filePreviewParam.value = {
fileUrl: row.url,
fileName: row.originalFileName,
fileType: row.fileType
}
nextTick(() => {
filePreviewShow.value = true
})
}
const getTitleInfo = (taskId) => {
if (taskId) {
return '审批'
} else {
return '信息'
}
}
const getTagName = (type) => {
switch (type) {
case 'approval':
return '项目立项'
case 'execute':
return '项目验收'
case 'archivist':
return '项目归档'
case 'phase':
return '阶段变更'
}
}
const handleDownload = (row) => {
const loading = ElLoading.service({fullscreen: true})
downloadFile(row.fileId).then(res => {
@@ -661,50 +182,12 @@ const handleDownload = (row) => {
loading.close()
})
}
watchEffect(() => {
Object.keys(props.formData).length && (form.value?.setValues(props.formData))
watchEffect(()=>{
Object.keys(props.formData).length && (form.value.setValues(props.formData))
})
watch(() => props.loading, (newVal) => {
props.loading = newVal
}, {deep: true})
</script>
<style lang="scss">
.execute-table {
.el-table__header {
.el-table__cell:last-child {
.cell {
margin-left: -160px !important;
}
}
}
.el-table__body {
.el-table__cell:last-child {
.cell {
margin-left: -160px !important;
}
}
}
}
</style>
<style lang="scss" scoped>
:deep(.el-table__header) {
.is-leaf:first-child {
.cell {
margin-left: 10px !important;
white-space: nowrap;
padding: 0;
}
}
}
:deep(.el-table__body) {
.el-table__cell:first-child {
.cell {
margin-left: 5px !important;
}
}
}
</style>

View File

@@ -1,59 +1,53 @@
<template>
<div v-loading="loading" :style="type==='singleDetail'?'padding: 0 30px':''">
<baseTitle title="需求征集信息" v-if="type!=='singleDetail'"></baseTitle>
<el-form :model="formData" >
<el-row gutter="20" style="margin-left: 5px">
<el-col :span="6">
<el-form-item label="征集名称">
<div v-loading="loading">
<el-form :model="formData" ref="form" label-width="auto">
<el-row>
<el-col :span="12">
<el-form-item label="名称">
<span>{{ formData.requirementName }}</span>
</el-form-item>
</el-col>
<el-col :span="6">
<el-col :span="12">
<el-form-item label="所属公司">
<span>{{ formData.companyIds }}</span>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="征集类型">
<span>{{ formData.collectType }}</span>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="需求上报截止时间">
<el-col :span="12">
<el-form-item label="截止时间">
<span>{{ formData.deadline }}</span>
</el-form-item>
</el-col>
<el-col :span="6" v-if="formData.isSpecialFund">
<el-form-item label="专项资金名称">
<span>{{ formData.specialFund }}</span>
</el-form-item>
</el-col>
<el-col :span="24" v-if="type==='singleDetail'">
<el-form-item label="征集公司">
<span :class="showExpendClass(showMoreCompany,formData.companyIds)">{{
getCompanyName(formData.companyIds)
}}</span>
<div style="color: #2a99ff;text-align: center;width: 100%;font-size: 15px;cursor: pointer"
@click="handleExpend">{{ showExpendText }}
</div>
</el-form-item>
</el-col>
<el-col :span="24" style="margin-bottom: -15px">
<el-form-item label="征集说明">
<div v-if="formData.collectExplain" v-html="formData.collectExplain" style="white-space: pre-wrap;">
</div>
<div v-else>--</div>
</el-form-item>
</el-col>
</el-row>
<el-row>
<baseTitle title="征集说明"></baseTitle>
<el-col :span="24">
<baseTitle v-if="fileListShow === 'READ' || fileListShow === 'EDIT'" title="附件文件" style="margin-bottom: 0"></baseTitle>
<file-component title="" tag="需求征集"
v-model:value="formData.fileList" :processViewer="processViewer"
:file-list-show="fileListShow"/>
<el-form-item>
<el-card style="width: 100%">
<div v-html="formData.collectExplain">
</div>
</el-card>
</el-form-item>
</el-col>
<el-col :span="24" style="margin-top: -15px">
<div v-if="data.taskId">
<baseTitle title="附件列表"></baseTitle>
<el-col :span="24">
<el-form-item>
<fvTable style="width: 100%;max-height: 200px" v-if="processViewer" :tableConfig="tableConfig"
:data="formData.fileList" :isSettingCol="false" :pagination="false">
<template #empty>
<el-empty :image-size="90" description="暂无数据" style="padding: 0"/>
</template>
</fvTable>
</el-form-item>
</el-col>
<el-col :span="24">
<div v-if="formData.taskId">
<baseTitle title="审核意见"></baseTitle>
<el-form-item prop="_value">
<el-form-item prop="auditOpinion">
<el-input
v-model="_value"
v-model="formData.auditOpinion"
:rows="3"
type="textarea"
placeholder="请输入审核意见"
@@ -62,22 +56,12 @@
</div>
</el-col>
</el-row>
<div class="approval-record" style="margin-top: -15px">
<div class="approval-title">
<baseTitle title="审批记录"></baseTitle>
<div class="diagram">
<div class="base-title">流程图</div>
<el-switch
v-model="changeDiagram"
style="--el-switch-on-color:#BEA266; --el-switch-off-color:#cecdcd"
/>
</div>
</div>
<div class="approval-record">
<baseTitle title="审批记录"></baseTitle>
<div class="process">
<operation-render v-if="processViewer && data.operationList && data.operationList.length > 0&&!changeDiagram"
:operation-list="data.operationList"
<operation-render v-if="processViewer" :operation-list="data.operationList"
:state="data.state"/>
<process-diagram-viewer v-if="processViewer&&changeDiagram" id-name="collectionProcess"/>
<process-diagram-viewer v-if="processViewer" id-name="collectionProcess"/>
</div>
</div>
</el-form>
@@ -87,11 +71,14 @@
<script setup lang="jsx">
import OperationRender from '@/views/workflow/common/OperationRender.vue'
import ProcessDiagramViewer from '@/views/workflow/common/ProcessDiagramViewer.vue'
import {matterTree} from '@/utils/matterTree.js';
import {downloadFile} from "@/api/project-demand";
const emit = defineEmits(['update:value'])
const showExpendText = ref('')
const showMoreCompany = ref(false)
const emit = defineEmits(['getInfo',"update:formData"])
const form = ref()
const showTable = ref(false)
const companyNameArray = ref([])
const props = defineProps({
formData: {
type: Array,
@@ -108,54 +95,48 @@ const props = defineProps({
companyOption: {
type: Array,
default: []
},
loading: {
}, loading: {
type: Boolean,
default: false
},
fileListShow: {
type: String,
default: ''
},
type: {
type: String,
default: ''
},
value: {
type: String,
default: ''
}
})
const changeDiagram = ref(false)
const _value = computed({
get() {
return props.value;
},
set(val) {
emit("update:value", val);
}
})
const getCompanyName = (data) => {
if (data) {
return data.join('')
}
}
const handleExpend = () => {
showMoreCompany.value = !showMoreCompany.value;
showExpendClass(showMoreCompany.value, props.formData.companyIds)
}
const showExpendClass = (showMoreCompany, data) => {
if (!showMoreCompany) {
if (data && data.length > 14) {
showExpendText.value = '展开'
return 'company-style'
const tableConfig = reactive({
columns: [
{
prop: 'index',
type: 'index',
label: '序号',
align: 'center',
width: '80',
},
{
prop: 'originalFileName',
label: '文件名',
align: 'center',
},
{
prop: 'tag',
label: '标签',
align: 'center'
},
{
prop: 'size',
label: '文件大小',
align: 'center',
currentRender: ({row, index}) => (parseInt(row.size / 1024) + 'KB')
},
{
prop: 'oper',
label: '操作',
align: 'center',
currentRender: ({row, index}) => {
return (
<el-button type="primary" link onClick={() => handleDownload(row)}>下载</el-button>
)
}
}
} else {
showExpendText.value = '收缩'
return ''
}
}
]
})
const handleDownload = (row) => {
downloadFile(row.fileId).then(res => {
const blob = new Blob([res])
@@ -165,44 +146,33 @@ const handleDownload = (row) => {
a.click()
})
}
const getDataSourceOptionItem = (val) => {
if (val instanceof Array) {
val.forEach(item => {
matterTree(companyNameArray.value, props.companyOption, item)
})
}
let uniqueArr = Array.from(new Set(companyNameArray.value));
return uniqueArr.join('');
}
watch(() => props.loading, (newVal) => {
props.loading = newVal
}, {deep: true})
watch(() => props.companyOption, (newVal) => {
props.companyOption = newVal
}, {deep: true})
watch(() => props.formData, (newVal) => {
if(newVal!=null){
props.formData.companyIds = getDataSourceOptionItem(newVal.companyIds)
}
}, {deep: true})
watch(() => props.processViewer, (newVal) => {
props.processViewer = newVal
}, {deep: true})
</script>
<style scoped lang="scss">
:deep(.el-empty__description) {
margin-top: 0;
}
<style scoped>
.company-style {
//width: 98%;
min-height: 30px;
max-height: 60px;
overflow: hidden;
text-overflow: ellipsis;
-webkit-line-clamp: 2;
display: -webkit-box;
-webkit-box-orient: vertical;
}
:deep(.el-table__header) {
.is-leaf:first-child {
.cell {
margin-left: -53px !important;
}
}
}
:deep(.el-table__body) {
.el-table__cell:first-child {
.cell {
margin-left: -26px !important;
}
}
}
</style>

View File

@@ -1,424 +0,0 @@
<template>
<el-dialog custom-class="custom-dialog" class="border" :border="false" width="1000px" style="height: 676px"
:title="title" :show-close="false" :visible.sync="visible" v-model="visible" append-to-body :close-on-click-modal="false" @close="closeDialog">
<div class="picker">
<div class="candidate" v-loading="loading">
<el-input v-model="filterText"
clearable placeholder="输入公司进行搜索">
<template #append>
<el-button @click="getList()">搜索</el-button>
</template>
</el-input>
<fvCheckbox style="margin-left: 10px" :options="checkOptions" v-model="checkList" @change="checkBoxChange"/>
<!-- 人员选择 -->
<el-empty :image-size="100" description="似乎没有数据" v-show="dataList.length === 0"/>
<el-scrollbar style="height:87%;">
<div class="tree">
<el-tree :data="dataList" ref="tree" :props="defaultProps" empty-text="" node-key="value"
:show-checkbox="showCheckbox" highlight-current default-expand-all
:default-checked-keys="defaultChecked" :disabled="disabled"
:check-strictly="!checkStrictly" @node-click="(node,check)=>handleNodeClick(node,check)"
@check-change="handleCheckClick" :filter-node-method="filterNode">
<template #default="{ node, data }">
<div class="tree-node">
<div style="display: flex;align-items: center;padding: 3px 0">
{{ node.label }}
</div>
</div>
</template>
</el-tree>
</div>
</el-scrollbar>
</div>
<div class="selected">
<div class="count">
<span>已选 {{ selectList.length }} 项</span>
<span @click="clearSelected">清空</span>
</div>
<div class="org-items">
<el-empty :image-size="100" description="请点击左侧列表选择数据" v-show="selectList.length === 0"/>
<div v-for="(selectItem, selectIndex) in selectList" :key="selectIndex" class="org-item">
{{ selectItem.label }}
<el-icon @click="removeSingleSelected(selectItem)" size="20" style="margin-left: 10px;cursor: pointer;">
<CircleClose/>
</el-icon>
</div>
</div>
</div>
</div>
<div class="footer">
<el-button size="mini" @click="cancelUserPicker">取 消</el-button>
<el-button size="mini" color="#DED0B2" @click="selectConfirm">确 定</el-button>
</div>
</el-dialog>
</template>
<script setup>
import {ElMessageBox} from "element-plus";
import {getSubCompOpt} from "@/api/user/user";
const checkList = ref(['1'])
const checkStrictly = ref(false)
const isExpand = ref('展开')
const expandedKeys = ref(['-1']);
const checkOptions = ref([
{
label: isExpand.value,
value: '1'
},
// {
// label: '父子联动',
// value: '2'
// },
])
const props = defineProps({
value: {
type: Array,
default: () => {
return [];
}
},
multiple: { //是否多选
default: true,
type: Boolean
},
showCheckbox: { //是否显示左侧选择框
default: true,
type: Boolean
}
});
let selectItem = reactive({
type: -1,
value: "0"
});
const visible = ref(false);
const loading = ref(false);
const title = ref("请选择");
const selectList = ref([]);
const filterText = ref("");
const dataList = ref([]);
const defaultChecked = ref([]);
const tree = ref([]);
const defaultProps = {
value: "value",
label: "label",
children: "children",
disabled: "disabled",
};
const isRemoveSingleSelected = ref(false);
const emit = defineEmits(['update:modelValue'])
const _value = computed({
get() {
return props.value;
},
set(value) {
emit('update:modelValue', value)
}
});
watch(() => filterText.value, (newVal) => {
tree.value.filter(newVal);
});
const closeDialog=()=>{
console.log('关闭')
visible.value=false
filterText.value=''
}
const checkBoxChange = (val) => {
checkStrictly.value = val.includes('2')
let nodes = tree.value.store.nodesMap
if (val.includes('1')) {
for (const node in nodes) {
nodes[node].expanded = true;
}
isExpand.value = '折叠'
} else {
for (const node in nodes) {
nodes[node].expanded = false;
}
isExpand.value = '展开'
}
}
const getList = () => {
getSubCompOpt().then(res => {
dataList.value = [
{
label: "所有公司",
value: -1,
},
...res.data
]
});
};
//通过关键字过滤树节点
const filterNode = (value, data) => {
//通过关键字过滤树节点
if (!value) return true;
return data.label.indexOf(value) !== -1;
};
//用于用户选择
const show = () => {
//用于弹开部门选择
visible.value = true;
selectList.value = _value.value
defaultChecked.value = _value.value.map(item => item.value)
getList()
};
const updateTreeCheck = (list, flag) => {
list.forEach(item => {
if (item.value !== -1) {
tree.value.setChecked(item, flag)
if (item.children !== undefined) {
updateTreeCheck(item.children, flag)
}
}
})
}
const handleCheckClick = (data, checked) => {
if (data.value == -1) {
if(checked){
updateTreeCheck(dataList.value, false)
tree.value.setChecked(data,true);
}
}
if(tree.value.getCheckedKeys().length>1&&tree.value.getCheckedKeys().indexOf(-1)!==-1){
tree.value.setChecked(-1,false);
}
// 左侧有选择框 + 多选
if (props.multiple) {
//不添加重复的数据到右边
for (let i = 0; i < selectList.value.length; i++) {
if (selectList.value[i].value === data.value) {
selectList.value.splice(i, 1);
break;
}
}
if (checked) {
// if (data.children === undefined) {
selectList.value.push(data);
// }
} else if (data === "1") {
tree.value.setCheckedKeys([]);
selectList.value = [];
}
} else {// 左侧有选择框 + 单选
//不添加重复的数据到右边
for (let i = 0; i < selectList.value.length; i++) {
if (selectList.value[i].value === data.value) {
selectList.value.splice(i, 1);
break;
}
}
if (checked) {
tree.value.setCheckedNodes([data]);
selectList.value = [data];
} else if (data === "1") {
selectList.value = [];
tree.value.setCheckedKeys([]);
}
}
};
const handleNodeClick = (node, check) => {
if (check.isLeaf !== false) {
if (props.multiple) {
//不添加重复的数据到右边
for (let i = 0; i < selectList.value.length; i++) {
if (selectList.value[i].value === node.value) {
selectList.value.splice(i, 1);
break;
}
}
check.checked = true;
selectList.value.push(node);
} else {
check.checked = true;
selectList.value = [node];
}
}
// _value.value = selectList.value
};
const removeSingleSelected = (selectItem) => {
//左侧无选择框时,右侧显示×
for (let i = 0; i < selectList.value.length; i++) {
if (selectList.value[i].value === selectItem.value) {
tree.value.setChecked(selectList.value[i].value, false);
selectList.value.splice(i, 1);
break;
}
}
if (props.showCheckbox) {
// 左侧有选择框 + 单选
if (props.multiple === false) {
tree.value.setCheckedKeys([]);
}
}
// isRemoveSingleSelected.value = true
};
const clearSelected = () => {
//清空
ElMessageBox.confirm("您确定要清空已选中的项?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
}).then(() => {
// isRemoveSingleSelected.value = true
if (!props.showCheckbox) {
selectList.value = [];
} else {
handleCheckClick("1");
}
});
};
const cancelUserPicker = () => {
if (localStorage.getItem('originallyCompanySelectedList')) {
selectList.value = JSON.parse(localStorage.getItem('originallyCompanySelectedList'))
}else{
selectList.value=[]
handleCheckClick("1");
}
emit("cancelOrClear", selectList.value);
visible.value = false;
// nextTick(()=>{
// isRemoveSingleSelected.value=false
// })
}
const selectConfirm = () => {
//确定按钮
emit("ok", selectList.value);
dataList.value = []
visible.value = false;
localStorage.setItem('originallyCompanySelectedList', JSON.stringify(selectList.value))
};
defineExpose({
show
});
getList()
</script>
<style lang="scss" scoped>
$containWidth: 480px;
:deep(.tree) {
.el-tree-node__content {
height: 34px;
.tree-node {
font-size: 18px;
}
}
//.el-tree-node {
// .is-leaf + .el-checkbox .el-checkbox__inner {
// display: inline-block;
// }
//
// .el-checkbox .el-checkbox__inner {
// display: none;
// }
//}
}
.footer {
float: right;
margin-top: 10px;
}
.picker {
height: 560px;
position: relative;
text-align: left;
.candidate {
position: absolute;
display: block;
width: $containWidth;
height: 100%;
border: 1px solid #e8e8e8;
:deep(.el-input) {
height: 40px;
.el-input__inner, .el-input-group__append {
font-size: 16px;
}
}
}
.selected {
right: 0;
top: 0;
position: absolute;
display: inline-block;
width: 450px;
height: 100%;
border: 1px solid #e8e8e8;
.count {
width: 100%;
padding: 10px;
display: inline-block;
border-bottom: 1px solid #e8e8e8;
margin-bottom: 5px;
font-size: 16px;
> span:nth-child(2) {
float: right;
color: #c75450;
cursor: pointer;
margin-left: 10px;
}
}
.org-items {
overflow-y: auto;
height: 90%;
.el-icon-close {
position: absolute;
right: 5px;
cursor: pointer;
font-size: larger;
}
.org-item {
margin: 0 5px;
border-radius: 5px;
position: relative;
padding: 7px 5px;
display: flex;
align-items: center;
font-size: 16px;
&:hover {
background: #f1f1f1;
}
> span {
margin-left: 5px;
}
}
}
}
}
.el-scrollbar .el-scrollbar__wrap {
overflow-x: hidden;
}
::-webkit-scrollbar {
float: right;
width: 4px;
height: 4px;
background-color: white;
}
::-webkit-scrollbar-thumb {
border-radius: 16px;
background-color: #efefef;
}
</style>

View File

@@ -1,255 +0,0 @@
<template>
<el-button color="#DED0B2" style="float: right;margin: 0 10px 10px 0" @click="exportTable">导出</el-button>
<el-table ref="reportTable" :data="tableData" style="width: 100%;height: 479px"
:span-method="objectSpanMethod" v-loading="loading">
<el-table-column label="四川省国有资产经营投资管理有限责任公司科技创新项目人工成本分摊明细表" align="center">
<el-table-column v-for="column in columnInfo" :prop="column.prop" :label="column.label" align="center"
:fixed="(!column.children) ? ((column.prop === 'totalSeparation' || column.prop === 'totalSeparationCost') ? 'right' : 'left') : false"
:width="(column.prop === 'totalSeparation' || column.prop === 'totalSeparationCost') ? 160:130">
<template #default="scope">
<template v-if="column.children">
<el-table-column v-for="childColumn in column.children"
:prop="column.prop + '.'+ childColumn.prop"
:label="childColumn.label"
:width="childColumn.prop === 'subtotal' ? 160 : 130">
<template #default="columnScope">
<template v-if="(tableData.length -1) !== columnScope.$index">
{{
columnScope.row[column.prop][childColumn.prop] ? columnScope.row[column.prop][childColumn.prop] : '/'
}}
</template>
<template v-else>
{{ columnScope.row[column.prop][childColumn.prop] }}
</template>
</template>
</el-table-column>
</template>
<template v-else>
<!--分摊金额合计与分摊金额总计计算-->
<template
v-if="(column.prop === 'totalSeparation' || column.prop === 'totalSeparationCost') && (tableData.length -1) !== scope.$index">
{{ getTotalSeparation(scope.row, column.prop) }}
</template>
<template
v-else-if="(tableData.length -1) === scope.$index && (column.prop === 'totalSeparation' || column.prop === 'totalSeparationCost')">
{{ getTotalSummary(scope.row, column.prop) }}
</template>
<template v-else>
{{ scope.row[column.prop] }}
</template>
</template>
</template>
</el-table-column>
</el-table-column>
</el-table>
</template>
<script setup lang="jsx">
import {getResearchUser, getAllocationDetails} from "@/api/expense-manage";
import {exportExcel} from "@/utils/export-excel";
import {ElNotification} from "element-plus";
const route = useRoute()
const tableIns = ref()
const reportTable = ref({});
const columnInfo = ref([])
const monthConcat = new Map()
const tableData = ref([])
const loading = ref(false)
const researchOptions = ref([])
const objectSpanMethod = ({row, column, rowIndex, columnIndex}) => {
if (columnIndex === 0) {
if (monthConcat.has(rowIndex)) {
return {
rowspan: monthConcat.get(rowIndex),
colspan: 1,
}
} else {
return {
rowspan: 0,
colspan: 0,
}
}
} else {
let length = Object.keys(row).length
// console.log(length)
if (length > 5) {
if (concatColumn(columnIndex, length, rowIndex)) {
if (rowIndex % 5 === 0) {
return {
rowspan: 5,
colspan: 1,
}
} else {
return {
rowspan: 0,
colspan: 0,
}
}
}
}
}
}
const getTotalSeparation = (row, prop) => {
let totalSeparation = 0.00
for (let key of Object.keys(row)) {
if (key.startsWith('personInfo')) {
let value = prop === 'totalSeparation' ? (row[key].separationAmount ? row[key].separationAmount : 0) : row[key].subtotal
if ("/" !== value) {
try {
totalSeparation += parseFloat(value)
} catch (e) {
}
}
}
}
if (totalSeparation !== 0) {
return totalSeparation.toFixed(2);
} else {
return "/"
}
}
const getTotalSummary = (row, prop) => {
let key;
if (prop === 'totalSeparation') {
key = 'separationAmount'
} else {
key = 'subtotal'
}
let result = 0
for (const rowKey of Object.keys(row)) {
if (rowKey.startsWith('personInfo')) {
let value = row[rowKey][key]
if (value && "/" !== value) {
try {
result += parseFloat(value)
} catch (e) {
}
}
}
}
return result.toFixed(2);
}
const concatColumn = (columnIndex, length, rowIndex) => {
if (rowIndex === tableData.value.length - 1) {
return false
}
let columnLength = 5 + (length - 5) * 5
if (columnIndex === 1
|| columnIndex === columnLength - 1) {
return true;
}
for (let i = 0; i < length - 5; i++) {
if (columnIndex === 4 + (i * 5)
|| columnIndex === 5 + (i * 5)
|| columnIndex === 7 + (i * 5)) {
return true
}
}
return false
}
const init = () => {
loading.value = true
getAllocationDetails(route.query.id).then(res => {
if (res.code !== 1000) {
ElNotification({
title: '提示',
message: res.msg,
type: 'error'
})
}
columnInfo.value = res.data.columns
let tableDataLet = res.data.tableData;
let personInfoKey = []
columnInfo.value.forEach(item => {
if (item.prop.startsWith('personInfo')) {
personInfoKey.push(item.prop)
}
})
tableData.value = []
let rowIndex = 0;
let summary = {
month: "",
salaryType: '',
projectName: "合计",
totalSeparation: 10,
totalSeparationCost: 10
}
for (const key of personInfoKey) {
summary[key] = {
researchDuration: "",
separationAmount: 0,
subtotal: 0,
wagesPayable: "",
workday: "",
}
}
tableDataLet.forEach((tableDatum) => {
let rowspan = tableDatum.rows.length * 5
monthConcat.set(rowIndex, rowspan)
rowIndex += rowspan
for (const tableDatumElement of tableDatum.rows) {
tableData.value = tableData.value.concat(tableDatumElement)
let row = tableDatumElement[0]
for (const key of personInfoKey) {
try {
if (row[key].subtotal && '/' !== row[key].subtotal) {
summary[key].subtotal += parseFloat(row[key].subtotal)
}
} catch (e) {
}
}
}
})
for (const row of tableData.value) {
for (const key of personInfoKey) {
try {
if (row[key].separationAmount && '/' !== row[key].separationAmount) {
summary[key].separationAmount += parseFloat(row[key].separationAmount)
}
} catch (e) {
}
}
}
for (const key of personInfoKey) {
summary[key].subtotal = summary[key].subtotal.toFixed(2)
summary[key].separationAmount = summary[key].separationAmount.toFixed(2)
}
monthConcat.set(rowIndex, 1)
tableData.value.push(summary)
loading.value = false
})
}
const getResearchOptions = async () => {
const res = await getResearchUser()
researchOptions.value = res.data
}
const search = (val) => {
tableConfig.params = {
allocationId: route.query.id,
...val
}
tableIns.value.refresh()
}
getResearchOptions()
init()
const exportTable = () => {
const $e = reportTable.value.$el
let $table = $e.querySelector('.el-table__fixed')
if (!$table) {
$table = $e
}
exportExcel($table, (5 + (Object.keys(tableData.value[0]).length - 5) * 5), "四川省国有资产经营投资管理有限责任公司科技创新项目人工成本分摊明细表", 2)
}
</script>

View File

@@ -1,212 +0,0 @@
<template>
<el-form :label-position="labelAlign">
<el-form-item :label="title" v-if="fileListShow === 'READ' || fileListShow === 'EDIT'" :label-position="labelAlign" :style="{marginTop: '10px',marginLeft: tag!=='需求上报'?'15px':'0'}">
<file-upload @getFile="getOtherFile" v-if="fileListShow === 'EDIT'"/>
<!-- :style="{width:isOpenPrint?'610px': '100%'}" table-layout="auto" id="printTable"-->
<fvTable style="width:100%;" :height="tag=='项目立项'?'160':'160'" :style="{maxHeight:tag=='项目立项'?'160px':'160px',height:tag=='项目立项'?'160px':'160px'}" v-if="processViewer" :scrollbar-always-on="true" :tableConfig="tableConfig"
:data="_value" :isSettingCol="false" :pagination="false">
<template #empty>
<el-empty :image-size="55" description="暂无数据" style="padding: 0"/>
</template>
</fvTable>
</el-form-item>
</el-form>
<file-preview ref="filePreviewRef" :fullscreen="fullscreen" v-if="filePreviewShow" :fileName="filePreviewParam.fileName" :fileUrl="filePreviewParam.fileUrl"
:fileType="filePreviewParam.fileType"/>
</template>
<script setup lang="jsx">
import {downloadFile, deleteFile} from "@/api/project-demand";
import {ElNotification} from "element-plus";
import FilePreview from "../filePreview/index.vue";
const props = defineProps({
title: {
type: String,
default: ''
},
tag: {
type: String,
default: ''
},
fileNameTableWidth: {
type: String,
default: '400'
},
fileListShow: {
type: String,
default: 'READ'
},
value: {
type: Array,
default: []
},
processViewer: {
type: Boolean,
default: false
},
labelAlign: {
type: String,
default: 'right'
},
//弹窗是否铺满全屏
fullscreen: {
type: Boolean,
default: false
},
//是否开始打印
isOpenPrint: {
type: Boolean,
default: false
},
})
const emit = defineEmits(['update:value'])
const tableConfig = reactive({
columns: [
{
prop: 'index',
type: 'index',
label: '序号',
align: 'center',
width: 85,
},
{
prop: 'originalFileName',
label: '文件名',
align: 'center',
width: props.fileNameTableWidth,
showOverflowTooltip: false,
currentRender: ({row, index}) => (<div style="color: #2a99ff;cursor: pointer;" onClick={()=>clickToPreview(row)}>{row.originalFileName}</div>)
},
{
prop: 'tag',
label: '标签',
align: 'center',
showOverflowTooltip: false,
minWidth: props.fileNameTableWidth,
},
{
prop: 'size',
label: '文件大小',
align: 'center',
width: 150,
currentRender: ({row, index}) => (parseInt(row.size / 1024) + 'KB')
},
{
prop: 'oper',
label: '操作',
align: 'center',
showOverflowTooltip: false,
currentRender: ({row, index}) => {
let btn = []
btn.push({label: '下载', func: () => handleDownload(row), type: 'primary'})
// if (row.newFile) {
// btn.push({label: '删除', func: () => handleDelete(row), type: 'primary'})
// }
return (
<div style={{width: '100%'}}>
{
btn.map(item => (
<el-button
type={item.type}
onClick={() => item.func()}
link>
{item.label}
</el-button>
))
}
{
row.newFile ? <popover-delete name={row.originalFileName} type={'文件'} btnType={'danger'}
onDelete={() => handleDelete(row)}/>
: ''
}
</div>
)
}
}
]
})
const filePreviewParam = ref({
fileUrl: '',
fileName: '',
fileType: 'pdf'
})
const filePreviewShow = ref(false)
const _value = computed({
get() {
return props.value;
},
set(val) {
emit("update:value", val);
}
})
const clickToPreview=(row)=>{
filePreviewShow.value = false
filePreviewParam.value = {
fileUrl: row.url,
fileName: row.originalFileName,
fileType: row.fileType
}
nextTick(()=>{
filePreviewShow.value = true
})
}
const getOtherFile = (val) => {
props.processViewer = false
let fileObj = compositeParam(val)
_value.value.push(fileObj)
nextTick(() => {
props.processViewer = true
})
}
const compositeParam = (item, type) => {
return {
fileId: item.id,
size: item.size,
originalFileName: item.originalFilename,
fileType: item.fileType,
url: item.url,
newFile: true,
tag: props.tag
}
}
const handleDownload = (row) => {
downloadFile(row.fileId).then(res => {
const blob = new Blob([res])
let a = document.createElement('a')
a.href = URL.createObjectURL(blob)
a.download = row.originalFileName
a.click()
})
}
const handleDelete = (row) => {
deleteFile(row.fileId).then(res => {
ElNotification({
title: '提示',
message: res.msg,
type: res.code === 1000 ? 'success' : 'error'
})
if (res.code === 1000) {
_value.value.splice(_value.value.findIndex((item) => item.fileId === row.fileId), 1);
}
});
}
watch(() => props.processViewer, (newVal) => {
props.processViewer = newVal
}, {deep: true})
</script>
<style scoped lang="scss">
:deep(.el-table--fit ) {
height: 160px !important;
}
@media print {
//#printTable{
// width: 400px!important;
//}
}
</style>

View File

@@ -1,62 +1,16 @@
<template>
<!-- <baseTitle title="审核意见"></baseTitle>-->
<!-- <fvForm :schema="schema" @getInstance="(e)=>form = e"></fvForm>-->
<div class="oper-page-btn" style="display: flex">
<baseTitle title="审核意见"></baseTitle>
<fvForm :schema="schema" @getInstance="(e)=>form = e"></fvForm>
<div class="oper-page-btn">
<el-button type="danger" @click="handleReject">驳回</el-button>
<el-button color="#DED0B2" @click="handleAgree">同意</el-button>
</div>
<div class="opinion-dialog">
<el-dialog v-model="showBackNode" title="请选择退回节点" width="400">
<el-table :data="taskUserOptionList" style="width: 100%"
:header-cell-style="{background:'#f5f7fa'}">
<el-table-column width="55">
<template #default="scope">
<el-radio
class="radio"
:label="scope.row"
v-model="backNode"
>&emsp;&emsp;&emsp;
</el-radio>
</template>
</el-table-column>
<el-table-column
prop="nodeName"
label="节点名称">
<!-- <template #default="scope">-->
<!-- {{scope.row.nodeId==-1?'发起节点':scope.row.nodeName}}-->
<!-- </template>-->
</el-table-column>
<el-table-column
prop="name"
label="操作者">
<template #default="scope">
<el-tag v-if="scope.row.userInfo" type="success">{{ scope.row.userInfo.name }}</el-tag>
</template>
</el-table-column>
</el-table>
<div class="oper" style="display: flex;justify-content: flex-end;margin-top: 10px">
<el-button type="danger" @click="rollbackHandler">确定</el-button>
<el-button @click="showBackNode=false">取消</el-button>
</div>
<!-- <el-select v-if="taskUserOptionList?.length>0" v-model="backNode" placeholder="请选择退回节点" clearable>-->
<!-- <el-option-->
<!-- v-for="item in taskUserOptionList"-->
<!-- :key="item.nodeId"-->
<!-- :label="item.nodeName + (item.userInfo ? ':' + item.userInfo.name : '')"-->
<!-- :value="item.nodeId">-->
<!-- </el-option>-->
<!-- </el-select>-->
<!-- <el-button type="danger" @click="rollbackHandler">确认</el-button>-->
</el-dialog>
</div>
</template>
<script setup lang="jsx">
import {ElNotification} from 'element-plus';
import {agreeTask, rejectTask} from "@/api/project-demand/index.js";
import {useTagsView} from '@/stores/tagsview.js'
const tagsViewStore = useTagsView()
const route = useRoute()
const router = useRouter()
const props = defineProps({
@@ -67,21 +21,10 @@ const props = defineProps({
formData: {
type: Object,
default: {}
},
value: {
type: String,
default: ''
},
//退回节点选择框数据
taskUserOptionList: {
type: Array,
default: []
}
})
const form = ref()
const backNode = ref({})
const showBackNode = ref(false)
const schema = computed(() => {
return [
{
@@ -94,19 +37,11 @@ const schema = computed(() => {
props: {
placeholder: '请输入审核意见',
type: 'textarea',
rows: 3
maxlength: 140
}
}
]
})
const _value = computed({
get() {
return props.value;
},
set(val) {
emit("update:value", val);
}
})
const back = () => {
switch (route.name) {
case 'Initiation/detail':
@@ -116,97 +51,20 @@ const back = () => {
router.push({name: 'Filing'})
break;
case 'Implementation/detail':
if (route.query.source === 'home') {
router.push('/home')
} else {
if (route.query.step === '10') {
router.push({name: 'Summary'})
} else if (route.query.step === '20') {
router.push({name: 'Initiation'})
} else if (route.query.step === '40') {
router.push({name: 'Implementation'})
} else if (route.query.step === '50') {
router.push({name: 'Filing'})
} else if (route.query.step === '00') {
router.push({name: 'Requirement'})
}
}
router.push({name: 'Implementation'})
break;
case 'Summary/detail':
router.push({name: 'Summary'})
break;
// case 'Summary/detail':
// if (route.query.source === 'home') {
// router.push('/home')
// } else {
// router.push({name: 'Summary'})
// }
// break;
case 'Requirement/detail':
if (route.query.source === 'home') {
router.push('/home')
} else {
router.push({name: 'Requirement'})
}
break;
case 'Fund/detail':
if (route.query.source === 'home') {
router.push('/home')
} else {
router.push({name: 'Fund'})
}
break;
case 'Share/detail':
if (route.query.source === 'home') {
router.push('/home')
} else {
router.push({name: 'Expense/share'})
}
break;
case 'Phase/detail':
if (route.query.source === 'home') {
router.push('/home')
} else {
router.push({name: 'Implementation'})
}
router.push({name: 'Requirement'})
break;
}
}
// 驳回
const handleReject = async () => {
if (!_value.value) {
ElNotification({
title: '提示',
message: '请填写审核意见',
type: 'warning'
})
return
}
showBackNode.value = true
backNode.value = {}
}
//回退节点
const rollbackHandler = async () => {
// const values = form.value.getValues()
const params = {
taskId: props.taskId,
// ...values
auditOpinion: _value.value,
rollBackId: backNode.value.nodeId
}
// console.log('params', params)
const res = await rejectTask(params)
ElNotification({
title: '提示',
message: res.msg,
type: res.code === 1000 ? 'success' : 'error'
})
if (res.code === 1000) {
tagsViewStore.delVisitedViews(router.currentRoute.value.path)
back()
}
}
const handleAgree = async () => {
if (!_value.value) {
const values = form.value.getValues()
if (!values.auditOpinion) {
ElNotification({
title: '提示',
message: '请填写审核意见',
@@ -214,11 +72,26 @@ const handleAgree = async () => {
})
return
}
// const values = form.value.getValues()
console.log('values', values)
const params = {
taskId: props.taskId,
...values
}
const res = await rejectTask(params)
ElNotification({
title: '提示',
message: res.msg,
type: res.code === 1000 ? 'success' : 'error'
})
back()
}
const handleAgree = async () => {
const values = form.value.getValues()
const params = {
taskId: props.taskId,
formData: props.formData,
auditOpinion: _value.value
...values
}
const res = await agreeTask(params)
ElNotification({
@@ -226,17 +99,10 @@ const handleAgree = async () => {
message: res.msg,
type: res.code === 1000 ? 'success' : 'error'
})
if (res.code === 1000) {
tagsViewStore.delVisitedViews(router.currentRoute.value.path)
back()
}
back()
}
</script>
<style lang="scss">
.opinion-dialog {
.el-dialog__body {
padding: 0 !important;
}
}
<style lang="scss" scoped>
</style>

View File

@@ -1,956 +0,0 @@
<template>
<div class="apply-block">
<baseTitle :title="getTitleName(title)+'信息'"></baseTitle>
<el-form :model="localFormData" ref="formRef" label-width="auto" v-if="step!=='50'" :rules="rules">
<el-row v-if="title==='apply'">
<el-col :span="6">
<!-- label-width="106"-->
<el-form-item label="实际经费预算(元)" prop="actualEconomicEstimate" label-width="130">
<el-input-number v-model="localFormData.actualEconomicEstimate" placeholder="请输入实际经费预算" :controls="false">
</el-input-number>
</el-form-item>
</el-col>
<el-col :span="6" v-if="isSpecialFund">
<!-- label-width="106" -->
<el-form-item label="实际专项资金(元)" prop="specialFundAmount" label-width="140">
<el-input-number v-model="localFormData.specialFundAmount" placeholder="请输入实际专项资金" :controls="false">
</el-input-number>
</el-form-item>
</el-col>
</el-row>
<el-row v-if="title==='check'">
<el-col :span="6">
<el-form-item label="实际专利(项)" prop="actualNewPatent" label-width="130">
<el-input-number v-model="localFormData.actualNewPatent" placeholder="请输入实际专利数量" style="margin-right: 20px" :controls="false">
</el-input-number>
</el-form-item>
</el-col>
<el-col :span="6" style="margin-left: -10px">
<el-form-item label="实际软件著作权(项)" prop="actualSoftwareCopyright" label-width="150">
<el-input-number v-model="localFormData.actualSoftwareCopyright" placeholder="请输入实际软件著作权数量":controls="false">
</el-input-number>
</el-form-item>
</el-col>
<el-col :span="6" style="margin-left: -5px">
<el-form-item label="实际技术标准(项)" prop="actualTechnicalNorms" label-width="150">
<el-input-number v-model="localFormData.actualTechnicalNorms" placeholder="请输入实际技术标准数量":controls="false">
</el-input-number>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="实际新产品(项)" prop="actualNewProduct" label-width="160" style="margin-right: -10px">
<el-input-number v-model="localFormData.actualNewProduct" placeholder="请输入实际新产品数量" :controls="false">
</el-input-number>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="实际新工艺(项)" prop="actualNewProcess" label-width="130" >
<el-input-number v-model="localFormData.actualNewProcess" placeholder="请输入实际新工艺数量" style="margin-right: 20px" :controls="false">
</el-input-number>
</el-form-item>
</el-col>
<el-col :span="6" style="margin-left: -10px">
<el-form-item label="实际新装置(项)" prop="actualNewDevice" label-width="150">
<el-input-number v-model="localFormData.actualNewDevice" placeholder="请输入实际新装置数量" :controls="false">
</el-input-number>
</el-form-item>
</el-col>
<el-col :span="6" style="margin-left: -5px">
<el-form-item label="实际新材料(项)" prop="actualNewMaterials" label-width="150">
<el-input-number v-model="localFormData.actualNewMaterials" placeholder="请输入实际新材料数量" :controls="false">
</el-input-number>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="实际计算机软件(项)" prop="actualComputerSoftware" label-width="160" style="margin-right: -10px">
<el-input-number v-model="localFormData.actualComputerSoftware" placeholder="请输入实际计算机软件数量" :controls="false">
</el-input-number>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="实际论文论著(项)" prop="actualThesis" label-width="130" style="margin-right: 20px">
<el-input-number v-model="localFormData.actualThesis" placeholder="请输入实际论文论著数量" :controls="false">
</el-input-number>
</el-form-item>
</el-col>
<el-col :span="6" style="margin-left: -10px">
<el-form-item label="实际研究报告(项)" prop="actualResearchReport" label-width="150">
<el-input-number v-model="localFormData.actualResearchReport" placeholder="请输入实际研究报告数量" :controls="false">
</el-input-number>
</el-form-item>
</el-col>
<el-col :span="6" style="margin-left: -5px">
<el-form-item label="实际商标(项)" prop="actualTrademark" label-width="150">
<el-input-number v-model="localFormData.actualTrademark" placeholder="请输入实际商标数量" :controls="false">
</el-input-number>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="实际其他(项)" prop="actualOther" label-width="130" style="margin-right: 10px">
<el-input rows="4" type="textarea" v-model="localFormData.actualOther" placeholder="请输入实际其他项" >
</el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="6" v-if="title==='apply'">
<!-- label-width="106"-->
<el-form-item label="项目负责人" :required="true" prop="" label-width="130">
<el-button style="margin-right: 10px" color="#DED0B2" @click="handleShowProjectChargePersonTable">
{{ projectChargePersonUserList?.length !== 0 ? '更改' : '请选择' }}
</el-button>
<div v-for="item in projectChargePersonUserList" :key="item.id" style="margin-right: 5px">
{{ item.name }}
</div>
<user-picker :multiple="false" ref="projectChargePersonUserPicker" title="请选择项目负责人"
v-model:value="projectChargePersonUserList" @ok="projectChargePersonUserPickerOk"
@cancelOrClear="projectChargePersonUserPickerCancel"/>
</el-form-item>
</el-col>
<el-col :span="6" v-if="title==='apply'">
<el-form-item label="项目成员" :required="true" prop="" label-width="140"
>
<el-button color="#DED0B2" style="margin-right: 10px" @click="handleShowProjectPersonTable">
{{
projectPersonUserList?.length !== 0 ? '更改' : getProjectPerson(projectPersonUserList) ? '更改' : '请选择'
}}
</el-button>
<div v-for="(item,index) in getProjectPerson(projectPersonUserList)" :key="item.id">
{{ item.name }}{{ index != getProjectPerson(projectPersonUserList)?.length - 1 ? '' : '' }}
</div>
<user-picker :multiple="true" ref="projectPersonUserPicker" title="请选择项目成员"
v-model:value="projectPersonUserList" @ok="projectPersonUserPickerOk"
@cancelOrClear="projectPersonUserPickerCancel"/>
</el-form-item>
</el-col>
<el-col :span="6" v-if="title==='apply'||title==='check'">
<el-form-item label="部门分管领导" :label-width="title==='check'?130:115" :required="isKcjUser()">
<el-button color="#DED0B2" style="margin-right: 10px" @click="handleShowOptionalChargeLeadershipPicker">
{{
optionalChargeLeadershipList?.length !== 0 ? '更改' : getOptionalChargeLeadershipList(optionalChargeLeadershipList) ? '更改' : '请选择'
}}
</el-button>
<div v-for="(item,index) in getOptionalChargeLeadershipList(optionalChargeLeadershipList)" :key="item.id">
{{
item.name
}}{{ index != getOptionalChargeLeadershipList(optionalChargeLeadershipList)?.length - 1 ? '' : '' }}
</div>
<user-picker :multiple="true" ref="optionalChargeLeadershipPickerRef" title="请选择部门分管领导"
v-model:value="optionalChargeLeadershipList" @ok="optionalChargeLeaderPickerOk"
@cancelOrClear="optionalChargeLeaderPickerCancel"/>
</el-form-item>
</el-col>
<el-col :span="24" v-if="preProcessShow === 'EDIT'||title==='apply'||title==='check'">
<el-form-item label="前置流程" :required="preProcessRequired" prop="preProcess" :label-width="title==='apply'?130:125">
<select-pre-process :formData="localFormData" :basicData="basicData"/>
<!-- <el-button color="#DED0B2" @click="handleShowPreTable" style="margin-right: 10px">-->
<!-- {{-->
<!-- localFormData.preProcess && localFormData.preProcess?.length > 0 ? '更改' : sessionParams.preProcess && sessionParams.preProcess?.length > 0 ? '更改' : '请选择'-->
<!-- }}-->
<!-- </el-button>-->
<!-- <div v-for="(item,index) in getRequestName(localFormData.preProcess)" :key="item.requestId">-->
<!-- <a :href="item.baseUrl" target="_blank"-->
<!-- style="color: #2a99ff;cursor: pointer">{{ item.requestName }}<span-->
<!-- v-if="index != localFormData.preProcess?.length -1"></span>-->
<!-- </a>-->
<!-- </div>-->
</el-form-item>
</el-col>
</el-row>
</el-form>
<!-- v-if="showAttachment"-->
<AttachmentUpload ref="attachment" :label="getTitleName(title)+'附件'" :showTable="showTable"
v-model:otherFileList="otherFileList" :tag="getTitleName(props.title)"
:templateName="getTemplateName(props.title)"
:templateDownloadBtnShow="props.title==='apply'?true:props.title==='check'"
@getAttachment="getAttachment" v-model:singleList="singleList" :showSingleTable="showSingleTable"
@getOtherFile="getOtherFile" :showFileList="true" :formData="localFormData"
:preview="mode == 'resubmit'"/>
<div>
<div class="approval-record">
<div class="approval-title" style="margin-top: -15px">
<!-- <baseTitle title="审批记录" v-if="mode === 'resubmit'"></baseTitle>-->
<!-- <div v-else></div>-->
<baseTitle title="审批记录"></baseTitle>
<div class="diagram">
<div class="base-title">流程图</div>
<el-switch
v-model="changeDiagram"
style="--el-switch-on-color:#BEA266 ; --el-switch-off-color:#cecdcd"
/>
</div>
</div>
<el-empty :image-size="100" description="暂无审批记录" v-if="!data?.operationList&&!changeDiagram"/>
<div class="process">
<operation-render
v-if="mode === 'resubmit'&&processDiagramViewer&& data?.operationList && data?.operationList.length > 0&&!changeDiagram"
:operation-list="data.operationList"
:state="data.state"/>
<process-diagram-viewer mode="view" :idName="title" v-if="processDiagramViewer&&changeDiagram"/>
</div>
</div>
</div>
<div class="oper-page-btn">
<el-button color="#DED0B2" v-if="mode === 'submit'" @click="handleSubmit(formRef)">提交</el-button>
<el-button color="#DED0B2" v-else-if="mode === 'resubmit'" @click="handleSubmit(formRef)">重新提交</el-button>
<el-button @click="handleBack">返回</el-button>
</div>
<file-preview ref="filePreviewRef" v-if="filePreviewShow" :fileName="filePreviewParam.fileName"
:fileUrl="filePreviewParam.fileUrl"
:fileType="filePreviewParam.fileType"/>
<el-dialog v-if="showPreTable" title="前置流程" v-model="showPreTable" width="80%">
<el-form :model="preProcessForm" inline @submit.prevent="searchPreProcess">
<el-form-item label="请求名称">
<el-input-number v-model="preProcessForm.requestName" placeholder="请输入请求名称" clearable>
</el-input-number>
</el-form-item>
<el-form-item>
<el-button color="#DED0B2" @click="searchPreProcess">搜索</el-button>
<el-button @click="handleReset">重置</el-button>
</el-form-item>
</el-form>
<el-table :data="preProcessList" v-loading="loading"
@select="handleSelect" @select-all="handleSelect" row-key="requestId" ref="preProcessTable">
<el-table-column type="selection" width="55" :reserve-selection="true"/>
<el-table-column prop="requestId" label="请求id"></el-table-column>
<el-table-column prop="requestName" label="请求名称"></el-table-column>
<el-table-column prop="lastOperatorName" label="最后操作人名称"></el-table-column>
<el-table-column prop="lastOperateTime" label="最后操作时间"></el-table-column>
<el-table-column prop="currentNodeName" label="当前节点"></el-table-column>
<el-table-column prop="creatorName" label="创建人"></el-table-column>
<el-table-column prop="createTime" label="创建时间"></el-table-column>
<el-table-column label="操作" align="center">
<template #default="scope">
<!-- <el-button type="primary" @click="choosePreProcess(scope.row)" link>选择</el-button>-->
<a :href="scope.row.baseUrl" target="_blank" style="color: #2a99ff;margin-left: 10px">查看流程</a>
</template>
</el-table-column>
</el-table>
<paging :current-page="pageInfo.pageNum" :page-size="pageInfo.pageSize" :page-sizes="[10, 20, 30, 40,50]"
:total="total" @changeSize="handleSizeChange" @goPage="handleCurrentChange"/>
<div class="oper">
<el-button color="#DED0B2" @click="choosePreProcess">确定</el-button>
<el-button @click="handleCancel">取消</el-button>
</div>
</el-dialog>
</div>
</template>
<script setup lang="jsx">
import OperationRender from '@/views/workflow/common/OperationRender.vue'
import ProcessDiagramViewer from '@/views/workflow/common/ProcessDiagramViewer.vue';
import {ElLoading, ElNotification} from "element-plus";
import {
getApplyProcess,
getPreProcess,
getProjectCheckProcess,
getProjectConclusionProcess,
projectApply,
projectCheck,
projectConclusion,
resubmitApply,
resubmitCheck,
resubmitConclusion
} from "@/api/project-manage";
import {useProcessStore} from '@/stores/processStore.js';
import {useTagsView} from '@/stores/tagsview.js'
import Paging from "@/components/pagination/index.vue";
import UserPicker from "@/views/workflow/process/common/UserPicker.vue";
import {getBaseInfoApi, getMapProjectStateInfo} from "@/components/steps/api";
import {useAuthStore} from "@/stores/userstore";
const authStore = useAuthStore()
const userInfo =ref( authStore.userinfo)
const router = useRouter()
const route = useRoute()
const formRef = ref()
const changeDiagram = ref(false)
const showSingleTable = ref(false)
const projectChargePersonUserList = ref([])
const projectChargePersonUserPicker = ref()
const projectPersonUserList = ref([])
const projectPersonUserPicker = ref()
const singleList = ref([])
const emit = defineEmits(["getAttachment", "getOtherFile"])
const props = defineProps({
title: {
type: String,
default: 'apply'
},
showTable: {
type: Boolean,
default: false
},
mode: {
type: String,
default: "view"
},
data: {
type: Object,
default: {}
},
basicData: {
type: Object,
default: {}
},
formData: {
type: Object,
default: {}
},
step: {
type: String,
default: "20"
},
preProcessShow: {
type: String,
default: "READ"
}
})
const preProcessList = ref([])
//暂存数据
const currentList = ref([])
const preProcessRequired = ref(false)
const total = ref(0)
const preProcessForm = reactive({
requestName: ''
})
const pageInfo = reactive({
pageNum: 1,
pageSize: 10,
})
const rules = reactive({
actualEconomicEstimate: [{required: true, message: '请输入实际经费预算', trigger: ['blur', 'change']}],
specialFundAmount: [{required: true, message: '请输入实际专项资金', trigger: 'blur'}],
// projectPerson: [{required: true, message: '请选择项目成员', trigger: 'blur'}],
actualNewPatent: [{required: true, message: '请输入实际专利数量', trigger: ['blur', 'change']}],
actualTechnicalNorms: [{required: true, message: '请输入实际技术标准数量', trigger: ['blur', 'change']}],
actualSoftwareCopyright: [{required: true, message: '请输入实际软件著作权数量', trigger: ['blur', 'change']}],
actualNewProduct: [{required: true, message: '请输入实际新产品数量', trigger: ['blur', 'change']}],
actualNewProcess: [{required: true, message: '请输入实际新工艺数量', trigger: ['blur', 'change']}],
actualNewMaterials: [{required: true, message: '请输入实际新材料数量', trigger: ['blur', 'change']}],
actualNewDevice: [{required: true, message: '请输入实际新装置数量', trigger: ['blur', 'change']}],
actualComputerSoftware: [{required: true, message: '请输入实际计算机软件数量', trigger: ['blur', 'change']}],
actualThesis: [{required: true, message: '请输入实际论文论著数量', trigger: ['blur', 'change']}],
actualResearchReport: [{required: true, message: '请输入实际研究报告数量', trigger: ['blur', 'change']}],
actualTrademark: [{required: true, message: '请输入实际商标数量', trigger: ['blur', 'change']}],
actualOther: [{required: true, message: '请输入实际其他项数量', trigger: ['blur', 'change']}],
})
const tagsViewStore = useTagsView()
const processStore = useProcessStore()
const localProjectPerson = ref([])
const otherFileList = ref([])
const localFormData = ref({
projectPersonIds: [],
projectChargePerson: null,
preProcess: [
// {
// requestId: null,
// requestName: '',
// baseUrl: ''
// }
]
})
const attachment = ref()
const deploymentData = ref({})
const showPreTable = ref(false)
const showTable = ref(true)
const loading = ref(false)
const processDiagramViewer = ref(false)
const name = ref(router.currentRoute.value.name)
const deploymentId = ref()
const selectRows = ref([])
const projectId = ref(route.query.projectId)
const sessionParams = ref({})
const optionalChargeLeadershipPickerRef = ref()
const isSpecialFund = ref(false)
const optionalChargeLeadershipList = ref([])
const filePreviewParam = ref({
fileUrl: '',
fileName: '',
fileType: 'pdf'
})
const filePreviewShow = ref(false)
const isKcjUser=()=>{
const hasDstiAdmin = userInfo.value.roles?.some(item => item.roleKey != 'dsti_admin');
return hasDstiAdmin;
}
const getSummaryInfo = async () => {
if (props.mode === 'resubmit') return;
if(props.title === 'check'){
const loading = ElLoading.service({fullscreen: true})
try {
const projectId = route.query.projectId
const {code, data, msg} = await getMapProjectStateInfo(projectId, '10')
if (code === 1000) {
localFormData.value.actualNewPatent= data.formData.newPatent
localFormData.value.actualSoftwareCopyright= data.formData.softwareCopyright
localFormData.value.actualTechnicalNorms= data.formData.technicalNorms
localFormData.value.actualNewProduct= data.formData.newProduct
localFormData.value.actualNewProcess= data.formData.newProcess
localFormData.value.actualNewDevice= data.formData.newDevice
localFormData.value.actualNewMaterials= data.formData.newMaterials
localFormData.value.actualComputerSoftware= data.formData.computerSoftware
localFormData.value.actualThesis= data.formData.thesis
localFormData.value.actualResearchReport= data.formData.researchReport
localFormData.value.actualTrademark= data.formData.trademark
localFormData.value.actualOther= data.formData.other
loading.close()
} else {
ElNotification({
title: '提示',
message: msg,
type: 'error'
})
loading.close()
}
} catch {
loading.close()
}
}
}
getSummaryInfo()
const getInfo = async () => {
const {code, data} = await getBaseInfoApi(route.query.projectId)
isSpecialFund.value = data.isSpecialFund
}
getInfo()
const getTemplateName = (type) => {
switch (type) {
case 'apply':
return '科技创新项目立项模板'
case 'check':
return '科技创新项目验收申请表'
}
}
const handleShowOptionalChargeLeadershipPicker = () => {
optionalChargeLeadershipPickerRef.value.showUserPicker()
}
const optionalChargeLeaderPickerOk = (userList) => {
optionalChargeLeadershipList.value = userList
if (userList?.length > 0) {
localStorage.setItem('optionalChargeLeadershipList', JSON.stringify(optionalChargeLeadershipList.value))
} else {
localStorage.removeItem('optionalChargeLeadershipList')
}
}
const optionalChargeLeaderPickerCancel = (userList) => {
optionalChargeLeadershipList.value = userList
}
const clickToPreview = (row) => {
filePreviewShow.value = false
filePreviewParam.value = {
fileUrl: row.url,
fileName: row.originalFileName,
fileType: row.fileType
}
nextTick(() => {
filePreviewShow.value = true
})
}
const getOptionalChargeLeadershipList = (list) => {
if (!list || list && list.length === 0) {
if (localStorage.getItem('optionalChargeLeadershipList')) {
let param = JSON.parse(localStorage.getItem('optionalChargeLeadershipList'))
optionalChargeLeadershipList.value = param
return optionalChargeLeadershipList.value
}
} else {
return list
}
}
const getProjectPerson = (list) => {
if (!list || list && list.length === 0) {
if (localStorage.getItem('projectPersonUserList')) {
let param = JSON.parse(localStorage.getItem('projectPersonUserList'))
projectPersonUserList.value = param
return projectPersonUserList.value
}
} else {
return list
}
}
const getRequestName = (list) => {
if (!list || (list && list.length === 0)) {
if (sessionParams.value.preProcess) {
return sessionParams.value.preProcess
}
} else {
return list
}
}
const getProjectChargePersonUser = () => {
if (projectChargePersonUserList.value.length !== 0) {
return projectChargePersonUserList.value.map(item => item.name).join()
}
}
const handleSelect = async (selection) => {
selectRows.value = selection
}
const handleCancel = () => {
showPreTable.value = false
}
const searchPreProcess = () => {
getPreProcessList()
}
const handleReset = () => {
preProcessForm.requestName = ''
getPreProcessList()
}
const handleShowPreTable = () => {
showPreTable.value = true
getPreProcessList()
}
const handleShowProjectChargePersonTable = () => {
projectChargePersonUserPicker.value.showUserPicker()
}
const projectChargePersonUserPickerOk = (userList) => {
projectChargePersonUserList.value = userList
if (userList?.length > 0) {
localStorage.setItem('projectChargePersonUserList', JSON.stringify(projectChargePersonUserList.value))
} else {
localStorage.removeItem('projectPersonUserList')
}
}
const handleShowProjectPersonTable = () => {
projectPersonUserPicker.value.showUserPicker()
}
const projectChargePersonUserPickerCancel = (userList) => {
projectChargePersonUserList.value = userList
}
const projectPersonUserPickerCancel = (userList) => {
projectPersonUserList.value = userList
}
const projectPersonUserPickerOk = (userList) => {
projectPersonUserList.value = userList
if (userList?.length > 0) {
localStorage.setItem('projectPersonUserList', JSON.stringify(userList))
} else {
localStorage.removeItem('projectPersonUserList')
}
}
const getPreProcessList = () => {
loading.value = true
getPreProcess().then(res => {
loading.value = false
let searchArray = []
let regexPattern = ("%" + preProcessForm.requestName + "%").replace(/%/g, '.*').replace(/_/g, '.');
let regex = new RegExp('^' + regexPattern + '$');
res.data.filter((item) => {
if (regex.test(item.requestName)) {
searchArray.push(item)
}
})
// res.data.forEach((item) => {
// localFormData.value.preProcess.forEach((item1) => {
// if (item.requestId == item1.requestId) {
// preProcessTable.value.toggleRowSelection(item)
// }
// })
// })
total.value = searchArray.length
currentList.value = searchArray
preProcessList.value = currentList.value.slice(0, 10)
})
}
const choosePreProcess = () => {
let preProcessObj = {}
let preProcessArray = []
selectRows.value.forEach((item) => {
preProcessObj = {
requestId: item.requestId,
requestName: item.requestName,
baseUrl: item.baseUrl
}
if(props.mode === 'resubmit'){
localFormData.value.preProcess.push(preProcessObj)
}else{
preProcessArray.push(preProcessObj)
}
})
if(props.mode !== 'resubmit'){
localFormData.value.preProcess = preProcessArray
}
showPreTable.value = false
localStorage.setItem('preProcess', JSON.stringify(preProcessArray))
}
//切换每页显示条数
const handleSizeChange = (val) => {
pageInfo.pageSize = val;
preProcessList.value = currentList.value.slice((pageInfo.pageNum - 1) * val, pageInfo.pageNum * val)
};
//点击页码进行分页功能
const handleCurrentChange = (val) => {
pageInfo.pageNum = val;
preProcessList.value = currentList.value.slice((val - 1) * pageInfo.pageSize, val * pageInfo.pageSize)
};
const getTitleName = (type) => {
switch (type) {
case 'apply':
return '项目立项'
case 'check':
return '项目验收'
case 'filing':
return '项目归档'
}
}
const handleBack = () => {
history.back()
}
const compositeParam = (item) => {
return {
fileId: item.id,
size: item.size,
originalFileName: item.originalFilename,
fileType: item.fileType,
url: item.url,
newFile: true,
tag: getTitleName(props.title)
}
}
const getAttachment = (val) => {
// console.log('上传文件getAttachment', val)
showSingleTable.value = false
localFormData.value.singleFile = compositeParam(val)
singleList.value.push(compositeParam(val))
nextTick(() => {
showSingleTable.value = true
if (attachment.value.singleFile == null) {
attachment.value.validate()
ElNotification({
title: '提示',
message: '请上传附件',
type: 'error'
})
return;
} else {
attachment.value.clearValidate()
}
})
localStorage.setItem('singleFile', JSON.stringify(compositeParam(val)))
}
watch(() => singleList.value, (newVal) => {
showSingleTable.value = newVal.length !== 0;
}, {deep: true})
const getOtherFile = (val) => {
// console.log('上传文件getOtherFile', val)
showTable.value = false
let fileObj = compositeParam(val)
otherFileList.value.push(fileObj)
nextTick(() => {
showTable.value = true
})
// localFormData.value.otherFileList = otherFileList.value
localStorage.setItem('otherFileList', JSON.stringify(otherFileList.value))
}
const getFileParam = (item) => {
return {
fileId: item.fileId,
tag: item.tag
}
}
const handleSubmit = async (instance) => {
if (props.step == 50) {
let files = []
if (props.mode === 'resubmit') {
attachment.value.allFileList.forEach(item => {
files.push(getFileParam(item))
})
} else {
otherFileList.value.forEach(item => {
files.push(getFileParam(item))
})
}
// console.info("🚀 ~method:handleSubmit -----", files,attachment.value.isHaveOneFile)
// if (!attachment.value.isHaveOneFile) {
// attachment.value.validate()
// ElNotification({
// title: '提示',
// message: '请上传附件',
// type: 'error'
// })
// return;
// } else {
// attachment.value.clearValidate()
// }
let projectPersonIds = []
for (const item of projectPersonUserList.value) {
projectPersonIds.push(parseInt(item.id))
}
let params = {
...localFormData.value,
deploymentId: deploymentId.value,
requirementId: route.query.id,
fileList: files,
// singleFile: attachment.value.singleFile,
projectId: route.query.projectId,
actualEconomicEstimate: parseFloat(localFormData.value.actualEconomicEstimate),
specialFundAmount: parseFloat(localFormData.value.specialFundAmount),
preProcess: JSON.stringify(localFormData.value.preProcess)
}
if (sessionParams.value.preProcess && !localFormData.value.preProcess) {
params.preProcess = JSON.stringify(sessionParams.value.preProcess)
}
console.log('params', params.fileList)
let res
if (props.mode === 'resubmit') {
res = await resubmitConclusion(params)
} else {
res = await projectConclusion(params)
}
ElNotification({
title: '提示',
message: res.msg,
type: res.code === 1000 ? 'success' : 'error'
})
if (res.code === 1000) {
tagsViewStore.delVisitedViews(router.currentRoute.value.path)
await router.push({
name: 'Filing'
})
}
} else {
if (!instance) return
instance.validate(async (valid) => {
if (!valid) {
ElNotification({
title: '提示',
message: '请完善数据,再提交!',
type: 'error'
})
return;
}
let files = []
if (props.mode === 'resubmit') {
attachment.value.allFileList.forEach(item => {
files.push(getFileParam(item))
})
} else {
otherFileList.value.forEach(item => {
files.push(getFileParam(item))
})
}
// console.info("🚀 ~method:handleSubmit -----", files,attachment.value.isHaveOneFile)
if (!attachment.value.isHaveOneFile) {
attachment.value.validate()
ElNotification({
title: '提示',
message: '请上传附件',
type: 'error'
})
return;
} else {
attachment.value.clearValidate()
}
let projectPersonIds = []
for (const item of projectPersonUserList.value) {
projectPersonIds.push(parseInt(item.id))
}
let params = {
// singleFile: attachment.value.singleFile,
...localFormData.value,
projectId: route.query.projectId,
deploymentId: deploymentId.value,
requirementId: route.query.id,
fileList: files,
actualEconomicEstimate: parseFloat(localFormData.value.actualEconomicEstimate)||null,
specialFundAmount: parseFloat(localFormData.value.specialFundAmount)||null,
preProcess: JSON.stringify(localFormData.value.preProcess)
}
if (sessionParams.value.preProcess && !localFormData.value.preProcess) {
params.preProcess = JSON.stringify(sessionParams.value.preProcess)
}
console.log('params', params)
let res
if (props.step === '20') {
if (projectChargePersonUserList.value && projectChargePersonUserList.value.length === 0) {
ElNotification({
title: '提示',
message: '请选择项目负责人!',
type: 'error'
})
return;
}
if (projectPersonUserList.value && projectPersonUserList.value.length === 0) {
ElNotification({
title: '提示',
message: '请选择项目成员!',
type: 'error'
})
return;
}
if (optionalChargeLeadershipList.value && optionalChargeLeadershipList.value.length === 0&&isKcjUser()) {
ElNotification({
title: '提示',
message: '请选择部门分管领导!',
type: 'error'
})
return;
}
params.projectChargePerson = parseInt(projectChargePersonUserList.value[0].id)
params.projectPersonIds = projectPersonIds
params.optionalChargeLeadership = optionalChargeLeadershipList.value
if (props.mode === 'resubmit') {
res = await resubmitApply(params)
} else {
res = await projectApply(params)
}
} else if (props.step === '40') {
params.optionalChargeLeadership = optionalChargeLeadershipList.value
if (props.mode === 'resubmit') {
res = await resubmitCheck(params)
} else {
res = await projectCheck(params)
}
}
ElNotification({
title: '提示',
message: res.msg,
type: res.code === 1000 ? 'success' : 'error'
})
if (res.code === 1000) {
tagsViewStore.delVisitedViews(router.currentRoute.value.path)
if (props.step === '20') {
await router.push({
name: 'Initiation'
})
} else if (props.step === '40') {
await router.push({
name: 'Implementation'
})
}
}
})
}
}
const init = async () => {
let id = route.query.projectId
if (!id) return;
processDiagramViewer.value = false
let res
if (props.step === '20') {
res = await getApplyProcess(id)
} else if (props.step === '40') {
res = await getProjectCheckProcess(id)
} else if (props.step === '50') {
res = await getProjectConclusionProcess(id)
}
if (res.code === 1000) {
let data = res.data
deploymentId.value = data.deploymentId
deploymentData.value = data
// preProcessRequired.value = data.deploymentName === '重大项目立项' || data.deploymentName === '重大项目验收';
processStore.setDesign(data)
processStore.runningList.value = data.runningList;
processStore.endList.value = data.endList;
processStore.noTakeList.value = data.noTakeList;
processStore.refuseList.value = data.refuseList;
processStore.passList.value = data.passList;
nextTick(() => {
processDiagramViewer.value = true
})
} else {
ElNotification({
title: '提示',
message: res.msg,
type: 'error'
})
}
}
watchEffect(() => {
// console.info("🚀 ~method:;props.formData.projectChargePerson -----", props.formData.projectChargePerson)
if (props.formData.projectChargePerson == null) {
projectChargePersonUserList.value = []
} else {
projectChargePersonUserList.value = [props.formData.projectChargePerson]
}
if (props.formData.optionalChargeLeadership == null) {
optionalChargeLeadershipList.value = []
} else {
optionalChargeLeadershipList.value = props.formData.optionalChargeLeadership
}
projectPersonUserList.value = props.formData.projectPersonList ? props.formData.projectPersonList : []
let flag = Object.keys(props.formData).length && (localFormData.value = props.formData)
// if (props.formData.projectChargePerson != null) {
// localFormData.value.projectChargePerson = props.formData.projectChargePerson.id
// }
if (localStorage.getItem('preProcess')) {
let param = JSON.parse(localStorage.getItem('preProcess'))
localFormData.value.preProcess = param
sessionParams.value.preProcess = param
localStorage.setItem('preProcess', JSON.stringify(param))
}
if (localStorage.getItem('singleFile')) {
let param = JSON.parse(localStorage.getItem('singleFile'))
localFormData.value.singleFile = param
singleList.value = [param]
localStorage.setItem('singleFile', JSON.stringify(param))
showSingleTable.value = false
nextTick(() => {
showSingleTable.value = true
})
}
if (localStorage.getItem('otherFileList')) {
let param = JSON.parse(localStorage.getItem('otherFileList'))
localFormData.value.otherFileList = param
otherFileList.value = param
localStorage.setItem('otherFileList', JSON.stringify(param))
showTable.value = false
nextTick(() => {
showTable.value = true
})
}
if (localStorage.getItem('projectChargePersonUserList')) {
let param = JSON.parse(localStorage.getItem('projectChargePersonUserList'))
projectChargePersonUserList.value = param
localStorage.setItem('projectChargePersonUserList', JSON.stringify(param))
}
if (localStorage.getItem('projectPersonUserList')) {
let param = JSON.parse(localStorage.getItem('projectPersonUserList'))
projectPersonUserList.value = param
localProjectPerson.value = param
localStorage.setItem('projectPersonUserList', JSON.stringify(param))
}
if (localStorage.getItem('optionalChargeLeadershipList')) {
let param = JSON.parse(localStorage.getItem('optionalChargeLeadershipList'))
optionalChargeLeadershipList.value = param
// localProjectPerson.value = param
localStorage.setItem('optionalChargeLeadershipList', JSON.stringify(param))
}
return flag
})
onActivated(() => {
init()
})
onMounted(async () => {
await init()
})
</script>
<style scoped lang="scss">
.oper {
margin-top: 20px;
display: flex;
justify-content: flex-end;
}
</style>

View File

@@ -1,608 +0,0 @@
<template>
<el-row>
<el-col :span="24">
<baseTitle :title="'项目附件'"></baseTitle>
</el-col>
<el-tabs v-model="activeName" class="demo-tabs" @tab-click="handleTabClick" @tab-remove="tabRemove"
style="margin-left: 15px;margin-top: -10px">
<el-tab-pane name="all" :closable="false" label="全部">
</el-tab-pane>
<el-tab-pane v-for="item in tagsOption" :closable="item.isClose==1&&uploadState"
:key="item.tagId"
:label="item.fileTag"
:name="item.tagId">
<div class="tag-title">
<div></div>
{{ item.fileTag }}
</div>
</el-tab-pane>
<el-tab-pane name="plus" v-if="uploadState" :closable="false">
<template #label>
<div style="margin-top: 4px;">
<el-icon color="#BEA266">
<Plus/>
</el-icon>
</div>
</template>
</el-tab-pane>
</el-tabs>
</el-row>
<div style="margin-top:10px;margin-bottom: 8px;margin-left: 15px;display: flex">
<!-- <el-button color="#DED0B2" @click="handleUpload">上传附件</el-button>-->
<file-upload v-if="!isLineBtn&&uploadState&&activeName!='plus'&&activeName!='all'" @getFile="getFile"/>
<el-button color="#DED0B2" @click="handleEditTag"
v-if="activeName!='all'&&activeName!='plus'&&uploadState&&!isDefault"
style="margin-left: 10px;">编辑
</el-button>
</div>
<fvTable style="width: 100%;min-height:311px;max-height: 311px" v-if="showAttachmentTable" height="311"
:scrollbar-always-on="true"
:tableConfig="executeTableConfig" class="execute-apply-table"
:data="otherAttachmentList" :isSettingCol="false" :pagination="false">
<template #empty>
<el-empty :image-size="90" description="暂无数据" style="padding: 0"/>
</template>
</fvTable>
<div class="oper-page-btn" style="margin-right: 90px" v-if="uploadState">
<el-button color="#DED0B2" @click="handleSubmit()">提交</el-button>
</div>
<file-preview ref="filePreviewRef" :fullscreen="false" v-if="filePreviewShow" :fileName="filePreviewParam.fileName"
:fileUrl="filePreviewParam.fileUrl"
:fileType="filePreviewParam.fileType"/>
<el-dialog v-model="tagNameShow" center width="450" top="40vh">
<div style="display: flex;align-items: center">标签
<el-input v-model="fileParam.tagName" placeholder="请输入标签名称" style="width: 335px;" clearable/>
</div>
<div class="oper" style="display: flex;justify-content: flex-end;margin-top: 10px">
<el-button color="#DED0B2" @click="changeTag()">确定</el-button>
<el-button @click="tagNameShow=false">取消</el-button>
</div>
</el-dialog>
</template>
<script setup lang="jsx">
import {addTag, delTag, getTagList, updateTag} from "@/api/project-manage";
import {ElLoading, ElMessageBox, ElNotification} from "element-plus";
import {searchImplementationFileList, uploadFileList} from "@/api/project-manage/attachment";
import {deleteFile, downloadFile} from "@/api/project-demand";
import {nextTick, onActivated} from "vue";
const router = useRouter()
const route = useRoute()
const attachmentParam = reactive({
tag: ''
})
const fileParam = ref({
tagName: ''
})
const uploadState = ref(false)
const tagNameShow = ref(false)
const isDefault = ref(false)
const tagsOption = ref([])
const fileList = ref([])
const allFiles = ref([])
const showAttachmentTable = ref(true)
const activeName = ref('all')
const props = defineProps({
fileNameTableWidth: {
type: String,
default: '400'
},
isLineBtn: {
type: Boolean,
default: false
},
})
const executeTableConfig = reactive({
columns: [
{
prop: 'index',
type: 'index',
label: '序号',
align: 'center',
width: 85,
},
{
prop: 'originalFileName',
label: '文件名',
align: 'center',
width: props.fileNameTableWidth,
showOverflowTooltip: false,
currentRender: ({row, index}) => (
<div style="color: #2a99ff;cursor: pointer;" onClick={() => clickToPreview(row)}>{row.originalFileName}</div>)
},
{
prop: 'tag',
label: '标签',
align: 'center',
showOverflowTooltip: false,
},
{
prop: 'size',
label: '文件大小',
align: 'center',
currentRender: ({row, index}) => (parseInt(row.size / 1024) + 'KB')
},
{
prop: 'oper',
label: '操作',
align: 'center',
showOverflowTooltip: false,
currentRender: ({row, index}) => {
return (
<div>
<el-button type="primary" link onClick={() => handleDownload(row)}>下载</el-button>
{
uploadState.value ?
<popover-delete name={row.originalFileName} type={'文件'} btnType={'danger'}
onDelete={() => deleteSingleFile(row)}/> : ''
}
</div>
)
}
}
]
})
// row.newFile ?: ''
const otherAttachmentList = ref([])
const filePreviewParam = ref({
fileUrl: '',
fileName: '',
fileType: 'pdf'
})
const filePreviewShow = ref(false)
const uploadLoading = ref(false)
const isEdit = ref(false)
const isCloseByList = (index) => {
// otherAttachmentList.length>0?false:true
return otherAttachmentList.value.length == 0;
}
const handleDownload = (row) => {
downloadFile(row.fileId).then(res => {
const blob = new Blob([res])
let a = document.createElement('a')
a.href = URL.createObjectURL(blob)
a.download = row.originalFileName
a.click()
})
}
const deleteSingleFile = (row) => {
console.log("🚀 ~ file: ", row)
deleteFile(row.fileId).then(res => {
ElNotification({
title: '提示',
message: res.msg,
type: res.code === 1000 ? 'success' : 'error'
})
if (res.code === 1000) {
if (row.newFile) {
const finalList = getLocalList().filter(item => item.fileId !== row.fileId);
localStorage.setItem(`implementAllFileList-${route.query.projectId}`, JSON.stringify(finalList))
} else {
otherAttachmentList.value.splice(otherAttachmentList.value.findIndex((item) => item.fileId === row.fileId), 1);
}
getAttachmentList()
activeName.value = 'all'
}
});
}
const changeTag = async () => {
let res = null
if (isEdit.value) {
res = await updateTag({
tagId: activeName.value,
fileTag: fileParam.value.tagName,
projectId: route.query.projectId,
})
changeFileList(fileParam.value.tagName, true)
} else {
res = await addTag({
projectId: route.query.projectId,
fileTag: fileParam.value.tagName
})
getAttachmentList()
fileParam.value.tagName = ''
activeName.value = 'all'
}
ElNotification({
title: '提示',
message: res.msg,
type: res.code === 1000 ? 'success' : 'error'
})
tagNameShow.value = false;
}
const tabRemove = async (val) => {
if (otherAttachmentList.value && otherAttachmentList.value.length > 0) {
ElNotification({
title: '提示',
message: '该标签下存在文件,不能删除标签。如需删除标签,请先删除该标签下的所有文件。',
type: 'error'
})
return;
}
ElMessageBox.confirm(`确认删除名称为${getTagName(val)}的标签吗?`, '系统提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(async () => {
let res = await delTag(val)
ElNotification({
title: '提示',
message: res.msg,
type: res.code === 1000 ? 'success' : 'error'
})
if (res.code === 1000) {
getTagsOption()
otherAttachmentList.value = allFiles.value
}
})
}
const handleEditTag = () => {
fileParam.value.tagName = getTagName(activeName.value)
if (otherAttachmentList.value && otherAttachmentList.value.length > 0) {
ElNotification({
title: '提示',
message: '该标签下存在文件,不能编辑标签。如需编辑标签,请先删除该标签下的所有文件。',
type: 'error'
})
return;
}
tagNameShow.value = true
isEdit.value = true
}
const getTagName = (name) => {
const tagArray = tagsOption.value.filter((item1) => item1.tagId == name)
let tagName = ''
if (tagArray && tagArray.length > 0) {
tagName = tagArray[0].fileTag
}
return tagName
}
const handleTabClick = (item, e) => {
const defaultArray = tagsOption.value.filter(item1 => item1.tagId == item.props.name)
if (defaultArray && defaultArray.length > 0) {
isDefault.value = defaultArray[0].isDefault == 1
} else {
isDefault.value = false
}
tagNameShow.value = item.props.name == 'plus';
if (item.props.name == 'plus') {
isEdit.value = false
fileParam.value.tagName = ''
}
if (item.props.name != 'plus') {
if (item.props.name == 'all') {
changeFileList('all')
} else {
changeFileList(getTagName(item.props.name))
}
// if (item.props.name == 'all') {
// otherAttachmentList.value = allFiles.value
// } else {
// otherAttachmentList.value = allFiles.value.filter(item1 => item1.tag == getTagName(item.props.name))
// }
}
// showAttachmentTable.value = false
// nextTick(() => {
// showAttachmentTable.value = true
// })
}
const compositeParam = (item) => {
return {
fileId: item.id,
size: item.size,
originalFileName: item.originalFilename,
fileType: item.fileType,
url: item.url,
newFile: true,
tag: getTagName(activeName.value) || '项目实施',
}
}
const getFile = (val) => {
console.log('上传文件', val)
fileList.value = getLocalList()
let fileObj = compositeParam(val)
fileList.value.push(fileObj)
localStorage.setItem(`implementAllFileList-${route.query.projectId}`, JSON.stringify(fileList.value))
otherAttachmentList.value.push(fileObj)
// handleSubmit([fileObj])
}
const handleSubmit = async () => {
if (getLocalList().length == 0) {
ElNotification({
title: '提示',
message: '暂无文件可提交',
type: 'warning'
})
return;
} else {
let params = {
fileList: getLocalList(),
projectId: route.query.projectId,
targetState: "30"
}
let res = await uploadFileList(params)
if (res.code !== 1000) {
ElNotification({
title: '提示',
message: res.msg,
type: 'error'
})
} else {
ElNotification({
title: '提示',
message: res.msg,
type: 'success'
})
localStorage.removeItem(`implementAllFileList-${route.query.projectId}`)
// list.forEach(item => {
// otherAttachmentList.value.push(item)
// })
getAttachmentList()
fileList.value = []
}
// changeFileList('all',true)
}
}
const clickToPreview = (row) => {
filePreviewShow.value = false
filePreviewParam.value = {
fileUrl: row.url,
fileName: row.originalFileName,
fileType: row.fileType
}
nextTick(() => {
filePreviewShow.value = true
})
}
const changeFileList = (tag, flag) => {
let params = {}
if (tag == 'all') {
otherAttachmentList.value = allFiles.value
// params = {
// targetId: route.query.projectId,
// targetState: "30",
// }
otherAttachmentList.value = [...otherAttachmentList.value, ...getLocalList()];
} else {
const filw = getLocalList().filter(item1 => item1.tag === tag);
const filteredAllFiles = allFiles.value.filter(item1 => item1.tag === tag);
// 使用 fileId 作为唯一标识进行去重
const seen = new Set();
const uniqueFiles = [...filteredAllFiles, ...filw].filter(item => {
if (!seen.has(item.fileId)) {
seen.add(item.fileId);
return true;
}
return false;
});
otherAttachmentList.value = uniqueFiles;
// params = {
// targetId: route.query.projectId,
// targetState: "30",
// tag: tag
// }
}
showAttachmentTable.value = false
// searchImplementationFileList(params).then(res => {
// if (res.code === 1000) {
// if(tag == 'all'&&flag){
// // allFiles.value = res.data.fileList
// }else{
// otherAttachmentList.value =res.data.fileList
// }
if (flag) {
getTagsOption(flag)
}
nextTick(() => {
showAttachmentTable.value = true
})
// }
// })
}
const getLocalList = () => {
if (localStorage.getItem(`implementAllFileList-${route.query.projectId}`) && JSON.parse(localStorage.getItem(`implementAllFileList-${route.query.projectId}`))) {
return JSON.parse(localStorage.getItem(`implementAllFileList-${route.query.projectId}`))
} else {
return []
}
}
const getAttachmentList = () => {
const loading = ElLoading.service({fullscreen: true})
let params = {
targetId: route.query.projectId,
targetState: "30"
}
showAttachmentTable.value = false
searchImplementationFileList(params).then(res => {
if (res.code === 1000) {
otherAttachmentList.value = [...res.data.fileList, ...getLocalList()]
allFiles.value = [...res.data.fileList, ...getLocalList()]
uploadState.value = res.data.upload
getTagsOption()
nextTick(() => {
showAttachmentTable.value = true
})
activeName.value = 'all'
loading.close()
} else {
ElNotification({
title: '提示',
message: res.msg,
type: 'error'
})
loading.close()
}
})
}
const getTagsOption = (flag) => {
if (!route.query.projectId) return
getTagList(route.query.projectId).then(res => {
if (res.code === 1000) {
tagsOption.value = res.data.rows
let list = []
if (flag) {
list = allFiles.value
} else {
list = otherAttachmentList.value
}
tagsOption.value.forEach((tag, index) => {
// const filterArray = list.filter(item => tag.fileTag == item.tag)
// console.log("🚀 ~ file:filterArray ", filterArray)
tagsOption.value[index].isClose = 1
// tagsOption.value[index].isClose = filterArray.length > 0 ? 0 : 1
})
console.log("🚀 otherAttachmentList.value", allFiles.value)
console.log("🚀 ~ file:\tagsOption.value ", tagsOption.value)
let defaultArray = [
{
tagId: 'd1',
fileTag: '合同(专项任务书)',
isDefault: 1,
isClose: 2
},
{
tagId: 'd2',
fileTag: '周报',
isDefault: 1,
isClose: 2
},
{
tagId: 'd3',
fileTag: '阶段性验收',
isDefault: 1,
isClose: 2
},
{
tagId: 'd4',
fileTag: '科研成果',
isDefault: 1,
isClose: 2
}
]
tagsOption.value = [...defaultArray, ...tagsOption.value]
// if (!res.data.rows || res.data.rows.length == 0) return;
// activeName.value=res.data.rows[0].tagId
} else {
ElNotification({
title: '提示',
message: res.msg,
type: 'error'
})
}
})
}
const handleUpload = () => {
router.push({
name: 'Implementation/upload',
query: {
id: route.query.id,
projectId: route.query.projectId,
state: route.query.state,
step: '30'
}
})
}
getAttachmentList()
onActivated(() => {
getAttachmentList()
})
</script>
<style lang="scss">
.execute-apply-table {
//.el-table__header {
// .el-table__cell:last-child {
// .cell {
// margin-left: -108px !important;
// }
// }
//}
//.el-table__body {
// .el-table__cell:last-child {
// .cell {
// margin-left: -108px !important;
// }
// }
//}
.is-leaf:first-child {
.cell {
margin-left: -25px !important;
}
}
.el-table__body {
.el-table__cell:first-child {
.cell {
margin-left: -13px !important;
}
}
}
}
</style>
<style scoped lang="scss">
:deep(.el-dialog__body) {
padding: 0 !important;
}
.tag-title {
display: flex;
align-items: center;
margin-top: 15px;
> div {
margin-right: 5px;
width: 4px;
height: 20px;
background-color: #BEA266;
}
}
:deep(.el-table--fit ) {
height: 311px !important;
}
:deep(.el-tabs__nav) {
//width: 75vw;
}
:deep(.el-tabs__item) {
flex: none !important;
}
:deep(.el-tabs__header) {
margin-bottom: 0;
}
:deep(.el-tabs__item.is-active) {
color: #BEA266;
}
:deep(.el-tabs__active-bar) {
background-color: #BEA266;
}
.file-tag {
width: 100%;
display: flex;
border-bottom: 2px solid #f6f6f6;
/*align-items: center;*/
}
</style>

View File

@@ -1,275 +0,0 @@
<template>
<div v-loading="loading" style="padding: 0 30px">
<baseTitle title="专项资金详情"></baseTitle>
<el-form :model="formData" ref="form" >
<el-row style="margin-left: 15px;margin-bottom: -18px">
<el-col :span="6">
<el-form-item label="专项名称">
<span>{{ formData.name }}</span>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="金额(元)">
<span>{{ toThousands(formData.fundAmount) }}</span>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="剩余金额(元)">
<span>{{ toThousands(formData.residualAmount) }}</span>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="专项资金情况说明" >
<div style="white-space: pre-wrap">{{formData.introduce}}
</div>
</el-form-item>
</el-col>
</el-row>
<el-row style="margin-bottom: -18px" class="projects">
<baseTitle title="关联项目" v-if="!data.taskId"></baseTitle>
<el-col :span="24" v-if="!data.taskId" >
<el-form-item >
<fvTable style="width: 100%;max-height:160px" height="160" v-if="showTable" :tableConfig="projectTable"
:data="formData.projects" :isSettingCol="false" :pagination="false">
<template #empty>
<el-empty :image-size="55" description="暂无数据" style="padding: 0"/>
</template>
</fvTable>
</el-form-item>
</el-col>
<baseTitle title="附件文件"></baseTitle>
<el-col :span="24">
<el-form-item>
<fvTable style="width: 100%;max-height: 160px;" height="160" v-if="showTable" :tableConfig="fileTable"
:data="formData.files" :isSettingCol="false" :pagination="false">
<template #empty>
<el-empty :image-size="55" description="暂无数据" style="padding: 0"/>
</template>
</fvTable>
</el-form-item>
</el-col>
<el-col :span="24" style="margin-top: -18px">
<div v-if="data.taskId">
<baseTitle title="审核意见"></baseTitle>
<el-form-item prop="auditOpinion">
<el-input
v-model="formData.auditOpinion"
:rows="3"
type="textarea"
placeholder="请输入审核意见"
/>
</el-form-item>
</div>
</el-col>
</el-row>
<div class="approval-record">
<div class="approval-title">
<baseTitle title="审批记录"></baseTitle>
<div class="diagram">
<div class="base-title">流程图</div>
<el-switch
v-model="changeDiagram"
style="--el-switch-on-color:#BEA266 ; --el-switch-off-color:#cecdcd"
/>
</div>
</div>
<div class="process">
<operation-render v-if="processViewer && data.operationList && data.operationList.length > 0&&!changeDiagram"
:operation-list="data.operationList"
:state="data.state"/>
<process-diagram-viewer v-if="processViewer&&changeDiagram" id-name="fundProcess"/>
</div>
</div>
</el-form>
<opinion v-if="data.taskId" :formData="data.formData" :taskId="data.taskId"
:taskUserOptionList="data.taskUserOptionList"
v-model:value="formData.auditOpinion"></opinion>
<file-preview ref="filePreviewRef" v-if="filePreviewShow" :fileName="filePreviewParam.fileName" :fileUrl="filePreviewParam.fileUrl"
:fileType="filePreviewParam.fileType"/>
</div>
</template>
<script setup lang="jsx">
import {toThousands} from '@/utils/changePrice.js'
import OperationRender from '@/views/workflow/common/OperationRender.vue'
import ProcessDiagramViewer from '@/views/workflow/common/ProcessDiagramViewer.vue'
import {downloadFile} from "@/api/project-demand";
const changeDiagram = ref(false)
const emit = defineEmits(['getInfo', "update:formData"])
const form = ref()
const router = useRouter()
const props = defineProps({
formData: {
type: Array,
default: []
},
data: {
type: Array,
default: []
},
processViewer: {
type: Boolean,
default: false
}, showTable: {
type: Boolean,
default: false
},
loading: {
type: Boolean,
default: false
}
})
const projectTable = reactive({
columns: [
{
prop: 'index',
type: 'index',
label: '序号',
align: 'center',
width: '80',
},
{
prop: 'projectName',
label: '项目名称',
align: 'center',
width: 400
},
{
prop: 'specialFundAmount',
label: '项目金额',
align: 'center',
currentRender:({row})=>{
return <span>{toThousands(row.specialFundAmount)}</span>
}
},
{
prop: 'startTime',
label: '项目时间',
align: 'center'
},
{
prop: 'oper',
label: '操作',
align: 'center',
currentRender: ({row, index}) => {
return (
<el-button type="primary" link onClick={() => handleView(row)}>查看</el-button>
)
}
}
]
})
const fileTable = reactive({
columns: [
{
prop: 'index',
type: 'index',
label: '序号',
align: 'center',
width: '80',
},
{
prop: 'originalFileName',
label: '文件名',
align: 'center',
width: 400,
showOverflowTooltip: false,
currentRender: ({row, index}) => (<div style="color: #2a99ff;cursor: pointer;" onClick={()=>clickToPreview(row)}>{row.originalFileName}</div>)
},
{
prop: 'tag',
label: '标签',
align: 'center'
},
{
prop: 'size',
label: '文件大小',
align: 'center',
currentRender: ({row, index}) => (parseInt(row.size / 1024) + 'KB')
},
{
prop: 'oper',
label: '操作',
align: 'center',
currentRender: ({row, index}) => {
return (
<el-button type="primary" link onClick={() => handleDownload(row)}>下载</el-button>
)
}
}
]
})
const filePreviewParam = ref({
fileUrl: '',
fileName: '',
fileType: 'pdf'
})
const filePreviewShow = ref(false)
const clickToPreview=(row)=>{
filePreviewShow.value = false
filePreviewParam.value = {
fileUrl: row.url,
fileName: row.originalFileName,
fileType: row.fileType
}
nextTick(()=>{
filePreviewShow.value = true
})
}
const handleView=(row)=>{
router.push({
name: 'Implementation/detail',
query: {
id: row.requirementId,
projectId: row.projectId,
step: '10'
}
})
}
const handleDownload = (row) => {
downloadFile(row.fileId).then(res => {
const blob = new Blob([res])
let a = document.createElement('a')
a.href = URL.createObjectURL(blob)
a.download = row.originalFileName
a.click()
})
}
watch(() => props.loading, (newVal) => {
props.loading = newVal
}, {deep: true})
watch(() => props.processViewer, (newVal) => {
props.processViewer = newVal
}, {deep: true})
watch(() => props.showTable, (newVal) => {
props.showTable = newVal
}, {deep: true})
</script>
<style scoped lang="scss">
.projects{
:deep(.el-table--fit ) {
height: 300px !important;
}
}
:deep(.el-table__header) {
.is-leaf:first-child {
.cell {
margin-left: -20px !important;
}
}
}
:deep(.el-table__body) {
.el-table__cell:first-child {
.cell {
margin-left: -10px !important;
}
}
}
</style>

View File

@@ -1,157 +1,150 @@
<template>
<div class="detail-block" v-loading="loading">
<el-form :model="localFormData" ref="summaryForm" :rules="rules">
<baseTitle title="预期知识产权"></baseTitle>
<el-row gutter="20" style="margin-bottom: -18px;margin-left: 5px">
<!-- <el-col :span="6">-->
<!-- <el-form-item label="预期成果形式" prop="resultForm">-->
<!-- <span>{{ filterDict(cacheStore.getDict('result_form'), localFormData.resultForm) }}</span>-->
<!-- </el-form-item>-->
<!-- </el-col>-->
<el-col :span="6">
<el-form-item label="知识产权归属" prop="intellectualProperty">
<span>{{
filterDict(cacheStore.getDict('intellectual_property'), localFormData.intellectualProperty)
}}</span>
<el-row gutter="50">
<el-col :span="12">
<el-form-item label="名称" prop="projectName">
<span>{{ localFormData.projectName }}</span>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="专项资金" prop="specialFund">
<span>{{ localFormData.specialFund }}</span>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="开始时间" prop="startTime">
<span>{{ localFormData.startTime }}</span>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="结束时间" prop="endTime">
<span>{{ formData.endTime }}</span>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="所属公司" prop="affiliatedCompanyId">
<span>{{ localFormData.affiliatedCompanyId }}</span>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="项目类型" prop="projectType">
<span>{{ localFormData.projectType }}</span>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="研发主体" prop="rdSubject">
<span>{{ localFormData.rdSubject }}</span>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="出资类型" prop="investmentType">
<span>{{ localFormData.investmentType }}</span>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="项目影响" prop="projectImpact">
<span>{{ localFormData.projectImpact }}</span>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="所属业务板块" prop="businessSegment">
<span>{{ localFormData.businessSegment }}</span>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="预期成果形式" prop="resultForm">
<span>{{ localFormData.resultForm }}</span>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="预期技术标准制定" prop="technicalStandard">
<span>{{ localFormData.technicalStandard }}</span>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="产学研联合" prop="industryUniversityResearch">
<span>{{ localFormData.industryUniversityResearch }}</span>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="开展政府申报" prop="governmentDeclaration">
<span>{{ localFormData.governmentDeclaration }}</span>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="知识产权状况" prop="intellectualProperty">
<span>{{ localFormData.intellectualProperty }}</span>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="预估专利(项)" prop="newPatent">
<el-form-item label="发明专利(项)" prop="inventionPatent">
<span>{{ localFormData.inventionPatent }}</span>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="实用性新型专利(项)" prop="newPatent">
<span>{{ localFormData.newPatent }}</span>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="预估软件著作权(项)" prop="softwareCopyright">
<el-form-item label="软件著作权(项)" prop="softwareCopyright">
<span>{{ localFormData.softwareCopyright }}</span>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="预估技术标准(项)" prop="technicalNorms">
<span>{{ localFormData.technicalNorms }}</span>
<el-form-item label="著作权(项)" prop="copyright">
<span>{{ localFormData.copyright }}</span>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="预估新产品(项)" prop="newProduct">
<span>{{ localFormData.newProduct }}</span>
<el-form-item label="其他(项)" prop="other">
<span>{{ localFormData.other }}</span>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="预估新工艺(项)" prop="newProcess">
<span>{{ localFormData.newProcess }}</span>
<el-form-item label="经济概算(万元)" prop="economicEstimate">
<span>{{ localFormData.economicEstimate }}</span>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="预估新装置(项)" prop="newDevice">
<span>{{ localFormData.newDevice }}</span>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="预估新材料(项)" prop="newMaterials">
<span>{{ localFormData.newMaterials }}</span>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="预估计算机软件(项)" prop="computerSoftware">
<span>{{ localFormData.computerSoftware }}</span>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="预估论文论著(项)" prop="thesis">
<span>{{ localFormData.thesis }}</span>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="预估研究报告(项)" prop="researchReport">
<span>{{ localFormData.researchReport }}</span>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="预估商标(项)" prop="trademark">
<span>{{ localFormData.trademark }}</span>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="预估其他(项)" prop="other">
<span style="white-space: pre-wrap">{{ localFormData.other }}</span>
</el-form-item>
</el-col>
</el-row>
<baseTitle title="项目描述"></baseTitle>
<el-row gutter="20" style="margin-left: 5px;margin-bottom: -18px;">
<el-col :span="24">
<el-form-item label="现有业务描述" prop="serviceDescription">
<span style="white-space: pre-wrap">{{ localFormData.serviceDescription }}</span>
<el-form-item label="其中申请公司总部科技创新专项资金(万元)" prop="specialFundAmount">
<span>{{ localFormData.specialFundAmount }}</span>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="建设目标描述" prop="contentDescription">
<span style="white-space: pre-wrap">{{ localFormData.contentDescription }}</span>
<el-form-item label="现有业务描述" prop="serviceDescription">
<span>{{ localFormData.serviceDescription }}</span>
</el-form-item>
</el-col>
</el-row>
<baseTitle title="需求上报申请书" style="margin-bottom: -3px;"></baseTitle>
<!-- <el-row gutter="20" style="margin-bottom: -15px;">-->
<!-- <el-col :span="24">-->
<!-- <single-file-component tag="需求上报" v-model:value="localFormData.singleFile" :processViewer="processViewer"/>-->
<!-- &lt;!&ndash; <el-form-item>&ndash;&gt;-->
<!-- &lt;!&ndash; {{localFormData.singleFile}}&ndash;&gt;-->
<!-- &lt;!&ndash; <el-button type="primary" link @click="handleDownload(localFormData.singleFile)" style="font-size: 16px">&ndash;&gt;-->
<!-- &lt;!&ndash; {{ localFormData.singleFile?.originalFileName }}&ndash;&gt;-->
<!-- &lt;!&ndash; </el-button>&ndash;&gt;-->
<!-- &lt;!&ndash; </el-form-item>&ndash;&gt;-->
<!-- </el-col>-->
<!-- </el-row>-->
<!--/* <baseTitle title="附件文件" style="margin-bottom: 0"></baseTitle>*/-->
<el-row gutter="20" style="margin-bottom: -18px;">
<el-col :span="24" class="file-table-style">
<file-component tag="需求上报"
v-model:value="localFormData.fileList" :processViewer="processViewer"
:file-list-show="fileListShow"/>
<el-col :span="24">
<el-form-item label="研发项目关键内容描述" prop="contentDescription">
<span>{{ localFormData.contentDescription }}</span>
</el-form-item>
</el-col>
<el-col :span="24" style="margin-top: -15px">
<el-col :span="24">
<el-form-item label="需求上报申请书">
<el-button type="primary" link @click="handleDownload(localFormData.singleFile)">
{{ localFormData.singleFile?.originalFileName }}
</el-button>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="需求上报附件">
<fvTable style="width: 100%;max-height: 400px;" v-if="processViewer" :tableConfig="tableConfig"
:data="localFormData.fileList" :isSettingCol="false" :pagination="false">
<template #empty>
<el-empty :image-size="90" description="暂无数据" style="padding: 0"/>
</template>
</fvTable>
</el-form-item>
</el-col>
<el-col :span="24">
<div v-if="data.taskId">
<baseTitle title="审核意见"></baseTitle>
<el-form-item prop="_value">
<el-form-item prop="auditOpinion">
<el-input
v-model="_value"
:rows="3"
type="textarea"
placeholder="请输入审核意见"
/>
</el-form-item>
</div>
<div v-if="data.state==='5'" style="margin-bottom: 15px">
<baseTitle title="前置流程" v-if="localFormData.preProcess"></baseTitle>
<div style="display: flex;align-items: center;flex-wrap: wrap;">
<div v-for="(item,index) in localFormData.preProcess" :key="item.requestId">
<a :href="item.baseUrl" target="_blank"
style="color: #2a99ff;cursor: pointer">{{ item.requestName }}<span
v-if="index != localFormData.preProcess.length -1"></span>
</a>
</div>
</div>
</div>
<div v-perm="['annual:plan:approve']" v-if="data.state==='4'">
<!-- <baseTitle title="前置流程"></baseTitle>-->
<!-- <select-pre-process :formData="localFormData"/>-->
<baseTitle title="审核意见"></baseTitle>
<el-form-item prop="_value">
<el-input
v-model="_value"
v-model="localFormData.auditOpinion"
:rows="3"
type="textarea"
placeholder="请输入审核意见"
@@ -161,58 +154,30 @@
</el-col>
</el-row>
<div class="approval-record">
<div class="approval-title" style="margin-top: -12px">
<baseTitle title="审批记录"></baseTitle>
<div class="diagram">
<div class="base-title">流程图</div>
<el-switch
v-model="changeDiagram"
style="--el-switch-on-color:#BEA266 ; --el-switch-off-color:#cecdcd"
/>
</div>
<el-button color="#DED0B2" style="margin-left: 10px"
@click="handleCarbonCopy()">立即抄送
</el-button>
</div>
<baseTitle title="审批记录"></baseTitle>
<div class="process">
<operation-render v-if="processViewer && data.operationList && data.operationList.length > 0&&!changeDiagram"
:operation-list="data.operationList"
:step="'report'"
<operation-render v-if="processViewer" :operation-list="data.operationList"
:state="data.state"/>
<process-diagram-viewer v-if="processViewer&&changeDiagram" id-name="summaryProcess"/>
<process-diagram-viewer v-if="processViewer" id-name="summaryProcess"/>
</div>
</div>
<!-- <div class="oper-page-btn" v-if="data.state === '1' && data.taskId">-->
<!-- <el-button @click="handleReject(summaryForm)">驳回</el-button>-->
<!-- <el-button color="#DED0B2" @click="handleAgree">同意</el-button>-->
<!-- </div>-->
</el-form>
<user-picker :multiple="true" ref="carbonCopyUserRef" title="请选择抄送人员"
v-model:value="carbonCopyUserList" @ok="carbonCopyUserPickerOk"
@cancelOrClear="carbonCopyUserPickerOk"/>
<div class="oper-page-btn" v-perm="['annual:plan:approve']" v-if="data.state==='4'">
<el-button type="danger" @click="handleRejectPlan">驳回年度计划</el-button>
<el-button color="#DED0B2" @click="handleAgreePlan">通过年度计划</el-button>
</div>
</div>
</template>
<script setup lang="jsx">
import {toThousands} from '@/utils/changePrice.js'
import {downloadFile, deleteFile} from "@/api/project-demand";
import {downloadFile} from "@/api/project-demand";
import OperationRender from '@/views/workflow/common/OperationRender.vue'
import ProcessDiagramViewer from '@/views/workflow/common/ProcessDiagramViewer.vue'
import {ElMessage, ElNotification} from "element-plus";
import {agreeTask, rejectTask} from "@/api/project-demand";
import {useTagsView} from '@/stores/tagsview.js'
import {getFundOption} from "@/api/special-fund";
import {useCacheStore} from '@/stores/cache.js'
import {getSubCompOpt} from "@/api/user/user";
import FileComponent from "./FileComponent.vue";
import {ElNotification} from "element-plus";
import {approvePlan} from "@/api/project-demand/summary";
import SelectPreProcess from "@/components/SelectPreProcess.vue";
import {applyCcSend} from "@/api/expense-manage";
import UserPicker from "@/views/workflow/process/common/UserPicker.vue";
const emit = defineEmits(['update:value','ccSend'])
const tagsViewStore = useTagsView()
const cacheStore = useCacheStore()
const props = defineProps({
formData: {
type: Object,
@@ -220,173 +185,101 @@ const props = defineProps({
},
data: {
type: Object,
default: {
state: '1'
}
default: {}
},
processViewer: {
type: Boolean,
default: false
},
fileListShow: {
type: String,
default: 'READ'
},
loading: {
}, loading: {
type: Boolean,
default: false
},
value: {
type: String,
default: ''
}
})
const changeDiagram = ref(false)
const localFormData = ref({})
const route = useRoute()
const tableConfig = reactive({
columns: [
{
prop: 'index',
type: 'index',
label: '序号',
align: 'center',
width: '80',
},
{
prop: 'originalFileName',
label: '文件名',
align: 'center',
},
{
prop: 'tag',
label: '标签',
align: 'center'
},
{
prop: 'size',
label: '文件大小',
align: 'center',
currentRender: ({row, index}) => (parseInt(row.size / 1024) + 'KB')
},
{
prop: 'oper',
label: '操作',
align: 'center',
currentRender: ({row, index}) => {
return (
<el-button type="primary" link onClick={() => handleDownload(row)}>下载</el-button>
)
}
}
]
})
const router = useRouter()
const fundOption = ref([])
const companyOption = ref([])
const dictName = ref({})
const carbonCopyUserList = ref([])
const carbonCopyUserRef = ref()
const summaryForm = ref()
const rules = reactive({
auditOpinion: [{required: true, message: '请输入审核意见', trigger: 'blur'}],
})
const _value = computed({
get() {
return props.value;
},
set(val) {
emit("update:value", val);
}
})
const handleCarbonCopy = () => {
carbonCopyUserRef.value.showUserPicker()
}
const carbonCopyUserPickerOk = (userList) => {
carbonCopyUserList.value = userList.map(item => item.id)
console.log('localFormData.value', props.data)
console.log("🚀 ~ file:'carbonCopyUserList.value ", carbonCopyUserList.value)
addUser()
}
const addUser = async () => {
const res = await applyCcSend({
instanceId: props.data.processInstanceId,
projectId: route.query.projectId,
state: route.query.step,
userIds: carbonCopyUserList.value
})
console.log('res', res)
if (res.code === 1000) {
ElNotification({
title: '提示',
message: '抄送成功',
type: 'success'
const handleReject = (instance) => {
if (!instance) return
instance.validate(async (valid) => {
if (!valid) return
let approve = {
taskId: props.data.taskId,
auditOpinion: localFormData.value.auditOpinion,
}
rejectTask(approve).then(res => {
ElNotification({
title: '提示',
message: res.msg,
type: res.code === 1000 ? 'success' : 'error'
})
if (res.code === 1000) {
tagsViewStore.delVisitedViews(router.currentRoute.value.path)
router.push({
name: 'Summary'
})
}
})
emit('ccSend')
} else {
})
}
const handleAgree = () => {
let approve = {
taskId: props.data.taskId,
auditOpinion: localFormData.value.auditOpinion,
formData: localFormData.value
}
agreeTask(approve).then(res => {
ElNotification({
title: '提示',
message: res.msg,
type: 'error'
type: res.code === 1000 ? 'success' : 'error'
})
}
}
const handleRejectPlan = async () => {
// const values = form.value.getValues()
// console.log('route',route.query.projectId)
if (!_value.value) {
ElNotification({
title: '提示',
message: '请填写审核意见',
type: 'warning'
})
return
}
const params = {
auditOpinion: _value.value,
projectId: parseInt(route.query.projectId),
state: false
}
// console.log('params', params)
const res = await approvePlan(params)
ElNotification({
title: '提示',
message: res.msg,
type: res.code === 1000 ? 'success' : 'error'
})
tagsViewStore.delVisitedViews(router.currentRoute.value.path)
router.push({
name: 'Summary'
})
}
const handleAgreePlan = async () => {
if (!_value.value) {
ElNotification({
title: '提示',
message: '请填写审核意见',
type: 'warning'
})
return
}
const params = {
auditOpinion: _value.value,
projectId: parseInt(route.query.projectId),
preProcess: JSON.stringify(localFormData.value.preProcess),
state: true
}
const res = await approvePlan(params)
ElNotification({
title: '提示',
message: res.msg,
type: res.code === 1000 ? 'success' : 'error'
})
tagsViewStore.delVisitedViews(router.currentRoute.value.path)
router.push({
name: 'Summary'
})
}
const filterDict = (data, value) => {
if (data === undefined || value === undefined) return;
let label = ''
let result = []
if (value instanceof Array) {
value.forEach(item1 => {
data.find(item => {
if (item.value == item1) {
result.push(item.label)
}
})
})
label = result.map(item => item).join('')
} else {
if (data instanceof Array) {
data.find(item => {
if (item.value == value) {
label = item.label
}
if (res.code === 1000) {
tagsViewStore.delVisitedViews(router.currentRoute.value.path)
router.push({
name: 'Summary'
})
}
}
return label
}
const getFundOptions = async () => {
const resFund = await getFundOption()
fundOption.value = resFund.data
const res = await getSubCompOpt()
companyOption.value = res.data
}
const changeName = (option, value) => {
let name = ''
option.forEach(item => {
if (item.value == value) {
name = item.label
}
})
return name
}
const handleDownload = (row) => {
downloadFile(row.fileId).then(res => {
@@ -398,45 +291,32 @@ const handleDownload = (row) => {
})
}
watch(
() => props.formData,
(val) => {
}
)
watch(() => props.processViewer, (newVal) => {
props.processViewer = newVal
}, {deep: true})
watch(() => props.loading, (newVal) => {
props.loading = newVal
}, {deep: true})
watchEffect(() => {
props.formData.singleFile = [props.formData.singleFile]
return Object.keys(props.formData).length && (localFormData.value = props.formData)
Object.keys(props.formData).length && (localFormData.value = props.formData)
})
getFundOptions()
</script>
<style scoped lang="scss">
<style scoped>
:deep(.el-table--fit) {
height: auto !important;
}
.detail-block {
overflow-x: hidden;
overflow-y: auto;
padding-bottom: 0 !important;
}
.file-table-style {
:deep(.el-table__header) {
.is-leaf:first-child {
.cell {
margin-left: -25px !important;
}
}
}
:deep(.el-table__body) {
.el-table__cell:first-child {
.cell {
margin-left: -13px !important;
}
}
}
padding-bottom: 20px;
}
</style>

View File

@@ -1,209 +0,0 @@
<template>
<el-form :label-position="labelAlign">
<el-form-item :label="title?'其他文件':''" :label-position="labelAlign" :label-width="title?95:''">
<fvTable style="width: 100%;max-height: 80px;" v-if="processViewer" height="80" :tableConfig="tableConfig"
:data="_value" :isSettingCol="false" :pagination="false">
<template #empty>
<el-empty :image-size="55" description="暂无数据" style="padding: 0"/>
</template>
</fvTable>
</el-form-item>
</el-form>
<file-preview ref="filePreviewRef" :fullscreen="fullscreen" v-if="filePreviewShow" :fileName="filePreviewParam.fileName" :fileUrl="filePreviewParam.fileUrl"
:fileType="filePreviewParam.fileType"/>
</template>
<script setup lang="jsx">
import {downloadFile, deleteFile} from "@/api/project-demand";
import {ElNotification} from "element-plus";
const props = defineProps({
title: {
type: String,
default: ''
},
tag: {
type: String,
default: ''
},
fileNameTableWidth: {
type: String,
default: '400'
},
value: {
type: Array,
default: []
},
processViewer: {
type: Boolean,
default: false
},
labelAlign: {
type: String,
default: 'right'
},
//弹窗是否铺满全屏
fullscreen: {
type: Boolean,
default: false
}
})
const emit = defineEmits(['update:value'])
const tableConfig = reactive({
columns: [
{
prop: 'index',
type: 'index',
label: '序号',
align: 'center',
width: 85,
},
{
prop: 'originalFileName',
label: '文件名',
align: 'center',
width: props.fileNameTableWidth,
showOverflowTooltip: false,
currentRender: ({row, index}) => (<div style="color: #2a99ff;cursor: pointer;" onClick={()=>clickToPreview(row)}>{row.originalFileName}</div>)
},
{
prop: 'tag',
label: '标签',
align: 'center'
},
{
prop: 'size',
label: '文件大小',
align: 'center',
width: 150,
currentRender: ({row, index}) => (parseInt(row.size / 1024) + 'KB')
},
{
prop: 'oper',
label: '操作',
align: 'center',
showOverflowTooltip: false,
currentRender: ({row, index}) => {
let btn = []
btn.push({label: '下载', func: () => handleDownload(row), type: 'primary'})
// if (row.newFile) {
// btn.push({label: '删除', func: () => handleDelete(row), type: 'primary'})
// }
return (
<div style={{width: '100%'}}>
{
btn.map(item => (
<el-button
type={item.type}
onClick={() => item.func()}
link>
{item.label}
</el-button>
))
}
{
row.newFile ? <popover-delete name={row.originalFileName} type={'文件'} btnType={'danger'}
onDelete={() => handleDelete(row)}/>
: ''
}
</div>
)
}
}
]
})
const filePreviewParam = ref({
fileUrl: '',
fileName: '',
fileType: 'pdf'
})
const filePreviewShow = ref(false)
const clickToPreview=(row)=>{
filePreviewShow.value = false
filePreviewParam.value = {
fileUrl: row.url,
fileName: row.originalFileName,
fileType: row.fileType
}
nextTick(()=>{
filePreviewShow.value = true
})
}
const _value = computed({
get() {
return props.value;
},
set(val) {
emit("update:value", val);
}
})
const getOtherFile = (val) => {
props.processViewer = false
let fileObj = compositeParam(val)
_value.value.push(fileObj)
nextTick(() => {
props.processViewer = true
})
}
const compositeParam = (item, type) => {
return {
fileId: item.id,
size: item.size,
originalFileName: item.originalFilename,
fileType: item.fileType,
url: item.url,
newFile: true,
tag: props.tag
}
}
const handleDownload = (row) => {
downloadFile(row.fileId).then(res => {
const blob = new Blob([res])
let a = document.createElement('a')
a.href = URL.createObjectURL(blob)
a.download = row.originalFileName
a.click()
})
}
const handleDelete = (row) => {
deleteFile(row.fileId).then(res => {
ElNotification({
title: '提示',
message: res.msg,
type: res.code === 1000 ? 'success' : 'error'
})
if (res.code === 1000) {
_value.value.splice(_value.value.findIndex((item) => item.fileId === row.fileId), 1);
}
});
}
watch(() => props.processViewer, (newVal) => {
props.processViewer = newVal
}, {deep: true})
</script>
<style scoped lang="scss">
:deep(.el-table--fit ) {
height: 80px !important;
}
:deep(.el-table__header) {
.is-leaf:first-child {
.cell {
margin-left: -25px !important;
}
}
}
:deep(.el-table__body) {
.el-table__cell:first-child {
.cell {
margin-left: -13px !important;
}
}
}
</style>

View File

@@ -1,39 +1,34 @@
<template>
<el-upload :file-list="_value" ref="uploadRef"
action="#"
<el-upload :file-list="_value"
:action="uploadFileUrl"
:headers="headers"
:limit="maxSize"
with-credentials
:multiple="multiple"
:data="uploadParams" :on-change="handleChange"
:http-request="customUpload"
:multiple="maxSize > 0"
:data="uploadParams"
:show-file-list="showFileList"
:auto-upload="false"
:auto-upload="true"
:before-upload="beforeUpload"
:on-success="handleUploadSuccess"
:on-error="uploadError"
:before-remove="beforeRemove"
:on-remove="handleRemove"
>
<el-button color="#DED0B2" :loading="loading" :disabled="disabled">上传文件</el-button>
<el-button color="#DED0B2" :loading="loading">上传文件</el-button>
</el-upload>
</template>
<script setup>
import {ElLoading, ElMessage, ElMessageBox, ElNotification} from "element-plus";
import {ElMessage,ElMessageBox} from "element-plus";
import {getToken} from '@/utils/auth'
import {nextTick} from "vue";
import axios from "axios";
const baseURL = import.meta.env.VITE_BASE_URL
const uploadFileUrl = ref(baseURL + "/workflow/process/file/upload")
const headers = reactive({
'Content-Type': 'multipart/form-data',
authorization: getToken()
})
const disabled = ref(false)
const loading = ref(false)
const showTable = ref(false)
const uploadIndex = ref(0)
const uploadParams = ref({})
const props = defineProps({
value: {
@@ -44,24 +39,15 @@ const props = defineProps({
},
maxSize: {
type: Number,
default: 999999
default: 30
},
showFileList: {
type: Boolean,
default: false
},
disabled: {
type: Boolean,
default: false
},
multiple: {
type: Boolean,
default: true
}
})
const uploadRef = ref(null); // el-upload 的 ref
const uploadPromises = ref([]); // 跟踪每个文件的上传状态
const emit = defineEmits(["input", "beforeUpload","getFile", "delete"])
const emit = defineEmits(["input", "getFile","delete"])
const fileList = ref([])
const _value = computed({
get() {
@@ -71,7 +57,7 @@ const _value = computed({
emit("input", val);
}
})
const beforeRemove = (file) => {
const beforeRemove = (file, fileList) => {
return ElMessageBox.confirm(`确认删除名称为${file.name}的文件吗?`, '系统提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
@@ -79,106 +65,40 @@ const beforeRemove = (file) => {
}).then(() => true)
}
const uploadLoading = ref(false)
const uploadFile = ref([])
const handleRemove = (file) => {
emit("delete", file.response.data.id)
const handleRemove = (file, fileList) => {
emit("delete",file.response.data.id)
}
// 文件选择变化时触发
const handleChange = (file, files) => {
console.log(file, files,'files')
uploadIndex.value++
uploadFile.value.push(file)
};
watch(() => uploadIndex.value, (newVal) => {
console.log('newVal',newVal)
startUpload(uploadFile.value); // 自动触发上传
},{
deep: true
})
// 自定义上传逻辑
const customUpload = async (options) => {
const formData = new FormData();
formData.append('file', options.raw);
try {
const response = await axios.post(uploadFileUrl.value, formData, {
headers: headers,
});
fileList.value.push(response.data.data)
emit("getFile", response.data.data)
return response.data; // 成功时返回响应
} catch (error) {
throw new Error('上传失败'); // 失败时抛出错误
}
};
// 触发所有文件上传
const startUpload = (files) => {
uploadLoading.value= ElLoading.service({
fullscreen: true,
text: '文件上传中...',
})
if (files.length === 0) {
return; // 没有文件时直接返回
}
uploadPromises.value = []; // 重置 Promise 数组
files.forEach((file) => {
// 触发每个文件的上传
const promise = new Promise((resolve, reject) => {
customUpload(file).then(resolve)
.catch(reject);
});
uploadPromises.value.push(promise);
});
// 使用 Promise.all 监听所有文件上传完成
Promise.all(uploadPromises.value)
.then(() => {
ElNotification({
title: '提示',
message: '所有文件上传完成!',
type: 'success'
})
files = []; // 清空文件列表
uploadRef.value.clearFiles(); // 清空上传组件
nextTick(() => {
uploadLoading.value.close()
uploadLoading.value=null
})
})
};
const beforeUpload = () => {
const beforeUpload = (file) => {
// const FileExt = file.name.replace(/.+\./, "");
// if (['zip', 'rar', 'pdf', 'doc', 'docx', 'xlsx'].indexOf(FileExt.toLowerCase()) === -1) {
// ElMessage.warning('请上传后缀名为pdf、doc、docx、xlsx、zip或rar的文件');
// return false;
// } else
// if (props.maxSize > 0 && file.size / 1024 / 1024 > props.maxSize) {
// ElMessage.warning(`每个文件最大不超过 ${props.maxSize}MB`)
// } else {
loading.value = true
return true
// }
}
const handleUploadSuccess = (res) => {
ElNotification({
title: '提示',
message: res.code === 1000 ? '上传成功' : '上传失败',
type: res.code === 1000 ? 'success' : 'error'
})
loading.value = false
const handleUploadSuccess = (res, file) => {
if (res.code !== 1000) {
loading.value = false
ElMessage.error("上传失败")
} else {
loading.value = false
ElMessage.success("上传成功")
}
showTable.value = true
let data = res.data
fileList.value.push(data)
emit("getFile", res.data)
}
const uploadError = () => {
const uploadError=(err)=>{
loading.value = false
ElNotification({
title: '提示',
message: "上传失败,请稍后再试!",
type: 'error'
})
ElMessage.error("上传失败,请稍后再试!")
}
defineExpose({
handleRemove
})
</script>
<style lang="scss" scoped>
@@ -186,7 +106,6 @@ a {
font-size: 14px;
color: #2a99ff;
}
:deep(.el-upload-list) {
width: 400px;
}

View File

@@ -1,114 +0,0 @@
<template>
<el-upload :file-list="[]"
:limit="maxSize"
with-credentials
:multiple="multiple"
:http-request="httpRequestHandle"
:data="uploadParams"
:auto-upload="true"
:show-file-list="false"
:before-upload="beforeUpload"
:before-remove="beforeRemove"
:on-remove="handleRemove"
>
<el-button color="#DED0B2" style="margin-right: 10px;" :disabled="disabled">导入</el-button>
</el-upload>
</template>
<script setup>
import {ElMessageBox, ElNotification} from "element-plus";
import {getToken} from '@/utils/auth'
import axios from "axios";
const props = defineProps({
value: {
type: Array,
default: () => {
return []
}
},
maxSize: {
type: Number,
default: 30
},
disabled: {
type: Boolean,
default: false
},
multiple: {
type: Boolean,
default: false
},
})
const baseURL = import.meta.env.VITE_BASE_URL
const uploadFileUrl = ref(baseURL + "/workflow/mosr/rd/expense/import")
const headers = reactive({
authorization: getToken()
})
// const loading = ref(false)
const uploadParams = ref({})
const emit = defineEmits(["input", "getFile", "delete"])
const beforeRemove = (file) => {
return ElMessageBox.confirm(`确认删除名称为${file.name}的文件吗?`, '系统提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => true)
}
const handleRemove = (file) => {
emit("delete", file.response.data.id)
}
const beforeUpload = () => {
// loading.value = true
return true
}
const httpRequestHandle = (param) => {
let file = param.file
axios.post(uploadFileUrl.value, {
file: file
}, {
headers: {
'Content-Type': 'multipart/form-data',
...headers
}
}).then(res => {
handleUploadSuccess(res)
}).catch(error => {
uploadError(error)
})
}
const handleUploadSuccess = (res) => {
let data = res.data
ElNotification({
title: '提示',
message: data.code === 1000 ? '上传成功' : '上传失败',
type: data.code === 1000 ? 'success' : 'error'
})
emit("success")
}
const uploadError = (error) => {
console.log("🚀 ~ file:'error ", error.response.data.msg)
// loading.value = false
ElNotification({
title: '提示',
message: error.response.data.msg,
type: 'error'
})
}
defineExpose({
handleRemove
})
</script>
<style lang="scss" scoped>
a {
font-size: 14px;
color: #2a99ff;
}
</style>

View File

@@ -1,116 +0,0 @@
<template>
<el-upload :file-list="[]"
:limit="maxSize"
with-credentials
:multiple="multiple"
:http-request="httpRequestHandle"
:data="uploadParams"
:auto-upload="true"
:show-file-list="false"
:before-upload="beforeUpload"
:before-remove="beforeRemove"
:on-remove="handleRemove"
>
<el-button color="#DED0B2" style="margin-left: 10px; margin-right: 10px;" :disabled="disabled">导入</el-button>
</el-upload>
</template>
<script setup>
import {ElMessageBox, ElNotification} from "element-plus";
import {getToken} from '@/utils/auth'
import axios from "axios";
const props = defineProps({
value: {
type: Array,
default: () => {
return []
}
},
maxSize: {
type: Number,
default: 30
},
disabled: {
type: Boolean,
default: false
},
multiple: {
type: Boolean,
default: false
},
projectId: {
type: Number,
default: 0
}
})
const baseURL = import.meta.env.VITE_BASE_URL
const uploadFileUrl = ref(baseURL + "/workflow/mosr/expense/ledger/import?projectId=" + props.projectId)
const headers = reactive({
authorization: getToken()
})
// const loading = ref(false)
const uploadParams = ref({})
const emit = defineEmits(["input", "getFile", "delete"])
const beforeRemove = (file) => {
return ElMessageBox.confirm(`确认删除名称为${file.name}的文件吗?`, '系统提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => true)
}
const handleRemove = (file) => {
emit("delete", file.response.data.id)
}
const beforeUpload = () => {
// loading.value = true
return true
}
const httpRequestHandle = (param) => {
let file = param.file
axios.post(uploadFileUrl.value, {
file: file
}, {
headers: {
'Content-Type': 'multipart/form-data',
...headers
}
}).then(res => {
handleUploadSuccess(res)
}).catch(error => {
uploadError(error)
})
}
const handleUploadSuccess = (res) => {
let data = res.data
ElNotification({
title: '提示',
message: data.code === 1000 ? '上传成功' : '上传失败',
type: data.code === 1000 ? 'success' : 'error'
})
emit("success")
}
const uploadError = (error) => {
// loading.value = false
ElNotification({
title: '提示',
message: "上传失败,请稍后再试!",
type: 'error'
})
}
defineExpose({
handleRemove
})
</script>
<style lang="scss" scoped>
a {
font-size: 14px;
color: #2a99ff;
}
</style>

View File

@@ -1,27 +1,29 @@
<template>
<div style="display: block">
<div>
<slot name="pre"></slot>
<div class="user-audit">
<div class="circle-user">
<Tooltip v-if="userName" :content="userName" placement="bottom-start" width="45px"/>
<Tooltip v-else :content="user.name" placement="bottom-start" width="45px"/>
<!-- :style="{-->
<!-- backgroundColor: '#fff'-->
<!-- }">-->
<Tooltip :content="user.name" placement="bottom-start" width="45"/>
<div v-if="user.icon"
class="el-timeline-item__node">
<div v-if="user.isAgent&&!showIcon">
</div>
<el-icon v-else size="15" :color="user.color" :class="user.class">
class="el-timeline-item__node" :style="{
backgroundColor: user.color
}">
<el-icon v-if="user.icon" size="15" :class="user.class">
<component :is="user.icon"/>
</el-icon>
</div>
</div>
<div class="username" v-if="user.auditOpinion">
<div style="margin-bottom: 10px;color: #909399">{{user.operationTime}}</div>
<Tooltip :content="user.auditOpinion" placement="bottom-start" width="140" :lines="true"/>
</div>
</div>
</div>
</template>
<script setup>
import {Loading, Close, CircleCheckFilled, MoreFilled} from '@element-plus/icons-vue'
import {defineProps} from "vue";
const props = defineProps({
row: {
@@ -32,26 +34,14 @@ const props = defineProps({
type: Boolean,
default: false
},
showIcon: {
type: Boolean,
default: false
},
user: {
type: Object,
default: {}
},
userName: {
type: String,
default: ''
},
mode: {
type: String,
default: 'design'
},
type: {
type: String,
default: ''
},
}
})
const init = () => {
@@ -64,41 +54,29 @@ const initUser = (user) => {
let state = user.state
//创建节点
if (state === 'CREATE') {
user["icon"] = 'CircleCheckFilled'
user["icon"] = CircleCheckFilled
user["color"] = "#0bbd87"
}
//审批通过
if (state === 'AGREE' || state === 'AUTO_PASS') {
user["icon"] = 'CircleCheckFilled'
user["icon"] = CircleCheckFilled
user["color"] = "#0bbd87"
}
if (props.type === "CC") {
user["icon"] = "Promotion"
user["color"] = "#3395f8"
}
//审批处理中
if (state === 'RUNNING') {
user["icon"] = 'Loading'
user["icon"] = Loading
user["color"] = "#f78f5f"
user["class"] = 'is-loading'
}
//拒绝后评论
if (state === 'REFUSE' || state === 'ROLLBACK') {
// user["icon"] = 'Close'
// user["color"] = "#f56c6c"
user["icon"] = 'CircleCloseFilled'
if (state === 'REFUSE') {
user["icon"] = Close
user["color"] = "#f56c6c"
}
if (state === 'PASS') {
user["icon"] = 'MoreFilled'
user["icon"] = MoreFilled
user["color"] = "#c0c4cc"
}
// if (state === 'ROLLBACK') {
// // user["icon"] = 'RefreshLeft'
// // user["color"] = "#f78f5f"
// user["icon"] = 'CircleCloseFilled'
// user["color"] = "#f56c6c"
// }
return user;
}
@@ -112,16 +90,14 @@ init()
align-items: center;
.circle-user {
width: 46px;
height: 46px;
width: 50px;
height: 50px;
display: flex;
justify-content: center;
align-items: center;
border-radius: 50%;
border: 1px solid #ACACAC;
position: relative;
background-color: #8a7243;
color: #fff;
.el-timeline-item__node {
position: absolute;
@@ -129,5 +105,22 @@ init()
right: 1px;
}
}
.username {
//width: 90px;
margin-top: 10px;
background: #f5f5f5;
padding: 5px;
.el-tooltip__trigger {
width: 90px;
text-align: center;
//padding-top: 2px;
//text-align: center;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden
}
}
}
</style>

View File

@@ -1,7 +1,7 @@
<template>
<div style="display: flex;justify-content: center">
<span class="stateIcon" :style="{backgroundColor: filterDictClass(cacheStore.getDict(dictType), value)}"></span>
<span>{{tagConfig.label}}</span>
<span>{{tag.label}}</span>
<span> {{ filterDict(cacheStore.getDict(dictType), value) }}</span>
</div>
</template>
@@ -21,43 +21,37 @@ const props = defineProps({
default: null
}
});
const tagConfig = reactive({
const tag = reactive({
listClass: "green",
isType: true,
label: ""
});
// const dictList = cacheStore.getDict(props.dictType);
// const dictFormat = () => {
// if(dictList===undefined) return;
// for (let i = 0; i < dictList.length; i++) {
// if(dictList[i].value=== props.value){
// tag.label = dictList[i].label;
// tag.listClass=changeParams(dictList[i].listClass)
// tag.isType = dictList[i].isType;
// }
// }
// };
const filterDictClass = (data, value) => {
if (!data|| value == null) return 'gray'
if (data instanceof Array) {
tagConfig.value = data.find(item => item.value == value)
if (!tagConfig.value) {
return '#409EFF'
} else {
if (tagConfig.value?.isType) {
return changeParams(tagConfig.value.listClass)
} else {
return tagConfig.value.listClass
}
}
if(!data) return
if(data instanceof Array) {
tag.value = data.find(item => item.value == value)
}
return changeParams(tag.value.listClass)
}
const filterDict = (data, value) => {
if (!data || value == null) return '未知'
if (data instanceof Array) {
if (value == true || value == false) {
tagConfig.value = data.find(item => item.value == value.toString())
} else if (typeof value === "object") {
if (value !== null) {
tagConfig.value = data.find(item => item.value == value[0])
} else {
tagConfig.value = {}
}
} else {
tagConfig.value = data.find(item => item.value == value)
}
if(!data) return
if(data instanceof Array) {
tag.value = data.find(item => item.value == value)
}
return tagConfig.value?.label || '未知'
return tag.value.label
}
/**
* 根据接口返回的listClass切换成对应的颜色

View File

@@ -9,10 +9,7 @@
@cancel="handleCancel"
>
<template #reference>
<el-button :type="btnType" size="mini" :disabled="isDisabled" v-if="perm" v-perm="perm" :icon="btnIcon" :plain="isPlain" :link="link">
{{ btnText }}
</el-button>
<el-button :type="btnType" size="mini" :disabled="isDisabled" v-else :icon="btnIcon" :plain="isPlain" :link="link">
<el-button v-perm="perm" :type="btnType" size="mini" :disabled="isDisabled" :icon="btnIcon" :plain="isPlain" :link="link">
{{ btnText }}
</el-button>
</template>
@@ -47,7 +44,7 @@ const props = defineProps({
},
perm: {
type: Array,
default: null
default: ['']
},
isDisabled: {
type: Boolean,
@@ -68,6 +65,7 @@ const handleCancel = () => {
visible.value = false
}
const handleDelete = () => {
console.log('确认')
emit("delete")
}
</script>

View File

@@ -1,275 +0,0 @@
<template>
<div v-loading="_value">
<el-form :model="attachment" inline style="margin-left: 15px" @submit.prevent="handleSearch">
<el-form-item label="名称" prop="fileName">
<el-input v-model="attachment.fileName" placeholder="请输入文件名查询" clearable filterable style="width: 300px"/>
</el-form-item>
<el-form-item label="项目阶段" prop="targetState" v-if="allFile">
<el-select v-model="attachment.targetState" placeholder="请选择项目阶段" clearable filterable style="width: 300px">
<el-option
v-for="item in cacheStore.getDict('archive_file_type')"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item label="标签" prop="tag" v-if="type==='30'">
<el-select v-model="attachment.tag" placeholder="请选择标签" clearable filterable style="width: 300px">
<el-option
v-for="item in tagsOption"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button @click="handleSearch" color="#DED0B2">搜索</el-button>
<el-button @click="handleReset">重置</el-button>
<el-button v-if="uploadState&&!allFile" color="#DED0B2" @click="handleUpload">上传附件</el-button>
</el-form-item>
</el-form>
<el-card style="width: 100%;overflow-y: hidden">
<fvTable style="width: 100%;max-height: 318px" v-if="showTable" height="318" :tableConfig="allFile?tableConfigAll:tableConfig"
:data="fileList" :isSettingCol="false" :pagination="false">
<template #empty>
<el-empty :image-size="99" description="暂无数据" style="padding: 0"/>
</template>
</fvTable>
</el-card>
<file-preview ref="filePreviewRef" v-if="filePreviewShow" :fileName="filePreviewParam.fileName" :fileUrl="filePreviewParam.fileUrl"
:fileType="filePreviewParam.fileType"/>
</div>
</template>
<script setup lang="jsx">
import {downloadFile} from "@/api/project-demand";
import {ElNotification} from "element-plus";
import {getTags} from "@/api/project-manage";
import {computed, ref} from "vue";
import {useCacheStore} from '@/stores/cache.js'
const route = useRoute()
const router = useRouter()
const cacheStore = useCacheStore()
const attachment = reactive({})
const emit = defineEmits(['search','update:modelValue'])
const props = defineProps({
fileList: {
type: Array,
default: []
},
type: {
type: String,
default: '00'
},
uploadState: {
type: Boolean,
default: false
},
loading: {
type: Boolean,
default: true
},
allFile: {
type: Boolean,
default: false
}
})
const tagsOption = ref([])
const tableConfig = reactive({
columns: [
{
prop: 'index',
type: 'index',
label: '序号',
align: 'center',
width:85,
},
{
prop: 'originalFileName',
label: '文件名',
align: 'center',
currentRender: ({row, index}) => (<div style="color: #2a99ff;cursor: pointer;" onClick={()=>clickToPreview(row)}>{row.originalFileName}</div>)
},
{
prop: 'tag',
label:'标签',
align: 'center'
},
{
prop: 'size',
label: '文件大小',
align: 'center',
currentRender: ({row, index}) => (parseInt(row.size / 1024) + 'KB')
},
{
prop: 'createTime',
label: '上传时间',
align: 'center',
},
{
prop: 'oper',
label: '操作',
align: 'center',
showOverflowTooltip: false,
currentRender: ({row, index}) => {
return (
<div>
<el-button type="primary" link onClick={() => handleDownload(row)}>下载</el-button>
</div>
)
}
}
]
})
const tableConfigAll = reactive({
columns: [
{
prop: 'index',
type: 'index',
label: '序号',
align: 'center',
width:85,
},
{
prop: 'originalFileName',
label: '文件名',
align: 'center',
currentRender: ({row, index}) => (<div style="color: #2a99ff;cursor: pointer;" onClick={()=>clickToPreview(row)}>{row.originalFileName}</div>)
},
{
prop: 'targetState',
label:'项目阶段',
align: 'center',
showOverflowTooltip: false,
currentRender: ({row, index}) => {
if (row.targetState&&row.targetState !== null&&row.targetState!==undefined) {
return (<Tag dictType={'archive_file_type'} value={row.targetState}/>)
} else {
return '--'
}
}
},
{
prop: 'tag',
label:'标签',
align: 'center'
},
{
prop: 'size',
label: '文件大小',
align: 'center',
currentRender: ({row, index}) => (parseInt(row.size / 1024) + 'KB')
},
{
prop: 'createTime',
label: '上传时间',
align: 'center',
},
{
prop: 'oper',
label: '操作',
align: 'center',
showOverflowTooltip: false,
currentRender: ({row, index}) => {
return (
<div>
<el-button type="primary" link onClick={() => handleDownload(row)}>下载</el-button>
</div>
)
}
}
]
})
const showTable = ref(true)
const _value = computed({
get() {
return props.loading || ""
},
set(value) {
emit('update:modelValue', value)
}
})
const filePreviewParam = ref({
fileUrl: '',
fileName: '',
fileType: 'pdf'
})
const filePreviewShow = ref(false)
const clickToPreview=(row)=>{
filePreviewShow.value = false
filePreviewParam.value = {
fileUrl: row.url,
fileName: row.originalFileName,
fileType: row.fileType
}
nextTick(()=>{
filePreviewShow.value = true
})
}
const getTagsOption = () => {
if (!route.query.id) return
getTags(route.query.id).then(res => {
if (res.code === 1000) {
tagsOption.value = res.data
} else {
ElNotification({
title: '提示',
message: res.msg,
type: 'error'
})
}
})
}
const handleSearch = () => {
emit('search', attachment)
}
const handleReset=()=>{
attachment.fileName=''
attachment.targetState=''
attachment.tag=null
emit('search', {})
}
const handleUpload = () => {
emit('upload')
}
const handleDownload = (row) => {
downloadFile(row.fileId).then(res => {
const blob = new Blob([res])
let a = document.createElement('a')
a.href = URL.createObjectURL(blob)
a.download = row.originalFileName
a.click()
})
}
watch(() => props.type, (val) => {
props.type = val
})
watch(() => props.fileList, (val) => {
showTable.value = false
nextTick(() => {
showTable.value = true
})
props.fileList = val
})
if (props.type === '30') {
getTagsOption()
}
onActivated(()=>{
if (props.type === '30') {
getTagsOption()
}
handleSearch()
})
</script>
<style scoped>
:deep(.el-table--fit ) {
height: 318px !important;
}
</style>

View File

@@ -1,226 +0,0 @@
<template>
<div style="display: flex;align-items: center;flex-wrap: wrap;">
<el-button color="#DED0B2" @click="handleShowPreTable" style="margin-right: 10px">
{{
localFormData.preProcess && localFormData.preProcess.length > 0 ? '更改' : '请选择前置流程'
}}
</el-button>
<div v-for="(item,index) in localFormData.preProcess" :key="item.requestId">
<a :href="item.baseUrl" target="_blank"
style="color: #2a99ff;cursor: pointer">{{ item.requestName }}<span
v-if="index != localFormData.preProcess.length -1"></span>
</a>
</div>
</div>
<el-dialog v-if="showPreTable" title="前置流程" v-model="showPreTable" width="80%">
<el-form :model="preProcessForm" inline @submit.prevent="getPreProcessList">
<el-form-item label="请求名称">
<el-input v-model="preProcessForm.requestName" placeholder="请输入请求名称" clearable>
</el-input>
</el-form-item>
<el-form-item>
<el-button color="#DED0B2" @click="getPreProcessList">搜索</el-button>
<el-button @click="handleReset">重置</el-button>
</el-form-item>
<el-form-item>
<el-tag type="danger" style="font-size: 16px;color: red;" >特别提示{{ getPreProcessTag(localFormData.projectImpact,basicData.projectImpact) }}</el-tag>
</el-form-item>
</el-form>
<el-table :data="preProcessList" v-loading="loading"
@select="handleSelect" @select-all="handleSelect" row-key="requestId" ref="preProcessTable">
<el-table-column type="selection" width="55" :reserve-selection="true"
:selectable="checkSelectable"/>
<el-table-column prop="requestId" label="请求id"></el-table-column>
<el-table-column prop="requestName" label="请求名称"></el-table-column>
<el-table-column prop="lastOperatorName" label="最后操作人名称"></el-table-column>
<el-table-column prop="lastOperateTime" label="最后操作时间"></el-table-column>
<el-table-column prop="currentNodeName" label="当前节点"></el-table-column>
<el-table-column prop="creatorName" label="创建人"></el-table-column>
<el-table-column prop="createTime" label="创建时间"></el-table-column>
<el-table-column label="操作" align="center">
<template #default="scope">
<a :href="scope.row.baseUrl" target="_blank" style="color: #2a99ff;margin-left: 10px">查看流程</a>
</template>
</el-table-column>
</el-table>
<paging :current-page="pageInfo.pageNum" :page-size="pageInfo.pageSize" :page-sizes="[10, 20, 30, 40,50]"
:total="total" @changeSize="handleSizeChange" @goPage="handleCurrentChange"/>
<div class="oper">
<el-button color="#DED0B2" @click="choosePreProcess">确定</el-button>
<el-button @click="handleCancel">取消</el-button>
</div>
</el-dialog>
</template>
<script setup>
import {
getPreProcess
} from "@/api/project-manage";
import Paging from "@/components/pagination/index.vue";
const props = defineProps({
formData: {
type: Object,
default: {}
},
basicData: {
type: Object,
default: {}
},
})
const loading = ref(false)
//暂存数据
const originalProcess = ref([])
const currentList = ref([])
const showPreTable = ref(false)
const selectRows = ref([])
const preProcessList = ref([])
const total = ref(0)
const preProcessTable = ref()
const localFormData = ref({
projectPersonIds: [],
projectChargePerson: null,
preProcess: [
// {
// requestId: null,
// requestName: '',
// baseUrl: ''
// }
]
})
const preProcessForm = reactive({
requestName: ''
})
const pageInfo = reactive({
pageNum: 1,
pageSize: 10,
})
const getPreProcessTag = (impact,basicImpact) => {
let data=''
if(impact){
data= impact
}else if(basicImpact){
data= basicImpact
}
if (data == 1) {
//一般项目
return '研发费用20万元以下科技创新项目报总经理审批'
} else if (data == 2) {
//重大项目
return '重大项目20万元到500万元之间要总办会审批'
} else if (data == 3) {
//特别重大项目
return '特别重大项目500万元以上要董事会审批'
}
}
const handleReset = () => {
preProcessForm.requestName = ''
getPreProcessList()
}
const handleSelect = async (selection) => {
selectRows.value = selection
}
const checkSelectable=(row)=>{
const detailProcessStr = localStorage.getItem('detailProcess');
let preProcessArray = []
if (detailProcessStr) {
try {
preProcessArray = JSON.parse(detailProcessStr)
} catch (e) {
preProcessArray=[]
}
if (preProcessArray&&preProcessArray.length > 0) {
for (let i = 0; i < preProcessArray.length; i++) {
return preProcessArray[i].requestId !== row.requestId;
}
}else{
return true
}
}
}
const handleShowPreTable = () => {
showPreTable.value = true
nextTick(() => {
localFormData.value.preProcess?.forEach((item) => {
if (preProcessTable.value) {
preProcessTable.value.toggleRowSelection(item, true)
}
})
})
getPreProcessList()
}
const handleCancel = () => {
showPreTable.value = false
}
const choosePreProcess = () => {
let preProcessObj = {}
let preProcessArray = []
const detailProcessStr = localStorage.getItem('detailProcess');
try {
originalProcess.value = JSON.parse(detailProcessStr)
} catch (e) {
originalProcess.value=[]
}
selectRows.value.forEach((item) => {
const exists = originalProcess.value?.some(dp => dp.requestId === item.requestId)
if (!exists) {
preProcessObj = {
requestId: item.requestId,
requestName: item.requestName,
baseUrl: item.baseUrl
}
preProcessArray.push(preProcessObj)
}
})
if(props.formData.mode === 'view'||props.formData.mode === 'resubmit'){
localFormData.value.preProcess = [...originalProcess.value,...preProcessArray]
}else{
localFormData.value.preProcess = preProcessArray
}
localStorage.setItem('preProcess', JSON.stringify(preProcessArray))
showPreTable.value = false
}
const getPreProcessList = () => {
loading.value = true
getPreProcess().then(res => {
loading.value = false
let searchArray = []
let regexPattern = ("%" + preProcessForm.requestName + "%").replace(/%/g, '.*').replace(/_/g, '.');
let regex = new RegExp('^' + regexPattern + '$');
res.data.filter((item) => {
if (regex.test(item.requestName)) {
searchArray.push(item)
}
})
total.value = searchArray.length
currentList.value = searchArray
preProcessList.value = currentList.value.slice(0, 10)
})
}
//切换每页显示条数
const handleSizeChange = (val) => {
pageInfo.pageSize = val;
preProcessList.value = currentList.value.slice((pageInfo.pageNum - 1) * val, pageInfo.pageNum * val)
};
//点击页码进行分页功能
const handleCurrentChange = (val) => {
pageInfo.pageNum = val;
preProcessList.value = currentList.value.slice((val - 1) * pageInfo.pageSize, val * pageInfo.pageSize)
};
watchEffect(() => {
return Object.keys(props.formData).length && (localFormData.value = props.formData)
})
</script>
<style scoped>
.oper {
margin-top: 20px;
display: flex;
justify-content: flex-end;
}
</style>

View File

@@ -1,9 +1,9 @@
<template>
<div class="tag-style">
<el-tag v-if="tagConfig?.isType" :type="tagConfig?.listClass" :effect="tagConfig?.theme || 'plain'">
<el-tag v-if="tagConfig.isType" :type="tagConfig.listClass" :effect="tagConfig.theme || 'plain'">
{{ filterDict(cacheStore.getDict(dictType), value) }}
</el-tag>
<el-tag v-else :color="tagConfig?.listClass" :effect="tagConfig?.theme || 'plain'"
<el-tag v-else :color="tagConfig.listClass" :effect="tagConfig.theme || 'plain'"
:class="{'null-tag':filterDict(cacheStore.getDict(dictType), value)===undefined}">
{{ filterDict(cacheStore.getDict(dictType), value) }}
</el-tag>
@@ -31,7 +31,7 @@ const props = defineProps({
const tagConfig = ref({})
const filterDict = (data, value) => {
if (!data || value == null) return
if (!data) return
if (data instanceof Array) {
if (value == true || value == false) {
tagConfig.value = data.find(item => item.value == value.toString())
@@ -45,7 +45,7 @@ const filterDict = (data, value) => {
tagConfig.value = data.find(item => item.value == value)
}
}
return tagConfig.value?.label || '未知'
return tagConfig.value.label
}
</script>

View File

@@ -1,120 +0,0 @@
<template>
<baseTitle title="标签名称"></baseTitle>
<el-form :model="formData" ref="tagForm" label-width="auto" :rules="rules">
<el-form-item label="标签名称" prop="tagName">
<el-input v-model="formData.tagName" placeholder="请输入标签名称" style="width: 300px" v-if="showInput"/>
<el-select v-model="formData.tagName" placeholder="请选择标签" remote clearable filterable style="width: 300px" v-else>
<el-option
v-for="item in tagsOption"
:key="item.label"
:label="item.value"
:value="item.label"
/>
</el-select>
</el-form-item>
</el-form>
<baseTitle title="其他文件"></baseTitle>
<el-card style="width: 100%;margin: 15px 0">
<file-upload @getFile="getFiles"/>
<fvTable style="width: 100%;max-height: 160px;height: 160px" height="160" v-if="showTable" :tableConfig="tableConfig"
:data="fileList" :isSettingCol="false" :pagination="false">
<template #empty>
<el-empty :image-size="55" description="暂无数据" style="padding: 0"/>
</template>
</fvTable>
</el-card>
<div class="oper-page-btn">
<el-button color="#DED0B2" @click="handleSubmit(tagForm)">提交</el-button>
</div>
</template>
<script setup lang="jsx">
const props = defineProps({
tagsOption: {
type: Array,
default: []
}, formData: {
type: Array,
default: []
}, showInput: {
type: Boolean,
default: true
},
})
const rules = reactive({
tagName: [{required: true, message: '请输入标签名称', trigger: ['blur', 'change']}],
})
const tagForm = ref()
const showTable = ref(true)
const emits = defineEmits(['getFile'])
const fileList = ref([])
const tableConfig = reactive({
columns: [
{
prop: 'index',
type: 'index',
label: '序号',
align: 'center',
width: '80',
},
{
prop: 'originalFileName',
label: '文件名',
align: 'center',
},
{
prop: 'tag',
label: '标签',
align: 'center'
},
{
prop: 'tag',
label: '文件大小',
align: 'center',
currentRender: ({row, index}) => (parseInt(row.size / 1024) + 'KB')
},
{
prop: 'oper',
label: '操作',
align: 'center',
currentRender: ({row, index}) => {
return (
<div>
<el-button type="primary" link onClick={() => handleDownload(row)}>下载</el-button>
</div>
)
}
}
]
})
const compositeParam = (item) => {
return {
fileId: item.id,
size: item.size,
originalFileName: item.originalFilename,
fileType: item.fileType,
url: item.url,
newFile: true,
tag: formData.value.tagName,
}
}
const getFiles = (val) => {
showTable.value = false
let fileObj = compositeParam(val)
// emit("getFile", fileObj)
fileList.value.push(fileObj)
nextTick(() => {
showTable.value = true
})
}
watch(() => fileList.value, (val) => {
fileList.value = val
})
defineExpose({
fileList
})
</script>
<style scoped>
</style>

View File

@@ -1,5 +1,5 @@
<template>
<div class="tinymce-boxz" style="width: 100%">
<div class="tinymce-boxz">
<Editor v-model="content" :init="init"/>
</div>
</template>
@@ -8,7 +8,7 @@
import tinymce from 'tinymce'
import Editor from "@tinymce/tinymce-vue";
import {defineProps} from "vue";
import {ElLoading, ElMessage, ElNotification} from "element-plus";
import {ElMessage} from "element-plus";
import {getToken} from '@/utils/auth'
import axios from "axios";
@@ -36,9 +36,8 @@ import 'tinymce/plugins/insertdatetime'
import 'tinymce/plugins/lists'
import 'tinymce/plugins/wordcount'
import 'tinymce/plugins/autosave'
import '@/assets/axupimgs/plugin.js'//多图上传插件
const emit = defineEmits(['update:value','getFiles'])
const emit = defineEmits(['update:value'])
const props = defineProps({
//默认值
value: {
@@ -56,7 +55,7 @@ const props = defineProps({
plugins: {
type: [String, Array],
default:
"preview searchreplace autolink directionality visualblocks visualchars fullscreen image axupimgs link media template code codesample table pagebreak nonbreaking anchor insertdatetime advlist lists wordcount autosave",
"preview searchreplace autolink directionality visualblocks visualchars fullscreen image link media template code codesample table pagebreak nonbreaking anchor insertdatetime advlist lists wordcount autosave",
},
toolbar: {
type: [String, Array],
@@ -69,16 +68,15 @@ const props = defineProps({
type: [String, Array],
default: "微软雅黑=Microsoft YaHei,Helvetica Neue,PingFang SC,sans-serif;苹果苹方=PingFang SC,Microsoft YaHei,sans-serif;宋体=simsun,serif;仿宋体=FangSong,serif;黑体=SimHei,sans-serif;Arial=arial,helvetica,sans-serif;Arial Black=arial black,avant garde;Book Antiqua=book antiqua,palatino;"
},
width: {
width:{
type: String,
default: 'auto'
},
height: {
height:{
type: Number,
default: 500
default: 450
}
})
const fileLists=ref([])
const content = ref(props.value);
const imgUrl = ref();
// const apiKey = reactive("v4zo4n22oanvco29ws5drh0pecuf3gh53clx53cccj3grjwg");
@@ -90,21 +88,21 @@ const init = reactive({
placeholder: "在这里输入文字", //textarea中的提示信息
min_width: 300,
min_height: 200,
width: props.width,
width:props.width,
height: props.height, //注引入autoresize插件时此属性失效
resize: "both", //编辑器宽高是否可变false-否,true-高可变,'both'-宽高均可,注意引号
promotion: false,
branding: false, //tiny技术支持信息是否显示
statusbar: false, //最下方的元素路径和字数统计那一栏是否显示
elementpath: false, //元素路径是否显示
// statusbar: false, //最下方的元素路径和字数统计那一栏是否显示
// elementpath: false, //元素路径是否显示
font_formats: props.fontFormats, //字体样式
plugins: props.plugins, //插件配置 axupimgs indent2em
toolbar: props.toolbar, //工具栏配置设为false则隐藏
menubar: "file edit view format table tools", //菜单栏配置设为false则隐藏不配置则默认显示全部菜单也可自定义配置--查看 http://tinymce.ax-z.cn/configure/editor-appearance.php --搜索“自定义菜单”
images_upload_url: '/workflow/process/file/upload', //后端处理程序的url建议直接自定义上传函数image_upload_handler这个就可以不用了
// menubar: "file edit my1", //菜单栏配置设为false则隐藏不配置则默认显示全部菜单也可自定义配置--查看 http://tinymce.ax-z.cn/configure/editor-appearance.php --搜索“自定义菜单”
// images_upload_url: '/apib/api-upload/uploadimg', //后端处理程序的url建议直接自定义上传函数image_upload_handler这个就可以不用了
// images_upload_base_path: '/demo', //相对基本路径--关于图片上传建议查看--http://tinymce.ax-z.cn/general/upload-images.php
paste_data_images: true, //图片是否可粘贴
file_picker_types: "file image", //file image media分别对应三个类型文件的上传link插件image和axupimgs插件media插件。想屏蔽某个插件的上传就去掉对应的参数
file_picker_types: "file image media", //file image media分别对应三个类型文件的上传link插件image和axupimgs插件media插件。想屏蔽某个插件的上传就去掉对应的参数
// 文件上传处理函数
setup: function (editor) {
editor.on('change', function (e) {
@@ -117,16 +115,11 @@ const init = reactive({
let formData = new FormData()
formData.append('file', blobInfo.blob())
//上传图片接口 上传成功后返回图片地址,用于显示在富文本中
uploadFile(formData, props.imageUrl, success, true)
uploadFile(formData, props.imageUrl, success)
// }),
},
images_upload_handler_not_loading: (blobInfo, success) => {
let formData = new FormData()
formData.append('file', blobInfo.blob())
//上传图片接口
uploadFile(formData, props.imageUrl, success, false)
},
file_picker_callback: (callback, value, meta) => {
// console.log('callback, value, meta',callback, value, meta)
// 使用案例http://tinymce.ax-z.cn/general/upload-images.php
// meta.filetype //根据这个判断点击的是什么file image media
let filetype; //限制文件的上传类型,需要什么就添加什么的后缀
@@ -144,62 +137,16 @@ const init = reactive({
inputElem.click();
inputElem.onchange = () => {
let file = inputElem.files[0]; //获取文件信息
let xhr, formData;
xhr = new XMLHttpRequest();
xhr.withCredentials = false;
xhr.open('POST', import.meta.env.VITE_BASE_URL + props.imageUrl);
xhr.setRequestHeader(
'Authorization', getToken()
)
let loading = ElLoading.service({
lock: true,
text: '文件上传中...',
background: 'rgba(0, 0, 0, 0.7)',
})
xhr.onload = function () {
let res;
// if (xhr.status != 200) {
// failure('HTTP Error: ' + xhr.status);
// return;
// }
res = JSON.parse(xhr.responseText);
ElNotification({
title: '提示',
message: res.code === 1000 ? '上传成功' : '上传失败',
type: res.code === 1000 ? 'success' : 'error'
})
loading.close()
console.log("🚀 ~ file:res.data ", res.data)
res.data.originalFileName=res.data.originalFilename
console.log("🚀 ~ file:'meta.filetype ",meta.filetype )
if (res && res.data && res.data.fileType &&
!["png", "jpg", "jpeg","gif", "svg","ico"].includes(res.data.fileType.toLowerCase())){
fileLists.value.push(res.data)
emit('getFiles',fileLists.value)
}
const fileUrl = res.data.url;
// '?fileId='+res.data.id+
callback(fileUrl + '?fileName=' + res.data.originalFilename, {text: file.name, title: file.name});
let reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function () {
let id = "blobid" + new Date().getTime();
let blobCache = tinymce.activeEditor.editorUpload.blobCache;
let base64 = reader.result.split(",")[1];
let blobInfo = blobCache.create(id, file, base64);
blobCache.add(blobInfo);
callback(blobInfo.blobUri(), {alt: file.name});
};
formData = new FormData();
formData.append('file', file, file.name);
xhr.send(formData);
//
// let reader = new FileReader();
// reader.readAsDataURL(file);
// reader.onload = function () {
// let formData;
// let id = "blobid" + new Date().getTime();
// let blobCache = tinymce.activeEditor.editorUpload.blobCache;
// let base64 = reader.result.split(",")[1];
// let blobInfo = blobCache.create(id, file, base64);
// blobCache.add(blobInfo);
// // callback(blobInfo.blobUri(), {alt: file.name});
// formData = new FormData();
// formData.append('file', file, file.name );
// uploadFile(formData, props.imageUrl,callback)
// };
};
},
});
@@ -207,16 +154,7 @@ const init = reactive({
watch(() => {
emit("update:value", content.value);
});
const uploadFile = (formData, url, success, isLoading) => {
let loading = null
if (isLoading) {
loading = ElLoading.service({
lock: true,
text: '图片上传中...',
background: 'rgba(0, 0, 0, 0.7)',
})
}
const uploadFile = (formData, url,success) => {
axios.post(
import.meta.env.VITE_BASE_URL + url,
formData,
@@ -233,48 +171,18 @@ const uploadFile = (formData, url, success, isLoading) => {
let data = res.data
if (data.code !== 1000) {
ElMessage.error(data.msg)
if (loading) {
loading.close()
}
} else {
if (isLoading) {
success(data.data.url)
} else {
success(data.data.url, data.data.originalFilename)
}
if (loading) {
loading.close()
}
}else {
success(data.data.url)
}
})
}
</script>
<style scoped lang="scss">
.tox-sidebar-wrap {
&::-webkit-scrollbar {
width: 6px;
}
// 滚动条轨道
&::-webkit-scrollbar-track {
background: rgb(239, 239, 239);
border-radius: 2px;
}
// 小滑块
&::-webkit-scrollbar-thumb {
background: rgba(80, 81, 82, 0.29);
border-radius: 10px;
}
}
<style scoped>
.tinymce-boxz > textarea {
display: none;
}
</style>
<style lang="scss">
<style>
/* 隐藏apikey没有绑定当前域名的提示 */
.tox-notifications-container .tox-notification--warning {
display: none !important;

View File

@@ -5,7 +5,7 @@
placement="bottom-start"
:disabled="isShow"
>
<div :class="lines?'content-lines':textAlign=='left'?'left-content':'content'" :style="{width: props.width+'px'}" @mouseover="isShowTooltip">
<div :class="lines?'content-lines':'content'" :style="{width: props.width+'px'}" @mouseover="isShowTooltip">
<span ref="contentRef">
<slot name="content">{{ props.content }}</slot>
</span>
@@ -17,34 +17,21 @@ const props = defineProps({
content: {
type: String,
default: ''
},
width: {
type: String,
default: '100%'
},
lines: {
type: Boolean,
default: false
},
textAlign: {
}, width: {
type: String,
default: ''
},
}, lines: {
type: Boolean,
default: false
}
})
const contentRef = ref()
const isShow = ref(false)
const isShowTooltip = () => {
isShow.value = parseInt(props.width) > contentRef.value.offsetWidth;
isShow.value = props.width > contentRef.value.offsetWidth;
}
</script>
<style scoped>
.left-content{
width: 45px;
text-align: left;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
<style>
.content {
width: 45px;
text-align: center;
@@ -53,7 +40,6 @@ const isShowTooltip = () => {
overflow: hidden;
}
.content-lines{
word-break:break-all;
overflow:hidden;
text-overflow: ellipsis;
-webkit-line-clamp: 2;

View File

@@ -1,112 +0,0 @@
<template>
<div class="docx-preview">
<div
ref="docxDiv"
class="docxDiv"
v-loading="loading"
></div>
</div>
</template>
<script setup lang="jsx">
import {renderAsync} from "docx-preview";
import axios from "axios";
let docx = import.meta.glob("docx-preview"); // vite不支持require
const props = defineProps({
fileUrl: {
type: String,
default: ''
}
})
const loading = ref(false);
const previewFile = () => {
loading.value = true;
axios.request({
url: props.fileUrl,
method: 'get',
responseType: 'blob'
}).then((response) => {
let docData = response.data;
let docxDiv = document.getElementsByClassName("docxDiv");
renderAsync(docData, docxDiv[0], null, {
inWrapper: true, // 启用围绕文档内容渲染包装器
ignoreWidth: false, // 禁止页面渲染宽度
ignoreHeight: false, // 禁止页面渲染高度
ignoreFonts: false, // 禁止字体渲染
breakPages: true, // 在分页符上启用分页
ignoreLastRenderedPageBreak: true, //禁用lastRenderedPageBreak元素的分页
experimental: false, //启用实验性功能(制表符停止计算)
trimXmlDeclaration: true, //如果为真xml声明将在解析之前从xml文档中删除
debug: false,
}).then((res) => {
loading.value = false;
});
}).catch((error) => {
});
};
previewFile()
</script>
<style lang="scss">
.docx-preview {
overflow: auto;
height: 650px !important;
&::-webkit-scrollbar {
width: 6px;
height: 6px;
}
// 滚动条轨道
&::-webkit-scrollbar-track {
background: rgb(239, 239, 239);
border-radius: 2px;
}
// 小滑块
&::-webkit-scrollbar-thumb {
background: rgba(80, 81, 82, 0.29);
border-radius: 10px;
}
.docx-wrapper > section.docx {
margin-bottom: 0 !important;
}
.docx-wrapper {
padding: 10px !important;
.docx {
width: 100% !important;
min-height: 100vh !important;
overflow: auto !important;
//padding: 70pt 20pt 0 20pt !important;
table {
width: 100% !important;
}
&::-webkit-scrollbar {
width: 6px;
height: 6px;
}
// 滚动条轨道
&::-webkit-scrollbar-track {
background: rgb(239, 239, 239);
border-radius: 2px;
}
// 小滑块
&::-webkit-scrollbar-thumb {
background: rgba(80, 81, 82, 0.29);
border-radius: 10px;
}
}
}
}
</style>

View File

@@ -1,74 +0,0 @@
<template>
<div class="img-preview" >
<img id="previewImg" :src="fileUrl" :style="{width: fullscreen?windowWidth+'px':'100%',height: fullscreen?'auto':'650px;'}" alt="Preview"/>
</div>
</template>
<script setup>
const emit = defineEmits(["update:fileUrl"])
const props = defineProps({
fileUrl: {
type: String,
default: ''
},
fullscreen: {
type: Boolean,
default:false
}
})
const showImagePreview = ref(true)
const dialogWidth = ref('')
const dialogHeight = ref('')
// 屏幕宽度
const windowWidth = ref(0)
// 屏幕高度
const windowHeight = ref(0)
// onMounted(() => {
// })
// 获取屏幕尺寸
const getWindowResize = function () {
windowWidth.value = window.innerWidth-32
windowHeight.value = window.innerHeight
}
getWindowResize()
window.addEventListener('resize', getWindowResize)
nextTick(() => {
const previewImg = document.getElementById('previewImg');
// console.log(previewImg)
let offsetHeight = previewImg?.offsetHeight
// console.log(offsetHeight)
if (offsetHeight > 750){
// previewImg?.offsetHeight = 750
}
})
// dialogWidth.value=document.getElementById('previewImg')?.offsetWidth||1500
// dialogWidth.value=document.getElementById('previewImg')?.offsetHeight||750
</script>
<style lang="scss">
.img-preview {
display: flex;
justify-content: center;
overflow-y: auto;
overflow-x: auto;
&::-webkit-scrollbar {
width: 6px;
height: 6px;
}
// 滚动条轨道
&::-webkit-scrollbar-track {
background: rgb(239, 239, 239);
border-radius: 2px;
}
// 小滑块
&::-webkit-scrollbar-thumb {
background: rgba(80, 81, 82, 0.29);
border-radius: 10px;
}
}
</style>

Some files were not shown because too many files have changed in this diff Show More