初始化

This commit is contained in:
lichun
2025-12-03 09:30:19 +08:00
commit a02dd8c2f4
215 changed files with 114299 additions and 0 deletions

9
.env Normal file
View File

@@ -0,0 +1,9 @@
# 基础配置
VUE_APP_NAME="智慧政务平台"
VUE_APP_VERSION=1.0.0
# API基础路径会被各环境覆盖
VUE_APP_BASE_API=
# 功能开关
VUE_APP_ENABLE_DEBUG=false

4
.env.development Normal file
View File

@@ -0,0 +1,4 @@
# 开发环境配置
NODE_ENV=development
VUE_APP_BASE_API = 'http://gz.viphk.nnhk.cc' # API基础路径
VUE_APP_TITLE = '开发环境'

4
.env.production Normal file
View File

@@ -0,0 +1,4 @@
# 生产环境配置
NODE_ENV=production
VUE_APP_BASE_API = 'http://gz.viphk.nnhk.cc' # 生产环境API地址
VUE_APP_TITLE = '生产环境'

23
.gitignore vendored Normal file
View File

@@ -0,0 +1,23 @@
.DS_Store
node_modules
/dist
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

73
LICENSE Normal file
View File

@@ -0,0 +1,73 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
(a) You must give any other recipients of the Work or Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives.
Copyright 2025 chenxiang
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

24
README.md Normal file
View File

@@ -0,0 +1,24 @@
# website
## Project setup
```
npm install
```
### Compiles and hot-reloads for development
```
npm run serve
```
### Compiles and minifies for production
```
npm run build
```
### Lints and fixes files
```
npm run lint
```
### Customize configuration
See [Configuration Reference](https://cli.vuejs.org/config/).

5
babel.config.js Normal file
View File

@@ -0,0 +1,5 @@
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
]
}

19
jsconfig.json Normal file
View File

@@ -0,0 +1,19 @@
{
"compilerOptions": {
"target": "es5",
"module": "esnext",
"baseUrl": "./",
"moduleResolution": "node",
"paths": {
"@/*": [
"src/*"
]
},
"lib": [
"esnext",
"dom",
"dom.iterable",
"scripthost"
]
}
}

12732
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

52
package.json Normal file
View File

@@ -0,0 +1,52 @@
{
"name": "website",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build"
},
"dependencies": {
"axios": "^1.9.0",
"chart.js": "^4.4.9",
"core-js": "^3.8.3",
"echarts": "^5.6.0",
"element-ui": "^2.15.14",
"quill": "^2.0.3",
"vue": "^2.6.14",
"vue-quill-editor": "^3.0.6",
"vue-router": "^3.5.1",
"vuex": "^3.6.2"
},
"devDependencies": {
"@babel/core": "^7.12.16",
"@babel/eslint-parser": "^7.12.16",
"@types/quill": "^2.0.14",
"@vue/cli-plugin-babel": "~5.0.0",
"@vue/cli-plugin-router": "~5.0.0",
"@vue/cli-plugin-vuex": "~5.0.0",
"@vue/cli-service": "~5.0.0",
"sass": "^1.32.7",
"sass-loader": "^12.0.0",
"vue-template-compiler": "^2.6.14"
},
"eslintConfig": {
"root": true,
"env": {
"node": true
},
"extends": [
"plugin:vue/essential",
"eslint:recommended"
],
"parserOptions": {
"parser": "@babel/eslint-parser"
},
"rules": {}
},
"browserslist": [
"> 1%",
"last 2 versions",
"not dead"
]
}

BIN
public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

74
public/index.html Normal file
View File

@@ -0,0 +1,74 @@
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
<style>
<!-- html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
display: block;
}
body {
line-height: 1;
}
ol, ul {
list-style: none;
}
blockquote, q {
quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
content: '';
content: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
h1,h2,h3,h4,h5{font-weight:normal;}
ul,ol,dl,li{list-style:none;}
input,textarea,select{font-family:inherit;font-size:inherit;font-weight:inherit;*font-size:100%;}
input{outline:none;background:none;}input::-ms-clear{display:none;}input::-ms-reveal{display:none;}input[type=text]::-ms-clear{display:none;}
textarea{resize:none;}
table{font-size:inherit;border-collapse:collapse;border-spacing:0;}
img,input,button{border:0px;}:focus{outline:0;}
a:link,a:visited{text-decoration:none;}
::-webkit-scrollbar{width:5px;height:5px;}
::-webkit-scrollbar-thumb{min-height:28px;padding-top:100;background-color:rgba(0,0,0,0.2);
-webkit-background-clip:padding-box;background-clip:padding-box;border-radius:5px;-webkit-box-shadow:inset 1px 1px 0 rgba(0,0,0,0.1),inset 0 -1px 0 rgba(0,0,0,0.07);}
</style>
</html>

109
src/App.vue Normal file
View File

@@ -0,0 +1,109 @@
<template>
<div class="app-container">
<router-view/>
</div>
</template>
<script>
export default {
name: 'App'
}
</script>
<style>
/* 全局样式 */
html, body {
margin: 0;
padding: 0;
height: 100%;
width: 100%;
}
body {
background: #f8f8f8; /* 你想要的颜色 */
}
/* 确保app容器撑满全屏 */
.app-container {
min-height: 100vh;
width: 100%;
}
/* ========== 统一所有模块右侧图片显示样式 ========== */
/* 右侧区域容器 - 统一居中布局 */
.right-area {
display: flex !important;
justify-content: center !important;
align-items: flex-start !important;
}
/* 上传区域容器 - 统一居中布局 */
.upload-area {
display: flex !important;
justify-content: center !important;
align-items: flex-start !important;
}
/* 统一 el-upload picture-card 列表布局 */
.right-area .el-upload-list--picture-card,
.upload-area .el-upload-list--picture-card {
display: flex !important;
justify-content: center !important;
flex-wrap: wrap !important;
gap: 16px !important;
}
/* 统一图片卡片尺寸148px × 148px */
.right-area .el-upload-list--picture-card .el-upload-list__item,
.upload-area .el-upload-list--picture-card .el-upload-list__item {
width: 148px !important;
height: 148px !important;
margin: 0 !important;
border: 1px solid #c0ccda !important;
border-radius: 6px !important;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1) !important;
background: white !important;
}
.right-area .el-upload-list--picture-card .el-upload-list__item:hover,
.upload-area .el-upload-list--picture-card .el-upload-list__item:hover {
border-color: #409EFF !important;
box-shadow: 0 2px 8px rgba(64, 158, 255, 0.2) !important;
}
.right-area .el-upload-list--picture-card .el-upload-list__item-thumbnail,
.upload-area .el-upload-list--picture-card .el-upload-list__item-thumbnail {
width: 100% !important;
height: 100% !important;
object-fit: cover !important;
}
/* 统一自定义图片项样式(用于非 el-upload 的情况) */
.preview-images {
display: flex !important;
flex-wrap: wrap !important;
justify-content: center !important;
gap: 16px !important;
}
.image-item {
width: 148px !important;
height: 148px !important;
border: 1px solid #c0ccda !important;
border-radius: 6px !important;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1) !important;
background: white !important;
}
.image-item:hover {
border-color: #409EFF !important;
box-shadow: 0 2px 8px rgba(64, 158, 255, 0.2) !important;
}
.image-item img {
width: 100% !important;
height: 100% !important;
object-fit: cover !important;
}
</style>

View File

@@ -0,0 +1,6 @@
import { get, post, put, del } from '../request'
//获取列表
export const myList = data => post('/api/recommend/all', data)

View File

@@ -0,0 +1,23 @@
import { get, post, put, del } from '../request'
//获取列表
export const myList = data => post('/api/recommend/my', data)
//发布单位
export const govAddr = data => post('/api/recommend/govAddr', data)
//保存关键词
export const save = data => post('/api/recommend/save', data)
//获取关键词
export const getLastKeyWords = data => post('/api/recommend/getLastKeyWords', data)
// 政府地址管理相关接口
// 获取政府官网列表
export const getGovList = data => post('/api/recommend/govAddr', data)
// 添加政府官网
export const addGov = data => post('/api/recommend/saveGovAddr', data)
// 删除政府官网
export const deleteGov = data => post('/api/recommend/delete', data)

View File

@@ -0,0 +1,9 @@
import { get, post, put, del } from '../request'
//收入类型
export const all = data => post('/api/dictData/all', data)
//列表
export const list = data => post('/api/product/list', data)
//保存
export const save = data => post('/api/product/save', data)

View File

@@ -0,0 +1,6 @@
import { get, post, put, del } from '../request'
//销售数据列表
export const list = data => post('/api/ProductSales/list', data)

View File

@@ -0,0 +1,10 @@
import { get, post, put, del } from '@/api/request'
//列表
export const list = data => post('/api/Situation/list', data)
//详情
export const Details = id => get(`/api/Situation/Details?id=${id}`, null, { skipTimestamp: true })
//新增
export const save = data => post('/api/Situation/save', data)
//删除
export const deletes = id => del(`/api/Situation/delete`, { id: id })

View File

View File

@@ -0,0 +1,7 @@
import { get, post, put, del } from '@/api/request'
//统计
export const statistic = data => post('/api/corporateProfit/statistic', data)

View File

@@ -0,0 +1,15 @@
import { get, post, put, del } from '@/api/request'
//列表
export const list = data => get('/api/corporateProfit/list', data)
//新增
export const save = data => post('/api/corporateProfit/save', data, { skipMessage: true })
//删除
export const deletes = data => DELETE('/api/orporateProfit/delete?id='+data, data)
//详情
export const Detailss = data => get('/api/corporateProfit/Details', { id: data })

View File

@@ -0,0 +1,15 @@
import { get, post, put, del } from '@/api/request'
//列表
export const list = data => get('/api/BalanceSheet/list', data)
//新增
export const save = data => post('/api/BalanceSheet/save', data, { skipMessage: true })
//删除
export const deletes = data => DELETE('/api/BalanceSheet/delete?id='+data, data)
//详情
export const Detailss = id => get(`/api/BalanceSheet/Details?id=${id}`)

View File

@@ -0,0 +1,11 @@
import { get, post, put, del } from '@/api/request'
//列表
export const list = data => post('/api/Situation/list', data)
//详情
export const Details = id => get(`/api/Situation/Details?id=${id}`)
//新增
export const save = data => post('/api/Situation/save', data)
//删除
export const deletes = id => del(`/api/Situation/delete`, { id: id })

View File

@@ -0,0 +1,11 @@
import { get, post, put, del } from '@/api/request'
//列表
export const list = data => post('/api/Situation/list', data)
//详情
export const Details = id => get(`/api/Situation/Details?id=${id}`)
//新增
export const save = data => post('/api/Situation/save', data)
//删除
export const deletes = id => del(`/api/Situation/delete`, { id: id })

View File

@@ -0,0 +1,12 @@
import { get, post, put, del } from '../request'
//获取企业数据
export const show = data => post('/api/enterprise/show', data)
//保存企业数据
export const save = data => post('/api/enterprise/save', data)
//获取企业列表
export const list = data => post('/api/enterprise/list', data)

22
src/api/index.js Normal file
View File

@@ -0,0 +1,22 @@
import { get, post, put, del } from './request'
// 示例接口
export const contentlPage= data => get('/front-api/portal/content/page', data)
export const contentlList = data => get('/front-api/portal/channel/list', data)
//统计
export const contentCount = id => get(`/front-api/portal/content/count/${id}`)
//栏目管理树/front-api/portal/channel/tree
export const channelTree = data => get('/front-api/portal/channel/tree', data)
//内容详情
export const portalCount = id => get(`/front-api/portal/content/${id}`)
//站点信息
export const simpleAllList = data => get('/front-api/portal/site/list-all-simple', data)
export const getUserInfo = () => get('/user/info')
export const updateUser = data => put('/user/update', data)
export const deleteUser = id => del(`/user/delete/${id}`)
// 其他模块接口...
// export const getData = params => get('/api/data', params)

32
src/api/login/login.js Normal file
View File

@@ -0,0 +1,32 @@
import { get, post, put, del } from '../request'
//密码登录
export const login = data => post('/api/login/login', data)
//短信验证码登陆
export const smsLogin = data => post('/api/login/smsLogin', data)
//发送短信验证码
export const sendSmsCode = data => post('/api/login/sendSmsCode', data)
//退出接口
export const logout = data => get('/api/login/logout', data)
//修改密码
export const updatePwd = data => post('/api/admin/updatePwd', data)
//修改手机号
export const changePhone = data => post('/api/admin/changePhone', data)
//发送短信验证码
export const adminsendSmsCode = data => post('/api/admin/sendSmsCode', data)
//获取用户详情
export const details = data => post('/api/admin/detail?id='+data, data)

View File

@@ -0,0 +1,10 @@
import { get, post, put, del } from '@/api/request'
//列表
export const list = data => post('/api/Project/list', data)
//详情
export const Details = id => get(`/api/Project/details?id=${id}`)
//新增
export const save = data => post('/api/Project/save', data)
//删除
export const deletes = id => del(`/api/Project/delete`, { id: id })

View File

@@ -0,0 +1,10 @@
import { get, post, put, del } from '@/api/request'
//列表
export const list = data => post('/api/ProjectContract/list', data)
//详情
export const Details = id => get(`/api/ProjectContract/details?id=${id}`)
//新增
export const save = data => post('/api/ProjectContract/save', data)
//删除
export const deletes = id => del(`/api/ProjectContract/delete`, { id: id })

View File

@@ -0,0 +1,10 @@
import { get, post, put, del } from '@/api/request'
//列表
export const list = data => post('/api/ProjectReport/list', data)
//详情
export const Details = id => get(`/api/ProjectReport/details?id=${id}`)
//新增
export const save = data => post('/api/ProjectReport/save', data)
//删除
export const deletes = id => del(`/api/ProjectReport/delete`, { id: id })

View File

@@ -0,0 +1,10 @@
import { get, post, put, del } from '@/api/request'
//列表
export const list = data => post('/api/ProjectBudget/list', data)
//详情
export const Details = id => get(`/api/ProjectBudget/details?id=${id}`)
//新增
export const save = data => post('/api/ProjectBudget/save', data)
//删除
export const deletes = id => del(`/api/ProjectBudget/delete`, { id: id })

View File

@@ -0,0 +1,10 @@
import { get, post, put, del } from '@/api/request'
//列表
export const list = data => post('/api/ProjectPhaseDocument/list', data)
//详情
export const Details = id => get(`/api/ProjectPhaseDocument/details?id=${id}`)
//新增
export const save = data => post('/api/ProjectPhaseDocument/save', data)
//删除
export const deletes = id => del(`/api/ProjectPhaseDocument/delete`, { id: id })

View File

@@ -0,0 +1,14 @@
import { get, post, put, del } from '@/api/request'
//立项阶段资料
export const ProjectPhaseDocument = data => post('/api/ProjectPhaseDocument/list', data)
//立项预算
export const ProjectBudgetList = data => post('/api/ProjectBudget/list', data)
//任务清单
export const ProjectTaskList = data => post('/api/ProjectTask/list', data)
//项目人员
export const ProjectMemberList = data => post('/api/ProjectMember/list', data)
//合同明细
export const ProjectContractList = data => post('/api/ProjectContract/list', data)
//进度报告
export const ProjectReportList = data => post('/api/ProjectReport/list', data)

View File

@@ -0,0 +1,10 @@
import { get, post, put, del } from '@/api/request'
//列表
export const list = data => post('/api/ProjectTask/list', data)
//详情
export const Details = id => get(`/api/ProjectTask/details?id=${id}`)
//新增
export const save = data => post('/api/ProjectTask/save', data)
//删除
export const deletes = id => del(`/api/ProjectTask/delete`, { id: id })

6
src/api/public.js Normal file
View File

@@ -0,0 +1,6 @@
import { get, post, put, del } from './request'
//获取企业数据
export const images = data => post('/api/common/uploadFile', data)

223
src/api/request.js Normal file
View File

@@ -0,0 +1,223 @@
import axios from 'axios'
import { getToken, removeToken } from '@/utils/auth'
import { Message } from 'element-ui' // 修改为 Element UI 的引入方式
// 根据环境变量设置 baseURL
// 直接使用完整的服务器地址,避免代理配置问题
const baseURL = 'http://api.sg199.net'
const isDevelopment = process.env.NODE_ENV === 'development'
// 创建axios实例
const service = axios.create({
baseURL: baseURL,
timeout: 150000,
headers: {
'Content-Type': 'application/json;charset=UTF-8'
}
})
// 请求拦截器
service.interceptors.request.use(
config => {
// 在发送请求之前做些什么
const token = getToken()
if (token) {
// 添加 token 到请求头,支持多种格式
// 方式1: 使用 token 字段(直接值)
config.headers['token'] = token
// 方式2: 使用 Authorization 字段Bearer 格式)
config.headers['Authorization'] = `Bearer ${token}`
// 方式3: 使用 Authorization 字段(直接值,如果需要可以取消注释)
// config.headers['Authorization'] = token
}
// 如果是 FormData文件上传删除 Content-Type让浏览器自动设置 multipart/form-data
if (config.data instanceof FormData) {
delete config.headers['Content-Type']
}
// 添加请求时间戳,防止缓存(排除详情接口)
if (config.method === 'get' && !config.skipTimestamp) {
config.params = config.params || {}
config.params._t = Date.now()
}
// 开发环境下打印请求信息,方便调试
if (isDevelopment) {
console.log('请求配置:', {
url: config.url,
method: config.method,
baseURL: config.baseURL,
fullURL: (config.baseURL || '') + config.url,
hasToken: !!token,
isFormData: config.data instanceof FormData,
headers: {
token: token ? '已设置' : '未设置',
Authorization: token ? '已设置' : '未设置'
}
})
}
return config
},
error => {
// 对请求错误做些什么
console.log('Request Error:', error)
return Promise.reject(error)
}
)
// 响应拦截器
service.interceptors.response.use(
response => {
// 对响应数据做点什么
const res = response.data
// 自定义状态码验证(根据后端接口调整)
// code: 1 表示成功code: 200/0 也表示成功
// 其他code值表示业务错误
// 检查是否需要跳过自动提示(通过 config.skipMessage 配置)
const skipMessage = response.config.skipMessage || false
if (res.code !== 200 && res.code !== 0 && res.code !== 1) {
// 特殊状态码处理(无论是否跳过提示都需要处理)
if (res.code === 401 || res.code === 403) {
// 重新登录
removeToken()
location.reload()
}
// 只有在不跳过提示时才显示错误消息
if (!skipMessage) {
Message({
message: res.msg || res.message || 'Error',
type: 'error',
duration: 5 * 1000
})
}
// 创建错误对象并保留原始 config以便 catch 拦截器也能检查 skipMessage
const error = new Error(res.msg || res.message || 'Error')
error.response = response
error.config = response.config
error.response.data = res
return Promise.reject(error)
} else {
// 成功时返回整个响应对象包含code、msg、data
return res
}
},
error => {
// 对响应错误做点什么
console.log('Response Error:', error)
// 检查是否需要跳过自动提示(通过 config.skipMessage 配置)
const skipMessage = error.config?.skipMessage || false
// HTTP状态码处理
let message = ''
if (error.response) {
switch (error.response.status) {
case 400:
message = '请求错误(400)'
break
case 401:
message = '未授权,请重新登录(401)'
removeToken()
location.reload()
break
case 403:
message = '拒绝访问(403)'
break
case 404:
message = '请求出错(404)'
break
case 408:
message = '请求超时(408)'
break
case 500:
message = '服务器错误(500)'
break
case 501:
message = '服务未实现(501)'
break
case 502:
message = '网络错误(502)'
break
case 503:
message = '服务不可用(503)'
break
case 504:
message = '网络超时(504)'
break
case 505:
message = 'HTTP版本不受支持(505)'
break
default:
message = `连接出错(${error.response.status})!`
}
} else {
// Network Error 通常是跨域或服务器无法访问
if (error.code === 'ERR_NETWORK' || error.message === 'Network Error') {
message = '网络连接失败,请检查服务器地址或网络连接'
} else if (error.message) {
message = error.message
} else {
message = '连接服务器失败!'
}
}
// 只有在不跳过提示时才显示错误消息
if (!skipMessage) {
Message({
message,
type: 'error',
duration: 5 * 1000
})
}
return Promise.reject(error)
}
)
// 封装通用请求方法
export function request(config) {
return service(config)
}
// 封装GET方法带参数
export function get(url, params, config = {}) {
return service({
url,
method: 'get',
params,
...config
})
}
// 封装POST方法
export function post(url, data, config = {}) {
return service({
url,
method: 'post',
data,
...config
})
}
// 封装PUT方法
export function put(url, data) {
return service({
url,
method: 'put',
data
})
}
// 封装DELETE方法
export function del(url, params) {
return service({
url,
method: 'delete',
params
})
}
export default service

View File

@@ -0,0 +1,10 @@
import { get, post, put, del } from '@/api/request'
//列表
export const list = data => post('/api/CooperationContract/list', data)
//详情
export const Details = id => get(`/api/CooperationContract/details?id=${id}`)
//新增
export const save = data => post('/api/CooperationContract/save', data)
//删除
export const deletes = id => del(`/api/CooperationContract/delete`, { id: id })

View File

@@ -0,0 +1,10 @@
import { get, post, put, del } from '@/api/request'
//列表
export const list = data => post('/api/EnterpriseQualification/list', data)
//详情
export const Details = id => get(`/api/EnterpriseQualification/details?id=${id}`)
//新增
export const save = data => post('/api/EnterpriseQualification/save', data)
//删除
export const deletes = id => del(`/api/EnterpriseQualification/delete`, { id: id })

View File

@@ -0,0 +1,10 @@
import { get, post, put, del } from '@/api/request'
//列表
export const list = data => post('/api/PatentInfo/list', data)
//详情
export const Details = id => get(`/api/PatentInfo/Details?id=${id}`)
//新增
export const save = data => post('/api/PatentInfo/save', data)
//删除
export const deletes = id => del(`/api/PatentInfo/delete`, { id: id })

View File

@@ -0,0 +1,10 @@
import { get, post, put, del } from '@/api/request'
//列表
export const list = data => post('/api/PaperInfo/list', data)
//详情
export const Details = id => get(`/api/PaperInfo/details?id=${id}`)
//新增
export const save = data => post('/api/PaperInfo/save', data)
//删除
export const deletes = id => del(`/api/PaperInfo/delete`, { id: id })

View File

@@ -0,0 +1,10 @@
import { get, post, put, del } from '@/api/request'
//列表
export const list = data => post('/api/StandardInfo/list', data)
//详情
export const Details = id => get(`/api/StandardInfo/details?id=${id}`)
//新增
export const save = data => post('/api/StandardInfo/save', data)
//删除
export const deletes = id => del(`/api/StandardInfo/delete`, { id: id })

View File

@@ -0,0 +1,10 @@
import { get, post, put, del } from '@/api/request'
//列表
export const list = data => post('/api/TechnicalContract/list', data)
//详情
export const Details = id => get(`/api/TechnicalContract/details?id=${id}`)
//新增
export const save = data => post('/api/TechnicalContract/save', data)
//删除
export const deletes = id => del(`/api/TechnicalContract/delete`, { id: id })

View File

@@ -0,0 +1,10 @@
import { get, post, put, del } from '@/api/request'
//列表
export const list = data => post('/api/EnterpriseHonor/list', data)
//详情
export const Details = id => get(`/api/EnterpriseHonor/details?id=${id}`)
//新增
export const save = data => post('/api/EnterpriseHonor/save', data)
//删除
export const deletes = id => del(`/api/EnterpriseHonor/delete`, { id: id })

View File

@@ -0,0 +1,10 @@
import { get, post, put, del } from '@/api/request'
//列表
export const list = data => post('/api/EnterpriseQualification/list', data)
//详情
export const Details = id => get(`/api/EnterpriseQualification/details?id=${id}`)
//新增
export const save = data => post('/api/EnterpriseQualification/save', data)
//删除
export const deletes = id => del(`/api/EnterpriseQualification/delete`, { id: id })

View File

@@ -0,0 +1,10 @@
import { get, post, put, del } from '@/api/request'
//列表
export const list = data => post('/api/InstitutionDocument/list', data)
//详情
export const Details = id => get(`/api/InstitutionDocument/details?id=${id}`)
//新增
export const save = data => post('/api/InstitutionDocument/save', data)
//删除
export const deletes = id => del(`/api/InstitutionDocument/delete`, { id: id })

View File

@@ -0,0 +1,19 @@
import { get, post, put, del } from '@/api/request'
//查询所有的数据字典类型列表
export const all = data => post('/api/dictType/list', data)
//获取菜单列表
export const menuList = data => post('/api/menu/list', data)
//系统配置列表
export const configList = data => post('/api/config/list', data)

View File

@@ -0,0 +1,22 @@
import { get, post, put, del } from '@/api/request'
//获取用户列表
export const admin = data => post('/api/admin', data)
//创建和更新用户
export const save = data => post('/api/admin/save', data)
//获取用户详情
export const detail = (id) => get(`/api/admin/detail?id=${id}`)
//删除用户
export const deletes = (id) => del(`/api/admin/delete?id=${id}`)
//获取角色列表
export const role = data => post('/api/role', data)
//人员列表
export const staffList = data => post('/api/staff/list', data)

View File

@@ -0,0 +1,23 @@
import { get, post, put, del } from '@/api/request'
//创建和更新角色
export const save = data => post('/api/role/save', data)
//删除角色
export const deletes = (id) => del(`/api/role/delete?id=${id}`)
//获取角色列表
export const role = data => post('/api/role', data)
//获取指定角色
export const detail = (id) => get(`/api/role/detail?id=${id}`)
//获取菜单列表
export const all = () => get(`/api/menu/all`)
//获取我的菜单列表
export const my = () => get(`/api/menu/my`)

View File

@@ -0,0 +1,12 @@
import { get, post, put, del } from '@/api/request'
//用户操作日志
export const operation_logmin = data => post('/api/admin/operation_log', data)
//用户登陆日志
export const login_log = data => post('/api/admin/login_log', data)

View File

@@ -0,0 +1,12 @@
import { get, post, put, del } from '@/api/request'
//用户操作日志
export const operation_logmin = data => post('/api/admin/operation_log', data)
//用户登陆日志
export const login_log = data => post('/api/admin/login_log', data)

View File

@@ -0,0 +1,13 @@
import { get, post, put, del } from '@/api/request'
//消息列表
export const list = data => post('/api/message/list', data)
//消息详情
export const details = data => post('/api/message/details?id='+data, data)
//全部设为已处
export const messagedo = data => post('/api/message/do', data)

BIN
src/assets/banner.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 221 KiB

BIN
src/assets/err.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

BIN
src/assets/icon/xiaoxi.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 938 B

BIN
src/assets/icon/yuan.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 699 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 483 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 487 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 491 B

BIN
src/assets/succes.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

BIN
src/assets/ziti.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 KiB

1340
src/components/header.vue Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,227 @@
<template>
<div >
<div class="headers">
<div class="headers-left">
<div class="imgs">
</div>
<div class="img-right">
<div class="name-title">微育科技</div>
<div class="right-name">数智科创 · 通达未来 </div>
</div>
</div>
<div class="headers-right">
<div class="rights">
<div class="rights-names"
v-for="(item,index) in rightDate"
:key="index"
:class="{'active':active == index}"
@click="btnName(item,index)"
>
{{ item.name }}
<div :class="{'shu':shu == index}"></div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default{
data(){
return{
shu: localStorage.getItem('headerActiveShu') || 0, // 读取存储值
active: localStorage.getItem('headerActiveIndex') || 0,
lastActiveKey: 'headerActiveIndex',
// rightDate: []
}
},
props:{
rightDate:[]
},
created() {
},
watch: {
$route(to, from) {
// 判断是否是详情页返回
if (from.path.includes('/detail')) {
this.$nextTick(() => {
// 延迟执行确保DOM更新
const matchedIndex = this.rightDate.findIndex(item =>
item.route === to.path ||
(item.children && item.children.some(child => child.route === to.path))
)
if (matchedIndex !== -1) {
this.active = matchedIndex
this.shu = matchedIndex
}
})
} else {
// 常规路由处理
this.updateActiveFromRoute()
}
}
},
watch: {
$route(to) {
// 如果是从详情页返回,优先从 localStorage 恢复
if (from?.path.includes('/detail')) {
const savedIndex = localStorage.getItem(this.lastActiveKey);
if (savedIndex !== null) {
this.active = parseInt(savedIndex);
this.shu = parseInt(savedIndex);
return;
}
}
// 否则正常匹配路由
const matchedIndex = this.rightDate.findIndex(item =>
item.route === to.path ||
(item.children && item.children.some(child => child.route === to.path))
);
if (matchedIndex !== -1) {
this.active = matchedIndex;
this.shu = matchedIndex;
}
}
},
watch: {
// 监听路由变化(如果有路由关联)
$route() {
this.updateActiveFromRoute()
},
$route(to) {
// ✅ 当前路由匹配到的选项卡索引
const matchedIndex = this.rightDate.findIndex(item =>
item.route === to.path ||
(item.children && item.children.some(child => child.route === to.path))
);
// 如果匹配成功,就更新 `active`
if (matchedIndex !== -1) {
console.log('这个状态是多少', this.active)
this.active = matchedIndex;
this.shu = matchedIndex;
localStorage.setItem(this.lastActiveKey, matchedIndex.toString());
}
},
},
methods:{
btnName(item, index) {
this.active = index;
this.shu = index;
localStorage.setItem('headerActiveIndex', index.toString()); // 存储index
localStorage.setItem('headerActiveShu', index.toString()); // 存储shu
this.$emit('menu-click', item);
},
handleMenuClick(item, index) {
this.activeIndex = index
localStorage.setItem(this.lastActiveKey, index)
this.$emit('menu-click', item)
// 如果菜单项有路由,则跳转
if (item.route) {
this.$router.push(item.route)
}
},
restoreActiveState() {
const savedIndex = localStorage.getItem(this.lastActiveKey)
if (savedIndex !== null) {
this.activeIndex = parseInt(savedIndex)
}
// 如果有路由关联,检查当前路由
this.updateActiveFromRoute()
},
updateActiveFromRoute() {
const currentPath = this.$route.path
// 查找当前路由对应的菜单项
const matchedIndex = this.rightDate.findIndex(item =>
item.route === currentPath ||
(item.children && item.children.some(child => child.route === currentPath))
)
if (matchedIndex !== -1) {
this.activeIndex = matchedIndex
localStorage.setItem(this.lastActiveKey, matchedIndex)
}
}
}
}
</script>
<style scoped>
.shu{
width: 10px;
height: 20px;
background: #5165f7;
position: relative;
top: -24px;
left: 40%;
}
.active{
color: #5165f7 !important;
}
.rights-names{
margin-left: 32px;
cursor: pointer;
}
.rights{
width: 96%;
height: 100%;
margin: 0 auto;
line-height: 94px;
display: flex;
position: relative;
left: -27px;
}
.name-title{
position: relative;
top: -6px;
font-weight: bold;
}
.right-name{
font-size: 12px;
}
.img-right{
font-size: 14px;
position: relative;
top: 40px;
height: 40px;
margin-left: 12px;
}
.imgs{
width: 45px;
height: 46px;
background: #5165f7;
border-radius: 6px;
position: relative;
top: 26px;
margin-left: 24px
}
.headers-right{
flex: 1;
background: white;
}
.headers-left{
width: 222px;
height: 100%;
display: flex;
background: white;
}
.headers{
width: 100%;
height: 90px;
display: flex
;
border-bottom: 1px solid #EDEFFE;
}
</style>

View File

@@ -0,0 +1,138 @@
<template>
<div style="width: 222px;">
<div class="lefts">
<div class="left-content">
<div class="left-img">
<img src="@/assets/resource/ziliao.png" alt="">
</div>
<div class="right-name">
<span class="ziliao">资料完整度</span>
<span class="dushu">38%</span>
</div>
</div>
<div class="content-area">
<div class="area-name">
<div class="yuan"></div>
<span class="namess">111</span>
<span style="float: right;color: #5165f7;"><i class="el-icon-arrow-right"></i></span>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
activeItemIndex: null,
activeMenu: '0',
activeColor: '#409EFF',
openedMenus:[
{
name:''
}
],
}
},
methods: {
},
mounted() {
},
beforeDestroy() {
},
}
</script>
<style scoped>
.yuan{
width: 10px;
height: 10px;
background-color: #EAEBF0;
border-radius: 50%;
z-index: 99;
position: absolute;
left: -6px;
}
.namess{
margin-left: 18px;
margin-left: 18px;
position: relative;
top: -5px;
}
.area-name{
width: 100%;
height: 70px;
position: relative;
border-left: 1px solid #F2F2F2;
}
.content-area{
width: 78%;
margin: 0 auto;
margin-top: 32px;
}
.right-name{
position: relative;
top: -12px;
}
.dushu{
font-size: 20px;
font-weight: bold;
margin-left: 7px;
}
.ziliao{
color: #979BBC;
font-size: 14px;
}
.left-img{
width: 36px;
height: 36px;
}
.left-content{
width: 78%;
margin: 0 auto;
display: flex
;
justify-content: space-between;
height: 42px;
border-bottom: 1px solid #EDEFFE;
line-height: 52px;
margin-top: 14px;
}
.shu{
width: 3px;
height: 40px;
background: #ebebeb;
position: absolute;
left: 28px;
}
:deep .el-menu-item.is-active{
color: #5165f7 !important;
}
/* 调整整体间距 */
.lefts {
padding: 8px 0;
height: 95vh;
background: white;
border-top: 1px solid #EDEFFE
}
</style>

752
src/components/sidebar.vue Normal file
View File

@@ -0,0 +1,752 @@
<template>
<div>
<div class="lefts">
<el-row class="tac">
<el-col :span="12">
<el-menu
class="el-menu-vertical-demo"
:default-active="activeItemIndex"
:default-openeds="openedMenus"
:unique-opened="true"
:active-text-color="activeColor">
<!-- 动态渲染菜单 -->
<el-submenu
v-for="menu in menuData"
:key="menu.index"
:index="menu.index"
:class="{ 'active-menu': activeMenu === menu.index }">
<template slot="title">
<div>
<i :class="menu.icon"></i>
<span>{{ menu.title }}</span>
</div>
</template>
<div class="submenu-content">
<el-menu-item-group
v-for="group in menu.groups"
:key="group.title || group.items[0].index">
<template v-if="group.title" slot="title">{{ group.title }}</template>
<el-menu-item
v-for="(item, $index) in group.items"
:key="item.index"
:index="item.index"
@click="setActiveItem(item,item.index)"
>
<div class="shu" :style="{ height: $index === group.items.length - 1 ? '16px' : '40px' }"></div>
<div
class="yuan"
:style="{ backgroundColor: activeItemIndex === item.index ? '#5165f7' : '#ebebeb' }"
></div>
{{ item.name }}
</el-menu-item>
</el-menu-item-group>
</div>
</el-submenu>
</el-menu>
</el-col>
</el-row>
</div>
</div>
</template>
<script>
export default {
data() {
return {
activeItemIndex: null,
activeMenu: '0',
activeColor: '#409EFF',
openedMenus:[],
menuData: [
{
index: '0',
title: '企业总览',
icon: 'el-icon-location',
groups: [
{
items: [
{ index: '0-1', name: '企业概况',
route: '/home',
children:[
{
name: "数据概览",
route: '/home'
}, {
name: "资料检索",
route: '/home/dataretrieval'
},
{
name: "企业信息",
route: '/home/corporateInformation'
},
]
},
]
},
]
},
{
index: '1',
title: '资源资料',
icon: 'el-icon-location',
groups: [
{
items: [
{
index: '1-1', name: '财务概览',
route: '/operate',
children:[
{
name: "经营情况",
route: '/operate'
}, {
name: "年度审计情况",
route: '/annual'
},
{
name: "专项审计情况",
route: '/special'
},
{
name: "企业所得税纳税情况",
route: '/paytaxes'
}
]
},
{ index: '1-2', name: '人力资源',
route:'/organization',
children:[
{
name: "组织架构",
route: '/organization'
}, {
name: "职工管理",
route: '/employee'
},
{
name: "科技专家",
route: '/technology'
},
]
},
{ index: '1-3', name: '成果管理',
route:'/knowledge',
children:[
{
name: "知识产权",
route: '/knowledge'
}, {
name: "论文管理",
route: '/paper'
},
{
name: "标准制定",
route: '/standard'
},
]
},
{ index: '1-4', name: '资质荣誉',
route:'/enterprise',
children:[
{
name: "企业资质",
route: '/enterprise'
}, {
name: "企业荣誉",
route: '/corporatehonors'
},
]
},
{ index: '1-5', name: '制度文件',
route:'/systemnotice',
children:[
{
name: "制度通知",
route: '/systemnotice'
}
]
},
{ index: '1-6', name: '合同登记',
route:'/contract',
children:[
{
name: "合同登记",
route: '/contract'
}
]
},
{ index: '1-7', name: '校企合作',
route:'/Schoolenterprise',
children:[
{
name: "校企合作",
route: '/Schoolenterprise'
}
]
},
]
},
]
},
{
index: '2',
title: '研发项目',
icon: 'el-icon-menu',
groups: [
{
items: [
{ index: '2-1', name: '项目管理',
route:'/projecthours',
children:[
{
name: "项目情况",
route: '/projecthours'
}
]
},
{ index: '2-2', name: '工时管理' ,
route:'/examstatus',
children:[
{
name: "考情管理",
route: '/examstatus'
},
{
name: "人员降薪",
route: '/personnel'
},
{
name: "项目工时",
route: '/projecthours'
}
]
}
]
}
]
},
{
index: '3',
title: '经营项目',
icon: 'el-icon-document',
groups: [
{
items: [
{ index: '3-1', name: '经营项目',
route:'/productService',
children:[
{
name: "产品服务",
route: '/productService'
},
{
name: "销售情况",
route: '/salesperformance'
},
]
}
]
}
]
},
{
index: '4',
title: '审核中心',
icon: 'el-icon-document',
groups: [
{
items: [
{ index: '4-1', name: '审核管理',
route:'/myreview',
children:[
{
name: "我的审核",
route: '/myreview'
},
{
name: "我的提交",
route: '/mysubmission'
},
{
name: "权限节点",
route: '/permissionnode'
},
]
}
]
}
]
},
{
index: '5',
title: '高企认定',
icon: 'el-icon-document',
groups: [
{
items: [
{ index: '5-1', name: '申报管理',
route:'/declarationmanagement',
children:[
{
name: "申报情况",
route: '/declarationmanagement'
}
]
}
]
}
]
},
{
index: '6',
title: '专精特新',
icon: 'el-icon-document',
groups: [
{
items: [
{ index: '6-1', name: '申报管理',
route:'/specialized',
children:[
{
name: "申报管理",
route: '/specialized'
}
]
}
]
}
]
},
{
index: '7',
title: '加计扣除',
icon: 'el-icon-document',
groups: [
{
items: [
{ index: '7-1', name: '申报管理',
route:'/declarationstatus',
children:[
{
name: "申报情况",
route: '/declarationstatus'
},
{
name: "研发支出辅助账",
route: '/rds'
}
]
}
]
}
]
},
{
index: '8',
title: '科创汇',
icon: 'el-icon-document',
groups: [
{
items: [
{ index: '8-1', name: '通知公告',
route:'/follow',
children:[
{
name: "关注",
route: '/follow'
},
{ name: '全部',
route: '/government'
}
]
},
{ index: '8-2', name: '政府网站',
route:'/home/government/address',
children:[
{
name: "地址管理",
route: '/home/government/address'
}
]
},
]
}
]
},
{
index: '9',
title: '系统管理',
icon: 'el-icon-document',
groups: [
{
items: [
{ index: '9-1', name: '权限管理',
route:'/role',
children:[
{
name: "用户管理",
route: '/role'
},
{ name: '角色管理',
route: '/user'
}
]
},
{ index: '9-2', name: '系统日志',
route:'/userbehavior',
children:[
{
name: "用户行为",
route: '/userbehavior'
},
{ name: '运行日志',
route: '/operationlog'
}
]
},
{ index: '9-3', name: '配置管理',
route:'/dictionary',
children:[
{
name: "数据字典",
route: '/dictionary'
},
{ name: '菜单管理',
route: '/menu'
},
{ name: '系统配置',
route: '/systemconfiguration'
}
]
}
]
}
]
}
]
}
},
methods: {
restoreMenuState() {
if (!this.activeItemIndex) {
const savedIndex = localStorage.getItem('activeItemIndex');
const savedMenu = localStorage.getItem('activeMenu');
if (savedIndex) {
this.activeItemIndex = savedIndex;
this.activeMenu = savedMenu || savedIndex.split('-')[0];
}
}
},
handleStorageChange(event) {
if (event.key === 'activeItemIndex') {
this.activeItemIndex = event.newValue
this.activeMenu = event.newValue.split('-')[0]
}
},
// 统一的方法
setActiveItem(item, index) {
// 更新当前激活的菜单项
this.activeItemIndex = index;
this.activeMenu = index.split('-')[0];
// 确保当前菜单是展开状态(防抖避免频繁操作)
if (!this.openedMenus.includes(this.activeMenu)) {
this.openedMenus = [this.activeMenu];
}
// 存储到 localStorage
localStorage.setItem('activeItemIndex', index);
localStorage.setItem('activeMenu', this.activeMenu);
const normalizedRoute = this.normalizeRoute(item.route);
localStorage.setItem('lastRoute', normalizedRoute); // 存储当前路由
// 触发路由跳转(如果路由变更)
if (normalizedRoute && this.$route.path !== normalizedRoute) {
this.$router.push(normalizedRoute);
}
// 传递给父组件(如有需要)
this.$emit('headerDate', item);
},
// 匹配当前路由对应的菜单项
matchRouteWithMenu(currentPath) {
let matchedItem = null;
// 处理 /home 和 /home/ 路由,统一转换为 /home/ 进行匹配
let normalizedPath = currentPath;
if (currentPath === '/home') {
normalizedPath = '/home/';
}
// 深度遍历菜单数据
outerLoop:
for (const menu of this.menuData) {
for (const group of menu.groups) {
for (const item of group.items) {
// 标准化路由路径进行匹配
const itemRoute = this.normalizeRoute(item.route);
const normalizedItemRoute = itemRoute === '/home' ? '/home/' : itemRoute;
// 匹配主路由(支持 /home 和 /home/ 两种格式)
// 特别处理:当路由是 /home 或 /home/ 时,匹配 route 为 / 的菜单项
if (normalizedItemRoute === normalizedPath ||
(normalizedPath === '/home/' && item.route === '/')) {
matchedItem = item;
break outerLoop;
}
// 匹配子路由
if (item.children) {
const matchedChild = item.children.find(child => {
const childRoute = this.normalizeRoute(child.route);
const normalizedChildRoute = childRoute === '/home' ? '/home/' : childRoute;
// 特别处理:当路由是 /home 或 /home/ 时,匹配 route 为 / 的子菜单项
return normalizedChildRoute === normalizedPath ||
(normalizedPath === '/home/' && child.route === '/');
});
if (matchedChild) {
matchedItem = item;
break outerLoop;
}
}
}
}
}
// 更新状态
if (matchedItem) {
this.activeItemIndex = matchedItem.index;
this.activeMenu = matchedItem.index.split('-')[0];
localStorage.setItem('activeItemIndex', matchedItem.index);
localStorage.setItem('activeMenu', this.activeMenu);
// 更新 lastRoute 为当前路由
localStorage.setItem('lastRoute', normalizedPath);
}
},
normalizeRoute(route) {
if (!route) return '/home'
if (route === '/') return '/home'
if (route.startsWith('/home')) return route
return '/home' + (route.startsWith('/') ? route : '/' + route)
}
},
// sidebar.vue
watch: {
$route: {
immediate: true,
handler(newVal) {
this.matchRouteWithMenu(newVal.path);
}
}
},
mounted() {
// 如果当前路由是 /home 或 /home/,不恢复 lastRoute直接匹配菜单
const currentPath = this.$route.path;
if (currentPath === '/home' || currentPath === '/home/') {
// 直接匹配当前路由对应的菜单
this.matchRouteWithMenu(currentPath);
return;
}
// 从localStorage恢复路由仅当不是 /home 或 /home/ 时)
const lastRoute = localStorage.getItem('lastRoute')
if (lastRoute) {
const normalizedRoute = this.normalizeRoute(lastRoute)
// 如果 lastRoute 是 /home 或 /home/,不恢复,使用当前路由
if (normalizedRoute && normalizedRoute !== '/home' && normalizedRoute !== '/home/' && this.$route.path !== normalizedRoute) {
this.$router.push(normalizedRoute)
}
}
},
created() {
// 如果当前路由是 /home 或 /home/,优先匹配路由,不恢复 localStorage 状态
const currentPath = this.$route.path;
if (currentPath === '/home' || currentPath === '/home/') {
// 直接匹配当前路由对应的菜单
this.matchRouteWithMenu(currentPath);
window.addEventListener('storage', this.handleStorageChange);
return;
}
// 优先从localStorage恢复状态仅当不是 /home 或 /home/ 时)
const savedIndex = localStorage.getItem('activeItemIndex');
const savedMenu = localStorage.getItem('activeMenu');
const savedOpened = JSON.parse(localStorage.getItem('openedMenus') || '[]');
if (savedIndex) {
this.activeItemIndex = savedIndex;
this.activeMenu = savedMenu || savedIndex.split('-')[0];
this.openedMenus = savedOpened;
}
// 再匹配路由(确保路由优先级更高)
this.matchRouteWithMenu(this.$route.path);
// 如果路由未匹配但localStorage有数据则使用存储的数据
if (!this.activeItemIndex && savedIndex) {
this.activeItemIndex = savedIndex;
this.activeMenu = savedMenu;
this.openedMenus = savedOpened;
}
window.addEventListener('storage', this.handleStorageChange);
},
beforeDestroy() {
// 移除事件监听
window.removeEventListener('storage', this.handleStorageChange)
},
}
</script>
<style scoped>
.shu{
width: 3px;
height: 40px;
background: #ebebeb;
position: absolute;
left: 28px;
}
.yuan{
width: 6px;
height: 6px;
background-color: #ebebeb;
border-radius: 50%;
z-index: 99;
position: absolute;
top: 16px;
left: 26px;
}
:deep .el-menu-item.is-active{
color: #5165f7 !important;
}
/* 调整整体间距 */
.lefts {
flex: 1;
padding: 0 0 8px 0;
height: 100%;
background: transparent;
box-sizing: border-box;
display: flex;
flex-direction: column;
}
/* 菜单项间距调整 */
.el-menu {
padding: 0 !important;
}
.el-menu-item,
.el-submenu__title {
height: 40px !important;
line-height: 40px !important;
}
/* 子菜单居中 */
.submenu-content {
display: flex;
flex-direction: column;
align-items: center;
}
.el-menu-item-group {
width: 100%;
}
.el-menu-item {
text-align: center !important;
padding: 0 10px !important;
min-width: auto !important;
}
/* 激活状态样式(重点修改部分) */
.el-submenu.active-menu > .el-submenu__title,
.el-submenu.active-menu > .el-submenu__title:hover {
color: #409EFF !important;
background-color: red !important;
}
/* 确保子菜单展开时也有高亮 */
.el-submenu.is-opened > .el-submenu__title {
color: #409EFF !important;
}
.el-submenu.active-menu .el-icon-arrow-down,
.el-submenu.is-active .el-icon-arrow-down,
/* 分组标题样式 */
::v-deep .el-menu-item-group__title {
padding: 0 !important;
font-size: 12px !important;
text-align: center;
}
/* 菜单宽度调整 */
.el-menu-vertical-demo {
width: 222px !important;
}
.el-menu--inline {
padding-left: 0 !important;
}
/* 调整图标间距 */
.el-submenu__title i {
margin-right: 8px !important;
}
/* :deep .el-submenu__title {
background: red !important;
} */
/* ✅ 正确写法:作用于被选中的 "导航一" */
.el-submenu.active-menu :deep(.el-submenu__title) {
background: #5165f7 !important;
color: white !important;
}
.el-submenu.active-menu :deep(.el-submenu__title i) {
color: white !important; /* 强制图标变白 */
}
</style>

19
src/main.js Normal file
View File

@@ -0,0 +1,19 @@
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.config.productionTip = false
Vue.use(ElementUI);
// 定义全局方法
Vue.prototype.$toDetail = function(id) {
localStorage.setItem('id', id
);
this.$router.push('/details');
};
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')

863
src/router/index.js Normal file
View File

@@ -0,0 +1,863 @@
import Vue from 'vue'
import VueRouter from 'vue-router'
import operate from '@/views/resource/finance/operate' // 经营情况
import annual from '@/views/resource/finance/annual' // 年度审计
import special from '@/views/resource/finance/special/index.vue' // 专项审计情况
import paytaxes from '@/views/resource/finance/paytaxes/index.vue' // 企业所得税纳税情况
import organization from '@/views/resource/manpower/organization/index.vue' // 组织架构
import employee from '@/views/resource/manpower/employee/index.vue' // 职工管理
import technology from '@/views/resource/manpower/technology/index.vue' // 科学专家
import knowledge from '@/views/resource/achievement/knowledge/index.vue' // 知识产权
import knowledgeEdit from '@/views/resource/achievement/knowledge/knowledgeEdit.vue' // 知识产权编辑
import knowledgeDetial from '@/views/resource/achievement/knowledge/knowledgeDetial.vue' // 知识产权详情
import paper from '@/views/resource/achievement/paper/index.vue' // 论文管理
import paperDetail from '@/views/resource/achievement/paper/paperDetail.vue' // 论文管理详情
import standardDetial from '@/views/resource/achievement/standard/standardDetial.vue' // 标准详情
import standardEdit from '@/views/resource/achievement/standard/standardEdit.vue' // 标准编辑
import paperAdd from '@/views/resource/achievement/paper/paperAdd.vue' // 论文管理新增
import standard from '@/views/resource/achievement/standard/index.vue' // 论文管理
import enterprise from '@/views/resource/qualification/enterprise/index.vue'
import corporatehonors from '@/views/resource/qualification/corporatehonors/index.vue'
import corporatehonorsDetail from '@/views/resource/qualification/corporatehonors/corporatehonorsDetail.vue' //企业荣誉详情
import corporatehonorsEdit from '@/views/resource/qualification/corporatehonors/corporatehonorsEdit.vue' //企业荣誉编辑
import enterpriseDetail from '@/views/resource/qualification/enterprise/enterpriseDetail.vue' //资质详情
import enterpriseEdit from '@/views/resource/qualification/enterprise/enterpriseEdit.vue' //资质编辑
import systemnotice from '@/views/resource/systemnotice/index.vue'
import systemnoticeEdit from '@/views/resource/systemnotice/systemnoticeEdit.vue' //制度编辑
import systemnoticeDetail from '@/views/resource/systemnotice/systemnoticeDetail.vue' //制度详情
import Schoolenterprise from '@/views/resource/Schoolenterprise/index.vue'
import SchoolenterpriseDetail from '@/views/resource/Schoolenterprise/SchoolenterpriseDetail.vue' //校企合作详情
import SchoolenterpriseEdit from '@/views/resource/Schoolenterprise/SchoolenterpriseEdit.vue' //校企合作编辑
import examstatus from '@/views/project/Workhourmanagement/examstatus/index.vue'
import examstatusEdint from '@/views/project/Workhourmanagement/examstatus/examstatusEdint.vue'//工时编辑
import examstatusDetail from '@/views/project/Workhourmanagement/examstatus/examstatusDetail.vue'//工时详情
import personnel from '@/views/project/Workhourmanagement/personnel/index.vue' //人员降薪
import personnelEdint from '@/views/project/Workhourmanagement/personnel/personnelEdint.vue' //人员降薪编辑
import personnelDetail from '@/views/project/Workhourmanagement/personnel/personnelDetail.vue' //人员降薪详情
import projecthours from '@/views/project/projectmanagement/ProjectStatus/index.vue'
import projecthoursDetai from '@/views/project/projectmanagement/projecthoursDetai.vue' //项目主页
import lixiangziliao from '@/views/project/projectmanagement/lixiangziliao/index.vue' //立项阶段资料
import lixiangziliaoEdint from '@/views/project/projectmanagement/lixiangziliao/lixiangziliaoEdint.vue' //立项阶段资料编辑
import lixiangyusuan from '@/views/project/projectmanagement/lixiangyusuan/index.vue' //立即预算编辑
import renwuqingdan from '@/views/project/projectmanagement/renwuqingdan/index.vue' //任务清单编辑
import chengyuan from '@/views/project/projectmanagement/chengyuan/index.vue' //任务清单编辑
import hetongmingxin from '@/views/project/projectmanagement/hetongmingxin/index.vue' //合同明细编辑
import hetongmingxinDetails from '@/views/project/projectmanagement/hetongmingxin/indexDetails.vue' //合同明细编辑
import jindubaogao from '@/views/project/projectmanagement/jindubaogao/index.vue' //进度报告编辑
import jindubaogaoDetail from '@/views/project/projectmanagement/jindubaogao/jindubaogaoDetail.vue' //进度报告详情
import feiyongmingxi from '@/views/project/projectmanagement/feiyongmingxi/index.vue' //支出费用编辑
import feiyongmingxikeji from '@/views/project/projectmanagement/feiyongmingxi/keji/index.vue' //支出费用编辑
import indexzhu from '@/views/project/projectmanagement/feiyongmingxi/indexzhu.vue' //支出费用主页
import feiyongmingxiDetail from '@/views/project/projectmanagement/feiyongmingxi/feiyongmingxiDetail.vue' //支出费用详情
import projectmanagementEdint from '@/views/project/projectmanagement/projectmanagementEdint/index.vue' //项目主页
import xiangmujiedian from '@/views/project/projectmanagement/xiangmujiedian/index.vue' //项目节点
import xiangmujiedianEdint from '@/views/project/projectmanagement/xiangmujiedian/xiangmujiedianEdint.vue' //项目节点详情
import zhongqi from '@/views/project/projectmanagement/zhongqi/index.vue' //中期检查编辑
import zhongqiDetai from '@/views/project/projectmanagement/zhongqi/zhongqiDetai.vue' //中期检查详情
import jianti from '@/views/project/projectmanagement/jianti/index.vue' //结题情况编辑
import jiantiDetial from '@/views/project/projectmanagement/jianti/jiantiDetial.vue' //结题情况详情
import wendang from '@/views/project/projectmanagement/wendang/index.vue' //文档编辑
import wendangDetai from '@/views/project/projectmanagement/wendang/wendangDetai.vue' //文档详情
import kejichengguo from '@/views/project/projectmanagement/kejichengguo/index.vue' //科技成果编辑
import kejichengguoDetail from '@/views/project/projectmanagement/kejichengguo/kejichengguoDetail.vue' //科技成果详情
import chengguo from '@/views/project/projectmanagement/chengguo/index.vue' //成果图示编辑
import touziyusuanEdit from '@/views/project/projectmanagement/touziyusuan/touziyusuanEdit.vue' //投资预算编辑
import touziyusuanDetail from '@/views/project/projectmanagement/touziyusuan/touziyusuanDetail.vue' //投资预算详情
import contract from '@/views/resource/contract/index.vue'
import conponentEdit from '@/views/resource/contract/conponentEdit.vue' //合同新增
import conponentDetail from '@/views/resource/contract/conponentDetail.vue' //合同详情
import productService from '@/views/businessScope/productService/index.vue' //经营项目
import productServiceDetail from '@/views/businessScope/productService/productServiceDetail.vue' //经营详情
import xiaoshouqingkuan from '@/views/businessScope/productService/xiaoshouqingkuan.vue' //经营销售详情
import salesperformance from '@/views/businessScope/salesperformance/index.vue' //销售情况
import salesperformanceDetial from '@/views/businessScope/salesperformance/salesperformanceDetial.vue'
import salesperformanceEdint from '@/views/businessScope/salesperformance/salesperformanceEdint.vue'
import permissionnode from '@/views/auditmanagement/permissionnode/index.vue'
import mysubmission from '@/views/auditmanagement/mysubmission/index.vue'
import myreview from '@/views/auditmanagement/myreview/index.vue' //审核管理
import myreviewSee from '@/views/auditmanagement/myreview/myreviewSee.vue' //审核详情
import follow from '@/views/Innovation/follow/index.vue'
import government from '@/views/Innovation/government/index.vue'
import governmentAddress from '@/views/Innovation/government/address/index.vue'
import declarationmanagement from '@/views/declarationmanagement/index.vue'
import role from '@/views/system/permission/role/index.vue'
import user from '@/views/system/permission/user/index.vue'
import userbehavior from '@/views/system/logs/userbehavior/index.vue'
import operationlog from '@/views/system/logs/operationlog/index.vue'
import declarationstatus from '@/views/specializeds/declarationstatus/index.vue' //申报管理
import declarationstatusDetail from '@/views/specializeds/declarationstatus/declarationstatusDetail.vue' //申报管理主页
import specialized from '@/views/specialized/index.vue'
import specializedDetail from '@/views/specialized/specializedDetail.vue'
import rds from '@/views/specializeds/rds/index.vue'
import dictionary from '@/views/system/configuration/dictionary/index.vue'
import menu from '@/views/system/configuration/menu/index.vue'
import systemconfiguration from '@/views/system/configuration/systemconfiguration/index.vue'
import Layout from '@/views/Layout.vue' // 新建的布局组件
import corporateInformation from '@/views/homepage/corporateInformation/index' // 企业信息
import dataoverview from '@/views/homepage/dataoverview/index' // 数据概览
import dataretrieval from '@/views/homepage/dataretrieval/index' // 资料检索
import qiyeDetail from '@/views/resource/finance/operate/qiyeDetail.vue' // 企业详情
import qiyeEdit from '@/views/resource/finance/operate/qiyeEdit.vue' // 企业编辑
import zichangDetail from '@/views/resource/finance/operate/zichangDetail.vue' // 资产详情
import zichangEdit from '@/views/resource/finance/operate/zichangEdit.vue' // 资产详情
import auditDetail from '@/views/resource/finance/annual/auditDetail.vue' // 年度审计报告详情
import auditEdit from '@/views/resource/finance/annual/auditEdit.vue' // 年度审计报告编辑
import technologypiliang from '@/views/resource/manpower/technology/piliang.vue' // 年度审计报告编辑
import selectexperts from '@/views/resource/manpower/technology/selectexperts.vue' // 专家抽取设置
import extractdetail from '@/views/resource/manpower/technology/extractdetail.vue' // 抽取专家名单
import employeepidetial from '@/views/resource/manpower/employee/employeepi.vue' // 职工管理批量
import Login from '@/views/login/index.vue' // 登录页面
import messageCenter from '@/views/message/index.vue' // 消息中心
Vue.use(VueRouter)
const routes = [
{
path: '/login',
name: 'Login',
component: Login,
meta: { requiresAuth: false }
},
{
path: '/',
redirect: '/login'
},
{
path: '/role',
redirect: to => {
const isLogin = localStorage.getItem('isLogin') === 'true'
const token = localStorage.getItem('token')
if (isLogin || token) {
return '/home/role'
}
return '/login'
},
meta: { requiresAuth: true }
},
{
path: '/home',
name: 'Layout',
component: Layout, // 使用布局组件作为容器
meta: { requiresAuth: true },
redirect: '/home/', // 重定向到默认子路由
children: [
{
path: 'dataretrieval',
name: 'dataretrieval',
component: dataretrieval // 资料检索
},
{
path: 'corporateInformation',
name: 'corporateInformation',
component: corporateInformation // 企业信息
},
{
path: '',
name: 'dataoverview',
component: dataoverview // 数据概览
},
{
path: 'operate',
name: 'operate',
component: operate
},
{
path: 'dictionary',
name: 'dictionary',
component: dictionary
},
{
path: 'menu',
name: 'menu',
component: menu
},
{
path: 'systemconfiguration',
name: 'systemconfiguration',
component: systemconfiguration
},
{
path: 'userbehavior',
name: 'userbehavior',
component: userbehavior
},
{
path: 'operationlog',
name: 'operationlog',
component: operationlog
},
{
path: 'role',
name: 'role',
component: role
},
{
path: 'user',
name: 'user',
component: user
},
{
path: 'follow',
name: 'follow',
component: follow
},
{
path: 'government',
name: 'government',
component: government
},
{
path: 'declarationstatus',
name: 'declarationstatus',
component: declarationstatus
},
{
path: 'rds',
name: 'rds',
component: rds
},
{
path: 'declarationmanagement',
name: 'declarationmanagement',
component: declarationmanagement
},
{
path: 'specialized',
name: 'specialized',
component: specialized
},
{
path: 'specializedDetail',
name: 'specializedDetail',
component: specializedDetail
},
{
path: 'permissionnode',
name: 'permissionnode',
component: permissionnode
},
{
path: 'mysubmission',
name: 'mysubmission',
component: mysubmission
},
{
path: 'myreview',
name: 'myreview',
component: myreview
},
{
path: 'productService',
name: 'productService',
component: productService
},
{
path: 'salesperformance',
name: 'salesperformance',
component: salesperformance
},
{
path: 'projecthours',
name: 'projecthours',
component: projecthours
},
{
path: 'examstatus',
name: 'examstatus',
component: examstatus
},
{
path: 'personnel',
name: 'personnel',
component: personnel
},
{
path: 'Schoolenterprise',
name: 'Schoolenterprise',
component: Schoolenterprise
},
{
path: 'contract',
name: 'contract',
component: contract
},
{
path: 'systemnotice',
name: 'systemnotice',
component: systemnotice
},
{
path: 'standard',
name: 'standard',
component: standard
},
{
path: 'enterprise',
name: 'enterprise',
component: enterprise
},
{
path: 'corporatehonors',
name: 'corporatehonors',
component: corporatehonors
},
{
path: 'annual',
name: 'annual',
component: annual
},
{
path: 'special',
name: 'special',
component: special
},
{
path: 'paytaxes',
name: 'paytaxes',
component: paytaxes
},
{
path: 'organization',
name: 'organization',
component: organization
},
{
path: 'employee',
name: 'employee',
component: employee
},
{
path: 'paper',
name: 'paper',
component: paper
},
{
path: 'technology',
name: 'technology',
component: technology
},
{
path: 'knowledge',
name: 'knowledge',
component: knowledge
},
{
path: 'message',
name: 'message',
component: messageCenter
},
{
path: 'government/address',
name: 'governmentAddress',
component: governmentAddress
}
// 可以继续添加其他内容路由
]
},
{
path: '/projectmanagementEdint',
name: 'projectmanagementEdint',
component: projectmanagementEdint,
},
{
path: '/projecthoursDetai',
name: 'projecthoursDetai',
component: projecthoursDetai,
},
{
path: '/lixiangyusuan',
name: 'lixiangyusuan',
component: lixiangyusuan,
},
{
path: '/hetongmingxinDetails',
name: 'hetongmingxinDetails',
component: hetongmingxinDetails,
},
{
path: '/wendang',
name: 'wendang',
component: wendang,
},
{
path: '/wendangDetai',
name: 'wendangDetai',
component: wendangDetai,
},
{
path: '/jindubaogao',
name: 'jindubaogao',
component: jindubaogao,
},
{
path: '/xiangmujiedian',
name: 'xiangmujiedian',
component: xiangmujiedian,
},
{
path: '/zhongqi',
name: 'zhongqi',
component: zhongqi,
},
{
path: '/zhongqiDetai',
name: 'zhongqiDetai',
component: zhongqiDetai,
},
{
path: '/xiangmujiedianEdint',
name: 'xiangmujiedianEdint',
component: xiangmujiedianEdint,
},
{
path: '/jindubaogaoDetail',
name: 'jindubaogaoDetail',
component: jindubaogaoDetail,
},
{
path: '/feiyongmingxi',
name: 'feiyongmingxi',
component: feiyongmingxi,
},
{
path: '/feiyongmingxikeji',
name: 'feiyongmingxikeji',
component: feiyongmingxikeji,
},
{
path: '/indexzhu',
name: 'indexzhu',
component: indexzhu,
},
{
path: '/feiyongmingxiDetail',
name: 'feiyongmingxiDetail',
component: feiyongmingxiDetail,
},
{
path: '/chengyuan',
name: 'chengyuan',
component: chengyuan,
},
{
path: '/hetongmingxin',
name: 'hetongmingxin',
component: hetongmingxin,
},
{
path: '/renwuqingdan',
name: 'renwuqingdan',
component: renwuqingdan,
},
{
path: '/lixiangziliao',
name: 'lixiangziliao',
component: lixiangziliao,
},
{
path: '/lixiangziliaoEdint',
name: 'lixiangziliaoEdint',
component: lixiangziliaoEdint,
},
{
path: '/corporatehonorsDetail',
name: 'corporatehonorsDetail',
component: corporatehonorsDetail
},
{
path: '/systemnoticeEdit',
name: 'systemnoticeEdit',
component: systemnoticeEdit
},
{
path: '/systemnoticeDetail',
name: 'systemnoticeDetail',
component: systemnoticeDetail
},
{
path: '/corporatehonorsEdit',
name: 'corporatehonorsEdit',
component: corporatehonorsEdit
},
{
path: '/enterpriseDetail',
name: 'enterpriseDetail',
component: enterpriseDetail
},
{
path: '/enterpriseEdit',
name: 'enterpriseEdit',
component: enterpriseEdit
},
{
path: '/employeepidetial',
name: 'employeepidetial',
component: employeepidetial
},
{
path: '/paperDetail',
name: 'paperDetail',
component: paperDetail
},
{
path: '/productServiceDetail',
name: 'productServiceDetail',
component: productServiceDetail
},
{
path: '/standardDetial',
name: 'standardDetial',
component: standardDetial
},
{
path: '/salesperformanceEdint',
name: 'salesperformanceEdint',
component: salesperformanceEdint
},
{
path: '/chengguo',
name: 'chengguo',
component: chengguo
},
{
path: '/touziyusuanEdit',
name: 'touziyusuanEdit',
component: touziyusuanEdit
},
{
path: '/touziyusuanDetail',
name: 'touziyusuanDetail',
component: touziyusuanDetail
},
{
path: '/standardEdit',
name: 'standardEdit',
component: standardEdit
},
{
path: '/declarationstatusDetail',
name: 'declarationstatusDetail',
component: declarationstatusDetail
},
{
path: '/specializedDetail',
name: 'specializedDetail',
component: specializedDetail
},
{
path: '/paperAdd',
name: 'paperAdd',
component: paperAdd
},
{
path: '/myreviewSee',
name: 'myreviewSee',
component: myreviewSee
},
{
path: '/salesperformanceDetial',
name: 'salesperformanceDetial',
component: salesperformanceDetial
},
{
path: '/salesperformanceEdint',
name: 'salesperformanceEdint',
component: salesperformanceEdint
},
{
path: '/knowledgeEdit',
name: 'knowledgeEdit',
component: knowledgeEdit
},
{
path: '/conponentDetail',
name: 'conponentDetail',
component: conponentDetail
},
{
path: '/conponentEdit',
name: 'conponentEdit',
component: conponentEdit
},
{
path: '/xiaoshouqingkuan',
name: 'xiaoshouqingkuan',
component: xiaoshouqingkuan
},
{
path: '/SchoolenterpriseDetail',
name: 'SchoolenterpriseDetail',
component: SchoolenterpriseDetail
},
{
path: '/SchoolenterpriseEdit',
name: 'SchoolenterpriseEdit',
component: SchoolenterpriseEdit
},
{
path: '/knowledgeDetial',
name: 'knowledgeDetial',
component: knowledgeDetial
},
{
path: '/qiyeDetail',
name: 'qiyeDetail',
component: qiyeDetail,
},
{
path: '/selectexperts',
name: 'selectexperts',
component: selectexperts,
},
{
path: '/extractdetail',
name: 'extractdetail',
component: extractdetail,
},
{
path: '/jiantiDetial',
name: 'jiantiDetial',
component: jiantiDetial,
},
{
path: '/jianti',
name: 'jianti',
component: jianti,
},
{
path: '/technologypiliang',
name: 'technologypiliang',
component: technologypiliang,
},
{
path: '/auditDetail',
name: 'auditDetail',
component: auditDetail,
},
{
path: '/examstatusDetail',
name: 'examstatusDetail',
component: examstatusDetail,
},
{
path: '/personnelEdint',
name: 'personnelEdint',
component: personnelEdint,
},
{
path: '/personnelDetail',
name: 'personnelDetail',
component: personnelDetail,
},
{
path: '/examstatusEdint',
name: 'examstatusEdint',
component: examstatusEdint,
},
{
path: '/auditEdit',
name: 'auditEdit',
component: auditEdit,
},
{
path: '/qiyeEdit',
name: 'qiyeEdit',
component: qiyeEdit,
},
{
path: '/kejichengguo',
name: 'kejichengguo',
component: kejichengguo,
},
{
path: '/kejichengguoDetail',
name: 'kejichengguoDetail',
component: kejichengguoDetail,
},
{
path: '/zichangDetail',
name: 'zichangDetail',
component: zichangDetail,
},
{
path: '/zichangEdit',
name: 'zichangEdit',
component: zichangEdit,
},
{
path: '/follow',
name: 'follow',
component: follow,
meta: { requiresAuth: true }
},
{
path: '/government',
name: 'government',
component: government,
meta: { requiresAuth: true }
}
]
const router = new VueRouter({
routes,
mode: 'hash', // 确保使用 hash 模式
scrollBehavior(to, from, savedPosition) {
// 如果浏览器有保存的滚动位置,恢复它(支持回退)
if (savedPosition) {
return savedPosition
} else {
return { x: 0, y: 0 }
}
}
})
// 路由守卫
router.beforeEach((to, from, next) => {
try {
// 确保从 localStorage 正确读取值
const isLoginValue = localStorage.getItem('isLogin')
const token = localStorage.getItem('token')
const isLogin = isLoginValue === 'true' || isLoginValue === true
// 确保 token 不是空字符串、null 或 undefined
const hasToken = !!localStorage.getItem('token'); // 简化为布尔值
const hasAuth = isLogin && hasToken; // ✅ 必须同时满足登录态和 Token
// 开发环境下打印路由信息(强制输出,帮助排查)
console.log('🔍 路由守卫检查:', {
to: to.path,
from: from.path,
hasAuth,
isLogin,
isLoginValue,
isLoginType: typeof isLoginValue,
hasToken,
tokenLength: token ? token.length : 0,
tokenPreview: token ? (token.length > 20 ? token.substring(0, 20) + '...' : token) : '未设置',
meta: to.meta,
matched: to.matched.length,
allStorage: {
isLogin: localStorage.getItem('isLogin'),
token: localStorage.getItem('token') ? '已设置' : '未设置',
userId: localStorage.getItem('userId')
}
})
// 如果已登录
if (hasAuth) {
// 如果访问登录页,跳转到主页
if (to.path === '/') {
next('/home')
return
}
// 如果访问根路径,跳转到主页
if (to.path === '/') {
next('/home')
return
}
// 已登录用户允许访问所有其他路由
next()
return
}
// 未登录的情况
// 如果访问登录页,允许访问
if (to.path === '/login') {
next()
return
}
// 如果需要登录但未登录,跳转到登录页
if (to.meta && to.meta.requiresAuth === true) {
if (process.env.NODE_ENV === 'development') {
console.warn('路由守卫: 需要登录但未登录,重定向到登录页', {
path: to.path,
meta: to.meta
})
}
next('/login')
return
}
// 对于 /home 及其子路由,需要登录
if (to.path.startsWith('/home')) {
if (!hasAuth) {
// 开发环境下,提供详细的提示和解决方案
if (process.env.NODE_ENV === 'development') {
console.warn('⚠️ 路由守卫: 访问 /home 需要登录,但检测到未登录状态')
console.warn('📋 当前 localStorage 状态:')
console.warn(' isLogin:', localStorage.getItem('isLogin') || '未设置')
console.warn(' token:', localStorage.getItem('token') ? '已设置' : '未设置')
console.warn(' userId:', localStorage.getItem('userId') || '未设置')
console.warn('')
console.warn('💡 解决方案:')
console.warn(' 1. 请先访问登录页面进行登录: http://localhost:8080/#/login')
console.warn(' 2. 登录成功后isLogin 和 token 会被自动设置')
console.warn(' 3. 然后就可以正常访问 /home 页面了')
console.warn('')
console.warn('🔧 临时调试方案(仅开发环境):')
console.warn(' 在控制台执行以下命令,然后刷新页面:')
console.warn(' localStorage.setItem("isLogin", "true")')
console.warn(' localStorage.setItem("token", "temp_token_for_dev")')
}
// 静默重定向到登录页(不抛出错误,避免控制台报错)
next('/login')
return
}
}
// 其他路由,如果是公开路由(明确标记为不需要登录),允许访问
if (to.meta && to.meta.requiresAuth === false) {
next()
return
}
// 默认情况下,未登录用户跳转到登录页
if (process.env.NODE_ENV === 'development') {
console.warn('路由守卫: 默认重定向到登录页', {
path: to.path,
meta: to.meta
})
}
next('/login')
} catch (error) {
console.error('路由守卫错误:', error)
// 发生错误时,允许访问登录页
if (to.path === '/login') {
next()
} else {
next('/login')
}
}
})
export default router

18
src/store/index.js Normal file
View File

@@ -0,0 +1,18 @@
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
active:""
},
getters: {
},
mutations: {
},
actions: {
},
modules: {
}
})

28
src/utils/auth.js Normal file
View File

@@ -0,0 +1,28 @@
// 操作token的通用方法
export function getToken() {
return localStorage.getItem('token')
}
export function setToken(token) {
localStorage.setItem('token', token)
}
export function removeToken() {
localStorage.removeItem('token')
}
// 操作企业LOGO的通用方法
export function getEnterpriseLogo() {
return localStorage.getItem('enterpriseLogo') || ''
}
export function setEnterpriseLogo(logoUrl) {
if (logoUrl) {
localStorage.setItem('enterpriseLogo', logoUrl)
}
}
export function removeEnterpriseLogo() {
localStorage.removeItem('enterpriseLogo')
}

View File

@@ -0,0 +1,671 @@
<template>
<div>
<div class="coentent">
<div class="contents-area">
<div class="areas">
<div class="headers">
<div class="headers-left">
<div class="headers-name">内容关注表</div>
</div>
<div class="headers-right">
<div class="filter-item">
<span class="filter-label">发布单位</span>
<el-select clearable v-model="publish_unit" @change="handleFilterChange" style="border: 1px solid #ededed;" size="small" class="filter-select">
<el-option v-for="item in slelectDate" :key="item.name" :label="item.name" :value="item.name"></el-option>
</el-select>
</div>
<div class="filter-item">
<span class="filter-label">时间筛选</span>
<el-date-picker
v-model="filters.dateRange"
type="daterange"
range-separator=""
start-placeholder="开始时间"
end-placeholder="结束时间"
format="yyyy-MM-dd"
value-format="yyyy-MM-dd"
size="small"
class="filter-date-picker"
style="width: 240px; border: 1px solid #ededed !important;"
@change="handleDateRangeChange">
</el-date-picker>
</div>
<el-input
style="border: 1px solid #ededed;"
placeholder="搜索关键字"
v-model="filters.keyword"
class="search-input"
size="small"
clearable>
<el-button slot="append" icon="el-icon-search" @click="handleSearch">搜索</el-button>
</el-input>
<el-button type="primary" size="small" class="follow-btn" @click="openFollowSetting">关注设置</el-button>
</div>
</div>
<div class="content-table">
<el-table
:data="pagedData"
border
:header-cell-style="{ background: '#EDEFFE', color: '#363636', textAlign: 'center' }"
:cell-style="cellStyle"
:row-class-name="rowClassName"
style="width: 100%">
<el-table-column type="index" label="序号" width="70" align="center" :index="formatIndex"></el-table-column>
<el-table-column prop="title" label="内容" min-width="400">
<template #default="{ row }">
<div class="content-title">{{ row.title }}</div>
<div class="content-summary">{{ row.summary }}</div>
<div class="content-tags">
<span class="tag-label">涉及项</span>
<span class="tag-item" v-for="tag in row.tags" :key="tag">{{ tag }}</span>
</div>
</template>
</el-table-column>
<el-table-column prop="publisher" label="发布单位" min-width="180"></el-table-column>
<el-table-column prop="publishDate" label="发布日期" min-width="140"></el-table-column>
<el-table-column label="附件数量" width="110" align="center">
<template #default="{ row: item }">
{{ item.attachments?.length || 0 }}
</template>
</el-table-column>
<el-table-column label="操作" width="120" align="center">
<template #default="scope">
<el-button type="text" class="link-btn" @click="openDetail(scope.row)">详情</el-button>
</template>
</el-table-column>
</el-table>
<div class="footer">
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="pagination.currentPage"
:page-sizes="[10, 20, 30, 50]"
:page-size="pagination.pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="pagination.total">
</el-pagination>
</div>
</div>
</div>
</div>
</div>
<el-dialog
:visible.sync="detailDialogVisible"
width="840px"
class="follow-detail-dialog"
:close-on-click-modal="false"
:destroy-on-close="true">
<template #title>
<div class="detail-title">{{ detailData.title }}</div>
</template>
<div class="detail-body">
<div class="detail-meta">
<span>发布单位{{ detailData.publisher }}</span>
<span>发布时间{{ detailData.publishDate }}</span>
</div>
<div class="detail-content">
<p v-for="(paragraph, index) in detailData.content" :key="index">{{ paragraph }}</p>
</div>
<div class="detail-attachments" v-if="detailData.attachments?.length">
<div class="attachments-title">附件下载</div>
<el-table
:data="detailData.attachments"
border
size="small"
:header-cell-style="{ background: '#F0F2FF', color: '#363636', textAlign: 'left' }"
:cell-style="{ textAlign: 'left', color: '#363636' }">
<el-table-column prop="name" label="附件名称"></el-table-column>
<el-table-column label="操作" width="120" align="center">
<template #default>
<el-button type="text" class="link-btn">下载</el-button>
</template>
</el-table-column>
</el-table>
</div>
</div>
<template #footer>
<div class="detail-footer">
<el-button size="small" @click="detailDialogVisible = false">关闭</el-button>
</div>
</template>
</el-dialog>
<el-dialog
:visible.sync="followDialogVisible"
width="600px"
class="follow-setting-dialog"
:close-on-click-modal="false"
:destroy-on-close="true">
<template #title>
<div class="follow-setting-title">通知公告关注关键词设置</div>
</template>
<div class="follow-setting-section">
<div class="follow-setting-label">关键词设置</div>
<el-input
type="textarea"
v-model="followKeywords"
placeholder="请输入关注关键词,用“,”分组..."
class="follow-setting-input">
</el-input>
</div>
<div class="follow-setting-note">
<ol>
<li>请输入关注关键词,分组关键词数量不超过30个</li>
<li>设置关键词后系统将自动筛选最新的相关通知公告默认查找近一年的通知公告</li>
</ol>
</div>
<template #footer>
<div class="detail-footer">
<el-button type="primary" size="small" class="submit-btn" @click="submitFollowKeywords">保存提交</el-button>
<el-button size="small" @click="followDialogVisible = false">取消</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script>
import {myList,govAddr,save,getLastKeyWords} from '@/api/Innovation/government'
export default {
data() {
return {
publish_unit:"",
filters: {
category: 'all',
publisher: '',
dateRange: [],
keyword: ''
},
categoryOptions: [
{ value: 'all', label: '全部' },
{ value: 'notification', label: '通知公告' },
{ value: 'policy', label: '政策发布' }
],
publisherOptions: [
{ value: 'all', label: '全部' },
{ value: '贵州省科学技术厅', label: '贵州省科学技术厅' },
{ value: '贵州省工业和信息化厅', label: '贵州省工业和信息化厅' }
],
tableData: [],
pagination: {
currentPage: 1,
pageSize: 10,
total: 0
},
start_time:"",
end_time:"",
keyword:"",
detailDialogVisible: false,
detailData: {
title: '',
publisher: '',
publishDate: '',
content: [],
attachments: []
},
slelectDate:[],
page:1,
limit:10,
followDialogVisible: false,
followKeywords: ''
}
},
computed: {
pagedData() {
return this.tableData
}
},
mounted(){
this.getmyList()
this.getgovAddr()
},
methods: {
//关键词数据回显
getgetLastKeyWords(){
getLastKeyWords().then((res)=>{
this.followKeywords=res.data.keywords
})
},
//发布单位,
getgovAddr(){
govAddr().then((res)=>{
this.slelectDate=res.data.data
})
},
//列表数据
getmyList(){
// 处理筛选条件
let keyword = this.filters.keyword || ''
// 处理类别筛选parent_id
let parent_id = ''
if (this.filters.category === 'notification') {
parent_id = '1' // 通知公告
} else if (this.filters.category === 'policy') {
parent_id = '2' // 政策发布
}
// 处理时间筛选(日期范围)
let start_time = ''
let end_time = ''
if (this.filters.dateRange && this.filters.dateRange.length === 2) {
start_time = this.filters.dateRange[0]
end_time = this.filters.dateRange[1]
}
let parm = {
publish_unit: this.publish_unit,
start_time: start_time,
end_time: end_time,
keyword: keyword,
page: this.pagination.currentPage,
limit: this.pagination.pageSize
}
// 如果选择了类别,添加 parent_id 参数
if (parent_id) {
parm.parent_id = parent_id
}
myList(parm).then((res) => {
if (res && res.code === 1 && res.data) {
// 更新总数
this.pagination.total = res.data.total || 0
// 处理返回的数据
const dataList = res.data.data || []
this.tableData = dataList.map(item => {
// 解析附件
let attachments = []
if (item.file_address) {
try {
// 尝试解析 file_address JSON 字符串
const fileAddress = JSON.parse(item.file_address)
if (Array.isArray(fileAddress)) {
attachments = fileAddress.map(file => ({
name: file.name || file.destination || '附件',
url: file.url || file.destination || '#'
}))
}
} catch (e) {
// 如果解析失败,使用 file_num 作为附件数量
if (item.file_num > 0) {
attachments = Array(item.file_num).fill(null).map((_, index) => ({
name: `附件${index + 1}`,
url: '#'
}))
}
}
} else if (item.file_num > 0) {
attachments = Array(item.file_num).fill(null).map((_, index) => ({
name: `附件${index + 1}`,
url: '#'
}))
}
// 处理标签(从 keyword 字段)
let tags = []
if (item.keyword) {
tags = item.keyword.split(/[,]/).filter(tag => tag.trim())
}
// 格式化日期
let publishDate = item.article_time || item.create_time || ''
if (publishDate) {
publishDate = this.formatDisplayDate(publishDate)
}
return {
id: item.id,
title: item.title || '',
summary: item.abstract || '',
tags: tags,
publisher: item.publish_unit || '',
publishDate: publishDate,
attachments: attachments,
category: item.parent_id === '1' ? 'notification' : (item.parent_id === '2' ? 'policy' : 'notification'),
content: item.abstract ? [item.abstract] : [],
url: item.url || '',
content_url: item.content_url || '',
file_address: item.file_address || '',
keyword: item.keyword || ''
}
})
} else {
this.$message.error(res?.msg || '获取数据失败')
this.tableData = []
this.pagination.total = 0
}
}).catch((error) => {
console.error('获取列表数据失败:', error)
this.$message.error('获取数据失败')
this.tableData = []
this.pagination.total = 0
})
},
// 格式化显示日期
formatDisplayDate(dateStr) {
if (!dateStr) return ''
const date = new Date(dateStr)
const year = date.getFullYear()
const month = String(date.getMonth() + 1).padStart(2, '0')
const day = String(date.getDate()).padStart(2, '0')
return `${year}${month}${day}`
},
handleSearch() {
this.pagination.currentPage = 1
this.getmyList()
},
handleSizeChange(val) {
this.pagination.pageSize = val
this.pagination.currentPage = 1
this.getmyList()
},
handleCurrentChange(val) {
this.pagination.currentPage = val
this.getmyList()
},
formatIndex(index) {
return (this.pagination.currentPage - 1) * this.pagination.pageSize + index + 1
},
rowClassName() {
return 'follow-row'
},
cellStyle({ column }) {
const leftAlignedProps = ['title', 'publisher', 'publishDate']
return {
textAlign: leftAlignedProps.includes(column.property) ? 'left' : 'center',
color: '#363636'
}
},
openDetail(row) {
this.detailData = {
title: row.title,
publisher: row.publisher,
publishDate: row.publishDate,
content: row.content || [],
attachments: row.attachments || []
}
this.detailDialogVisible = true
},
openFollowSetting() {
this.followKeywords = this.filters.keyword || ''
this.followDialogVisible = true
this.getgetLastKeyWords()
},
submitFollowKeywords() {
// 调用保存接口
save({ keyword: this.followKeywords }).then((res) => {
if (res && res.code === 1) {
this.$message.success('关注关键词已保存')
this.followDialogVisible = false
// 保存成功后,可以重新获取列表数据
this.getmyList()
} else {
this.$message.error(res?.msg || '保存失败')
}
}).catch((error) => {
console.error('保存关注关键词失败:', error)
this.$message.error('保存失败')
})
},
handleFilterChange() {
this.pagination.currentPage = 1
this.getmyList()
},
handleDateRangeChange() {
// 当日期范围选择完成后,自动触发搜索
this.pagination.currentPage = 1
this.getmyList()
}
}
}
</script>
<style scoped>
.coentent {
width: 100%;
height: 100%;
background: white;
}
.contents-area {
width: 100%;
margin-top: 20px;
}
.areas {
width: 97%;
margin: 0 auto;
}
.headers {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
flex-wrap: wrap;
gap: 16px;
padding-top: 18px;
}
.headers-left {
display: flex;
align-items: center;
gap: 20px;
}
.headers-name {
font-size: 15px;
color: #17192C;
}
.headers-right {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 16px;
}
.filter-item {
display: flex;
align-items: center;
gap: 8px;
font-size: 13px;
color: #6A6E8C;
}
.filter-label {
min-width: 70px;
}
.filter-select {
width: 140px;
}
.filter-date-picker {
width: 240px;
}
.filter-date-picker ::v-deep .el-input__inner {
border: 1px solid #ededed !important;
}
.filter-date-picker ::v-deep .el-input__inner:focus {
border-color: #DCDFE6;
}
.filter-date-picker ::v-deep .el-range-input {
border: none;
}
.search-input {
width: 220px;
}
.follow-btn {
background: #5165F7;
border-color: #5165F7;
}
.content-table {
background: #fff;
border-radius: 8px;
}
.content-title {
font-size: 14px;
font-weight: 600;
color: #17192C;
}
.content-summary {
font-size: 13px;
color: #6A6E8C;
margin-top: 6px;
line-height: 1.5;
}
.content-tags {
margin-top: 8px;
font-size: 12px;
color: #6A6E8C;
}
.tag-label {
margin-right: 6px;
}
.tag-item {
display: inline-block;
margin-right: 8px;
color: #5165F7;
}
.footer {
display: flex;
justify-content: flex-end;
margin-top: 20px;
}
.link-btn {
color: #5165F7;
padding: 0;
}
::v-deep .follow-row td {
color: #363636;
}
::v-deep .el-table__body tr:hover > td {
background-color: #F7F8FF !important;
}
.follow-detail-dialog ::v-deep .el-dialog {
border-radius: 12px;
}
.follow-detail-dialog ::v-deep .el-dialog__header {
padding: 20px 28px 12px;
border-bottom: none;
}
.detail-title {
font-size: 18px;
font-weight: 600;
color: #17192C;
text-align: center;
}
.detail-body {
padding: 0 28px 20px;
}
.detail-meta {
display: flex;
justify-content: center;
gap: 24px;
font-size: 12px;
color: #6A6E8C;
margin-bottom: 20px;
}
.detail-content {
font-size: 14px;
color: #363636;
line-height: 1.7;
margin-bottom: 24px;
}
.detail-content p {
margin: 0 0 16px;
}
.follow-setting-dialog ::v-deep .el-dialog {
border-radius: 12px;
}
.follow-setting-dialog ::v-deep .el-dialog__header {
padding: 20px 28px 12px;
border-bottom: none;
}
.follow-setting-dialog ::v-deep .el-dialog__body {
padding: 0 28px 24px;
}
.follow-setting-dialog ::v-deep .el-dialog__footer {
padding: 18px 28px 28px;
border-top: none;
}
.follow-setting-title {
font-size: 18px;
font-weight: 600;
color: #17192C;
text-align: center;
}
.follow-setting-section {
margin-top: 16px;
}
.follow-setting-label {
font-size: 14px;
font-weight: 600;
color: #363636;
margin-bottom: 12px;
}
.follow-setting-input ::v-deep textarea {
background: #F8F9FF;
min-height: 140px;
}
.follow-setting-note {
margin-top: 16px;
background: #F8F9FF;
border-radius: 8px;
padding: 12px 16px;
font-size: 12px;
color: #6A6E8C;
line-height: 1.6;
}
.detail-footer {
display: flex;
justify-content: center;
gap: 16px;
}
.submit-btn {
background: #5165F7;
border-color: #5165F7;
}
</style>

View File

@@ -0,0 +1,536 @@
<template>
<div>
<div class="coentent">
<div class="contents-area">
<div class="areas">
<div class="headers">
<div class="headers-left">
<div class="headers-name">地址管理</div>
</div>
<div class="headers-right">
<div class="filter-item">
<span class="filter-label">级别</span>
<el-select
v-model="levelFilter"
@change="handleFilterChange"
style="border: 1px solid #ededed;"
placeholder="全部"
size="small"
class="filter-select"
clearable>
<el-option
v-for="item in levelOptions"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</div>
<el-button type="primary" size="small" class="add-btn" @click="handleAdd">添加</el-button>
</div>
</div>
<div class="content-table">
<el-table
:data="tableData"
border
:header-cell-style="{ background: '#EDEFFE', color: '#363636', textAlign: 'center' }"
:cell-style="cellStyle"
style="width: 100%">
<el-table-column type="index" label="序号" width="70" align="center" :index="formatIndex"></el-table-column>
<el-table-column prop="name" label="官网名称" min-width="200" align="left"></el-table-column>
<el-table-column prop="level" label="单位级别" width="150" align="center"></el-table-column>
<el-table-column prop="phone" label="咨询电话" width="150" align="center"></el-table-column>
<el-table-column label="操作" width="240" align="center">
<template #default="scope">
<el-button type="text" class="link-btn" @click="handleGo(scope.row)">前往网址</el-button>
<el-button type="text" class="link-btn" @click="handleCopy(scope.row)">复制网址</el-button>
<el-button type="text" class="link-btn delete-btn" @click="handleDelete(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<div class="footer">
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="pagination.currentPage"
:page-sizes="[10, 20, 30, 50]"
:page-size="pagination.pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="pagination.total">
</el-pagination>
</div>
</div>
</div>
</div>
</div>
<!-- 添加/编辑弹框 -->
<el-dialog
:title="dialogTitle"
:visible.sync="dialogVisible"
width="800px"
:close-on-click-modal="false"
:destroy-on-close="true"
class="add-dialog">
<div class="content-areas" style="top: 5px;">
<div class="contents-left">
<span class="table-name">官网名称</span>
</div>
<div class="contents-right" style="border: none;">
<div class="rightss rightss1">
<el-input v-model="formData.name" placeholder="请输入内容" style="width: 100%;"></el-input>
</div>
<div class="contents-left">
<span class="table-name">官网地址</span>
</div>
<div class="rightss rightss3">
<el-input v-model="formData.url" placeholder="请输入内容" style="width: 100%;"></el-input>
</div>
</div>
</div>
<div class="content-areas" style="top: 1px;">
<div class="contents-left">
<span class="table-name">单位级别</span>
</div>
<div class="contents-right" style="border: none;">
<div class="rightss rightss1">
<el-select v-model="formData.level" placeholder="请选择单位级别" style="width: 100%;">
<el-option
v-for="item in levelSelectOptions"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</div>
<div class="contents-left">
<span class="table-name">咨询电话选填</span>
</div>
<div class="rightss rightss3">
<el-input v-model="formData.phone" placeholder="请输入内容" style="width: 100%;"></el-input>
</div>
</div>
</div>
<template #footer>
<div class="dialog-footer-custom">
<el-button type="primary" size="small" class="save-btn" @click="handleSubmit">保存</el-button>
<el-button size="small" @click="dialogVisible = false">取消</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script>
import { getGovList, addGov, deleteGov } from '@/api/Innovation/government'
export default {
data() {
return {
levelFilter: '',
levelOptions: [
{ value: 'all', label: '全部' },
{ value: '省级', label: '省级' },
{ value: '市级', label: '市级' },
{ value: '区县级', label: '区县级' }
],
// 单位级别下拉选项(用于表单,传数字给后台)
levelSelectOptions: [
{ value: 1, label: '省级' },
{ value: 2, label: '市级' },
{ value: 3, label: '区县级' }
],
tableData: [],
pagination: {
currentPage: 1,
pageSize: 10,
total: 0
},
dialogVisible: false,
dialogTitle: '网站添加',
formData: {
id: '',
name: '',
level: null, // 数字类型1省, 2市, 3区
phone: '',
url: ''
},
formRules: {
name: [
{ required: true, message: '请输入官网名称', trigger: 'blur' }
],
level: [
{ required: true, message: '请选择单位级别', trigger: 'change' }
],
phone: [
// 咨询电话为选填,不需要必填验证
],
url: [
{ required: true, message: '请输入官网地址', trigger: 'blur' }
]
}
}
},
computed: {
// 过滤掉 'all' 选项,用于表单选择
filteredLevelOptions() {
return this.levelOptions.filter(item => item.value !== 'all')
}
},
mounted() {
this.getList()
},
methods: {
// 获取列表数据
getList() {
// 将筛选的级别转换为数字(省级=1, 市级=2, 区县级=3
let levelParam = ''
if (this.levelFilter && this.levelFilter !== 'all') {
const levelMap = {
'省级': 1,
'市级': 2,
'区县级': 3
}
levelParam = levelMap[this.levelFilter] || ''
}
const params = {
page: this.pagination.currentPage,
limit: this.pagination.pageSize,
level: levelParam
}
getGovList(params).then((res) => {
if (res && res.code === 1 && res.data) {
this.pagination.total = res.data.total || 0
this.tableData = res.data.data || []
} else {
this.$message.error(res?.msg || '获取数据失败')
this.tableData = []
this.pagination.total = 0
}
}).catch((error) => {
console.error('获取列表数据失败:', error)
this.$message.error('获取数据失败')
this.tableData = []
this.pagination.total = 0
})
},
// 筛选变化
handleFilterChange() {
this.pagination.currentPage = 1
this.getList()
},
// 添加
handleAdd() {
this.dialogTitle = '网站添加'
this.formData = {
id: '',
name: '',
level: null, // 初始化为 null确保下拉框显示 placeholder
phone: '',
url: ''
}
this.dialogVisible = true
},
// 提交表单
handleSubmit() {
// 表单验证
if (!this.formData.name || !this.formData.name.trim()) {
this.$message.warning('请输入官网名称')
return
}
if (!this.formData.url || !this.formData.url.trim()) {
this.$message.warning('请输入官网地址')
return
}
if (!this.formData.level) {
this.$message.warning('请选择单位级别')
return
}
const params = {
name: this.formData.name.trim(),
url: this.formData.url.trim(),
level: this.formData.level, // 数字1省, 2市, 3区
phone: this.formData.phone ? this.formData.phone.trim() : '' // 选填
}
// 添加
addGov(params).then((res) => {
if (res && res.code === 1) {
this.$message.success('添加成功')
this.dialogVisible = false
this.getList()
} else {
this.$message.error(res?.msg || '添加失败')
}
}).catch((error) => {
console.error('添加失败:', error)
this.$message.error('添加失败')
})
},
// 前往网址
handleGo(row) {
const url = row.url || row.website_url || ''
if (url) {
// 确保URL格式正确如果没有协议前缀则添加 http://
let targetUrl = url.trim()
if (targetUrl && !targetUrl.match(/^https?:\/\//i)) {
targetUrl = 'http://' + targetUrl
}
// 在新标签页中打开
window.open(targetUrl, '_blank')
} else {
this.$message.warning('该官网地址不存在')
}
},
// 复制网址
handleCopy(row) {
// 获取列表中的链接地址字段
const url = row.url || row.website_url || ''
if (url && url.trim()) {
const urlToCopy = url.trim()
// 使用 Clipboard API 复制
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(urlToCopy).then(() => {
this.$message.success('复制成功')
}).catch(() => {
this.fallbackCopyTextToClipboard(urlToCopy)
})
} else {
this.fallbackCopyTextToClipboard(urlToCopy)
}
} else {
this.$message.warning('该官网地址不存在')
}
},
// 备用复制方法
fallbackCopyTextToClipboard(text) {
const textArea = document.createElement('textarea')
textArea.value = text
textArea.style.position = 'fixed'
textArea.style.left = '-999999px'
document.body.appendChild(textArea)
textArea.focus()
textArea.select()
try {
document.execCommand('copy')
this.$message.success('复制成功')
} catch (err) {
this.$message.error('复制失败')
}
document.body.removeChild(textArea)
},
// 删除
handleDelete(row) {
this.$confirm('确定要删除这条记录吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
// 调用删除接口
const params = {
id: row.id
}
deleteGov(params).then((res) => {
if (res && res.code === 1) {
this.$message.success('删除成功')
// 删除成功后刷新列表
this.getList()
} else {
this.$message.error(res?.msg || '删除失败')
}
}).catch((error) => {
console.error('删除失败:', error)
this.$message.error('删除失败')
})
}).catch(() => {
// 用户取消删除,不做任何操作
})
},
handleSizeChange(val) {
this.pagination.pageSize = val
this.pagination.currentPage = 1
this.getList()
},
handleCurrentChange(val) {
this.pagination.currentPage = val
this.getList()
},
formatIndex(index) {
return (this.pagination.currentPage - 1) * this.pagination.pageSize + index + 1
},
cellStyle({ column }) {
const leftAlignedProps = ['name']
return {
textAlign: leftAlignedProps.includes(column.property) ? 'left' : 'center',
color: '#363636'
}
}
}
}
</script>
<style scoped>
.coentent {
width: 100%;
height: 100%;
background: white;
}
.contents-area {
width: 100%;
margin-top: 20px;
}
.areas {
width: 97%;
margin: 0 auto;
}
.headers {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
flex-wrap: wrap;
gap: 16px;
padding-top: 18px;
}
.headers-left {
display: flex;
align-items: center;
gap: 20px;
}
.headers-name {
font-size: 15px;
color: #17192C;
}
.headers-right {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 16px;
}
.filter-item {
display: flex;
align-items: center;
gap: 8px;
font-size: 13px;
color: #6A6E8C;
}
.filter-label {
min-width: 70px;
}
.filter-select {
width: 140px;
}
.add-btn {
background: #5165F7;
border-color: #5165F7;
}
.content-table {
background: #fff;
border-radius: 8px;
}
.footer {
display: flex;
justify-content: flex-end;
margin-top: 20px;
}
.link-btn {
color: #5165F7;
padding: 0;
margin: 0 8px;
}
.delete-btn {
color: #F56C6C;
}
.dialog-footer-custom {
display: flex;
justify-content:center;
gap: 16px;
padding: 0;
}
.content-areas {
display: flex;
height: 50px;
flex-wrap: wrap;
}
.save-btn {
background: #5165F7;
border-color: #5165F7;
}
.add-form ::v-deep .el-form-item {
margin-bottom: 20px;
}
.add-dialog ::v-deep .el-dialog__header {
text-align: center;
padding: 20px 20px 20px;
background: #F7F7FA;
}
.add-dialog ::v-deep .el-dialog__title {
font-size: 16px;
font-weight: 600;
color: #17192C;
}
.rightss {
height: 100%;
border: 1px solid #DCE0FD;
width: 26%;
border-top: none;
padding-left: 20px;
}
.content-areas2 {
position: relative;
top: 1px;
}
.contents-right {
flex: 1;
border: 1px solid #DCE0FD;
line-height: 50px;
font-size: 14px;
color: #363636;
display: flex
}
.contents-left {
width: 20%;
border: 1px solid #DCE0FD;
background: #EDEFFE;
;
line-height: 50px;
font-size: 14px;
color: #363636;
padding-left: 20px;
}
.add-dialog ::v-deep .el-dialog__body {
padding: 20px;
}
.add-dialog ::v-deep .el-dialog__footer {
padding: 10px 20px 20px;
}
</style>

View File

@@ -0,0 +1,607 @@
<template>
<div>
<div class="coentent">
<div class="contents-area">
<div class="areas">
<div class="headers">
<div class="headers-left">
<div class="headers-name">内容类别</div>
</div>
<div class="headers-right">
<div class="filter-item">
<span class="filter-label">发布单位</span>
<el-select v-model="filters.publisher" @change="handleFilterChange" style="border: 1px solid #ededed;" placeholder="全部" size="small" class="filter-select">
<el-option v-for="item in publisherOptions" :key="item.value" :label="item.label" :value="item.value"></el-option>
</el-select>
</div>
<el-input
style="border: 1px solid #ededed;"
placeholder="搜索关键字"
v-model="filters.keyword"
class="search-input"
size="small"
clearable>
<el-button slot="append" icon="el-icon-search" @click="handleSearch">搜索</el-button>
</el-input>
</div>
</div>
<div class="content-table">
<el-table
:data="pagedData"
border
:header-cell-style="{ background: '#EDEFFE', color: '#363636', textAlign: 'center' }"
:cell-style="cellStyle"
:row-class-name="rowClassName"
style="width: 100%">
<el-table-column type="index" label="序号" width="70" align="center" :index="formatIndex"></el-table-column>
<el-table-column prop="title" label="内容" min-width="400">
<template #default="{ row }">
<div class="content-title">{{ row.title }}</div>
<div class="content-summary">{{ row.summary }}</div>
<div class="content-tags">
<span class="tag-label">涉及项</span>
<span class="tag-item" v-for="tag in row.tags" :key="tag">{{ tag }}</span>
</div>
</template>
</el-table-column>
<el-table-column prop="publisher" label="发布单位" min-width="180"></el-table-column>
<el-table-column prop="publishDate" label="发布日期" min-width="140"></el-table-column>
<el-table-column label="附件数量" width="110" align="center">
<template #default="{ row: item }">
{{ item.attachments?.length || 0 }}
</template>
</el-table-column>
<el-table-column label="操作" width="120" align="center">
<template #default="scope">
<el-button type="text" class="link-btn" @click="openDetail(scope.row)">详情</el-button>
</template>
</el-table-column>
</el-table>
<div class="footer">
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="pagination.currentPage"
:page-sizes="[10, 20, 30, 50]"
:page-size="pagination.pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="pagination.total">
</el-pagination>
</div>
</div>
</div>
</div>
</div>
<el-dialog
:visible.sync="detailDialogVisible"
width="840px"
class="follow-detail-dialog"
:close-on-click-modal="false"
:destroy-on-close="true">
<template #title>
<div class="detail-title">{{ detailData.title }}</div>
</template>
<div class="detail-body">
<div class="detail-meta">
<span>发布单位{{ detailData.publisher }}</span>
<span>发布时间{{ detailData.publishDate }}</span>
</div>
<div class="detail-content">
<p v-for="(paragraph, index) in detailData.content" :key="index">{{ paragraph }}</p>
</div>
<div class="detail-attachments" v-if="detailData.attachments?.length">
<div class="attachments-title">附件下载</div>
<el-table
:data="detailData.attachments"
border
size="small"
:header-cell-style="{ background: '#F0F2FF', color: '#363636', textAlign: 'left' }"
:cell-style="{ textAlign: 'left', color: '#363636' }">
<el-table-column prop="name" label="附件名称"></el-table-column>
<el-table-column label="操作" width="120" align="center">
<template #default>
<el-button type="text" class="link-btn">下载</el-button>
</template>
</el-table-column>
</el-table>
</div>
</div>
<template #footer>
<div class="detail-footer">
<el-button size="small" @click="detailDialogVisible = false">关闭</el-button>
</div>
</template>
</el-dialog>
<el-dialog
:visible.sync="followDialogVisible"
width="600px"
class="follow-setting-dialog"
:close-on-click-modal="false"
:destroy-on-close="true">
<template #title>
<div class="follow-setting-title">通知公告关注关键词设置</div>
</template>
<div class="follow-setting-section">
<div class="follow-setting-label">关键词设置</div>
<el-input
type="textarea"
v-model="followKeywords"
placeholder="请输入关注关键词,用“,”分组..."
class="follow-setting-input">
</el-input>
</div>
<div class="follow-setting-note">
<ol>
<li>请输入关注关键词,分组关键词数量不超过30个</li>
<li>设置关键词后系统将自动筛选最新的相关通知公告默认查找近一年的通知公告</li>
</ol>
</div>
<template #footer>
<div class="detail-footer">
<el-button type="primary" size="small" class="submit-btn" @click="submitFollowKeywords">保存提交</el-button>
<el-button size="small" @click="followDialogVisible = false">取消</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script>
import {myList} from '@/api/Innovation/follow'
export default {
data() {
return {
publish_unit:"",
filters: {
category: 'all',
publisher: 'all',
dateRange: [],
keyword: ''
},
categoryOptions: [
{ value: 'all', label: '全部' },
{ value: 'notification', label: '通知公告' },
{ value: 'policy', label: '政策发布' }
],
publisherOptions: [
{ value: 'all', label: '全部' },
{ value: '贵州省科学技术厅', label: '贵州省科学技术厅' },
{ value: '贵州省工业和信息化厅', label: '贵州省工业和信息化厅' }
],
tableData: [],
pagination: {
currentPage: 1,
pageSize: 10,
total: 0
},
start_time:"",
end_time:"",
keyword:"",
detailDialogVisible: false,
detailData: {
title: '',
publisher: '',
publishDate: '',
content: [],
attachments: []
},
page:1,
limit:10,
followDialogVisible: false,
followKeywords: ''
}
},
computed: {
pagedData() {
return this.tableData
}
},
mounted(){
this.getmyList()
},
methods: {
//列表数据
getmyList(){
// 处理筛选条件
let publish_unit = this.filters.publisher !== 'all' ? this.filters.publisher : ''
let keyword = this.filters.keyword || ''
// 处理类别筛选parent_id
let parent_id = ''
if (this.filters.category === 'notification') {
parent_id = '1' // 通知公告
} else if (this.filters.category === 'policy') {
parent_id = '2' // 政策发布
}
// 处理时间筛选(日期范围)
let start_time = ''
let end_time = ''
if (this.filters.dateRange && this.filters.dateRange.length === 2) {
start_time = this.filters.dateRange[0]
end_time = this.filters.dateRange[1]
}
let parm = {
publish_unit: publish_unit,
start_time: start_time,
end_time: end_time,
keyword: keyword,
page: this.pagination.currentPage,
limit: this.pagination.pageSize
}
// 如果选择了类别,添加 parent_id 参数
if (parent_id) {
parm.parent_id = parent_id
}
myList(parm).then((res) => {
if (res && res.code === 1 && res.data) {
// 更新总数
this.pagination.total = res.data.total || 0
// 处理返回的数据
const dataList = res.data.data || []
this.tableData = dataList.map(item => {
// 解析附件
let attachments = []
if (item.file_address) {
try {
// 尝试解析 file_address JSON 字符串
const fileAddress = JSON.parse(item.file_address)
if (Array.isArray(fileAddress)) {
attachments = fileAddress.map(file => ({
name: file.name || file.destination || '附件',
url: file.url || file.destination || '#'
}))
}
} catch (e) {
// 如果解析失败,使用 file_num 作为附件数量
if (item.file_num > 0) {
attachments = Array(item.file_num).fill(null).map((_, index) => ({
name: `附件${index + 1}`,
url: '#'
}))
}
}
} else if (item.file_num > 0) {
attachments = Array(item.file_num).fill(null).map((_, index) => ({
name: `附件${index + 1}`,
url: '#'
}))
}
// 处理标签(从 keyword 字段)
let tags = []
if (item.keyword) {
tags = item.keyword.split(/[,]/).filter(tag => tag.trim())
}
// 格式化日期
let publishDate = item.article_time || item.create_time || ''
if (publishDate) {
publishDate = this.formatDisplayDate(publishDate)
}
return {
id: item.id,
title: item.title || '',
summary: item.abstract || '',
tags: tags,
publisher: item.publish_unit || '',
publishDate: publishDate,
attachments: attachments,
category: item.parent_id === '1' ? 'notification' : (item.parent_id === '2' ? 'policy' : 'notification'),
content: item.abstract ? [item.abstract] : [],
url: item.url || '',
content_url: item.content_url || '',
file_address: item.file_address || '',
keyword: item.keyword || ''
}
})
} else {
this.$message.error(res?.msg || '获取数据失败')
this.tableData = []
this.pagination.total = 0
}
}).catch((error) => {
console.error('获取列表数据失败:', error)
this.$message.error('获取数据失败')
this.tableData = []
this.pagination.total = 0
})
},
// 格式化显示日期
formatDisplayDate(dateStr) {
if (!dateStr) return ''
const date = new Date(dateStr)
const year = date.getFullYear()
const month = String(date.getMonth() + 1).padStart(2, '0')
const day = String(date.getDate()).padStart(2, '0')
return `${year}${month}${day}`
},
handleSearch() {
this.pagination.currentPage = 1
this.getmyList()
},
handleSizeChange(val) {
this.pagination.pageSize = val
this.pagination.currentPage = 1
this.getmyList()
},
handleCurrentChange(val) {
this.pagination.currentPage = val
this.getmyList()
},
formatIndex(index) {
return (this.pagination.currentPage - 1) * this.pagination.pageSize + index + 1
},
rowClassName() {
return 'follow-row'
},
cellStyle({ column }) {
const leftAlignedProps = ['title', 'publisher', 'publishDate']
return {
textAlign: leftAlignedProps.includes(column.property) ? 'left' : 'center',
color: '#363636'
}
},
openDetail(row) {
this.detailData = {
title: row.title,
publisher: row.publisher,
publishDate: row.publishDate,
content: row.content || [],
attachments: row.attachments || []
}
this.detailDialogVisible = true
},
openFollowSetting() {
this.followKeywords = this.filters.keyword || ''
this.followDialogVisible = true
},
submitFollowKeywords() {
this.$message.success('关注关键词已保存')
this.followDialogVisible = false
},
handleFilterChange() {
this.pagination.currentPage = 1
this.getmyList()
}
}
}
</script>
<style scoped>
.coentent {
width: 100%;
height: 100%;
background: white;
}
.contents-area {
width: 100%;
margin-top: 20px;
}
.areas {
width: 97%;
margin: 0 auto;
}
.headers {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
flex-wrap: wrap;
gap: 16px;
padding-top: 18px;
}
.headers-left {
display: flex;
align-items: center;
gap: 20px;
}
.headers-name {
font-size: 15px;
color: #17192C;
}
.headers-right {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 16px;
}
.filter-item {
display: flex;
align-items: center;
gap: 8px;
font-size: 13px;
color: #6A6E8C;
}
.filter-label {
min-width: 70px;
}
.filter-select {
width: 140px;
}
.search-input {
width: 220px;
}
.follow-btn {
background: #5165F7;
border-color: #5165F7;
}
.content-table {
background: #fff;
border-radius: 8px;
}
.content-title {
font-size: 14px;
font-weight: 600;
color: #17192C;
}
.content-summary {
font-size: 13px;
color: #6A6E8C;
margin-top: 6px;
line-height: 1.5;
}
.content-tags {
margin-top: 8px;
font-size: 12px;
color: #6A6E8C;
}
.tag-label {
margin-right: 6px;
}
.tag-item {
display: inline-block;
margin-right: 8px;
color: #5165F7;
}
.footer {
display: flex;
justify-content: flex-end;
margin-top: 20px;
}
.link-btn {
color: #5165F7;
padding: 0;
}
::v-deep .follow-row td {
color: #363636;
}
::v-deep .el-table__body tr:hover > td {
background-color: #F7F8FF !important;
}
.follow-detail-dialog ::v-deep .el-dialog {
border-radius: 12px;
}
.follow-detail-dialog ::v-deep .el-dialog__header {
padding: 20px 28px 12px;
border-bottom: none;
}
.detail-title {
font-size: 18px;
font-weight: 600;
color: #17192C;
text-align: center;
}
.detail-body {
padding: 0 28px 20px;
}
.detail-meta {
display: flex;
justify-content: center;
gap: 24px;
font-size: 12px;
color: #6A6E8C;
margin-bottom: 20px;
}
.detail-content {
font-size: 14px;
color: #363636;
line-height: 1.7;
margin-bottom: 24px;
}
.detail-content p {
margin: 0 0 16px;
}
.follow-setting-dialog ::v-deep .el-dialog {
border-radius: 12px;
}
.follow-setting-dialog ::v-deep .el-dialog__header {
padding: 20px 28px 12px;
border-bottom: none;
}
.follow-setting-dialog ::v-deep .el-dialog__body {
padding: 0 28px 24px;
}
.follow-setting-dialog ::v-deep .el-dialog__footer {
padding: 18px 28px 28px;
border-top: none;
}
.follow-setting-title {
font-size: 18px;
font-weight: 600;
color: #17192C;
text-align: center;
}
.follow-setting-section {
margin-top: 16px;
}
.follow-setting-label {
font-size: 14px;
font-weight: 600;
color: #363636;
margin-bottom: 12px;
}
.follow-setting-input ::v-deep textarea {
background: #F8F9FF;
min-height: 140px;
}
.follow-setting-note {
margin-top: 16px;
background: #F8F9FF;
border-radius: 8px;
padding: 12px 16px;
font-size: 12px;
color: #6A6E8C;
line-height: 1.6;
}
.detail-footer {
display: flex;
justify-content: center;
gap: 16px;
}
.submit-btn {
background: #5165F7;
border-color: #5165F7;
}
</style>

169
src/views/Layout.vue Normal file
View File

@@ -0,0 +1,169 @@
<template>
<div>
<div class="app-container">
<headers :rightDate="rightDate" @menu-click="handleMenuClick"></headers>
<div class="contents">
<div class="sidebar-wrapper" v-if="!hideSidebar">
<sidebar @headerDate="headerDate"></sidebar>
</div>
<div class="content" :class="{ 'full-width': hideSidebar }">
<router-view></router-view>
</div>
</div>
</div>
</div>
</template>
<script>
import headers from '@/components/header'
import sidebar from '@/components/sidebar'
export default {
components: {
headers,
sidebar
},
data() {
return {
rightDate: JSON.parse(localStorage.getItem('rightDateKey')) || []
}
},
computed: {
// 判断是否隐藏侧边栏
hideSidebar() {
const hideRoutes = [
'/home/salesperformanceEdint'
]
return hideRoutes.includes(this.$route.path)
}
},
mounted() {
// 确保路由正常加载
console.log('Layout mounted, current route:', this.$route.path)
// 初始化头部数据
this.updateHeaderData()
},
watch: {
$route(to) {
// 路由变化时更新头部数据
this.updateHeaderData()
}
},
methods: {
// 根据路由更新头部数据
updateHeaderData() {
const currentPath = this.$route.path
if (currentPath === '/home/message') {
// 消息中心页面,保存当前头部数据(如果存在),然后设置为"消息中心"
const currentRightDate = this.rightDate && this.rightDate.length > 0 ? this.rightDate : []
if (currentRightDate.length > 0 && currentRightDate[0].name !== '消息中心') {
localStorage.setItem('rightDateKeyBackup', JSON.stringify(currentRightDate))
}
this.rightDate = [{ name: '消息中心' }]
localStorage.setItem('rightDateKey', JSON.stringify(this.rightDate))
} else {
// 其他页面,从 localStorage 恢复或使用默认值
// 优先使用备份数据(如果存在),否则使用保存的数据
const backupRightDate = localStorage.getItem('rightDateKeyBackup')
const savedRightDate = localStorage.getItem('rightDateKey')
if (backupRightDate) {
this.rightDate = JSON.parse(backupRightDate)
localStorage.setItem('rightDateKey', backupRightDate)
localStorage.removeItem('rightDateKeyBackup')
} else if (savedRightDate) {
const parsed = JSON.parse(savedRightDate)
// 如果不是消息中心的数据,就使用
if (!parsed || parsed.length === 0 || parsed[0].name !== '消息中心') {
this.rightDate = parsed
}
}
}
},
// 处理菜单点击事件
handleMenuClick(item) {
console.log('获取到这个路由数据', item,JSON.parse(localStorage.getItem('rightDateKey')));
if (item.route) {
// 如果路由路径不是以 /home 开头,则添加 /home 前缀
let routePath = item.route
if (!routePath.startsWith('/home') && routePath !== '/') {
routePath = '/home' + (routePath.startsWith('/') ? routePath : '/' + routePath)
}
if (this.$route.path !== routePath) {
this.$router.push(routePath);
}
}
},
//获取头部的数据
headerDate(e) {
// 如果当前在消息中心页面,不更新头部数据
if (this.$route.path === '/home/message') {
return
}
this.rightDate = e.children
// console.log('获取头部数据',this.rightDate)
localStorage.setItem('rightDateKey', JSON.stringify(this.rightDate))
if (e.route) {
// 如果路由路径不是以 /home 开头,则添加 /home 前缀
let routePath = e.route
if (!routePath.startsWith('/home') && routePath !== '/') {
routePath = '/home' + (routePath.startsWith('/') ? routePath : '/' + routePath)
}
if (this.$route.path !== routePath) {
this.$router.push(routePath);
}
}
}
}
}
</script>
<style scope>
.app-container {
min-height: 100vh; /* 确保容器至少占满整个视口 */
display: flex;
flex-direction: column; /* 垂直排列 */
}
.contents {
display: flex;
flex: 1; /* 填充剩余空间 */
align-items: stretch;
gap: 1%;
box-sizing: border-box;
}
.sidebar-wrapper {
width: 218px;
background: white;
/* margin-top: 20px; */
box-sizing: border-box;
display: flex;
flex-direction: column;
overflow: hidden;
}
.sidebar-wrapper > * {
flex: 1;
}
.content {
flex: 1;
/* background: white; */
margin-top: 0px;
border-radius: 10px;
overflow-x: clip;
box-sizing: border-box;
min-width: 0;
/* padding-right: 8px; */
}
.content.full-width {
width: 100%;
}
</style>

View File

@@ -0,0 +1,665 @@
<template>
<div>
<div class="coentent">
<div class="contents-area">
<div class="areas">
<div v-if="active==0">
<div class="headers">
<div class="headers-name">我的审批列表</div>
<div>
<el-form :inline="true" :model="form" class="demo-form-inline">
<el-form-item label="收入类型" size="small" style="position: relative;top: -3px;">
<el-select v-model="form.revenueType" placeholder="请选择" class="selects">
<el-option v-for="item in revenueTypeOptions" :key="item.value" :label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="时间筛选" size="small" style="position: relative;top: -3px;">
<el-select v-model="form.year" placeholder="请选择" class="selects">
<el-option v-for="item in yearOptions" :key="item.value" :label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item size="small" style="position: relative;top: -3px;">
<el-select v-model="form.quarter" placeholder="请选择" class="selects">
<el-option v-for="item in quarterOptions" :key="item.value" :label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
</el-form>
</div>
</div>
<div class="content-table">
<el-table
:data="tableData"
:header-cell-style="{ background: '#EDEFFE', color: '#363636', textAlign: 'center' }"
border
style="width: 100%">
<el-table-column prop="serial" label="序号" width="80" align="center"></el-table-column>
<el-table-column prop="productName" label="审批模块" align="center"></el-table-column>
<el-table-column prop="isMainProduct" label="提交内容" width="120" align="center">
<template slot-scope="scope">
<span>{{ scope.row.isMainProduct }}</span>
</template>
</el-table-column>
<el-table-column prop="revenueType" label="提交时间" width="150" align="center">
<template slot-scope="scope">
<span>{{ scope.row.revenueType }}</span>
</template>
</el-table-column>
<el-table-column prop="salesRevenue" label="提交人" align="center">
<template slot-scope="scope">
<span>{{ formatCurrency(scope.row.salesRevenue) }}</span>
</template>
</el-table-column>
<el-table-column prop="salesRevenue" label="审核状态" align="center">
<template slot-scope="scope">
<span>{{ formatCurrency(scope.row.salesRevenue) }}</span>
</template>
</el-table-column>
<el-table-column fixed="right" label="操作" align="center" width="150">
<template slot-scope="scope">
<el-button @click="handleHomepage(scope.row)" type="text" size="small" style="color: #5165f7;">查看</el-button>
</template>
</el-table-column>
</el-table>
<div class="footer">
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="currentPage"
:page-sizes="[100, 200, 300, 400]"
:page-size="100"
layout="total, sizes, prev, pager, next, jumper"
:total="400">
</el-pagination>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
active: 0,
currentPage: 1,
dialogVisible: false,
form: {
revenueType: '全部',
year: '2025',
quarter: '第一季度'
},
productForm: {
productName: '',
isMainProduct: '',
revenueType: '技术服务收入',
technologySource: '',
technologyField: '电子信息',
technologyFieldDetail: '网络应用技术'
},
productFormRules: {
productName: [
{ required: true, message: '请输入产品(服务)名称', trigger: 'blur' }
],
isMainProduct: [
{ required: true, message: '请选择是否主要产品', trigger: 'change' }
],
revenueType: [
{ required: true, message: '请选择收入类型', trigger: 'change' }
]
},
revenueTypeOptions: [
{
value: '全部',
label: '全部'
},
{
value: '产品收入',
label: '产品收入'
},
{
value: '技术转让收入',
label: '技术转让收入'
}
],
yearOptions: [
{
value: '2023',
label: '2023'
},
{
value: '2024',
label: '2024'
},
{
value: '2025',
label: '2025'
},
{
value: '2026',
label: '2026'
}
],
quarterOptions: [
{
value: '第一季度',
label: '第一季度'
},
{
value: '第二季度',
label: '第二季度'
},
{
value: '第三季度',
label: '第三季度'
},
{
value: '第四季度',
label: '第四季度'
}
],
dialogRevenueTypeOptions: [
{
value: '产品收入',
label: '产品收入'
},
{
value: '技术转让收入',
label: '技术转让收入'
},
{
value: '技术服务收入',
label: '技术服务收入'
}
],
technologySourceOptions: [
{
value: '计算机产品及其网络应用技术',
label: '计算机产品及其网络应用技术'
},
{
value: '自主开发',
label: '自主开发'
},
{
value: '合作开发',
label: '合作开发'
},
{
value: '引进技术',
label: '引进技术'
}
],
technologyFieldOptions: [
{
value: '电子信息',
label: '电子信息'
},
{
value: '生物与新医药',
label: '生物与新医药'
},
{
value: '航空航天',
label: '航空航天'
},
{
value: '新材料',
label: '新材料'
},
{
value: '高技术服务',
label: '高技术服务'
},
{
value: '新能源与节能',
label: '新能源与节能'
},
{
value: '资源与环境',
label: '资源与环境'
},
{
value: '先进制造与自动化',
label: '先进制造与自动化'
}
],
technologyFieldDetailOptions: [
{
value: '网络应用技术',
label: '网络应用技术'
},
{
value: '计算机软件技术',
label: '计算机软件技术'
},
{
value: '通信技术',
label: '通信技术'
},
{
value: '其他',
label: '其他'
}
],
tableData: [
{
serial: 1,
productName: '智慧收费产品',
isMainProduct: '是',
revenueType: '产品收入',
salesRevenue: 1600.00
},
{
serial: 2,
productName: '智慧照明产品',
isMainProduct: '否',
revenueType: '产品收入',
salesRevenue: 1600.00
},
{
serial: 3,
productName: '高速公路机电系统建管养一体化服务',
isMainProduct: '否',
revenueType: '技术转让收入',
salesRevenue: 1600.00
},
{
serial: 4,
productName: '隧道智慧管控运维系统及服务',
isMainProduct: '否',
revenueType: '技术转让收入',
salesRevenue: 0
},
{
serial: 5,
productName: '交通行业省级视频云联网产品及服务',
isMainProduct: '否',
revenueType: '技术转让收入',
salesRevenue: 0
}
]
}
},
methods: {
formatCurrency(value) {
if (value === 0 || value === '0') {
return '0'
}
return value.toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 })
},
handleHomepage(row) {
this.$router.push('/myreviewSee')
// 跳转到产品主页
},
handleDelete(row) {
this.$confirm('确定要删除该产品吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
console.log('删除', row)
// 处理删除逻辑
this.$message({
type: 'success',
message: '删除成功!'
})
}).catch(() => {
this.$message({
type: 'info',
message: '已取消删除'
})
})
},
btnAdd() {
this.dialogVisible = true
// 重置表单
this.productForm = {
productName: '',
isMainProduct: '',
revenueType: '技术服务收入',
technologySource: '',
technologyField: '电子信息',
technologyFieldDetail: '网络应用技术'
}
// 清除表单验证
if (this.$refs.productForm) {
this.$refs.productForm.clearValidate()
}
},
handleSave() {
this.$refs.productForm.validate((valid) => {
if (valid) {
console.log('保存产品', this.productForm)
// 处理保存逻辑
this.$message({
type: 'success',
message: '保存成功!'
})
this.dialogVisible = false
// 这里可以添加保存后的逻辑,比如刷新列表
} else {
console.log('表单验证失败')
return false
}
})
},
handleCancel() {
this.dialogVisible = false
// 重置表单
this.productForm = {
productName: '',
isMainProduct: '',
revenueType: '技术服务收入',
technologySource: '',
technologyField: '电子信息',
technologyFieldDetail: '网络应用技术'
}
if (this.$refs.productForm) {
this.$refs.productForm.clearValidate()
}
},
handleSizeChange() {
// 处理分页大小变化
},
handleCurrentChange() {
// 处理当前页变化
}
}
}
</script>
<style>
.el-tooltip__popper.is-dark {
color: #F04B4B !important;
background: #FCF1EB !important;
}
.el-tooltip__popper .popper__arrow {
border-top-color: #FCF1EB !important;
}
.el-tooltip__popper .popper__arrow::after {
border-top-color: #FCF1EB !important;
}
.el-tooltip__popper[x-placement^='bottom'] .popper__arrow {
border-bottom-color: #FCF1EB !important;
}
.el-tooltip__popper[x-placement^='left'] .popper__arrow {
border-left-color: #FCF1EB !important;
}
.el-tooltip__popper[x-placement^='right'] .popper__arrow {
border-right-color: #FCF1EB !important;
}
</style>
<style scoped>
.areas {
padding-bottom: 15px;
width: 97%;
margin: 0 auto;
margin-top: 12px;
padding-top: 20px;
}
.active {
color: #5165f7 !important;
}
.heng {
width: 20px;
height: 6px;
background: #5165f7;
margin: 0 auto;
margin-top: 6px;
}
.header-table {
cursor: pointer;
}
.contentss-header {
width: 100%;
display: flex;
justify-content: space-between;
width: 150px;
}
.contentss {
width: 97%;
margin: 0 auto;
padding-top: 12px;
}
.contents-area {
width: 100%;
background: white;
margin-top: 20px;
}
.header-title {
position: relative;
top: 20px;
left: 25px;
}
.numbers {
position: relative;
top: -7px;
color: #2AB95F;
}
.number-name2 {
margin-top: 8px;
font-size: 14px;
color: #979BBC;
}
.number-name {
font-weight: bold;
font-size: 25px;
color: #17192C;
}
.header-names {
display: flex;
width: 82%;
justify-content: space-between;
margin: 0 auto;
padding-top: 20px;
}
.header-area {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
width: 97%;
margin: 0 auto;
}
.content-header {
width: 100%;
background: white;
padding-bottom: 22px;
}
.footer {
display: flex;
justify-content: end;
margin-top: 20px;
}
.tianjia {
position: relative;
top: -9px;
background-color: #5065F6;
}
.tianjia2 {
position: relative;
top: -9px;
background-color: #EDEFFE;
color: #5065F6;
}
::v-deep .el-table thead {
background-color: #EDEFFE !important;
color: #363636 !important;
}
::v-deep .el-table__header th {
background-color: #EDEFFE !important;
color: #363636 !important;
}
.formitem {
position: relative;
top: -5px;
}
::deep .el-form-item__label {
font-size: 15px !important;
}
.selects {
width: 100px;
border: 1px solid #3333;
}
.headers-name {
font-size: 15px;
position: relative;
top: 14px;
}
.headers {
display: flex;
justify-content: space-between;
}
::v-deep .el-table__body tr:hover > td {
background-color: transparent !important;
}
::v-deep .el-table__body tr.el-table__row--striped td {
background-color: transparent;
}
/* 产品对话框样式 */
.product-dialog ::v-deep .el-dialog__header {
padding: 20px 20px 10px;
border-bottom: 1px solid #EBEEF5;
text-align: center;
}
.product-dialog ::v-deep .el-dialog__title {
font-size: 16px;
font-weight: bold;
color: #303133;
}
.product-dialog ::v-deep .el-dialog__body {
padding: 20px;
}
.product-dialog ::v-deep .el-form-item__label {
font-size: 14px;
color: #606266;
}
.product-dialog .dialog-footer {
text-align: center;
padding-top: 10px;
}
.product-dialog .dialog-footer .el-button {
margin: 0 10px;
}
.content-areas{
display: flex;
height: 50px;
flex-wrap: wrap;
margin-top: -1px;
}
.contents-left{
width: 30%;
border: 1px solid #DCE0FD;
background: #EDEFFE;
line-height: 50px;
font-size: 14px;
color: #363636;
display: flex;
align-items: center;
}
.contents-right{
flex: 1;
border: 1px solid #DCE0FD;
border-left: none;
line-height: 50px;
font-size: 14px;
color: #363636;
display: flex;
align-items: center;
position: relative;
}
.contents-right:last-child {
border-right: 1px solid #DCE0FD;
}
.content-areas2{
position: relative;
top: -1px;
}
.rightss{
height: 100%;
border: 1px solid #DCE0FD;
border-top: none;
border-bottom: none;
width: 100%;
display: flex;
align-items: center;
flex: 1;
}
.rightss1{
border-left: none !important;
border-right: 1px solid #DCE0FD !important;
}
.rightss2{
background: #EDEFFE;
border-left: 1px solid #DCE0FD;
border-right: 1px solid #DCE0FD;
width: auto;
min-width: 120px;
flex: 0 0 auto;
justify-content: center;
}
.rightss3{
border-left: none !important;
border-right: none !important;
flex: 1;
}
.rightss-full{
border-left: none !important;
border-right: 1px solid #DCE0FD !important;
flex: 1;
width: 100%;
min-width: 0;
display: flex;
align-items: center;
}
.table-name{
margin-left: 20px;
}
</style>

View File

@@ -0,0 +1,933 @@
<template>
<div>
<div class="headers">
<div class="headers-left">
<div class="imgs">
</div>
<div class="img-right">
<div class="name-title">微育科技</div>
<div class="right-name">数智科创 · 通达未来 </div>
</div>
</div>
<div class="headers-right">
<div class="rights">
<div class="rights-names" @click="btnShang">
<span>上一级 &lt; </span> <span style="color:#3333;">主页</span>
</div>
</div>
</div>
</div>
<div class="contents">
<div class="content-left">
<div class="content-lefts">
<div class="leftss">
<div class="leftss-header">
<div>高速公路管道与光缆</div>
<div @click="btnEdint">
<el-button size="small" type="danger" plain @click="closeguan">删除</el-button>
<el-button size="small" style="background-color: #5165f7;color:white;">编辑</el-button>
</div>
</div>
<div class="approval-flow">
<div class="table-header">
<div>
<div class="shu"></div> <span class="times"> 审核流 </span>
</div>
</div>
<div class="flow-wrapper">
<div
v-for="(step, index) in approvalSteps"
:key="step.label"
class="flow-item-container"
:class="{ 'is-last': index === approvalSteps.length - 1 }">
<div class="flow-node" :class="step.state">
{{ step.label }}
</div>
<div
v-if="index < approvalSteps.length - 1"
class="flow-connector"
:class="{ complete: step.state === 'done' }">
</div>
</div>
</div>
</div>
<div class="table-area">
<div class="table-header">
<div>
<div class="shu"></div> <span class="times"> 提交信息 </span>
</div>
</div>
</div>
</div>
<div class="content-table">
<div class="content-areas">
<div class="contents-left">
<span style="margin-left: 20px;">专利号</span>
</div>
<div class="contents-right">
<span style="margin-left: 20px;">ZL202311316235.7</span>
</div>
<div class="contents-left">
<span style="margin-left: 20px;">专利号</span>
</div>
<div class="contents-right">
<span style="margin-left: 20px;">ZL202311316235.7</span>
</div>
</div>
<div class="content-areas content-areas2">
<div class="contents-left">
<span class="table-name">授权公告号</span>
</div>
<div class="contents-right">
<div class="rightss rightss1"><span class="table-name">CN117056866B</span></div>
<div class="rightss rightss2"><span class="table-name">申请专利日</span></div>
<div class="rightss rightss3"><span class="table-name">2023-11-14</span></div>
</div>
</div>
<div class="content-areas content-areas2" style="top: 4px;">
<div class="contents-left" style="border-top: none;">
<span class="table-name">授权公告日</span>
</div>
<div class="contents-right" style="border: none;">
<div class="rightss rightss1"><span class="table-name">
2023-11-14
</span></div>
<div class="rightss rightss2" style="border-top: none;"><span
class="table-name">获得方式</span></div>
<div class="rightss rightss3"><span class="table-name">
自主研发
</span></div>
</div>
</div>
<div class="content-areas" style="position: relative;top: 5px;">
<div class="contents-left">
<span style="margin-left: 20px;">转让方</span>
</div>
<div class="contents-right" style="border-top: none;">
<span style="margin-left: 20px;">单位名称</span>
</div>
</div>
<div class="content-areas" style="position: relative;top: 5px;">
<div class="contents-left">
<span style="margin-left: 20px;">专利权人</span>
</div>
<div class="contents-right" style="border-top: none;">
<span style="margin-left: 20px;">xxxxxxx</span>
</div>
</div>
<div class="content-areas" style="position: relative;top: 5px;">
<div class="contents-left">
<span style="margin-left: 20px;">专利权人</span>
</div>
<div class="contents-right" style="border-top: none;">
<span style="margin-left: 20px;">xxxxxxx</span>
</div>
</div>
<div class="content-areas" style="position: relative;top: 5px;">
<div class="contents-left">
<span style="margin-left: 20px;">发明人</span>
</div>
<div class="contents-right" style="border-top: none;">
<span style="margin-left: 20px;">xxxxxxx</span>
</div>
</div>
<div class="content-areas" style="position: relative;top: 5px;">
<div class="contents-left">
<span style="margin-left: 20px;">地址</span>
</div>
<div class="contents-right" style="border-top: none;">
<span style="margin-left: 20px;">xxxxxxx</span>
</div>
</div>
<div class="content-areas" style="position: relative;top: 5px;">
<div class="contents-left">
<span style="margin-left: 20px;">下年度年费缴纳日期</span>
</div>
<div class="contents-right" style="border-top: none;">
<span style="margin-left: 20px;">2023-11-14</span>
</div>
<div class="contents-left">
<span style="margin-left: 20px;">年费缴纳情况</span>
</div>
<div class="contents-right" style="border-top: none;">
<span style="margin-left: 20px;">已缴纳</span>
</div>
</div>
</div>
</div>
</div>
<div class="content-right">
<div class="leftss-header right-header">
<div class="header-area">
<div class="area-name" v-for="(item, index) in listDate" :key="index" @click="btnNmae(index)"
:class="{ 'active': active == index }">
{{ item.name }}
</div>
</div>
<div> <el-button size="small" style="color:#5165f7;">
<i class="el-icon-download"></i> 下载</el-button>
</div>
</div>
<div class="right-area"></div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
active: 0,
listDate: [
{
name: '提交相关附件'
},
],
value1: "",
yuanright: 0,
tables: [
{
name: '有效'
},
{
name: '无效'
},
],
shu: 0,
lastActiveKey: 'headerActiveIndex',
tableData: [
{
date: "其中",
name: "",
address: "",
children: [
{ date: "2024", name: "年度审计报告及财务情况说明书", address: "8000" },
{ date: "2025", name: "年度审计报告及财务情况说明书", address: "7500" },
],
},
{ date: "其他项目", name: "5000", address: "4000" },
],
tableData2: [
{ date: "2025", name: "年度审计报告及财务情况说明书", address: "7500" },
],
approvalSteps: [
{ label: '提交', state: 'done' },
{ label: '已通过', state: 'done' },
{ label: '审核中', state: 'processing' },
{ label: '-', state: 'pending' }
]
}
},
created() {
},
watch: {
},
methods: {
//取消
closeguan() {
},
btnNmae(e) {
this.active = e
},
//切换时效性
btnYuan(e) {
this.yuanright = e
},
//编辑跳转
btnEdint() {
this.$router.push('/hetongmingxin')
},
btnShang() {
this.$router.go(-1)
}
}
}
</script>
<style>
.el-tooltip__popper.is-dark {
color: #F04B4B !important;
background: #FCF1EB !important;
}
.el-tooltip__popper .popper__arrow {
border-top-color: #FCF1EB !important;
/* 上方箭头 */
}
.el-tooltip__popper .popper__arrow::after {
border-top-color: #FCF1EB !important;
}
/* 其他方向的箭头(按需添加) */
.el-tooltip__popper[x-placement^='bottom'] .popper__arrow {
border-bottom-color: #FCF1EB !important;
}
.el-tooltip__popper[x-placement^='left'] .popper__arrow {
border-left-color: #FCF1EB !important;
}
.el-tooltip__popper[x-placement^='right'] .popper__arrow {
border-right-color: #FCF1EB !important;
}
</style>
<style scoped>
.tabless{
width: 90%;
margin: 0 auto;
margin-top: 30px;
}
.area-name {
margin-left: 30px;
cursor: pointer;
}
.active {
border-bottom: 3px solid #5165f7;
height: 45px;
}
.header-area {
display: flex;
position: relative;
left: -30px;
}
.rightss3 {
border-right: none;
border-left: none;
}
.table-name {
margin-left: 20px;
}
.rightss2 {
background: #EDEFFE;
}
.rightss1 {
border-left: none !important;
border-right: none !important;
}
.rightss {
height: 100%;
border: 1px solid #DCE0FD;
width: 100%;
border-top: none;
}
.content-areas2 {
position: relative;
top: 1px;
}
.contents-right {
flex: 1;
border: 1px solid #DCE0FD;
line-height: 50px;
font-size: 14px;
color: #363636;
display: flex
}
.contents-left {
width: 30%;
border: 1px solid #DCE0FD;
background: #EDEFFE;
;
line-height: 50px;
font-size: 14px;
color: #363636;
}
.content-areas {
display: flex;
height: 50px;
flex-wrap: wrap;
}
.tab-area {
margin-top: 24px;
}
.approval-flow {
width: 96%;
margin: -12px auto 20px;
padding: 20px 20px 0;
background: #ffffff;
border-radius: 12px;
}
.approval-flow .table-header {
margin-bottom: 12px;
}
.flow-wrapper {
display: flex;
align-items: center;
flex-wrap: nowrap;
margin-top: 24px;
}
.flow-item-container {
display: flex;
align-items: center;
flex: 1;
}
.flow-item-container.is-last .flow-connector {
display: none;
}
.flow-node {
padding: 6px 20px;
border-radius: 20px;
border: 1px solid #d5daf5;
background: #f8f9ff;
color: #8a8faf;
font-size: 14px;
line-height: 20px;
white-space: nowrap;
}
.flow-node.done {
border-color: #5165f7;
background: rgba(81, 101, 247, 0.08);
color: #5165f7;
box-shadow: 0 0 0 1px rgba(81, 101, 247, 0.2);
}
.flow-node.processing {
border-color: #e2e6f9;
background: #f7f8fe;
color: #909399;
}
.flow-node.pending {
border-color: #eff0f6;
background: #fafbff;
color: #c0c4cc;
}
.flow-connector {
flex: 1;
height: 2px;
background: #e5e7f8;
margin: 0 12px;
}
.flow-connector.complete {
background: #5165f7;
}
.namess {
color: #5B5E72;
font-size: 13px;
margin-left: 12px;
}
.names {
font-size: 14px;
color: #363636;
}
:deep .el-tooltip__popper.is-dark {
color: #F04B4B !important;
}
.right-area {
width: 90%;
margin: 0 auto;
height: 80vh;
background: #f8f8f8;
}
.right-header {
width: 90%;
margin: 0 auto;
}
.ths {
text-align: center;
background: #DCE0FD !important;
color: #363636;
}
.tou {
height: 30px;
line-height: 30px;
color: #606266;
text-align: center;
}
.financial-table {
width: 100%;
border-collapse: collapse;
font-family: Arial, sans-serif;
font-size: 14px;
}
.financial-table th,
.financial-table td {
border: 1px solid #ddd;
padding: 8px 7px;
text-align: center;
}
.financial-table th {
background-color: #f5f5f5;
font-weight: bold;
}
.financial-table .nested-label {
text-align: center;
vertical-align: middle;
font-weight: bold;
}
.table-right {
flex: 1;
}
.table-left {
flex: 1;
}
.content-table {
width: 90%;
margin: 0 auto;
margin-top: 14px;
}
/* 默认情况(有效)左边圆角 */
.left-radius {
border-bottom-left-radius: 16px !important;
border-top-left-radius: 16px !important;
}
/* 无效情况右边圆角 */
.right-radius {
border-bottom-right-radius: 16px !important;
border-top-right-radius: 16px !important;
}
.yuan-left {
flex: 1;
text-align: center;
line-height: 30px;
background: #f8f8f8;
/* border-bottom-left-radius: 16px;
border-top-left-radius: 16px; */
cursor: pointer;
}
.yuanright {
flex: 1;
background: #5165f7;
color: white;
/* border-bottom-right-radius: 16px;
border-top-right-radius: 16px; */
text-align: center;
line-height: 30px;
cursor: pointer;
}
.youxiaos {
position: relative;
top: 6px;
left: -12px;
cursor: pointer;
}
/* 修改.yuan的样式移除外层圆角 */
.yuan {
width: 100px;
height: 30px;
background: white;
display: flex;
font-size: 14px;
overflow: hidden;
/* 关键确保内部div的圆角效果不被截断 */
}
/* 默认状态下两个按钮的外侧圆角 */
.yuan-left:first-child {
border-top-left-radius: 16px;
border-bottom-left-radius: 16px;
}
.yuan-left:last-child {
border-top-right-radius: 16px;
border-bottom-right-radius: 16px;
}
/* 选中状态样式 */
.yuanright {
background: #5165f7;
color: white;
}
.rights-names {
margin-left: 32px;
cursor: pointer;
color: #5165f7;
}
/* 选中"有效"时的样式 */
.yuan-left.left-radius {
border-top-right-radius: 0 !important;
border-bottom-right-radius: 0 !important;
}
/* 选中"无效"时的样式 */
.yuan-left.right-radius {
border-top-left-radius: 0 !important;
border-bottom-left-radius: 0 !important;
}
.times {
position: relative;
top: 3px;
}
.youxiao {
color: #5B5D76;
font-size: 13px;
}
.table-header {
display: flex;
justify-content: space-between;
margin-top: 14px;
}
.table-area {
margin-top: 12px;
font-size: 15px;
}
.leftss-header {
display: flex;
height: 60px;
line-height: 60px;
border-bottom: 1px solid #3333;
font-weight: bold;
justify-content: space-between;
}
.leftss {
width: 90%;
margin: 0 auto;
}
.content-lefts {
background: white;
height: 100%;
width: 100%;
}
.content-left {
flex: 1;
padding-right: 12px;
height: 100%;
}
.content-right {
width: 600px;
height: 100%;
background: white;
}
.contents {
width: 100%;
height: 92vh;
background: #f8f8f8;
display: flex;
margin-top: 6px;
/* flex-wrap: wrap */
}
.shu {
width: 3px;
height: 18px;
background: #5165f7;
position: relative;
display: inline-block;
top: 7px;
}
::v-deep .el-table thead {
background-color: #DCE0FD !important;
color: #363636 !important;
font-weight: bold;
}
::v-deep .el-table__header th {
background-color: #DCE0FD !important;
color: #363636 !important;
font-weight: bold;
}
.rights {
width: 96%;
height: 100%;
margin: 0 auto;
line-height: 88px;
display: flex;
position: relative;
top: -6px;
}
.name-title {
position: relative;
top: -6px;
font-weight: bold;
}
.right-name {
font-size: 12px;
}
.img-right {
font-size: 14px;
position: relative;
top: 35px;
height: 40px;
margin-left: 12px;
}
.imgs {
width: 42px;
height: 40px;
background: #5165f7;
border-radius: 6px;
position: relative;
top: 26px;
margin-left: 24px
}
.headers-right {
flex: 1;
background: white;
}
.headers-left {
width: 222px;
height: 100%;
display: flex;
background: white;
}
.headers {
width: 100%;
display: flex;
}
.patent-container {
max-width: 1000px;
margin: 0 auto;
background: white;
border-radius: 8px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
overflow: hidden;
}
.patent-header {
background: linear-gradient(135deg, #6a5acd, #8a7dff);
color: white;
padding: 20px 30px;
text-align: center;
}
.patent-header h1 {
font-size: 24px;
margin-bottom: 10px;
font-weight: 600;
}
.patent-header p {
opacity: 0.9;
font-size: 14px;
}
.search-box {
padding: 15px 30px;
background-color: #f8f9fa;
border-bottom: 1px solid #eaeaea;
}
.search-box input {
width: 100%;
padding: 10px 15px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 14px;
transition: border-color 0.3s;
}
.search-box input:focus {
outline: none;
border-color: #8a7dff;
box-shadow: 0 0 0 2px rgba(138, 125, 255, 0.2);
}
.patent-table {
width: 100%;
border-collapse: collapse;
}
.patent-table th {
background-color: #f0e6ff;
color: #5a4fcf;
padding: 12px 15px;
text-align: left;
font-weight: 600;
border-bottom: 1px solid #ddd;
}
.patent-table td {
padding: 12px 15px;
border-bottom: 1px solid #f0f0f0;
transition: background-color 0.2s;
}
.patent-table tr:hover td {
background-color: #f9f7ff;
}
.patent-table tr:last-child td {
border-bottom: none;
}
.status-badge {
display: inline-block;
padding: 4px 8px;
border-radius: 4px;
font-size: 12px;
font-weight: 500;
}
.status-paid {
background-color: #e8f5e9;
color: #2e7d32;
}
.patent-footer {
padding: 15px 30px;
text-align: center;
color: #777;
font-size: 14px;
border-top: 1px solid #eaeaea;
background-color: #fafafa;
}
.active{
color: #5165f7 !important;
}
.rights-names{
margin-left: 32px;
cursor: pointer;
}
.rights{
width: 96%;
height: 100%;
margin: 0 auto;
line-height: 94px;
display: flex;
position: relative;
left: -27px;
}
.name-title{
position: relative;
top: -6px;
font-weight: bold;
}
.right-name{
font-size: 12px;
}
.img-right{
font-size: 14px;
position: relative;
top: 40px;
height: 40px;
margin-left: 12px;
}
.imgs{
width: 45px;
height: 46px;
background: #5165f7;
border-radius: 6px;
position: relative;
top: 26px;
margin-left: 24px
}
.headers-right{
flex: 1;
background: white;
}
.headers-left{
width: 222px;
height: 100%;
display: flex;
background: white;
border-right: 1px solid #EDEFFE;
}
.headers{
width: 100%;
height: 90px;
display: flex
;
border-bottom: 1px solid #EDEFFE;
}
</style>

View File

@@ -0,0 +1,665 @@
<template>
<div>
<div class="coentent">
<div class="contents-area">
<div class="areas">
<div v-if="active==0">
<div class="headers">
<div class="headers-name">我的提交列表</div>
<div>
<el-form :inline="true" :model="form" class="demo-form-inline">
<el-form-item label="收入类型" size="small" style="position: relative;top: -3px;">
<el-select v-model="form.revenueType" placeholder="请选择" class="selects">
<el-option v-for="item in revenueTypeOptions" :key="item.value" :label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="时间筛选" size="small" style="position: relative;top: -3px;">
<el-select v-model="form.year" placeholder="请选择" class="selects">
<el-option v-for="item in yearOptions" :key="item.value" :label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item size="small" style="position: relative;top: -3px;">
<el-select v-model="form.quarter" placeholder="请选择" class="selects">
<el-option v-for="item in quarterOptions" :key="item.value" :label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
</el-form>
</div>
</div>
<div class="content-table">
<el-table
:data="tableData"
:header-cell-style="{ background: '#EDEFFE', color: '#363636', textAlign: 'center' }"
border
style="width: 100%">
<el-table-column prop="serial" label="序号" width="80" align="center"></el-table-column>
<el-table-column prop="productName" label="审批模块" align="center"></el-table-column>
<el-table-column prop="isMainProduct" label="提交内容" width="120" align="center">
<template slot-scope="scope">
<span>{{ scope.row.isMainProduct }}</span>
</template>
</el-table-column>
<el-table-column prop="revenueType" label="提交时间" width="150" align="center">
<template slot-scope="scope">
<span>{{ scope.row.revenueType }}</span>
</template>
</el-table-column>
<el-table-column prop="salesRevenue" label="审核人" align="center">
<template slot-scope="scope">
<span>{{ formatCurrency(scope.row.salesRevenue) }}</span>
</template>
</el-table-column>
<el-table-column prop="salesRevenue" label="审核状态" align="center">
<template slot-scope="scope">
<span>{{ formatCurrency(scope.row.salesRevenue) }}</span>
</template>
</el-table-column>
<el-table-column fixed="right" label="操作" align="center" width="150">
<template slot-scope="scope">
<el-button @click="handleHomepage(scope.row)" type="text" size="small" style="color: #5165f7;">查看</el-button>
</template>
</el-table-column>
</el-table>
<div class="footer">
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="currentPage"
:page-sizes="[100, 200, 300, 400]"
:page-size="100"
layout="total, sizes, prev, pager, next, jumper"
:total="400">
</el-pagination>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
active: 0,
currentPage: 1,
dialogVisible: false,
form: {
revenueType: '全部',
year: '2025',
quarter: '第一季度'
},
productForm: {
productName: '',
isMainProduct: '',
revenueType: '技术服务收入',
technologySource: '',
technologyField: '电子信息',
technologyFieldDetail: '网络应用技术'
},
productFormRules: {
productName: [
{ required: true, message: '请输入产品(服务)名称', trigger: 'blur' }
],
isMainProduct: [
{ required: true, message: '请选择是否主要产品', trigger: 'change' }
],
revenueType: [
{ required: true, message: '请选择收入类型', trigger: 'change' }
]
},
revenueTypeOptions: [
{
value: '全部',
label: '全部'
},
{
value: '产品收入',
label: '产品收入'
},
{
value: '技术转让收入',
label: '技术转让收入'
}
],
yearOptions: [
{
value: '2023',
label: '2023'
},
{
value: '2024',
label: '2024'
},
{
value: '2025',
label: '2025'
},
{
value: '2026',
label: '2026'
}
],
quarterOptions: [
{
value: '第一季度',
label: '第一季度'
},
{
value: '第二季度',
label: '第二季度'
},
{
value: '第三季度',
label: '第三季度'
},
{
value: '第四季度',
label: '第四季度'
}
],
dialogRevenueTypeOptions: [
{
value: '产品收入',
label: '产品收入'
},
{
value: '技术转让收入',
label: '技术转让收入'
},
{
value: '技术服务收入',
label: '技术服务收入'
}
],
technologySourceOptions: [
{
value: '计算机产品及其网络应用技术',
label: '计算机产品及其网络应用技术'
},
{
value: '自主开发',
label: '自主开发'
},
{
value: '合作开发',
label: '合作开发'
},
{
value: '引进技术',
label: '引进技术'
}
],
technologyFieldOptions: [
{
value: '电子信息',
label: '电子信息'
},
{
value: '生物与新医药',
label: '生物与新医药'
},
{
value: '航空航天',
label: '航空航天'
},
{
value: '新材料',
label: '新材料'
},
{
value: '高技术服务',
label: '高技术服务'
},
{
value: '新能源与节能',
label: '新能源与节能'
},
{
value: '资源与环境',
label: '资源与环境'
},
{
value: '先进制造与自动化',
label: '先进制造与自动化'
}
],
technologyFieldDetailOptions: [
{
value: '网络应用技术',
label: '网络应用技术'
},
{
value: '计算机软件技术',
label: '计算机软件技术'
},
{
value: '通信技术',
label: '通信技术'
},
{
value: '其他',
label: '其他'
}
],
tableData: [
{
serial: 1,
productName: '智慧收费产品',
isMainProduct: '是',
revenueType: '产品收入',
salesRevenue: 1600.00
},
{
serial: 2,
productName: '智慧照明产品',
isMainProduct: '否',
revenueType: '产品收入',
salesRevenue: 1600.00
},
{
serial: 3,
productName: '高速公路机电系统建管养一体化服务',
isMainProduct: '否',
revenueType: '技术转让收入',
salesRevenue: 1600.00
},
{
serial: 4,
productName: '隧道智慧管控运维系统及服务',
isMainProduct: '否',
revenueType: '技术转让收入',
salesRevenue: 0
},
{
serial: 5,
productName: '交通行业省级视频云联网产品及服务',
isMainProduct: '否',
revenueType: '技术转让收入',
salesRevenue: 0
}
]
}
},
methods: {
formatCurrency(value) {
if (value === 0 || value === '0') {
return '0'
}
return value.toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 })
},
handleHomepage(row) {
this.$router.push('/myreviewSee')
// 跳转到产品主页
},
handleDelete(row) {
this.$confirm('确定要删除该产品吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
console.log('删除', row)
// 处理删除逻辑
this.$message({
type: 'success',
message: '删除成功!'
})
}).catch(() => {
this.$message({
type: 'info',
message: '已取消删除'
})
})
},
btnAdd() {
this.dialogVisible = true
// 重置表单
this.productForm = {
productName: '',
isMainProduct: '',
revenueType: '技术服务收入',
technologySource: '',
technologyField: '电子信息',
technologyFieldDetail: '网络应用技术'
}
// 清除表单验证
if (this.$refs.productForm) {
this.$refs.productForm.clearValidate()
}
},
handleSave() {
this.$refs.productForm.validate((valid) => {
if (valid) {
console.log('保存产品', this.productForm)
// 处理保存逻辑
this.$message({
type: 'success',
message: '保存成功!'
})
this.dialogVisible = false
// 这里可以添加保存后的逻辑,比如刷新列表
} else {
console.log('表单验证失败')
return false
}
})
},
handleCancel() {
this.dialogVisible = false
// 重置表单
this.productForm = {
productName: '',
isMainProduct: '',
revenueType: '技术服务收入',
technologySource: '',
technologyField: '电子信息',
technologyFieldDetail: '网络应用技术'
}
if (this.$refs.productForm) {
this.$refs.productForm.clearValidate()
}
},
handleSizeChange() {
// 处理分页大小变化
},
handleCurrentChange() {
// 处理当前页变化
}
}
}
</script>
<style>
.el-tooltip__popper.is-dark {
color: #F04B4B !important;
background: #FCF1EB !important;
}
.el-tooltip__popper .popper__arrow {
border-top-color: #FCF1EB !important;
}
.el-tooltip__popper .popper__arrow::after {
border-top-color: #FCF1EB !important;
}
.el-tooltip__popper[x-placement^='bottom'] .popper__arrow {
border-bottom-color: #FCF1EB !important;
}
.el-tooltip__popper[x-placement^='left'] .popper__arrow {
border-left-color: #FCF1EB !important;
}
.el-tooltip__popper[x-placement^='right'] .popper__arrow {
border-right-color: #FCF1EB !important;
}
</style>
<style scoped>
.areas {
padding-bottom: 15px;
width: 97%;
margin: 0 auto;
margin-top: 12px;
padding-top: 20px;
}
.active {
color: #5165f7 !important;
}
.heng {
width: 20px;
height: 6px;
background: #5165f7;
margin: 0 auto;
margin-top: 6px;
}
.header-table {
cursor: pointer;
}
.contentss-header {
width: 100%;
display: flex;
justify-content: space-between;
width: 150px;
}
.contentss {
width: 97%;
margin: 0 auto;
padding-top: 12px;
}
.contents-area {
width: 100%;
background: white;
margin-top: 20px;
}
.header-title {
position: relative;
top: 20px;
left: 25px;
}
.numbers {
position: relative;
top: -7px;
color: #2AB95F;
}
.number-name2 {
margin-top: 8px;
font-size: 14px;
color: #979BBC;
}
.number-name {
font-weight: bold;
font-size: 25px;
color: #17192C;
}
.header-names {
display: flex;
width: 82%;
justify-content: space-between;
margin: 0 auto;
padding-top: 20px;
}
.header-area {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
width: 97%;
margin: 0 auto;
}
.content-header {
width: 100%;
background: white;
padding-bottom: 22px;
}
.footer {
display: flex;
justify-content: end;
margin-top: 20px;
}
.tianjia {
position: relative;
top: -9px;
background-color: #5065F6;
}
.tianjia2 {
position: relative;
top: -9px;
background-color: #EDEFFE;
color: #5065F6;
}
::v-deep .el-table thead {
background-color: #EDEFFE !important;
color: #363636 !important;
}
::v-deep .el-table__header th {
background-color: #EDEFFE !important;
color: #363636 !important;
}
.formitem {
position: relative;
top: -5px;
}
::deep .el-form-item__label {
font-size: 15px !important;
}
.selects {
width: 100px;
border: 1px solid #3333;
}
.headers-name {
font-size: 15px;
position: relative;
top: 14px;
}
.headers {
display: flex;
justify-content: space-between;
}
::v-deep .el-table__body tr:hover > td {
background-color: transparent !important;
}
::v-deep .el-table__body tr.el-table__row--striped td {
background-color: transparent;
}
/* 产品对话框样式 */
.product-dialog ::v-deep .el-dialog__header {
padding: 20px 20px 10px;
border-bottom: 1px solid #EBEEF5;
text-align: center;
}
.product-dialog ::v-deep .el-dialog__title {
font-size: 16px;
font-weight: bold;
color: #303133;
}
.product-dialog ::v-deep .el-dialog__body {
padding: 20px;
}
.product-dialog ::v-deep .el-form-item__label {
font-size: 14px;
color: #606266;
}
.product-dialog .dialog-footer {
text-align: center;
padding-top: 10px;
}
.product-dialog .dialog-footer .el-button {
margin: 0 10px;
}
.content-areas{
display: flex;
height: 50px;
flex-wrap: wrap;
margin-top: -1px;
}
.contents-left{
width: 30%;
border: 1px solid #DCE0FD;
background: #EDEFFE;
line-height: 50px;
font-size: 14px;
color: #363636;
display: flex;
align-items: center;
}
.contents-right{
flex: 1;
border: 1px solid #DCE0FD;
border-left: none;
line-height: 50px;
font-size: 14px;
color: #363636;
display: flex;
align-items: center;
position: relative;
}
.contents-right:last-child {
border-right: 1px solid #DCE0FD;
}
.content-areas2{
position: relative;
top: -1px;
}
.rightss{
height: 100%;
border: 1px solid #DCE0FD;
border-top: none;
border-bottom: none;
width: 100%;
display: flex;
align-items: center;
flex: 1;
}
.rightss1{
border-left: none !important;
border-right: 1px solid #DCE0FD !important;
}
.rightss2{
background: #EDEFFE;
border-left: 1px solid #DCE0FD;
border-right: 1px solid #DCE0FD;
width: auto;
min-width: 120px;
flex: 0 0 auto;
justify-content: center;
}
.rightss3{
border-left: none !important;
border-right: none !important;
flex: 1;
}
.rightss-full{
border-left: none !important;
border-right: 1px solid #DCE0FD !important;
flex: 1;
width: 100%;
min-width: 0;
display: flex;
align-items: center;
}
.table-name{
margin-left: 20px;
}
</style>

View File

@@ -0,0 +1,933 @@
<template>
<div>
<div class="headers">
<div class="headers-left">
<div class="imgs">
</div>
<div class="img-right">
<div class="name-title">微育科技</div>
<div class="right-name">数智科创 · 通达未来 </div>
</div>
</div>
<div class="headers-right">
<div class="rights">
<div class="rights-names" @click="btnShang">
<span>上一级 &lt; </span> <span style="color:#3333;">主页</span>
</div>
</div>
</div>
</div>
<div class="contents">
<div class="content-left">
<div class="content-lefts">
<div class="leftss">
<div class="leftss-header">
<div>高速公路管道与光缆</div>
<div @click="btnEdint">
<el-button size="small" type="danger" plain @click="closeguan">删除</el-button>
<el-button size="small" style="background-color: #5165f7;color:white;">编辑</el-button>
</div>
</div>
<div class="approval-flow">
<div class="table-header">
<div>
<div class="shu"></div> <span class="times"> 审核流 </span>
</div>
</div>
<div class="flow-wrapper">
<div
v-for="(step, index) in approvalSteps"
:key="step.label"
class="flow-item-container"
:class="{ 'is-last': index === approvalSteps.length - 1 }">
<div class="flow-node" :class="step.state">
{{ step.label }}
</div>
<div
v-if="index < approvalSteps.length - 1"
class="flow-connector"
:class="{ complete: step.state === 'done' }">
</div>
</div>
</div>
</div>
<div class="table-area">
<div class="table-header">
<div>
<div class="shu"></div> <span class="times"> 提交信息 </span>
</div>
</div>
</div>
</div>
<div class="content-table">
<div class="content-areas">
<div class="contents-left">
<span style="margin-left: 20px;">专利号</span>
</div>
<div class="contents-right">
<span style="margin-left: 20px;">ZL202311316235.7</span>
</div>
<div class="contents-left">
<span style="margin-left: 20px;">专利号</span>
</div>
<div class="contents-right">
<span style="margin-left: 20px;">ZL202311316235.7</span>
</div>
</div>
<div class="content-areas content-areas2">
<div class="contents-left">
<span class="table-name">授权公告号</span>
</div>
<div class="contents-right">
<div class="rightss rightss1"><span class="table-name">CN117056866B</span></div>
<div class="rightss rightss2"><span class="table-name">申请专利日</span></div>
<div class="rightss rightss3"><span class="table-name">2023-11-14</span></div>
</div>
</div>
<div class="content-areas content-areas2" style="top: 4px;">
<div class="contents-left" style="border-top: none;">
<span class="table-name">授权公告日</span>
</div>
<div class="contents-right" style="border: none;">
<div class="rightss rightss1"><span class="table-name">
2023-11-14
</span></div>
<div class="rightss rightss2" style="border-top: none;"><span
class="table-name">获得方式</span></div>
<div class="rightss rightss3"><span class="table-name">
自主研发
</span></div>
</div>
</div>
<div class="content-areas" style="position: relative;top: 5px;">
<div class="contents-left">
<span style="margin-left: 20px;">转让方</span>
</div>
<div class="contents-right" style="border-top: none;">
<span style="margin-left: 20px;">单位名称</span>
</div>
</div>
<div class="content-areas" style="position: relative;top: 5px;">
<div class="contents-left">
<span style="margin-left: 20px;">专利权人</span>
</div>
<div class="contents-right" style="border-top: none;">
<span style="margin-left: 20px;">xxxxxxx</span>
</div>
</div>
<div class="content-areas" style="position: relative;top: 5px;">
<div class="contents-left">
<span style="margin-left: 20px;">专利权人</span>
</div>
<div class="contents-right" style="border-top: none;">
<span style="margin-left: 20px;">xxxxxxx</span>
</div>
</div>
<div class="content-areas" style="position: relative;top: 5px;">
<div class="contents-left">
<span style="margin-left: 20px;">发明人</span>
</div>
<div class="contents-right" style="border-top: none;">
<span style="margin-left: 20px;">xxxxxxx</span>
</div>
</div>
<div class="content-areas" style="position: relative;top: 5px;">
<div class="contents-left">
<span style="margin-left: 20px;">地址</span>
</div>
<div class="contents-right" style="border-top: none;">
<span style="margin-left: 20px;">xxxxxxx</span>
</div>
</div>
<div class="content-areas" style="position: relative;top: 5px;">
<div class="contents-left">
<span style="margin-left: 20px;">下年度年费缴纳日期</span>
</div>
<div class="contents-right" style="border-top: none;">
<span style="margin-left: 20px;">2023-11-14</span>
</div>
<div class="contents-left">
<span style="margin-left: 20px;">年费缴纳情况</span>
</div>
<div class="contents-right" style="border-top: none;">
<span style="margin-left: 20px;">已缴纳</span>
</div>
</div>
</div>
</div>
</div>
<div class="content-right">
<div class="leftss-header right-header">
<div class="header-area">
<div class="area-name" v-for="(item, index) in listDate" :key="index" @click="btnNmae(index)"
:class="{ 'active': active == index }">
{{ item.name }}
</div>
</div>
<div> <el-button size="small" style="color:#5165f7;">
<i class="el-icon-download"></i> 下载</el-button>
</div>
</div>
<div class="right-area"></div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
active: 0,
listDate: [
{
name: '提交相关附件'
},
],
value1: "",
yuanright: 0,
tables: [
{
name: '有效'
},
{
name: '无效'
},
],
shu: 0,
lastActiveKey: 'headerActiveIndex',
tableData: [
{
date: "其中",
name: "",
address: "",
children: [
{ date: "2024", name: "年度审计报告及财务情况说明书", address: "8000" },
{ date: "2025", name: "年度审计报告及财务情况说明书", address: "7500" },
],
},
{ date: "其他项目", name: "5000", address: "4000" },
],
tableData2: [
{ date: "2025", name: "年度审计报告及财务情况说明书", address: "7500" },
],
approvalSteps: [
{ label: '提交', state: 'done' },
{ label: '已通过', state: 'done' },
{ label: '审核中', state: 'processing' },
{ label: '-', state: 'pending' }
]
}
},
created() {
},
watch: {
},
methods: {
//取消
closeguan() {
},
btnNmae(e) {
this.active = e
},
//切换时效性
btnYuan(e) {
this.yuanright = e
},
//编辑跳转
btnEdint() {
this.$router.push('/hetongmingxin')
},
btnShang() {
this.$router.go(-1)
}
}
}
</script>
<style>
.el-tooltip__popper.is-dark {
color: #F04B4B !important;
background: #FCF1EB !important;
}
.el-tooltip__popper .popper__arrow {
border-top-color: #FCF1EB !important;
/* 上方箭头 */
}
.el-tooltip__popper .popper__arrow::after {
border-top-color: #FCF1EB !important;
}
/* 其他方向的箭头(按需添加) */
.el-tooltip__popper[x-placement^='bottom'] .popper__arrow {
border-bottom-color: #FCF1EB !important;
}
.el-tooltip__popper[x-placement^='left'] .popper__arrow {
border-left-color: #FCF1EB !important;
}
.el-tooltip__popper[x-placement^='right'] .popper__arrow {
border-right-color: #FCF1EB !important;
}
</style>
<style scoped>
.tabless{
width: 90%;
margin: 0 auto;
margin-top: 30px;
}
.area-name {
margin-left: 30px;
cursor: pointer;
}
.active {
border-bottom: 3px solid #5165f7;
height: 45px;
}
.header-area {
display: flex;
position: relative;
left: -30px;
}
.rightss3 {
border-right: none;
border-left: none;
}
.table-name {
margin-left: 20px;
}
.rightss2 {
background: #EDEFFE;
}
.rightss1 {
border-left: none !important;
border-right: none !important;
}
.rightss {
height: 100%;
border: 1px solid #DCE0FD;
width: 100%;
border-top: none;
}
.content-areas2 {
position: relative;
top: 1px;
}
.contents-right {
flex: 1;
border: 1px solid #DCE0FD;
line-height: 50px;
font-size: 14px;
color: #363636;
display: flex
}
.contents-left {
width: 30%;
border: 1px solid #DCE0FD;
background: #EDEFFE;
;
line-height: 50px;
font-size: 14px;
color: #363636;
}
.content-areas {
display: flex;
height: 50px;
flex-wrap: wrap;
}
.tab-area {
margin-top: 24px;
}
.approval-flow {
width: 96%;
margin: -12px auto 20px;
padding: 20px 20px 0;
background: #ffffff;
border-radius: 12px;
}
.approval-flow .table-header {
margin-bottom: 12px;
}
.flow-wrapper {
display: flex;
align-items: center;
flex-wrap: nowrap;
margin-top: 24px;
}
.flow-item-container {
display: flex;
align-items: center;
flex: 1;
}
.flow-item-container.is-last .flow-connector {
display: none;
}
.flow-node {
padding: 6px 20px;
border-radius: 20px;
border: 1px solid #d5daf5;
background: #f8f9ff;
color: #8a8faf;
font-size: 14px;
line-height: 20px;
white-space: nowrap;
}
.flow-node.done {
border-color: #5165f7;
background: rgba(81, 101, 247, 0.08);
color: #5165f7;
box-shadow: 0 0 0 1px rgba(81, 101, 247, 0.2);
}
.flow-node.processing {
border-color: #e2e6f9;
background: #f7f8fe;
color: #909399;
}
.flow-node.pending {
border-color: #eff0f6;
background: #fafbff;
color: #c0c4cc;
}
.flow-connector {
flex: 1;
height: 2px;
background: #e5e7f8;
margin: 0 12px;
}
.flow-connector.complete {
background: #5165f7;
}
.namess {
color: #5B5E72;
font-size: 13px;
margin-left: 12px;
}
.names {
font-size: 14px;
color: #363636;
}
:deep .el-tooltip__popper.is-dark {
color: #F04B4B !important;
}
.right-area {
width: 90%;
margin: 0 auto;
height: 80vh;
background: #f8f8f8;
}
.right-header {
width: 90%;
margin: 0 auto;
}
.ths {
text-align: center;
background: #DCE0FD !important;
color: #363636;
}
.tou {
height: 30px;
line-height: 30px;
color: #606266;
text-align: center;
}
.financial-table {
width: 100%;
border-collapse: collapse;
font-family: Arial, sans-serif;
font-size: 14px;
}
.financial-table th,
.financial-table td {
border: 1px solid #ddd;
padding: 8px 7px;
text-align: center;
}
.financial-table th {
background-color: #f5f5f5;
font-weight: bold;
}
.financial-table .nested-label {
text-align: center;
vertical-align: middle;
font-weight: bold;
}
.table-right {
flex: 1;
}
.table-left {
flex: 1;
}
.content-table {
width: 90%;
margin: 0 auto;
margin-top: 14px;
}
/* 默认情况(有效)左边圆角 */
.left-radius {
border-bottom-left-radius: 16px !important;
border-top-left-radius: 16px !important;
}
/* 无效情况右边圆角 */
.right-radius {
border-bottom-right-radius: 16px !important;
border-top-right-radius: 16px !important;
}
.yuan-left {
flex: 1;
text-align: center;
line-height: 30px;
background: #f8f8f8;
/* border-bottom-left-radius: 16px;
border-top-left-radius: 16px; */
cursor: pointer;
}
.yuanright {
flex: 1;
background: #5165f7;
color: white;
/* border-bottom-right-radius: 16px;
border-top-right-radius: 16px; */
text-align: center;
line-height: 30px;
cursor: pointer;
}
.youxiaos {
position: relative;
top: 6px;
left: -12px;
cursor: pointer;
}
/* 修改.yuan的样式移除外层圆角 */
.yuan {
width: 100px;
height: 30px;
background: white;
display: flex;
font-size: 14px;
overflow: hidden;
/* 关键确保内部div的圆角效果不被截断 */
}
/* 默认状态下两个按钮的外侧圆角 */
.yuan-left:first-child {
border-top-left-radius: 16px;
border-bottom-left-radius: 16px;
}
.yuan-left:last-child {
border-top-right-radius: 16px;
border-bottom-right-radius: 16px;
}
/* 选中状态样式 */
.yuanright {
background: #5165f7;
color: white;
}
.rights-names {
margin-left: 32px;
cursor: pointer;
color: #5165f7;
}
/* 选中"有效"时的样式 */
.yuan-left.left-radius {
border-top-right-radius: 0 !important;
border-bottom-right-radius: 0 !important;
}
/* 选中"无效"时的样式 */
.yuan-left.right-radius {
border-top-left-radius: 0 !important;
border-bottom-left-radius: 0 !important;
}
.times {
position: relative;
top: 3px;
}
.youxiao {
color: #5B5D76;
font-size: 13px;
}
.table-header {
display: flex;
justify-content: space-between;
margin-top: 14px;
}
.table-area {
margin-top: 12px;
font-size: 15px;
}
.leftss-header {
display: flex;
height: 60px;
line-height: 60px;
border-bottom: 1px solid #3333;
font-weight: bold;
justify-content: space-between;
}
.leftss {
width: 90%;
margin: 0 auto;
}
.content-lefts {
background: white;
height: 100%;
width: 100%;
}
.content-left {
flex: 1;
padding-right: 12px;
height: 100%;
}
.content-right {
width: 600px;
height: 100%;
background: white;
}
.contents {
width: 100%;
height: 92vh;
background: #f8f8f8;
display: flex;
margin-top: 6px;
/* flex-wrap: wrap */
}
.shu {
width: 3px;
height: 18px;
background: #5165f7;
position: relative;
display: inline-block;
top: 7px;
}
::v-deep .el-table thead {
background-color: #DCE0FD !important;
color: #363636 !important;
font-weight: bold;
}
::v-deep .el-table__header th {
background-color: #DCE0FD !important;
color: #363636 !important;
font-weight: bold;
}
.rights {
width: 96%;
height: 100%;
margin: 0 auto;
line-height: 88px;
display: flex;
position: relative;
top: -6px;
}
.name-title {
position: relative;
top: -6px;
font-weight: bold;
}
.right-name {
font-size: 12px;
}
.img-right {
font-size: 14px;
position: relative;
top: 35px;
height: 40px;
margin-left: 12px;
}
.imgs {
width: 42px;
height: 40px;
background: #5165f7;
border-radius: 6px;
position: relative;
top: 26px;
margin-left: 24px
}
.headers-right {
flex: 1;
background: white;
}
.headers-left {
width: 222px;
height: 100%;
display: flex;
background: white;
}
.headers {
width: 100%;
display: flex;
}
.patent-container {
max-width: 1000px;
margin: 0 auto;
background: white;
border-radius: 8px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
overflow: hidden;
}
.patent-header {
background: linear-gradient(135deg, #6a5acd, #8a7dff);
color: white;
padding: 20px 30px;
text-align: center;
}
.patent-header h1 {
font-size: 24px;
margin-bottom: 10px;
font-weight: 600;
}
.patent-header p {
opacity: 0.9;
font-size: 14px;
}
.search-box {
padding: 15px 30px;
background-color: #f8f9fa;
border-bottom: 1px solid #eaeaea;
}
.search-box input {
width: 100%;
padding: 10px 15px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 14px;
transition: border-color 0.3s;
}
.search-box input:focus {
outline: none;
border-color: #8a7dff;
box-shadow: 0 0 0 2px rgba(138, 125, 255, 0.2);
}
.patent-table {
width: 100%;
border-collapse: collapse;
}
.patent-table th {
background-color: #f0e6ff;
color: #5a4fcf;
padding: 12px 15px;
text-align: left;
font-weight: 600;
border-bottom: 1px solid #ddd;
}
.patent-table td {
padding: 12px 15px;
border-bottom: 1px solid #f0f0f0;
transition: background-color 0.2s;
}
.patent-table tr:hover td {
background-color: #f9f7ff;
}
.patent-table tr:last-child td {
border-bottom: none;
}
.status-badge {
display: inline-block;
padding: 4px 8px;
border-radius: 4px;
font-size: 12px;
font-weight: 500;
}
.status-paid {
background-color: #e8f5e9;
color: #2e7d32;
}
.patent-footer {
padding: 15px 30px;
text-align: center;
color: #777;
font-size: 14px;
border-top: 1px solid #eaeaea;
background-color: #fafafa;
}
.active{
color: #5165f7 !important;
}
.rights-names{
margin-left: 32px;
cursor: pointer;
}
.rights{
width: 96%;
height: 100%;
margin: 0 auto;
line-height: 94px;
display: flex;
position: relative;
left: -27px;
}
.name-title{
position: relative;
top: -6px;
font-weight: bold;
}
.right-name{
font-size: 12px;
}
.img-right{
font-size: 14px;
position: relative;
top: 40px;
height: 40px;
margin-left: 12px;
}
.imgs{
width: 45px;
height: 46px;
background: #5165f7;
border-radius: 6px;
position: relative;
top: 26px;
margin-left: 24px
}
.headers-right{
flex: 1;
background: white;
}
.headers-left{
width: 222px;
height: 100%;
display: flex;
background: white;
border-right: 1px solid #EDEFFE;
}
.headers{
width: 100%;
height: 90px;
display: flex
;
border-bottom: 1px solid #EDEFFE;
}
</style>

View File

@@ -0,0 +1,740 @@
<template>
<div>
<div class="coentent">
<div class="contents-area">
<div class="areas">
<div v-if="active==0">
<div class="headers">
<div class="headers-name">审核权限和节点列表</div>
<div>
<el-form :inline="true" :model="form" class="demo-form-inline">
<el-form-item label="收入类型" size="small" style="position: relative;top: -3px;">
<el-select v-model="form.revenueType" placeholder="请选择" class="selects">
<el-option v-for="item in revenueTypeOptions" :key="item.value" :label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="时间筛选" size="small" style="position: relative;top: -3px;">
<el-select v-model="form.year" placeholder="请选择" class="selects">
<el-option v-for="item in yearOptions" :key="item.value" :label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item size="small" style="position: relative;top: -3px;">
<el-select v-model="form.quarter" placeholder="请选择" class="selects">
<el-option v-for="item in quarterOptions" :key="item.value" :label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
</el-form>
</div>
</div>
<div class="content-table">
<el-table
:data="tableData"
:header-cell-style="{ background: '#EDEFFE', color: '#363636', textAlign: 'center' }"
border
style="width: 100%">
<el-table-column prop="serial" label="序号" width="80" align="center"></el-table-column>
<el-table-column prop="productName" label="审批模块" align="center"></el-table-column>
<el-table-column prop="isMainProduct" label="一级审核人" width="120" align="center">
<template slot-scope="scope">
<span>{{ scope.row.isMainProduct }}</span>
</template>
</el-table-column>
<el-table-column prop="revenueType" label="二级审核人" width="150" align="center">
<template slot-scope="scope">
<span>{{ scope.row.revenueType }}</span>
</template>
</el-table-column>
<el-table-column prop="salesRevenue" label="三级审核人" align="center">
<template slot-scope="scope">
<span>{{ formatCurrency(scope.row.salesRevenue) }}</span>
</template>
</el-table-column>
<el-table-column prop="salesRevenue" label="状态" align="center">
<template slot-scope="scope">
<span>{{ formatCurrency(scope.row.salesRevenue) }}</span>
</template>
</el-table-column>
<el-table-column fixed="right" label="操作" align="center" width="150">
<template slot-scope="scope">
<el-button type="text" size="small" style="color: #5165f7;">禁用</el-button>
<el-button @click="handleHomepage(scope.row)" type="text" size="small" style="color: #5165f7;">编辑</el-button>
</template>
</el-table-column>
</el-table>
<div class="footer">
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="currentPage"
:page-sizes="[100, 200, 300, 400]"
:page-size="100"
layout="total, sizes, prev, pager, next, jumper"
:total="400">
</el-pagination>
</div>
</div>
</div>
</div>
</div>
</div>
<el-dialog
:visible.sync="dialogVisible"
width="840px"
class="audit-dialog"
:close-on-click-modal="false"
:destroy-on-close="true"
@closed="resetDialog">
<template #title>
<div class="dialog-title">添加/编辑审核</div>
</template>
<div class="content-table">
<div class="content-areas">
<div class="contents-left">
<span style="margin-left: 20px;">一级审核人</span>
</div>
<div class="contents-right">
<span style="margin-left: 20px;">
<el-select v-model="value" placeholder="请选择">
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</span>
</div>
<div class="contents-left">
<span style="margin-left: 20px;">一级审核人</span>
</div>
<div class="contents-right">
<span style="margin-left: 20px;">
<el-select v-model="value" placeholder="请选择">
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</span>
</div>
<div class="contents-left">
<span style="margin-left: 20px;">一级审核人</span>
</div>
<div class="contents-right">
<span style="margin-left: 20px;">
<el-select v-model="value" placeholder="请选择">
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</span>
</div>
</div>
</div>
<div class="dialog-section module-section">
<div class="dialog-section-header">审核模块选择</div>
<el-tree
ref="moduleTree"
:data="moduleTreeData"
show-checkbox
node-key="id"
:default-checked-keys="selectedModules"
:props="moduleTreeProps"
default-expand-all
check-on-click-node
class="module-tree">
</el-tree>
</div>
<template #footer>
<div class="dialog-footer">
<el-button size="small" @click="handleDialogCancel">取消</el-button>
<el-button type="primary" size="small" @click="submitAudit">保存</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script>
export default {
data() {
return {
active: 0,
currentPage: 1,
dialogVisible: false,
editingRow: null,
reviewForm: {
firstReviewer: '',
secondReviewer: '',
thirdReviewer: ''
},
reviewerOptions: [
{ value: '陈翔', label: '陈翔' },
{ value: '刘伟', label: '刘伟' },
{ value: '王敏', label: '王敏' },
{ value: '李华', label: '李华' },
{ value: '张婷', label: '张婷' }
],
moduleTreeData: [
{
id: 'resource',
label: '资源资料',
children: [
{ id: 'affairs', label: '事务管理' },
{ id: 'hr', label: '人力资源' },
{
id: 'achievement',
label: '成果管理',
children: [
{
id: 'ip',
label: '知识产权',
children: [
{ id: 'patent', label: '发明专利' },
{ id: 'software', label: '软件著作' },
{ id: 'ic', label: '集成电路布图设计专有权' }
]
},
{ id: 'thesis', label: '论文管理' },
{ id: 'contract', label: '合同登记' }
]
}
]
},
{ id: 'research', label: '研发项目' },
{ id: 'economic', label: '经营项目' },
{ id: 'hightech', label: '高企法人' },
{ id: 'special', label: '专精特新' },
{ id: 'deduction', label: '加计扣除' }
],
moduleTreeProps: {
children: 'children',
label: 'label'
},
selectedModules: [],
form: {
revenueType: '全部',
year: '2025',
quarter: '第一季度'
},
revenueTypeOptions: [
{
value: '全部',
label: '全部'
},
{
value: '产品收入',
label: '产品收入'
},
{
value: '技术转让收入',
label: '技术转让收入'
}
],
yearOptions: [
{
value: '2023',
label: '2023'
},
{
value: '2024',
label: '2024'
},
{
value: '2025',
label: '2025'
},
{
value: '2026',
label: '2026'
}
],
quarterOptions: [
{
value: '第一季度',
label: '第一季度'
},
{
value: '第二季度',
label: '第二季度'
},
{
value: '第三季度',
label: '第三季度'
},
{
value: '第四季度',
label: '第四季度'
}
],
tableData: [
{
serial: 1,
productName: '智慧收费产品',
isMainProduct: '是',
revenueType: '产品收入',
salesRevenue: 1600.00
},
{
serial: 2,
productName: '智慧照明产品',
isMainProduct: '否',
revenueType: '产品收入',
salesRevenue: 1600.00
},
{
serial: 3,
productName: '高速公路机电系统建管养一体化服务',
isMainProduct: '否',
revenueType: '技术转让收入',
salesRevenue: 1600.00
},
{
serial: 4,
productName: '隧道智慧管控运维系统及服务',
isMainProduct: '否',
revenueType: '技术转让收入',
salesRevenue: 0
},
{
serial: 5,
productName: '交通行业省级视频云联网产品及服务',
isMainProduct: '否',
revenueType: '技术转让收入',
salesRevenue: 0
}
]
}
},
methods: {
formatCurrency(value) {
if (value === 0 || value === '0') {
return '0'
}
return value.toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 })
},
handleHomepage(row) {
this.dialogVisible = true
this.editingRow = row
this.reviewForm = {
firstReviewer: row?.firstReviewer || '',
secondReviewer: row?.secondReviewer || '',
thirdReviewer: row?.thirdReviewer || ''
}
this.$nextTick(() => {
if (this.$refs.moduleTree) {
this.selectedModules = row?.modules || []
this.$refs.moduleTree.setCheckedKeys(this.selectedModules)
}
})
},
handleDialogCancel() {
this.dialogVisible = false
},
resetDialog() {
this.editingRow = null
this.reviewForm = {
firstReviewer: '',
secondReviewer: '',
thirdReviewer: ''
}
this.selectedModules = []
if (this.$refs.moduleTree) {
this.$refs.moduleTree.setCheckedKeys([])
}
},
submitAudit() {
const checkedKeys = this.$refs.moduleTree ? this.$refs.moduleTree.getCheckedKeys(true) : []
const payload = {
...this.reviewForm,
modules: checkedKeys,
row: this.editingRow
}
console.log('保存审核配置', payload)
this.$message.success('保存成功!')
this.dialogVisible = false
},
handleDelete(row) {
this.$confirm('确定要删除该产品吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
console.log('删除', row)
// 处理删除逻辑
this.$message({
type: 'success',
message: '删除成功!'
})
}).catch(() => {
this.$message({
type: 'info',
message: '已取消删除'
})
})
},
handleSizeChange() {
// 处理分页大小变化
},
handleCurrentChange() {
// 处理当前页变化
}
}
}
</script>
<style>
.el-tooltip__popper.is-dark {
color: #F04B4B !important;
background: #FCF1EB !important;
}
.el-tooltip__popper .popper__arrow {
border-top-color: #FCF1EB !important;
}
.el-tooltip__popper .popper__arrow::after {
border-top-color: #FCF1EB !important;
}
.el-tooltip__popper[x-placement^='bottom'] .popper__arrow {
border-bottom-color: #FCF1EB !important;
}
.el-tooltip__popper[x-placement^='left'] .popper__arrow {
border-left-color: #FCF1EB !important;
}
.el-tooltip__popper[x-placement^='right'] .popper__arrow {
border-right-color: #FCF1EB !important;
}
</style>
<style scoped>
.areas {
padding-bottom: 15px;
width: 97%;
margin: 0 auto;
margin-top: 12px;
padding-top: 20px;
}
.active {
color: #5165f7 !important;
}
.heng {
width: 20px;
height: 6px;
background: #5165f7;
margin: 0 auto;
margin-top: 6px;
}
.header-table {
cursor: pointer;
}
.contentss-header {
width: 100%;
display: flex;
justify-content: space-between;
width: 150px;
}
.contentss {
width: 97%;
margin: 0 auto;
padding-top: 12px;
}
.contents-area {
width: 100%;
background: white;
margin-top: 20px;
}
.header-title {
position: relative;
top: 20px;
left: 25px;
}
.numbers {
position: relative;
top: -7px;
color: #2AB95F;
}
.number-name2 {
margin-top: 8px;
font-size: 14px;
color: #979BBC;
}
.number-name {
font-weight: bold;
font-size: 25px;
color: #17192C;
}
.header-names {
display: flex;
width: 82%;
justify-content: space-between;
margin: 0 auto;
padding-top: 20px;
}
.header-area {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
width: 97%;
margin: 0 auto;
}
.content-header {
width: 100%;
background: white;
padding-bottom: 22px;
}
.footer {
display: flex;
justify-content: end;
margin-top: 20px;
}
.tianjia {
position: relative;
top: -9px;
background-color: #5065F6;
}
.tianjia2 {
position: relative;
top: -9px;
background-color: #EDEFFE;
color: #5065F6;
}
::v-deep .el-table thead {
background-color: #EDEFFE !important;
color: #363636 !important;
}
::v-deep .el-table__header th {
background-color: #EDEFFE !important;
color: #363636 !important;
}
.formitem {
position: relative;
top: -5px;
}
::deep .el-form-item__label {
font-size: 15px !important;
}
.selects {
width: 100px;
border: 1px solid #3333;
}
.headers-name {
font-size: 15px;
position: relative;
top: 14px;
}
.headers {
display: flex;
justify-content: space-between;
}
::v-deep .el-table__body tr:hover > td {
background-color: transparent !important;
}
::v-deep .el-table__body tr.el-table__row--striped td {
background-color: transparent;
}
.audit-dialog ::v-deep .el-dialog {
border-radius: 8px;
}
.audit-dialog ::v-deep .el-dialog__header {
padding: 16px 24px;
border-bottom: 1px solid #EBEEF5;
}
.audit-dialog ::v-deep .el-dialog__body {
padding: 24px;
}
.audit-dialog ::v-deep .el-dialog__footer {
padding: 12px 24px 20px;
border-top: 1px solid #EBEEF5;
}
.dialog-title {
font-size: 16px;
font-weight: bold;
color: #303133;
}
.dialog-section {
margin-bottom: 24px;
}
.dialog-section-header {
font-size: 14px;
font-weight: 600;
color: #363636;
margin-bottom: 16px;
}
.reviewer-selects {
display: flex;
flex-wrap: wrap;
gap: 16px;
}
.reviewer-item {
display: flex;
align-items: center;
background: #F7F8FF;
border: 1px solid #DCE0FD;
border-radius: 6px;
padding: 12px 16px;
min-width: 240px;
}
.reviewer-label {
font-size: 13px;
color: #363636;
margin-right: 12px;
flex: 0 0 auto;
}
.reviewer-select {
flex: 1;
}
.module-section {
border-radius: 6px;
margin-top: 23px;
}
.module-tree {
max-height: 360px;
overflow: auto;
background: #fff;
border: 1px solid #DCE0FD;
border-radius: 6px;
padding: 12px 16px;
}
.dialog-footer {
text-align: center;
}
.dialog-footer .el-button + .el-button {
margin-left: 16px;
}
.content-areas{
display: flex;
height: 50px;
flex-wrap: wrap;
margin-top: -1px;
}
.contents-left{
padding-right: 20px;
border: 1px solid #DCE0FD;
background: #EDEFFE;
line-height: 50px;
font-size: 14px;
color: #363636;
display: flex;
align-items: center;
}
.contents-right{
flex: 1;
border: 1px solid #DCE0FD;
border-left: none;
line-height: 50px;
font-size: 14px;
color: #363636;
display: flex;
align-items: center;
position: relative;
}
.contents-right:last-child {
border-right: 1px solid #DCE0FD;
}
.content-areas2{
position: relative;
top: -1px;
}
.rightss{
height: 100%;
border: 1px solid #DCE0FD;
border-top: none;
border-bottom: none;
width: 100%;
display: flex;
align-items: center;
flex: 1;
}
.rightss1{
border-left: none !important;
border-right: 1px solid #DCE0FD !important;
}
.rightss2{
background: #EDEFFE;
border-left: 1px solid #DCE0FD;
border-right: 1px solid #DCE0FD;
width: auto;
min-width: 120px;
flex: 0 0 auto;
justify-content: center;
}
.rightss3{
border-left: none !important;
border-right: none !important;
flex: 1;
}
.rightss-full{
border-left: none !important;
border-right: 1px solid #DCE0FD !important;
flex: 1;
width: 100%;
min-width: 0;
display: flex;
align-items: center;
}
.table-name{
margin-left: 20px;
}
</style>

View File

@@ -0,0 +1,927 @@
<template>
<div>
<div class="coentent">
<div class="contents-area">
<div class="areas">
<div v-if="active==0">
<div class="headers">
<div class="headers-name">高新技术产品 (服务) 明细</div>
<div>
<el-form :inline="true" :model="form" class="demo-form-inline">
<el-form-item label="收入类型" size="small">
<el-select v-model="form.revenueType" clearable placeholder="请选择" class="selects" style="width: 140px;" @change="handleRevenueTypeChange">
<el-option v-for="item in typeDate" :key="item.id" :label="item.title"
:value="item.id">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="年度选择" size="small">
<el-date-picker
style="width: 140px;"
v-model="form.year"
type="year"
placeholder="选择年度"
format="yyyy"
value-format="yyyy"
@change="handleYearChange">
</el-date-picker>
</el-form-item>
<el-form-item label="时间段选择" size="small">
<el-cascader
style="width: 140px;"
v-model="periodValue"
:options="periodOptions"
size="small"
class="cascader-select"
@change="handlePeriodChange">
</el-cascader>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="btnAdd" size="small" class="tianjia">添加产品</el-button>
</el-form-item>
</el-form>
</div>
</div>
<div class="content-table">
<el-table
:data="tableData"
:header-cell-style="{ background: '#EDEFFE', color: '#363636', textAlign: 'center' }"
border
style="width: 100%">
<el-table-column prop="serial" label="序号" width="80" align="center"></el-table-column>
<el-table-column prop="productName" label="产品(服务)名称" align="center"></el-table-column>
<el-table-column prop="isMainProduct" label="是否主要产品" width="120" align="center">
<template slot-scope="scope">
<span>{{ scope.row.isMainProduct }}</span>
</template>
</el-table-column>
<el-table-column prop="revenueType" label="收入类型" width="200" align="center">
<template slot-scope="scope">
<span>{{ scope.row.revenueType }}</span>
</template>
</el-table-column>
<el-table-column prop="sale_income" label="销售收入(元)" align="center" width="150">
<template slot-scope="scope">
<span>{{ formatCurrency(scope.row.sale_income || scope.row.salesRevenue || 0) }}</span>
</template>
</el-table-column>
<el-table-column fixed="right" label="操作" align="center" width="150">
<template slot-scope="scope">
<el-button @click="handleHomepage(scope.row)" type="text" size="small" style="color: #5165f7;">主页</el-button>
<el-button @click="handleDelete(scope.row)" type="text" size="small" style="color: #F56C6C;">删除</el-button>
</template>
</el-table-column>
</el-table>
<div class="footer">
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="currentPage"
:page-sizes="[100, 200, 300, 400]"
:page-size="pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="total">
</el-pagination>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 添加编辑产品对话框 -->
<el-dialog
title="添加编辑产品"
:visible.sync="dialogVisible"
width="800px"
:close-on-click-modal="false"
class="product-dialog">
<div class="content-table">
<div class="content-areas">
<div class="contents-left">
<span style="margin-left: 20px;">产品服务名称</span>
</div>
<div class="contents-right">
<span style="margin-left: 20px;"><el-input v-model="productForm.name" placeholder="请输入内容"></el-input></span>
</div>
</div>
<div class="content-areas content-areas2" style="top: 1px;">
<div class="contents-left">
<span class="table-name">收入类型</span>
</div>
<div class="contents-right">
<div class="rightss rightss1"><span class="table-name">
<el-select v-model="productForm.income_type" placeholder="请选择" class="no-border-select">
<el-option
v-for="item in typeDate"
:key="item.id"
:label="item.title"
:value="item.id">
</el-option>
</el-select>
</span></div>
<div class="rightss rightss2"><span class="table-name" style="margin-left: 0;">是否主要产品</span></div>
<div class="rightss rightss3" ><span class="table-name">
<el-select v-model="productForm.is_main" placeholder="请选择" class="no-border-select">
<el-option
v-for="item in changpingDate"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</span></div>
</div>
</div>
<div class="content-areas content-areas2" style="top: 1px;">
<div class="contents-left" >
<span class="table-name" >技术来源</span>
</div>
<div class="contents-right">
<div class="rightss rightss-full">
<el-select v-model="productForm.tech_source" placeholder="请选择" class="no-border-select" style="width: calc(100% - 40px); margin: 0 20px;" clearable>
<el-option
v-for="item in jishuDate"
:key="item.id"
:label="item.title"
:value="item.id">
</el-option>
</el-select>
</div>
</div>
</div>
<div class="content-areas content-areas2" style="top: 1px;">
<div class="contents-left" >
<span class="table-name">技术领域</span>
</div>
<div class="contents-right">
<div class="rightss rightss-full">
<el-select v-model="productForm.tech_area_one" placeholder="请选择" class="no-border-select" style="width: calc(100% - 40px); margin: 0 20px;" clearable>
<el-option
v-for="item in lingyuDate"
:key="item.id"
:label="item.title"
:value="item.id">
</el-option>
</el-select>
</div>
</div>
</div>
</div>
<div slot="footer" class="dialog-footer">
<el-button @click="handleCancel">取消</el-button>
<el-button type="primary" @click="handleSave" style="background-color: #5165f7;">添加保存</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { all,list,save } from '@/api/businessScope/productService'
export default {
data() {
return {
typeDate:[],
active: 0,
currentPage: 1,
pageSize: 10,
total: 0,
dialogVisible: false,
form: {
income_type: '',
year: ''
},
changpingDate:[
{
label:'是',
value:1,
},
{
label:'否',
value:2,
}
], //产品数据
periodValue: [],
periodOptions: [
{
value: 1,
label: "全年"
},
{
value: 2,
label: "半年",
children: [
{
value: '1',
label: '上半年'
},
{
value: '2',
label: '下半年'
}
]
},
{
value: 3,
label: "季度",
children: [
{
value: '1',
label: '第一季度'
},
{
value: '2',
label: '第二季度'
},
{
value: '3',
label: '第三季度'
},
{
value: '4',
label: '第四季度'
}
]
},
{
value: 4,
label: "月度",
children: [
{
value: '1',
label: '1月'
},
{
value: '2',
label: '2月'
},
{
value: '3',
label: '3月'
},
{
value: '4',
label: '4月'
},
{
value: '5',
label: '5月'
},
{
value: '6',
label: '6月'
},
{
value: '7',
label: '7月'
},
{
value: '8',
label: '8月'
},
{
value: '9',
label: '9月'
},
{
value: '10',
label: '10月'
},
{
value: '11',
label: '11月'
},
{
value: '12',
label: '12月'
}
]
}
],
productForm: {
name: '',
income_type: '',
is_main: '',
tech_source: '',
tech_area_one: ''
},
revenueTypeOptions: [
{
value: '全部',
label: '全部'
},
{
value: '产品收入',
label: '产品收入'
},
{
value: '技术转让收入',
label: '技术转让收入'
}
],
dialogRevenueTypeOptions: [
{
value: '产品收入',
label: '产品收入'
},
{
value: '技术转让收入',
label: '技术转让收入'
},
{
value: '技术服务收入',
label: '技术服务收入'
}
],
technologySourceOptions: [
{
value: '计算机产品及其网络应用技术',
label: '计算机产品及其网络应用技术'
},
{
value: '自主开发',
label: '自主开发'
},
{
value: '合作开发',
label: '合作开发'
},
{
value: '引进技术',
label: '引进技术'
}
],
technologyFieldOptions: [
{
value: '电子信息',
label: '电子信息'
},
{
value: '生物与新医药',
label: '生物与新医药'
},
{
value: '航空航天',
label: '航空航天'
},
{
value: '新材料',
label: '新材料'
},
{
value: '高技术服务',
label: '高技术服务'
},
{
value: '新能源与节能',
label: '新能源与节能'
},
{
value: '资源与环境',
label: '资源与环境'
},
{
value: '先进制造与自动化',
label: '先进制造与自动化'
}
],
technologyFieldDetailOptions: [
{
value: '网络应用技术',
label: '网络应用技术'
},
{
value: '计算机软件技术',
label: '计算机软件技术'
},
{
value: '通信技术',
label: '通信技术'
},
{
value: '其他',
label: '其他'
}
],
tableData: [],
jishuDate:[],
lingyuDate:[],
}
},
mounted(){
this.getall()
this.getList()
this.getall2()
this.getall3()
},
methods: {
//获取技术来源
getall2(){
all({dict_type_id:17}).then((res)=>{
this.jishuDate=res.data
})
},
//获取技术领域
getall3(){
all({dict_type_id:16}).then((res)=>{
this.lingyuDate=res.data
})
},
//获取收入类型
getall(){
all({dict_type_id:5}).then((res)=>{
this.typeDate=res.data
})
},
formatCurrency(value) {
// 处理 undefined、null、空字符串等情况
if (value === null || value === undefined || value === '') {
return '0'
}
// 转换为数字
const numValue = Number(value)
// 如果转换失败或为 NaN返回 '0'
if (isNaN(numValue)) {
return '0'
}
// 如果是 0返回 '0'
if (numValue === 0) {
return '0'
}
// 格式化数字
return numValue.toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 })
},
// 获取级联选择器的值
getPeriodValue() {
if (!this.periodValue || this.periodValue.length === 0) return ''
// 如果选择的是全年返回1
if (this.periodValue.length === 1 && this.periodValue[0] === 1) return '1'
// 如果是其他选项,返回对应的值
return this.periodValue.join(',')
},
// 获取列表数据
getList() {
const params = {
income_type: this.form.revenueType || '',
year: this.form.year || '',
period: this.getPeriodValue(),
page: this.currentPage,
limit: this.pageSize
}
list(params).then((res) => {
if (res && res.code === 1 && res.data) {
// 映射后端数据到前端表格
this.tableData = (res.data.data || []).map((item, index) => {
return {
id: item.id,
serial: (this.currentPage - 1) * this.pageSize + index + 1,
productName: item.name || item.product_name || '',
isMainProduct: item.is_main_product === 1 || item.is_main_product === '1' ? '是' : '否',
revenueType: item.income_type_name || item.revenue_type || '',
salesRevenue: item.sales_revenue || item.sales_money || 0,
sale_income: item.sale_income || item.sales_revenue || item.sales_money || 0
}
})
this.total = res.data.total || 0
} else {
this.$message.error(res?.msg || '获取数据失败')
this.tableData = []
this.total = 0
}
}).catch((error) => {
console.error('获取列表数据失败:', error)
this.$message.error('获取数据失败')
this.tableData = []
this.total = 0
})
},
// 年度选择变化
handleYearChange() {
this.currentPage = 1
this.getList()
},
// 时间段选择变化
handlePeriodChange() {
this.currentPage = 1
this.getList()
},
// 收入类型变化
handleRevenueTypeChange() {
this.currentPage = 1
this.getList()
},
handleHomepage(row) {
this.$router.push('/productServiceDetail')
// 跳转到产品主页
},
handleDelete(row) {
this.$confirm('确定要删除该产品吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
console.log('删除', row)
// 处理删除逻辑
this.$message({
type: 'success',
message: '删除成功!'
})
}).catch(() => {
this.$message({
type: 'info',
message: '已取消删除'
})
})
},
btnAdd() {
this.dialogVisible = true
// 重置表单
this.productForm = {
name: '',
income_type: '',
is_main: '',
tech_source: '',
tech_area_one: ''
}
},
handleSave() {
// 表单验证
if (!this.productForm.name || this.productForm.name.trim() === '') {
this.$message.error('请输入产品(服务)名称')
return
}
if (!this.productForm.income_type) {
this.$message.error('请选择收入类型')
return
}
if (!this.productForm.is_main) {
this.$message.error('请选择是否主要产品')
return
}
// 构建提交参数
const params = {
name: this.productForm.name.trim(),
income_type: this.productForm.income_type,
is_main: this.productForm.is_main
}
// 可选字段
if (this.productForm.tech_source) {
params.tech_source = this.productForm.tech_source
}
if (this.productForm.tech_area_one) {
params.tech_area_one = this.productForm.tech_area_one
}
// 调用保存接口
save(params).then((res) => {
if (res && res.code === 1) {
this.$message({
type: 'success',
message: '保存成功!'
})
this.dialogVisible = false
// 刷新列表
this.getList()
} else {
this.$message.error(res?.msg || '保存失败')
}
}).catch((error) => {
console.error('保存产品失败:', error)
this.$message.error('保存失败,请稍后重试')
})
},
handleCancel() {
this.dialogVisible = false
// 重置表单
this.productForm = {
name: '',
income_type: '',
is_main: '',
tech_source: '',
tech_area_one: ''
}
},
handleSizeChange(val) {
this.pageSize = val
this.currentPage = 1
this.getList()
},
handleCurrentChange(val) {
this.currentPage = val
this.getList()
}
}
}
</script>
<style>
.el-tooltip__popper.is-dark {
color: #F04B4B !important;
background: #FCF1EB !important;
}
.el-tooltip__popper .popper__arrow {
border-top-color: #FCF1EB !important;
}
.el-tooltip__popper .popper__arrow::after {
border-top-color: #FCF1EB !important;
}
.el-tooltip__popper[x-placement^='bottom'] .popper__arrow {
border-bottom-color: #FCF1EB !important;
}
.el-tooltip__popper[x-placement^='left'] .popper__arrow {
border-left-color: #FCF1EB !important;
}
.el-tooltip__popper[x-placement^='right'] .popper__arrow {
border-right-color: #FCF1EB !important;
}
</style>
<style scoped>
.areas {
padding-bottom: 15px;
width: 97%;
margin: 0 auto;
padding-top: 20px;
}
.active {
color: #5165f7 !important;
}
.heng {
width: 20px;
height: 6px;
background: #5165f7;
margin: 0 auto;
margin-top: 6px;
}
.header-table {
cursor: pointer;
}
.contentss-header {
width: 100%;
display: flex;
justify-content: space-between;
width: 150px;
}
.contentss {
width: 97%;
margin: 0 auto;
padding-top: 12px;
}
.contents-area {
width: 100%;
background: white;
margin-top: 20px;
}
.header-title {
position: relative;
top: 20px;
left: 25px;
}
.numbers {
position: relative;
top: -7px;
color: #2AB95F;
}
.number-name2 {
margin-top: 8px;
font-size: 14px;
color: #979BBC;
}
.number-name {
font-weight: bold;
font-size: 25px;
color: #17192C;
}
.header-names {
display: flex;
width: 82%;
justify-content: space-between;
margin: 0 auto;
padding-top: 20px;
}
.header-area {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
width: 97%;
margin: 0 auto;
}
.content-header {
width: 100%;
background: white;
padding-bottom: 22px;
}
.footer {
display: flex;
justify-content: end;
margin-top: 20px;
}
.tianjia {
position: relative;
top: -9px;
background-color: #5065F6;
}
::deep .el-form-item__label {
font-size: 15px !important;
}
.tianjia2 {
position: relative;
top: -9px;
background-color: #EDEFFE;
color: #5065F6;
}
::v-deep .el-table thead {
background-color: #EDEFFE !important;
color: #363636 !important;
}
::v-deep .el-table__header th {
background-color: #EDEFFE !important;
color: #363636 !important;
}
::deep .el-form-item__label {
font-size: 15px !important;
}
.selects {
width: 100px;
border: 1px solid #3333;
}
.cascader-select {
width: 120px;
}
::v-deep .el-date-editor.el-input .el-input__inner {
border: 1px solid #DCDFE6 !important;
}
::v-deep .el-date-picker .el-input__inner {
border: 1px solid #DCDFE6 !important;
}
::v-deep .el-select .el-input__inner {
border: 1px solid #DCDFE6 !important;
}
::v-deep .el-cascader .el-input__inner {
border: 1px solid #DCDFE6 !important;
}
.headers-name {
font-size: 15px;
position: relative;
top: 14px;
}
.headers {
display: flex;
justify-content: space-between;
}
::v-deep .el-table__body tr:hover > td {
background-color: transparent !important;
}
::v-deep .el-table__body tr.el-table__row--striped td {
background-color: transparent;
}
/* 产品对话框样式 */
.product-dialog ::v-deep .el-dialog__header {
padding: 20px 20px 10px;
border-bottom: 1px solid #EBEEF5;
text-align: center;
}
.product-dialog ::v-deep .el-dialog__title {
font-size: 16px;
font-weight: bold;
color: #303133;
}
.product-dialog ::v-deep .el-dialog__body {
padding: 20px;
}
.product-dialog ::v-deep .el-form-item__label {
font-size: 14px;
color: #606266;
}
.product-dialog .dialog-footer {
text-align: center;
padding-top: 10px;
}
.product-dialog .dialog-footer .el-button {
margin: 0 10px;
}
.content-areas{
display: flex;
height: 50px;
flex-wrap: wrap;
margin-top: -1px;
}
.contents-left{
width: 30%;
border: 1px solid #DCE0FD;
background: #EDEFFE;
line-height: 50px;
font-size: 14px;
color: #363636;
display: flex;
align-items: center;
}
.contents-right{
flex: 1;
border: 1px solid #DCE0FD;
border-left: none;
line-height: 50px;
font-size: 14px;
color: #363636;
display: flex;
align-items: center;
position: relative;
}
.contents-right:last-child {
border-right: 1px solid #DCE0FD;
}
.content-areas2{
position: relative;
top: -1px;
}
.rightss{
height: 100%;
border: 1px solid #DCE0FD;
border-top: none;
border-bottom: none;
width: 100%;
display: flex;
align-items: center;
flex: 1;
}
.rightss1{
border-left: none !important;
border-right: 1px solid #DCE0FD !important;
}
.rightss2{
background: #EDEFFE;
border-left: 1px solid #DCE0FD;
border-right: 1px solid #DCE0FD;
width: auto;
min-width: 120px;
flex: 0 0 auto;
justify-content: center;
}
.rightss3{
border-left: none !important;
border-right: none !important;
flex: 1;
}
.rightss-full{
border-left: none !important;
border-right: 1px solid #DCE0FD !important;
flex: 1;
width: 100%;
min-width: 0;
display: flex;
align-items: center;
}
.table-name{
margin-left: 20px;
}
/* 移除对话框中下拉框的边框 */
.product-dialog .no-border-select ::v-deep .el-input__inner {
border: none !important;
}
.product-dialog .no-border-select ::v-deep .el-input {
border: none !important;
}
.product-dialog .no-border-cascader ::v-deep .el-input__inner {
border: none !important;
}
.product-dialog .no-border-cascader ::v-deep .el-input {
border: none !important;
}
</style>

View File

@@ -0,0 +1,864 @@
<template>
<div>
<div class="headers">
<div class="headers-left">
<div class="imgs">
</div>
<div class="img-right">
<div class="name-title">微育科技</div>
<div class="right-name" style="position: relative;top: 0.5px;">数智科创 · 通达未来 </div>
</div>
</div>
<div class="headers-right">
<div class="rights" @click="btnShng">
<div class="rights-names" style="color: #5165f7;">
上一页
</div>
</div>
</div>
</div>
<div class="areas">
<div style="width: 222px;">
<div class="lefts">
<div class="left-content">
<div class="left-img">
<img src="@/assets/resource/ziliao.png" alt="">
</div>
<div class="right-name">
<span class="ziliao">资料完整度</span>
<span class="dushu">38%</span>
</div>
</div>
<div class="content-area">
<div class="area-name" v-for="(item, index) in listDate" :key="index" @click="btnActive(index)">
<div class="yuan" :class="{ 'active2': active2 == index }"></div>
<span class="namess" :class="{ 'active': active == index }">{{ item.name }}</span>
<span class="fanhui" v-show="active == index"><i class="el-icon-arrow-right"></i></span>
</div>
</div>
</div>
</div>
<div class="area-right">
<div class="area-rights" id="basic-info">
<div class="neirongs">
<div class="zong">
<div class="shu"></div>
<span class="jib">基本情况</span>
</div>
<div class="table-area">
<div>
<div class="headerss">
<div class="jiben">情况概述</div>
<div><el-button class="bianji" type="primary" size="mini" @click="btnqingkuang">编辑</el-button></div>
</div>
<div class="table-areas" >
<el-table
:data="tableData"
:header-cell-style="{ background: '#EDEFFE', color: '#363636' }"
border
style="width: 100%"
class="no-child-header"> <!-- 添加 class -->
<el-table-column prop="date" label="产品(服务)名称" width="180" align="center">
</el-table-column>
<el-table-column prop="name" label="收入类型" width="180" align="center">
</el-table-column>
<el-table-column prop="address" label="技术来源" align="center">
</el-table-column>
<el-table-column prop="address" label="是否主要产品" align="center">
</el-table-column>
<!-- 技术领域父列 -->
<el-table-column prop="address" label="技术领域" align="center">
<!-- 子列1 -->
<el-table-column prop="address" align="center">
</el-table-column>
<!-- 子列2 -->
<el-table-column prop="address" align="center">
</el-table-column>
<!-- 子列3 -->
<el-table-column prop="address" align="center">
</el-table-column>
</el-table-column>
</el-table>
</div>
</div>
</div>
</div>
</div>
<div class="area-rights" id="project-info">
<div class="neirongs">
<div class="zong">
<div class="shu"></div>
<span class="jib">产权关联</span>
</div>
<div class="table-area">
<div>
<div class="headerss">
<div class="jiben">知识产权</div>
<div><el-button class="bianji" @click="btnLixiangziliao" type="primary" size="mini" >编辑</el-button></div>
</div>
<div class="table-areas" >
<el-table :data="[...tableData, ...investmentBudgetData]" :header-cell-style="{ background: '#EDEFFE', color: '#363636' }" border style="width: 100%">
<el-table-column prop="date2" label="序号" width="80" align="center">
</el-table-column>
<el-table-column prop="date" label="名称" align="center">
</el-table-column>
<el-table-column prop="name" label="类别" width="180" align="center">
</el-table-column>
<el-table-column prop="address" label="登记号/公告号/编号" width="180" align="center">
</el-table-column>
<el-table-column prop="address" label="获得方式" align="center">
</el-table-column>
<el-table-column label="操作" width="180" align="center">
<template slot-scope="scope">
<el-button v-if="scope.row.type === 'investment'" @click="btnTouziyusuanDetail(scope.row)" type="text" size="small" style="color: #5165f7;">详情</el-button>
</template>
</el-table-column>
</el-table>
</div>
</div>
</div>
</div>
</div>
<div class="area-rights" id="project-members">
<div class="neirongs">
<div class="zong">
<div class="shu"></div>
<span class="jib">技术说明</span>
</div>
<div class="table-area">
<div>
<div class="headerss">
<div class="jiben">高新技术产品服务关键技术和技术指标具体说明
<el-tooltip class="item" effect="dark" content="高新技术产品(服务)关键技术和技术指标具体说明" placement="top-start">
<i class="el-icon-info" style="color: #D6D8EA;margin-left: 9px;"></i>
</el-tooltip>
</div>
</div>
<div class="table-areas" >
<el-table :data="tableData" :header-cell-style="{ background: '#EDEFFE', color: '#363636' }" border style="width: 100%">
<el-table-column prop="date2" label="序号" width="80" align="center">
</el-table-column>
<el-table-column prop="date" label="说明内容" align="center">
</el-table-column>
<el-table-column prop="name" label="说明情况" width="200" align="center">
</el-table-column>
<el-table-column label="操作" width="180" align="center">
<template slot-scope="scope">
<el-button @click="btnTouziyusuanDetail(scope.row)" type="text" size="small" style="color: #5165f7;">查看编辑</el-button>
</template>
</el-table-column>
</el-table>
</div>
</div>
</div>
</div>
</div>
<div class="area-rights" id="contract-manage">
<div class="neirongs">
<div class="zong">
<div class="shu"></div>
<span class="jib">销售情况</span>
</div>
<div class="table-area">
<div>
<div class="headerss">
<div class="jiben">合同明细 <span>合计销售金额12344.00</span>
</div>
<div class="rightsss">
<el-form ref="form" :inline="true" :model="form" label-width="80px">
<el-form-item label="合同性质">
<el-select v-model="value" size="mini" style="height: 30px; line-height: 30px;width: 120px;" class="biankuang" clearable placeholder="请选择">
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
</el-form>
</div>
</div>
<div class="table-areas" >
<el-table :data="tableData" :header-cell-style="{ background: '#EDEFFE', color: '#363636' }" border style="width: 100%">
<el-table-column prop="date2" label="序号" width="80" align="center">
</el-table-column>
<el-table-column prop="date" label="销售(合同)项目名称" align="center">
</el-table-column>
<el-table-column prop="name" label="合同签订日期" width="200" align="center">
</el-table-column>
<el-table-column prop="address" label="销售(收款)金额(元)" width="200" align="center">
</el-table-column>
<el-table-column
align="center"
label="操作"
width="80">
<template slot-scope="scope">
<el-button @click="btnHetongmingxidetail(scope.row)" type="text" size="small">详情</el-button>
</template>
</el-table-column>
</el-table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<el-dialog
title="高新技术产品(服务)关键技术和技术指标具体说明"
:visible.sync="techDialogVisible"
width="800px"
class="tech-dialog"
:close-on-click-modal="false">
<el-form :model="techDialogForm" label-position="top">
<el-form-item label="关键技术及主要技术指标限400字">
<el-input
type="textarea"
v-model="techDialogForm.coreTechnology"
:rows="6"
maxlength="400"
show-word-limit
placeholder="请输入内容" />
</el-form-item>
<el-form-item label="与同类产品服务的竞争优势限400字">
<el-input
type="textarea"
v-model="techDialogForm.competitiveAdvantage"
:rows="6"
maxlength="400"
show-word-limit
placeholder="请输入内容" />
</el-form-item>
<el-form-item label="知识产权获得情况及其产品服务在技术上支撑的支持作用限400字">
<el-input
type="textarea"
v-model="techDialogForm.ipSupport"
:rows="6"
maxlength="400"
show-word-limit
placeholder="请输入内容" />
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="handleTechDialogCancel">取消</el-button>
<el-button type="primary" @click="handleTechDialogSave">保存</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
export default {
data() {
return {
zhishichangquanShow:false,
jiediantixinShow:false,
jisulianyuShow:false,
jiben:false,
tixingshezhiShow:false,
tupianAShow:false,
form:{
name:""
},
tableData: [{
date2:1,
date: '2016-05-02',
name: '王小虎',
province: '上海',
city: '普陀区',
address: '上海市普陀区金沙江路 1518 弄',
zip: 200333
}],
investmentBudgetData: [{
date2: 1,
date: '投资预算',
name: '-',
address: '-',
type: 'investment'
}],
techDialogVisible: false,
techDialogForm: {
coreTechnology: '',
competitiveAdvantage: '',
ipSupport: ''
},
currentTechRow: null,
active2: 0,
active: 0,
activeItemIndex: null,
activeMenu: '0',
activeColor: '#409EFF',
listDate: [
{ name: '基本情况', id: 'basic-info' },
{ name: '产权关联', id: 'project-info' },
{ name: '技术说明', id: 'project-members' },
{ name: '销售情况', id: 'contract-manage' },
]
}
},
components:{
},
created() {
},
mounted(){
},
methods: {
//科技费用明细
btnkejifeiyong(){
this.$router.push('/feiyongmingxikeji')
},
btnfeiyongzhukeji(){
this.$router.push('/feiyongmingxiDetail')
},
//成果图片
chengguoimg(){
this.tupianAShow=true
},
//成果编辑
btnChengguo(){
this.$router.push('/chengguo')
},
//知识产权编辑
btnzhichichang(){
this.zhishichangquanShow=true
},
//知识产权关闭
zhichiClose(){
this.zhishichangquanShow=false
},
//科技成果详情
btnkejichengguoDetail(){
this.$router.push('/kejichengguoDetail')
},
//科技成果编辑
btnkejichengguo(){
this.$router.push('/kejichengguo')
},
//文档详情
btnwendangxiang(){
this.$router.push('/wendangDetai')
},
//文档编辑
btnWen(){
this.$router.push('/wendang')
},
//结题详情
btnjietixiangqin(){
this.$router.push('/jiantiDetial')
},
//结题编辑
btnJieti(){
this.$router.push('/jianti')
},
//检查情况编辑
btnzhogni(){
this.$router.push('/zhongqi')
},
//检查情况详情
btnjianchaDetial(){
this.$router.push('/zhongqiDetai')
},
//节点详情
btnjiedianxiang(){
this.$router.push('/xiangmujiedianEdint')
},
//项目节点编辑
btnjeidian(){
this.$router.push('/xiangmujiedian')
},
//项目节点关闭
jinduClose(){
this.jiediantixinShow=false
},
//项目节点提醒
btntixing(){
this.jiediantixinShow=true
},
//进度报告详情
btnjindubaogao(){
this.$router.push('/jindubaogaoDetail')
},
//编辑进度报告
btnjinduEdint(){
this.$router.push('/jindubaogao')
},
//关闭提醒
tixinClose(){
this.tixingshezhiShow=false
},
//提醒设置
btntixin(){
this.tixingshezhiShow=true
},
//支出明细主页
btnfeiyongzhu(){
this.$router.push('/indexzhu')
},
//支出明细编辑
btnzhichu(){
this.$router.push('/feiyongmingxi')
},
//合同明细主页
btnHetongmingxidetail(){
this.$router.push('/xiaoshouqingkuan')
},
//合同明细
btnHetongmingxi(){
this.$router.push('/hetongmingxin')
},
//成员明细
btnCheng(){
this.$router.push('/chengyuan')
},
//任务清单
btnRen(){
this.$router.push('/renwuqingdan')
},
//立即预算
btnLiyusuan(){
this.$router.push('/lixiangyusuan')
},
//立项资料
btnLixiangziliao(){
this.$router.push('/lixiangziliao')
},
//投资预算编辑
btnTouziyusuanEdit(){
this.$router.push('/touziyusuanEdit')
},
//投资预算详情 / 技术说明查看
btnTouziyusuanDetail(row){
this.currentTechRow = row || null
this.techDialogVisible = true
},
//情况概述
btnqingkuang(){
this.jiben=true
},
closeOK(){
this.jiben=false
},
//技术领先和来源
jishuClose(){
this.jisulianyuShow=false
},
btnJishu(){
this.jisulianyuShow=true
},
//上一页
btnShng(){
this.$router.go(-1)
},
hideNestedHeaders({ column }) {
if (column.label === "立项时间" || column.label === "项目名称" || column.label === "项目类型") {
return { display: 'none' }; // ⭐️ 隐藏子列表头
}
return { background: '#EDEFFE', color: '#363636' }; // ⭐️ 主表头样式
},
//点击左边的切换
btnActive(e) {
this.active = e
this.active2 = e
this.scrollToSection(e);
},
scrollToSection(index) {
const targetId = this.listDate[index].id;
const element = document.getElementById(targetId);
if (element) {
// 计算需要滚动的距离(考虑顶部固定栏)
const headerHeight = document.querySelector('.headers').offsetHeight;
const scrollTop = element.offsetTop - headerHeight;
// 使用requestAnimationFrame实现平滑滚动
const startPos = window.pageYOffset;
const distance = scrollTop - startPos;
const duration = 500;
let startTime = null;
const animateScroll = (timestamp) => {
if (!startTime) startTime = timestamp;
const progress = timestamp - startTime;
const percent = Math.min(progress / duration, 1);
window.scrollTo(0, startPos + distance * percent);
if (progress < duration) {
window.requestAnimationFrame(animateScroll);
}
};
window.requestAnimationFrame(animateScroll);
}
},
handleTechDialogCancel() {
this.techDialogVisible = false
},
handleTechDialogSave() {
this.$message.success('保存成功')
this.techDialogVisible = false
}
}
}
</script>
<style>
.hide-nested-headers .el-table__header .el-table-column--nested th {
display: none;
}
.hide-all-headers .el-table__header-wrapper {
display: none !important;
}
</style>
<style scoped>
::v-deep .no-child-header thead tr:last-child {
display: none !important;
}
::v-deep .el-table--border th.el-table__cell, .el-table__fixed-right-patch {
border-bottom: 1px solid #DCE0FD !important;
border-left: 1px solid #DCE0FD !important;
border-right: 1px solid #DCE0FD !important;
}
::v-deep .el-input__prefix{
height: 100%;
left: 5px;
transition: all .3s;
position: relative !important;
top: -34px !important;
}
.selects{
position: relative;
left: -11px;
}
.biankuang{
border: 1px solid #EDEFFE;
height: 30px;
line-height: 30px
}
.biankuang ::v-deep .el-input__inner {
height: 28px !important;
line-height: 28px !important;
padding-top: 0;
padding-bottom: 0;
}
.rightsss{
position: relative;
top: -18px;
}
.jib{
position: relative;
left: 12px;
top: -4px;
font-size: 18px;
}
.jiben{
position: relative;
top: -4px;
left: 12px;
}
.bianji{
background-color: #DCE0FD;
color: #5065F6;
border: 1px solid #5065F6;
position: relative;
top: -6px;
}
.headerss{
display: flex;
justify-content: space-between;
width: 96%;
margin: 0 auto;
padding-top: 30px;
padding-bottom: 15px;
height: 18px;
}
.table-areas {
width: 96%;
margin: 0 auto;
}
.table-area {
width: 100%;
padding-bottom: 20px;
background: white;
border-radius: 10px;
}
.areas {
display: flex;
}
.area-right {
flex: 1;
}
.area-rights {
width: 97%;
margin: 0 auto;
margin-top: 32px;
}
.fanhui {
float: right;
color: #5165f7;
position: relative;
top: -3px;
}
.zong{
margin-left: 33px;
padding-bottom: 14px;
}
.shu {
width: 4px;
height: 18px;
background: #5165f7;
position: relative;
top: 0px;
/* left: 40%; */
display: inline-block;
}
.active {
color: #5165f7 !important;
}
.active2 {
background: #5165f7 !important;
}
.rights-names {
margin-left: 32px;
cursor: pointer;
}
.rights {
width: 96%;
height: 100%;
margin: 0 auto;
line-height: 94px;
display: flex;
position: relative;
left: -27px;
}
.name-title {
position: relative;
top: -6px;
font-weight: bold;
}
.right-name {
font-size: 12px;
}
.yanse{
color: #5065F6;
}
.img-right {
font-size: 14px;
position: relative;
top: 40px;
height: 40px;
margin-left: 12px;
}
.imgs {
width: 45px;
height: 46px;
background: #5165f7;
border-radius: 6px;
position: relative;
top: 26px;
margin-left: 24px
}
.headers-right {
flex: 1;
background: white;
}
.headers-left {
width: 222px;
height: 100%;
display: flex;
background: white;
border-right: 1px solid #EDEFFE;
}
.headers {
width: 100%;
height: 90px;
display: flex;
border-bottom: 1px solid #EDEFFE;
}
.yuan {
width: 10px;
height: 10px;
background-color: #EAEBF0;
border-radius: 50%;
z-index: 99;
position: absolute;
left: -6px;
}
.namess {
margin-left: 18px;
margin-left: 18px;
position: relative;
top: -5px;
}
.area-name {
width: 100%;
height: 56px;
position: relative;
border-left: 1px solid #F2F2F2;
cursor: pointer;
}
.content-area {
width: 78%;
margin: 0 auto;
margin-top: 32px;
}
.right-name {
position: relative;
top: -12px;
}
.dushu {
font-size: 20px;
font-weight: bold;
margin-left: 7px;
}
.ziliao {
color: #979BBC;
font-size: 14px;
}
.left-img {
width: 36px;
height: 36px;
}
.left-content {
width: 78%;
margin: 0 auto;
display: flex;
justify-content: space-between;
height: 42px;
border-bottom: 1px solid #EDEFFE;
line-height: 52px;
margin-top: 14px;
}
:deep .el-menu-item.is-active {
color: #5165f7 !important;
}
/* 调整整体间距 */
.lefts {
padding: 8px 0;
background: white;
border-top: 1px solid #EDEFFE
}
.tech-dialog ::v-deep .el-dialog__header {
padding: 18px 24px 12px;
border-bottom: 1px solid #EBEEF5;
}
.tech-dialog ::v-deep .el-dialog__title {
font-size: 16px;
font-weight: 600;
color: #303133;
}
.tech-dialog ::v-deep .el-dialog__body {
padding: 24px;
background: #f9faff;
}
.tech-dialog ::v-deep .el-form-item__label {
font-size: 14px;
color: #606266;
}
.tech-dialog ::v-deep .el-textarea__inner {
background: #fff;
border-radius: 8px;
border: 1px solid #dce0fd;
font-size: 14px;
color: #303133;
}
.tech-dialog ::v-deep .el-input__count {
background: transparent;
color: #909399;
}
.tech-dialog .dialog-footer {
text-align: right;
padding: 10px 24px 20px;
}
</style>

View File

@@ -0,0 +1,824 @@
<template>
<div>
<div class="headers">
<div class="headers-left">
<div class="imgs">
</div>
<div class="img-right">
<div class="name-title">微育科技</div>
<div class="right-name">数智科创 · 通达未来 </div>
</div>
</div>
<div class="headers-right">
<div class="rights">
<div class="rights-names" @click="fanhui">
<span style="color: #5165f7;">上一级 <span>产品销售情况详情</span> </span>
</div>
</div>
</div>
</div>
<div class="contents">
<div class="content-left">
<div class="content-lefts">
<div class="leftss">
<div class="leftss-header">
<div>2023智慧A231销售项目</div>
</div>
<div class="table-area" >
<div class="table-header">
<div>
<div class="shu"></div> <span class="times"> 销售合同信息 </span>
</div>
</div>
</div>
</div>
<div class="content-table">
<div class="content-areas">
<div class="contents-left">
<span style="margin-left: 20px;">合同签订日期</span>
</div>
<div class="contents-right">
<span style="margin-left: 20px;">2023-11-14</span>
</div>
<div class="contents-left">
<span style="margin-left: 20px;">合同编号</span>
</div>
<div class="contents-right">
<span style="margin-left: 20px;">CDS0092</span>
</div>
</div>
<div class="content-areas content-areas2">
<div class="contents-left">
<span style="margin-left: 20px;">合同金额</span>
</div>
<div class="contents-right">
<span style="margin-left: 20px;"> 248000.00</span>
</div>
<div class="contents-left">
<span style="margin-left: 20px;">合同金额</span>
</div>
<div class="contents-right">
<span style="margin-left: 20px;"> 248000.00</span>
</div>
</div>
<div class="content-areas content-areas2">
<div class="contents-left">
<span class="table-name">经办人</span>
</div>
<div class="contents-right">
<div class="rightss rightss1"><span class="table-name">刘方杰李关林 </span></div>
</div>
</div>
</div>
<div class="pingzherngs">
<div class="table-area" >
<div class="table-header">
<div>
<div class="shu"></div> <span class="times"> 本产品服务销售情况 </span>
</div>
</div>
</div>
</div>
<div style="width: 90%;margin: 0 auto;margin-top: 20px;">
<el-table
:data="tableData"
border
style="width: 100%">
<el-table-column
align="center"
prop="date"
label="序号"
width="80">
</el-table-column>
<el-table-column
align="center"
prop="name"
label="数量"
width="80">
</el-table-column>
<el-table-column
align="center"
prop="name"
label="数量"
width="80">
</el-table-column>
<el-table-column
align="center"
prop="address"
label="单价(元)"
>
</el-table-column>
<el-table-column
align="center"
prop="address"
label="收款日期"
>
</el-table-column>
<el-table-column
align="center"
prop="address"
label="销售(收款)金额(元)"
>
</el-table-column>
<el-table-column
align="center"
prop="address"
label="备注"
>
</el-table-column>
</el-table>
</div>
</div>
</div>
<div class="content-right">
<div class="leftss-header right-header">
<div class="header-area">
<div class="area-name" v-for="(item,index) in listDate"
:key="index"
@click="btnNmae(index)"
:class="{'active':active ==index}"
>
{{item.name }}
</div>
</div>
<div> <el-button size="small" style="color:#5165f7;">
下载</el-button>
</div>
</div>
<div class="right-area"></div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
active:0,
listDate:[
{
name:'销售合同'
},
{
name:'发票凭证'
},
],
value1:"",
yuanright: 0,
tables: [
{
name: '有效'
},
{
name: '无效'
},
],
shu: 0,
lastActiveKey: 'headerActiveIndex',
tableData: [
{
date: "其中",
name: "",
address: "",
children: [
{ date: "2024", name: "年度审计报告及财务情况说明书", address: "8000" },
{ date: "2025", name: "年度审计报告及财务情况说明书", address: "7500" },
],
},
{ date: "其他项目", name: "5000", address: "4000" },
],
tableData2: [
{ date: "2025", name: "年度审计报告及财务情况说明书", address: "7500" },]
}
},
created() {
},
watch: {
},
methods: {
//返回
fanhui(){
this.$router.go('-1')
},
//取消
closeguan(){
this.$router.go('-1')
},
btnNmae(e){
this.active=e
},
//切换时效性
btnYuan(e) {
this.yuanright = e
},
//编辑跳转
btnEdint() {
},
}
}
</script>
<style>
.el-tooltip__popper.is-dark {
color: #F04B4B !important;
background: #FCF1EB !important;
}
.el-tooltip__popper .popper__arrow {
border-top-color: #FCF1EB !important;
/* 上方箭头 */
}
.el-tooltip__popper .popper__arrow::after {
border-top-color: #FCF1EB !important;
}
/* 其他方向的箭头(按需添加) */
.el-tooltip__popper[x-placement^='bottom'] .popper__arrow {
border-bottom-color: #FCF1EB !important;
}
.el-tooltip__popper[x-placement^='left'] .popper__arrow {
border-left-color: #FCF1EB !important;
}
.el-tooltip__popper[x-placement^='right'] .popper__arrow {
border-right-color: #FCF1EB !important;
}
</style>
<style scoped>
.area-name{
margin-left: 30px;
cursor: pointer;
}
.active{
border-bottom: 3px solid #5165f7;
height: 45px;
}
.header-area{
display: flex;
position: relative;
left: -30px;
}
.rightss3{
border-right: none;
border-left: none;
}
.table-name{
margin-left: 20px;
}
.rightss2{
background: #EDEFFE;
}
.rightss1{
border-left: none !important;
border-right: none !important;
}
.rightss{
height: 100%;
border: 1px solid #DCE0FD;
width: 100%;
border-top: none;
}
.content-areas2{
position: relative;
top: 1px;
}
.contents-right{
flex: 1;
border: 1px solid #DCE0FD;
line-height: 50px;
font-size: 14px;
color: #363636;
display: flex
}
.contents-left{
width: 30%;
border: 1px solid #DCE0FD;
background: #EDEFFE;;
line-height: 50px;
font-size: 14px;
color: #363636;
}
.content-areas{
display: flex;
height: 50px;
flex-wrap: wrap;
}
.tab-area{
margin-top: 24px;
}
.namess{
color: #5B5E72;
font-size: 13px;
margin-left: 12px;
}
.names{
font-size: 14px;
color: #363636;
}
:deep .el-tooltip__popper.is-dark {
color: #F04B4B !important;
}
.right-area {
width: 90%;
margin: 0 auto;
height: 80vh;
background: #f8f8f8;
}
.right-header {
width: 90%;
margin: 0 auto;
}
.ths {
text-align: center;
background: #DCE0FD !important;
color: #363636;
}
.tou {
height: 30px;
line-height: 30px;
color: #606266;
text-align: center;
}
.financial-table {
width: 100%;
border-collapse: collapse;
font-family: Arial, sans-serif;
font-size: 14px;
}
.financial-table th,
.financial-table td {
border: 1px solid #ddd;
padding: 8px 7px;
text-align: center;
}
.financial-table th {
background-color: #f5f5f5;
font-weight: bold;
}
.financial-table .nested-label {
text-align: center;
vertical-align: middle;
font-weight: bold;
}
.table-right {
flex: 1;
}
.table-left {
flex: 1;
}
.content-table {
width: 90%;
margin: 0 auto;
margin-top: 14px;
}
/* 默认情况(有效)左边圆角 */
.left-radius {
border-bottom-left-radius: 16px !important;
border-top-left-radius: 16px !important;
}
/* 无效情况右边圆角 */
.right-radius {
border-bottom-right-radius: 16px !important;
border-top-right-radius: 16px !important;
}
.yuan-left {
flex: 1;
text-align: center;
line-height: 30px;
background: #f8f8f8;
/* border-bottom-left-radius: 16px;
border-top-left-radius: 16px; */
cursor: pointer;
}
.yuanright {
flex: 1;
background: #5165f7;
color: white;
/* border-bottom-right-radius: 16px;
border-top-right-radius: 16px; */
text-align: center;
line-height: 30px;
cursor: pointer;
}
.youxiaos {
position: relative;
top: 6px;
left: -12px;
cursor: pointer;
}
/* 修改.yuan的样式移除外层圆角 */
.yuan {
width: 100px;
height: 30px;
background: white;
display: flex;
font-size: 14px;
overflow: hidden;
/* 关键确保内部div的圆角效果不被截断 */
}
/* 默认状态下两个按钮的外侧圆角 */
.yuan-left:first-child {
border-top-left-radius: 16px;
border-bottom-left-radius: 16px;
}
.yuan-left:last-child {
border-top-right-radius: 16px;
border-bottom-right-radius: 16px;
}
/* 选中状态样式 */
.yuanright {
background: #5165f7;
color: white;
}
/* 选中"有效"时的样式 */
.yuan-left.left-radius {
border-top-right-radius: 0 !important;
border-bottom-right-radius: 0 !important;
}
/* 选中"无效"时的样式 */
.yuan-left.right-radius {
border-top-left-radius: 0 !important;
border-bottom-left-radius: 0 !important;
}
.times {
position: relative;
top: 3px;
}
.youxiao {
color: #5B5D76;
font-size: 13px;
}
.table-header {
display: flex;
justify-content: space-between;
margin-top: 14px;
}
.table-area {
margin-top: 12px;
font-size: 15px;
}
.leftss-header {
display: flex;
height: 60px;
line-height: 60px;
border-bottom: 1px solid #3333;
font-weight: bold;
justify-content: space-between;
}
.leftss {
width: 90%;
margin: 0 auto;
}
.content-lefts {
background: white;
height: 100%;
width: 100%;
}
.content-left {
flex: 1;
padding-right: 12px;
min-height: 100%; /* 确保最小高度填满父容器 */
}
.content-right {
width: 600px;
min-height: 100%;
background: white;
}
.contents {
width: 100%;
min-height: calc(100vh - 70px); /* 70px 是 headers 的高度 */
background: #f8f8f8;
display: flex;
margin-top: 6px;
}
.pingzherngs{
width: 90%;
margin: 0px auto;
margin-top: 20px;
display: flex
;
justify-content: space-between;
}
.shu {
width: 3px;
height: 18px;
background: #5165f7;
position: relative;
display: inline-block;
top: 7px;
}
::v-deep .el-table thead {
background-color: #DCE0FD !important;
color: #363636 !important;
font-weight: bold;
}
::v-deep .el-table__header th {
background-color: #DCE0FD !important;
color: #363636 !important;
font-weight: bold;
}
.rights {
width: 96%;
height: 100%;
margin: 0 auto;
line-height: 88px;
display: flex;
position: relative;
left: 32vw;
top: -6px;
}
.name-title {
position: relative;
top: -6px;
font-weight: bold;
}
.right-name {
font-size: 12px;
}
.img-right {
font-size: 14px;
position: relative;
top: 35px;
height: 40px;
margin-left: 12px;
}
.imgs {
width: 42px;
height: 40px;
background: #5165f7;
border-radius: 6px;
position: relative;
top: 26px;
margin-left: 24px
}
.headers-right {
flex: 1;
background: white;
}
.headers-left {
width: 222px;
height: 100%;
display: flex;
background: white;
}
.headers {
width: 100%;
height: 70px;
display: flex;
}
.patent-container {
max-width: 1000px;
margin: 0 auto;
background: white;
border-radius: 8px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
overflow: hidden;
}
.patent-header {
background: linear-gradient(135deg, #6a5acd, #8a7dff);
color: white;
padding: 20px 30px;
text-align: center;
}
.patent-header h1 {
font-size: 24px;
margin-bottom: 10px;
font-weight: 600;
}
.patent-header p {
opacity: 0.9;
font-size: 14px;
}
.search-box {
padding: 15px 30px;
background-color: #f8f9fa;
border-bottom: 1px solid #eaeaea;
}
.search-box input {
width: 100%;
padding: 10px 15px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 14px;
transition: border-color 0.3s;
}
.search-box input:focus {
outline: none;
border-color: #8a7dff;
box-shadow: 0 0 0 2px rgba(138, 125, 255, 0.2);
}
.patent-table {
width: 100%;
border-collapse: collapse;
}
.patent-table th {
background-color: #f0e6ff;
color: #5a4fcf;
padding: 12px 15px;
text-align: left;
font-weight: 600;
border-bottom: 1px solid #ddd;
}
.patent-table td {
padding: 12px 15px;
border-bottom: 1px solid #f0f0f0;
transition: background-color 0.2s;
}
.patent-table tr:hover td {
background-color: #f9f7ff;
}
.patent-table tr:last-child td {
border-bottom: none;
}
.status-badge {
display: inline-block;
padding: 4px 8px;
border-radius: 4px;
font-size: 12px;
font-weight: 500;
}
.status-paid {
background-color: #e8f5e9;
color: #2e7d32;
}
.patent-footer {
padding: 15px 30px;
text-align: center;
color: #777;
font-size: 14px;
border-top: 1px solid #eaeaea;
background-color: #fafafa;
}
.active{
color: #5165f7 !important;
}
.rights-names{
margin-left: 32px;
cursor: pointer;
}
.name-title{
position: relative;
top: -6px;
font-weight: bold;
}
.right-name{
font-size: 12px;
}
.img-right{
font-size: 14px;
position: relative;
top: 40px;
height: 40px;
margin-left: 12px;
}
.imgs{
width: 45px;
height: 46px;
background: #5165f7;
border-radius: 6px;
position: relative;
top: 26px;
margin-left: 24px
}
.headers-right{
flex: 1;
background: white;
}
.headers-left{
width: 222px;
height: 100%;
display: flex;
background: white;
border-right: 1px solid #EDEFFE;
}
.headers{
width: 100%;
height: 90px;
display: flex
;
border-bottom: 1px solid #EDEFFE;
}
.rights{
width: 96%;
height: 100%;
margin: 0 auto;
line-height: 94px;
display: flex;
position: relative;
left: -27px;
}
</style>

View File

@@ -0,0 +1,794 @@
<template>
<div>
<div class="coentent">
<div class="contents-area">
<div class="areas">
<div v-if="active==0">
<div class="headers">
<div class="headers-name">销售项目明细</div>
<div>
<el-form :inline="true" :model="form" class="demo-form-inline">
<el-form-item label="年度选择" size="small">
<el-date-picker
style="width: 140px;"
v-model="form.year"
type="year"
placeholder="选择年度"
format="yyyy"
value-format="yyyy"
@change="handleYearChange">
</el-date-picker>
</el-form-item>
<el-form-item class="formitem">
<el-cascader
style="width: 140px;"
v-model="periodValue"
:options="periodOptions"
size="small"
class="cascader-select"
@change="handlePeriodChange">
</el-cascader>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="btnAdd" size="small" class="tianjia">添加产品</el-button>
</el-form-item>
</el-form>
</div>
</div>
<div class="content-table">
<el-table
:data="tableData"
:header-cell-style="{ background: '#EDEFFE', color: '#363636', textAlign: 'center' }"
border
style="width: 100%">
<el-table-column type="index" label="序号" width="80" align="center" :index="formatIndex"></el-table-column>
<el-table-column prop="name" label="销售(合同)项目名称" align="center"></el-table-column>
<el-table-column prop="create_time" label="合同签订日期" align="center">
</el-table-column>
<el-table-column prop="contract_money" label="合同金额(元)" width="150" align="center">
<template slot-scope="scope">
<span>{{ formatCurrency(scope.row.contract_money) }}</span>
</template>
</el-table-column>
<el-table-column prop="purchaser" label="业主单位(购买方)" align="center">
</el-table-column>
<el-table-column prop="sales_money" label="销售金额(元)" width="120" align="center">
</el-table-column>
<el-table-column fixed="right" label="操作" align="center" width="80">
<template slot-scope="scope">
<el-button @click="handleDelete(scope.row)" type="text" size="small" style="color: #5165f7;">详情</el-button>
</template>
</el-table-column>
</el-table>
<div class="footer">
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="currentPage"
:page-sizes="[100, 200, 300, 400]"
:page-size="pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="total">
</el-pagination>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import {list} from '@/api/businessScope/salesperformance.js'
export default {
data() {
return {
active: 0,
currentPage: 1,
pageSize: 10,
total: 0,
dialogVisible: false,
form: {
year: '',
isValid: ''
},
periodValue: [],
periodOptions: [
{
value: 1,
label: "全年"
},
{
value: 2,
label: "半年",
children: [
{
value: '1',
label: '上半年'
},
{
value: '2',
label: '下半年'
}
]
},
{
value: 3,
label: "季度",
children: [
{
value: '1',
label: '第一季度'
},
{
value: '2',
label: '第二季度'
},
{
value: '3',
label: '第三季度'
},
{
value: '4',
label: '第四季度'
}
]
},
{
value: 4,
label: "月度",
children: [
{
value: '1',
label: '1月'
},
{
value: '2',
label: '2月'
},
{
value: '3',
label: '3月'
},
{
value: '4',
label: '4月'
},
{
value: '5',
label: '5月'
},
{
value: '6',
label: '6月'
},
{
value: '7',
label: '7月'
},
{
value: '8',
label: '8月'
},
{
value: '9',
label: '9月'
},
{
value: '10',
label: '10月'
},
{
value: '11',
label: '11月'
},
{
value: '12',
label: '12月'
}
]
}
],
isValidOptions: [
{
value: 1,
label: "有效"
},
{
value: 2,
label: "无效"
}
],
productForm: {
productName: '',
isMainProduct: '',
revenueType: '技术服务收入',
technologySource: '',
technologyField: '电子信息',
technologyFieldDetail: '网络应用技术'
},
productFormRules: {
productName: [
{ required: true, message: '请输入产品(服务)名称', trigger: 'blur' }
],
isMainProduct: [
{ required: true, message: '请选择是否主要产品', trigger: 'change' }
],
revenueType: [
{ required: true, message: '请选择收入类型', trigger: 'change' }
]
},
revenueTypeOptions: [
{
value: '全部',
label: '全部'
},
{
value: '产品收入',
label: '产品收入'
},
{
value: '技术转让收入',
label: '技术转让收入'
}
],
yearOptions: [
{
value: '2023',
label: '2023'
},
{
value: '2024',
label: '2024'
},
{
value: '2025',
label: '2025'
},
{
value: '2026',
label: '2026'
}
],
quarterOptions: [
{
value: '第一季度',
label: '第一季度'
},
{
value: '第二季度',
label: '第二季度'
},
{
value: '第三季度',
label: '第三季度'
},
{
value: '第四季度',
label: '第四季度'
}
],
dialogRevenueTypeOptions: [
{
value: '产品收入',
label: '产品收入'
},
{
value: '技术转让收入',
label: '技术转让收入'
},
{
value: '技术服务收入',
label: '技术服务收入'
}
],
technologySourceOptions: [
{
value: '计算机产品及其网络应用技术',
label: '计算机产品及其网络应用技术'
},
{
value: '自主开发',
label: '自主开发'
},
{
value: '合作开发',
label: '合作开发'
},
{
value: '引进技术',
label: '引进技术'
}
],
technologyFieldOptions: [
{
value: '电子信息',
label: '电子信息'
},
{
value: '生物与新医药',
label: '生物与新医药'
},
{
value: '航空航天',
label: '航空航天'
},
{
value: '新材料',
label: '新材料'
},
{
value: '高技术服务',
label: '高技术服务'
},
{
value: '新能源与节能',
label: '新能源与节能'
},
{
value: '资源与环境',
label: '资源与环境'
},
{
value: '先进制造与自动化',
label: '先进制造与自动化'
}
],
technologyFieldDetailOptions: [
{
value: '网络应用技术',
label: '网络应用技术'
},
{
value: '计算机软件技术',
label: '计算机软件技术'
},
{
value: '通信技术',
label: '通信技术'
},
{
value: '其他',
label: '其他'
}
],
tableData: []
}
},
mounted() {
this.getList()
},
methods: {
// 获取列表数据
getList() {
const params = {
year: this.form.year || '',
period: this.getPeriodValue(),
isValid: this.form.isValid || '',
page: this.currentPage,
limit: this.pageSize
}
list(params).then((res) => {
if (res && res.code === 1 && res.data) {
this.tableData = res.data.data || []
this.total = res.data.total || 0
} else {
this.$message.error(res?.msg || '获取数据失败')
this.tableData = []
this.total = 0
}
console.log('ererer',this.tableData)
}).catch((error) => {
console.error('获取列表数据失败:', error)
this.$message.error('获取数据失败')
this.tableData = []
this.total = 0
})
},
// 获取级联选择器的值
getPeriodValue() {
if (!this.periodValue || this.periodValue.length === 0) return ''
// 如果选择的是全年返回1
if (this.periodValue.length === 1 && this.periodValue[0] === 1) return '1'
// 如果是其他选项,返回对应的值
return this.periodValue.join(',')
},
// 年度选择变化
handleYearChange() {
this.currentPage = 1
this.getList()
},
// 时间段选择变化
handlePeriodChange() {
this.currentPage = 1
this.getList()
},
// 是否有效变化
handleIsValidChange() {
this.currentPage = 1
this.getList()
},
// 格式化序号
formatIndex(index) {
return (this.currentPage - 1) * this.pageSize + index + 1
},
formatCurrency(value) {
// 处理 undefined、null、空字符串等情况
if (value === null || value === undefined || value === '') {
return '0'
}
// 转换为数字
const numValue = Number(value)
// 如果转换失败或为 NaN返回 '0'
if (isNaN(numValue)) {
return '0'
}
// 如果是 0返回 '0'
if (numValue === 0) {
return '0'
}
// 格式化数字
return numValue.toLocaleString('zh-CN', { minimumFractionDigits: 2, maximumFractionDigits: 2 })
},
handleHomepage(row) {
this.$router.push('/productServiceDetail')
// 跳转到产品主页
},
handleDelete(row) {
// 跳转到详情页面
this.$router.push({
path: '/home/salesperformanceDetial',
query: { id: row.id }
})
},
btnAdd() {
this.$router.push('/salesperformanceEdint')
},
handleSave() {
this.$refs.productForm.validate((valid) => {
if (valid) {
console.log('保存产品', this.productForm)
// 处理保存逻辑
this.$message({
type: 'success',
message: '保存成功!'
})
this.dialogVisible = false
// 这里可以添加保存后的逻辑,比如刷新列表
} else {
console.log('表单验证失败')
return false
}
})
},
handleCancel() {
this.dialogVisible = false
// 重置表单
this.productForm = {
productName: '',
isMainProduct: '',
revenueType: '技术服务收入',
technologySource: '',
technologyField: '电子信息',
technologyFieldDetail: '网络应用技术'
}
if (this.$refs.productForm) {
this.$refs.productForm.clearValidate()
}
},
handleSizeChange(val) {
this.pageSize = val
this.currentPage = 1
this.getList()
},
handleCurrentChange(val) {
this.currentPage = val
this.getList()
}
}
}
</script>
<style>
.el-tooltip__popper.is-dark {
color: #F04B4B !important;
background: #FCF1EB !important;
}
.el-tooltip__popper .popper__arrow {
border-top-color: #FCF1EB !important;
}
.el-tooltip__popper .popper__arrow::after {
border-top-color: #FCF1EB !important;
}
.el-tooltip__popper[x-placement^='bottom'] .popper__arrow {
border-bottom-color: #FCF1EB !important;
}
.el-tooltip__popper[x-placement^='left'] .popper__arrow {
border-left-color: #FCF1EB !important;
}
.el-tooltip__popper[x-placement^='right'] .popper__arrow {
border-right-color: #FCF1EB !important;
}
</style>
<style scoped>
.areas {
padding-bottom: 15px;
width: 97%;
margin: 0 auto;
padding-top: 20px;
}
.active {
color: #5165f7 !important;
}
.heng {
width: 20px;
height: 6px;
background: #5165f7;
margin: 0 auto;
margin-top: 6px;
}
.header-table {
cursor: pointer;
}
.contentss-header {
width: 100%;
display: flex;
justify-content: space-between;
width: 150px;
}
.contentss {
width: 97%;
margin: 0 auto;
padding-top: 12px;
}
.contents-area {
width: 100%;
background: white;
margin-top: 20px;
}
.header-title {
position: relative;
top: 20px;
left: 25px;
}
.numbers {
position: relative;
top: -7px;
color: #2AB95F;
}
.number-name2 {
margin-top: 8px;
font-size: 14px;
color: #979BBC;
}
.number-name {
font-weight: bold;
font-size: 25px;
color: #17192C;
}
.header-names {
display: flex;
width: 82%;
justify-content: space-between;
margin: 0 auto;
padding-top: 20px;
}
.header-area {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
width: 97%;
margin: 0 auto;
}
.content-header {
width: 100%;
background: white;
padding-bottom: 22px;
}
.footer {
display: flex;
justify-content: end;
margin-top: 20px;
}
.tianjia {
position: relative;
top: -9px;
background-color: #5065F6;
}
.tianjia2 {
position: relative;
top: -9px;
background-color: #EDEFFE;
color: #5065F6;
}
::v-deep .el-table thead {
background-color: #EDEFFE !important;
color: #363636 !important;
}
::v-deep .el-table__header th {
background-color: #EDEFFE !important;
color: #363636 !important;
}
.formitem {
position: relative;
top: -5px;
}
::deep .el-form-item__label {
font-size: 15px !important;
}
.selects {
width: 100px;
border: 1px solid #3333;
}
.cascader-select {
width: 120px;
}
::v-deep .el-date-editor.el-input .el-input__inner {
border: 1px solid #DCDFE6 !important;
}
::v-deep .el-date-picker .el-input__inner {
border: 1px solid #DCDFE6 !important;
}
::v-deep .el-select .el-input__inner {
border: 1px solid #DCDFE6 !important;
}
::v-deep .el-cascader .el-input__inner {
border: 1px solid #DCDFE6 !important;
}
.headers-name {
font-size: 15px;
position: relative;
top: 14px;
}
.headers {
display: flex;
justify-content: space-between;
}
::v-deep .el-table__body tr:hover > td {
background-color: transparent !important;
}
::v-deep .el-table__body tr.el-table__row--striped td {
background-color: transparent;
}
/* 产品对话框样式 */
.product-dialog ::v-deep .el-dialog__header {
padding: 20px 20px 10px;
border-bottom: 1px solid #EBEEF5;
text-align: center;
}
.product-dialog ::v-deep .el-dialog__title {
font-size: 16px;
font-weight: bold;
color: #303133;
}
.product-dialog ::v-deep .el-dialog__body {
padding: 20px;
}
.product-dialog ::v-deep .el-form-item__label {
font-size: 14px;
color: #606266;
}
.product-dialog .dialog-footer {
text-align: center;
padding-top: 10px;
}
.product-dialog .dialog-footer .el-button {
margin: 0 10px;
}
.content-areas{
display: flex;
height: 50px;
flex-wrap: wrap;
margin-top: -1px;
}
.contents-left{
width: 30%;
border: 1px solid #DCE0FD;
background: #EDEFFE;
line-height: 50px;
font-size: 14px;
color: #363636;
display: flex;
align-items: center;
}
.contents-right{
flex: 1;
border: 1px solid #DCE0FD;
border-left: none;
line-height: 50px;
font-size: 14px;
color: #363636;
display: flex;
align-items: center;
position: relative;
}
.contents-right:last-child {
border-right: 1px solid #DCE0FD;
}
.content-areas2{
position: relative;
top: -1px;
}
.rightss{
height: 100%;
border: 1px solid #DCE0FD;
border-top: none;
border-bottom: none;
width: 100%;
display: flex;
align-items: center;
flex: 1;
}
.rightss1{
border-left: none !important;
border-right: 1px solid #DCE0FD !important;
}
.rightss2{
background: #EDEFFE;
border-left: 1px solid #DCE0FD;
border-right: 1px solid #DCE0FD;
width: auto;
min-width: 120px;
flex: 0 0 auto;
justify-content: center;
}
.rightss3{
border-left: none !important;
border-right: none !important;
flex: 1;
}
.rightss-full{
border-left: none !important;
border-right: 1px solid #DCE0FD !important;
flex: 1;
width: 100%;
min-width: 0;
display: flex;
align-items: center;
}
.table-name{
margin-left: 20px;
}
</style>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,3 @@
<template>
<div>申报情况</div>
</template>

117
src/views/home.vue Normal file
View File

@@ -0,0 +1,117 @@
<template>
<div>
<div>
<headers :rightDate="rightDate" @menu-click="handleMenuClick"></headers>
</div>
<div class="contents">
<div>
<sidebar @headerDate="headerDate"></sidebar>
</div>
<div class="content">
<router-view></router-view>
</div>
</div>
</div>
</template>
<script>
import headers from '@/components/header'
import sidebar from '@/components/sidebar'
export default {
components: {
headers,
sidebar
},
data() {
return {
rightDate: ""
}
},
mounted() {
},
methods: {
// 处理菜单点击事件
handleMenuClick(item) {
console.log('获取到这个路由', item);
if (item.route && this.$route.path !== item.route) { // 增加判断
this.$router.push(item.route);
}
},
//获取头部的数据
headerDate(e) {
console.log('查看数据111', e)
if (e.name == '财务概览') {
this.rightDate = [
{
name: "经营情况",
route: '/operate'
}, {
name: "年度审计情况",
route: '/annual'
},
{ name: "专项审计情况" },
{ name: "企业所得税纳税情况" }]
if (this.$route.path !== e.route) { // 增加判断
this.$router.push(e.route);
}
} else if (e.name == '企业概况') {
this.rightDate = [
{
name: "数据概览",
route: '/home'
}, {
name: "资料检索",
route: '/home/dataretrieval'
},
{
name: "企业信息",
route: '/home/corporateInformation'
},
]
// 强制跳转到数据概览页面
if (this.$route.path !== '/home' && !this.$route.path.startsWith('/home/')) {
this.$router.push('/home');
} else if (this.$route.path !== '/home') {
this.$router.push('/home');
}
}
else if (e.name == '人力资源') {
this.rightDate = [{ name: "组织架构" }, { name: "职工管理" },{ name: "科技专家" }]
} else if (e.name == '成果管理') {
this.rightDate = [{ name: "知识产权" }, { name: "论文管理" }, { name: "标准制定" }]
} else if (e.name == '资质荣誉') {
this.rightDate = [{ name: "企业资源" }, { name: "企业荣誉" }]
} else if (e.name == '制度文件') {
this.rightDate = [{ name: "制度通知" }]
} else if (e.name == '合同登记') {
this.rightDate = [{ name: "登记管理" }]
}
console.log('头部的数据', e, this.rightDate)
}
}
}
</script>
<style scope>
.contents {
display: flex;
}
.content {
margin-left: 40px;
width: 85%;
margin-top: 20px;
border-radius: 10px;
}
</style>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,783 @@
<template>
<div style="background-color: #f8f8f8;">
<div class="headers">
<div class="headers-header">
<div class="header-names">
<div><span class="header-number">9</span></div>
<div style="margin-top: 9px;">当前未结束的研发项目</div>
</div>
</div>
<div class="headers-header">
<div class="header-names">
<div><span class="header-number">21</span></div>
<div style="margin-top: 9px;">累计销售的产品(服务)</div>
</div>
</div>
<div class="headers-header">
<div class="header-names">
<div><span class="header-number">120</span></div>
<div style="margin-top: 9px;">专家库专家</div>
</div>
</div>
<div class="headers-header">
<div class="header-names">
<div><span class="header-number">16</span></div>
<div style="margin-top: 9px;">有效知识产权数量</div>
</div>
</div>
<div class="headers-header">
<div class="header-names">
<div><span class="header-number">19</span></div>
<div style="margin-top: 9px;">论文数量</div>
</div>
</div>
<div class="headers-header">
<div class="header-names">
<div><span class="header-number">23</span></div>
<div style="margin-top: 9px;">标准制定</div>
</div>
</div>
<div class="headers-header">
<div class="header-names">
<div><span class="header-number">36</span></div>
<div style="margin-top: 9px;">资质证书</div>
</div>
</div>
</div>
<div class="contents">
<div class="contents-one">
<div class="one-lefts" style="width: 48.6%;">
<div class="one-left">
<div class="one-left-left">
<div class="kechuang">科创评估 <span><i class="el-icon-info"></i></span> </div>
<div class="zuoyue-area">
<div style="position: relative;top: -9px;">
<div class="zhuoy">卓越</div>
<div class="dengji">科创等级 | 86 </div>
</div>
</div>
</div>
<div id="main" style="width: 407px;height:400px;"></div>
</div>
</div>
<div class="one-lefts" style="padding-left: 0.5%;width: 51%;">
<div class="one-right">
<div class="one-right">
<div class="right-header">
<div class="content-name">科创认定情况 <span><i class="el-icon-info"></i></span> </div>
<div class="ngakénan-area">
<div style="padding-right: 30px;">
<div class="wei"></div>
<span>已认定</span>
</div>
<div>
<div class="wei" style="background-color: #D6D8EA;"></div>
<span>未认定</span>
</div>
</div>
</div>
<div class="kechuang-area">
<div class="kechuangs">
<div class="kechuan-name" v-for="(item, index) in listDate" :key="index"
:class="{ 'active2': item.type === 0 }">
{{ item.name }}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="contents" style="position: relative;top: -28px;">
<div class="contents-one">
<div class="one-lefts" style="width:48.6%;">
<div class="one-left">
<div>
<div class="kechuang">经营情况 <span style="color: #3333;">(万元)</span> </div>
</div>
<div id="kahanan" style="width: 407px;height:400px;"></div>
</div>
</div>
<div class="one-lefts" style="padding-left: 0.5%;width: 51%;">
<div class="one-right">
<div class="one-right">
<div class="right-header">
<div class="content-name">近一年产品服务收入 <span><i class="el-icon-info"></i></span> </div>
</div>
<div class="project-area">
<div class="project-header">
<div>产品服务名称</div>
<div>合计收入 <span>1300万元</span> </div>
</div>
<div class="projects-area">
<div class="projects" v-for="(item, index) in fuwuDate" :key="index">
<div class="biaozhi">{{ index + 1 }}</div>
<div class="projects-name">{{ item.name }}</div>
<div class="jindu"><el-progress :text-inside="true" :stroke-width="26"
:percentage=item.percentage></el-progress></div>
<div class="project-price">{{ item.price }}万元</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="contents" style="position: relative;top: -56px;">
<div class="contents-one">
<div class="one-lefts" style="width: 48.5%;">
<div class="one-left">
<div>
<div class="kechuang">企业职工 <span style="color: #3333;">()</span> </div>
</div>
<div id="qiye" style="width: 607px;height:400px;"></div>
</div>
</div>
<div class="one-lefts" style="padding-left: 0.5%;width: 51%">
<div class="zhiwu-area">
<div class="zhiwu-left">
<div class="zhiwus">
<div class="kechuang" style="margin-top: 0;">职称分布</div>
<div>
<div id="professionaltitle" style="width: 307px;height:320px;"></div>
</div>
</div>
</div>
<div class="zhiwu-left">
<div class="zhiwus2">
<div class="kechuang" style="margin-top: 0;">有效知识产权</div>
<div id="knowledges" style="width: 307px;height:320px;"></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import * as echarts from 'echarts'
export default {
name: 'dataoverview',
data() {
return {
fuwuDate: [
{ name: 'AY-99802VOCR动态服务系统', price: 700, percentage: 51 },
{ name: 'CD-98832服务', price: 600, percentage: 41 },
{ name: 'AG-科技资讯服务', price: 500, percentage: 15 },
{ name: 'UY-09812', price: 400, percentage: 23 },
{ name: 'UT-09812JJ', price: 300, percentage: 12 },
{ name: '其他', price: 360, percentage: 18 },
],
listDate: [
{ name: '雏鹰企业', type: 1 },
{ name: '高新技术企业', type: 1 },
{ name: '专精特新中小企业', type: 1 },
{ name: '独角兽企业', type: 1 },
{ name: '创新型中小企业', type: 0 },
{ name: '科技型中小企业', type: 0 },
{ name: '研究型机构', type: 0 },
{ name: '民营科技企业', type: 1 },
{ name: '工业互联网与云平台企业', type: 1 },
{ name: '绿色制造', type: 1 },
]
}
},
mounted() {
this.ones()
this.getkahanan()
this.getqiye()
this.getprofessionaltitle()
this.getknowledge()
},
methods: {
//科创评估
ones() {
// 基于准备好的dom初始化echarts实例
var myChart = echarts.init(document.getElementById('main'));
// 指定图表的配置项和数据
let option = {
graphic: {
type: 'text',
left: '39%',
top: '46%',
style: {
text: '86',
fontSize: 40,
fontWeight: 'bold',
fontFamily: 'Arial',
fill: '#ffffff', // 文字颜色
textAlign: 'center',
textVerticalAlign: 'middle'
},
z: 10
},
radar: [
{
indicator: [
{ text: '成长性' },
{ text: '研发实力' },
{ text: '技术规模' },
{ text: '科研成果' }
],
center: ['45%', '50%'],
radius: 120,
startAngle: 90,
splitNumber: 4,
shape: 'circle',
axisName: {
formatter: '{value}',
color: '#1c37ea'
},
splitArea: {
areaStyle: {
color: ['#b2bbf8', '#d1d7fc', '#dfe3fd', '#eef0fe']
}
},
splitLine: {
lineStyle: {
color: '#b2bbf8', // 网状线颜色
width: 1
}
}
}
],
series: [
{
type: 'radar',
emphasis: {
lineStyle: {
width: 4
}
},
data: [
{
value: [60, 5, 0.3, -100, 1500],
name: 'Data B',
areaStyle: {
color: 'rgba(116, 133, 248, 0.5)'
}
}
]
}
]
};
// 使用刚指定的配置项和数据显示图表。
myChart.setOption(option);
},
//经营情况
getkahanan() {
var kahanans = echarts.init(document.getElementById('kahanan'));
const colors = ['#5070dd', '#b6d634',];
let option = {
color: colors,
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross'
}
},
grid: {
right: '5%'
},
xAxis: [
{
type: 'category',
axisTick: {
alignWithLabel: true
},
data: ['2018', '2019', '2020', '2021', '2022', '2023', '2024', '2025', '2026', '2027', '2028', '2029']
}
],
yAxis: [
{
type: 'value',
name: 'Evaporation',
position: 'left', name: ''
},
{
type: 'value',
name: 'Precipitation',
position: 'right',
alignTicks: true,
offset: 80,
},
{
type: 'value',
name: '温度 (°C)',
position: 'left', // 左边纵坐标
alignTicks: true,
axisLine: {
show: true,
lineStyle: {
color: colors[2] // 颜色匹配 Temperature
}
},
axisLabel: {
formatter: '{value} °C'
}
}
],
series: [
{
name: 'Evaporation',
type: 'bar',
yAxisIndex: 0, // 绑定到右边的 yAxis (Evaporation)
data: [3.0, 4.9, 7.0, 23.2, 25.6, 76.7, 135.6, 162.2, 32.6, 20.0, 6.4, 3.3]
},
{
name: 'Temperature (Line 1)',
type: 'line',
yAxisIndex: 2, // 绑定到左边的 yAxis (温度)
data: [2.0, 2.2, 3.3, 4.5, 6.3, 10.2, 20.3, 23.4, 23.0, 16.5, 12.0, 6.2]
},
{
name: 'Temperature (Line 2)',
type: 'line',
yAxisIndex: 2, // 也绑定到左边的 yAxis
data: [5.0, 3.2, 4.3, 5.5, 3.3, 15.2, 30.3, 13.4, 23.0, 26.5, 22.0, 16.2]
}
]
};
kahanans.setOption(option);
},
//企业职工
getqiye() {
var getqiyes = echarts.init(document.getElementById('qiye'));
const colors = ['#5070dd', '#b6d634',];
let option = {
color: colors,
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross'
}
},
grid: {
right: '5%'
},
xAxis: [
{
type: 'category',
axisTick: {
alignWithLabel: true
},
data: ['2018', '2019', '2020', '2021', '2022', '2023', '2024', '2025', '2026', '2027', '2028', '2029']
}
],
yAxis: [
{
type: 'value',
name: 'Evaporation',
position: 'left', name: ''
},
{
type: 'value',
name: 'Precipitation',
position: 'right',
alignTicks: true,
offset: 80,
},
{
type: 'value',
name: '温度 (°C)',
position: 'left', // 左边纵坐标
alignTicks: true,
axisLine: {
show: true,
lineStyle: {
color: colors[2] // 颜色匹配 Temperature
}
},
axisLabel: {
formatter: '{value} °C'
}
}
],
series: [
{
name: 'Evaporation',
type: 'bar',
yAxisIndex: 0, // 绑定到右边的 yAxis (Evaporation)
data: [3.0, 4.9, 7.0, 23.2, 25.6, 76.7, 135.6, 162.2, 32.6, 20.0, 6.4, 3.3]
},
{
name: 'Temperature (Line 1)',
type: 'line',
yAxisIndex: 2, // 绑定到左边的 yAxis (温度)
data: [2.0, 2.2, 3.3, 4.5, 6.3, 10.2, 20.3, 23.4, 23.0, 16.5, 12.0, 6.2]
},
{
name: 'Temperature (Line 2)',
type: 'line',
yAxisIndex: 2, // 也绑定到左边的 yAxis
data: [5.0, 3.2, 4.3, 5.5, 3.3, 15.2, 30.3, 13.4, 23.0, 26.5, 22.0, 16.2]
}
]
};
getqiyes.setOption(option);
},
//职称分布
getprofessionaltitle() {
var professional = echarts.init(document.getElementById('professionaltitle'));
let option = {
tooltip: {
trigger: 'item'
},
legend: {
top: '5%',
left: 'center'
},
series: [
{
name: 'Access From',
type: 'pie',
radius: ['40%', '70%'],
center: ['50%', '55%'],
avoidLabelOverlap: false,
label: {
show: false,
position: 'center'
},
emphasis: {
label: {
show: true,
fontSize: 20,
fontWeight: 'bold'
}
},
labelLine: {
show: false
},
data: [
{ value: 1048, name: '高级职称' },
{ value: 735, name: '中级职称' },
{ value: 580, name: '初级职称' },
]
}
]
}
professional.setOption(option);
},
//有效知识产权
getknowledge(){
var knowledge = echarts.init(document.getElementById('knowledges'));
let option = {
tooltip: {
trigger: 'item'
},
legend: {
top: '5%',
left: 'center'
},
series: [
{
name: 'Access From',
type: 'pie',
center: ['50%', '55%'],
radius: ['40%', '70%'],
avoidLabelOverlap: false,
label: {
show: false,
position: 'center'
},
emphasis: {
label: {
show: true,
fontSize: 20,
fontWeight: 'bold'
}
},
labelLine: {
show: false
},
data: [
{ value: 1048, name: 'Search Engine' },
{ value: 735, name: 'Direct' },
{ value: 580, name: 'Email' },
{ value: 484, name: 'Union Ads' },
{ value: 300, name: 'Video Ads' }
]
}
]
}
knowledge.setOption(option);
}
}
}
</script>
<style>
.el-progress-bar__inner {
background-color: #8391F7 !important;
color: white !important;
}
.el-progress-bar__innerText {
color: white !important;
}
.el-progress-bar__outer {
height: 20px !important;
}
</style>
<style lang="scss" scoped>
.zhiwu-left {
flex: 1;
height: 100%;
}
.zhiwus {
width: 99%;
background: white;
border-radius: 8px;
padding-top: 30px;
}
.zhiwus2 {
width: 97%;
margin-left: 3%;
background: white;
border-radius: 8px;
padding-top: 30px;
}
.projects-area {}
.project-price {
width: 100px;
position: relative;
left: 30px;
top: 1px;
}
.projects-name {
width: 264px;
margin-left: 18px;
}
.jindu {
width: 349px;
position: relative;
left: 20px;
}
.biaozhi {
width: 20px;
height: 20px;
background: #EDEFFE;
text-align: center;
font-size: 12px;
line-height: 20px;
}
.projects {
margin-top: 18px;
display: flex;
}
.project-header {
display: flex;
margin-top: 24px;
color: #5B5E72;
justify-content: space-between;
}
.project-area {
width: 90%;
margin: 0 auto;
margin-top: 12px;
color: #202638;
}
.active2 {
background: #8391F7 !important;
color: white !important;
}
.kechuan-name {
padding: 10px 12px 10px 12px;
background: #F7F7FA;
color: #979BBC;
margin-left: 23px;
margin-top: 12px;
border-radius: 30px;
margin-top: 14px;
}
.kechuangs {
display: flex;
flex-wrap: wrap;
width: 80%;
margin: 0 auto;
margin-top: 32px;
}
.kechuang-area {}
.ngakénan-area {
display: flex;
font-size: 14px;
color: #979BBC;
position: relative;
top: 30px;
margin-right: 28px;
}
.wei {
display: inline-block;
width: 12px;
height: 12px;
background: #8391F7;
margin-right: 6px;
}
.right-header {
width: 100%;
height: 48px;
display: flex;
justify-content: space-between;
}
.one-rihgt {
display: flex;
}
.dengji {
position: relative;
left: 90px;
top: 42px;
}
.zhuoy {
font-size: 24px;
font-weight: bold;
position: relative;
left: 6vw;
top: 33px;
}
.zuoyue-area {
width: 216px;
height: 100px;
background: #EDEFFE;
margin-top: 96px;
}
.kechuang {
font-size: 18px;
font-weight: bold;
margin-left: 31px;
margin-top: 30px
}
.content-name {
margin-left: 31px;
font-size: 18px;
font-weight: bold;
position: relative;
top: 30px;
}
.one-left-left {
flex: 1;
}
.header-number {
font-size: 20px;
color: black;
padding-right: 5px;
font-weight: bold;
}
.header-names {
color: #979BBC;
margin-left: 25px;
margin-top: 32px;
font-size: 12px;
}
.one-left {
width: 99%;
height: 92%;
background: white;
border-radius: 10px;
display: flex;
}
.zhiwu-area {
display: flex;
height: 100%;
}
.one-right {
width: 100%;
height: 92%;
background: white;
border-radius: 10px;
}
.one-lefts {
}
.contents-one {
display: flex;
width: 100%;
margin-top: 14px;
}
.contents {
width: 100%;
background: #f8f8f8;
}
.headers {
background: #f8f8f8;
position: relative;
margin-left: -1.1%;
}
.headers-header {
width: 13.1%;
height: 100px;
border-radius: 10px;
background: white;
margin-top: 12px;
display: inline-block;
margin-left: 1.1%;
}
</style>

View File

@@ -0,0 +1,668 @@
<template>
<div>
<div class="content">
<div class="tabs-area">
<div
class="tab-item"
:class="{ 'active': activeTab === 'knowledge' }"
@click="activeTab = 'knowledge'"
>
知识产权
</div>
<div
class="tab-item"
:class="{ 'active': activeTab === 'paper' }"
@click="activeTab = 'paper'"
>
论文
</div>
<div
class="tab-item"
:class="{ 'active': activeTab === 'standard' }"
@click="activeTab = 'standard'"
>
标准制定
</div>
</div>
<!-- 知识产权筛选 -->
<div class="filter-area" v-if="activeTab === 'knowledge'">
<div class="filter-row">
<span class="filter-label">产权类型:</span>
<div class="filter-buttons">
<div
class="filter-btn"
:class="{ 'active': selectedType === 'all' }"
@click="selectedType = 'all'"
>
全部
</div>
<div
class="filter-btn"
:class="{ 'active': selectedType === 'invention' }"
@click="selectedType = 'invention'"
>
发明专利
</div>
<div
class="filter-btn"
:class="{ 'active': selectedType === 'plant' }"
@click="selectedType = 'plant'"
>
植物新品种
</div>
<div
class="filter-btn"
:class="{ 'active': selectedType === 'drug' }"
@click="selectedType = 'drug'"
>
国家新药
</div>
<div
class="filter-btn"
:class="{ 'active': selectedType === 'circuit' }"
@click="selectedType = 'circuit'"
>
集成电路布图设计专有权
</div>
<div
class="filter-btn"
:class="{ 'active': selectedType === 'utility' }"
@click="selectedType = 'utility'"
>
实用新型
</div>
<div
class="filter-btn"
:class="{ 'active': selectedType === 'software' }"
@click="selectedType = 'software'"
>
软件著作权
</div>
<div
class="filter-btn"
:class="{ 'active': selectedType === 'design' }"
@click="selectedType = 'design'"
>
外观设计
</div>
<div
class="filter-btn"
:class="{ 'active': selectedType === 'trademark' }"
@click="selectedType = 'trademark'"
>
商标信息
</div>
</div>
</div>
<div class="filter-row">
<span class="filter-label">更多筛选:</span>
<el-select v-model="filterForm.acquisitionMethod" placeholder="获得方式" size="small" class="filter-select">
<el-option label="全部" value=""></el-option>
<el-option label="自主研发" value="self"></el-option>
<el-option label="受让" value="transfer"></el-option>
</el-select>
<el-select v-model="filterForm.acquisitionYear" placeholder="获得年度" size="small" class="filter-select">
<el-option label="全部" value=""></el-option>
<el-option label="2024" value="2024"></el-option>
<el-option label="2023" value="2023"></el-option>
</el-select>
<el-select v-model="filterForm.category" placeholder="种类" size="small" class="filter-select">
<el-option label="全部" value=""></el-option>
<el-option label="类型1" value="type1"></el-option>
<el-option label="类型2" value="type2"></el-option>
</el-select>
</div>
<div class="filter-row">
<el-button type="primary" size="small" @click="handleSearch" class="search-btn">搜索</el-button>
<el-button size="small" @click="handleReset" class="reset-btn">重置</el-button>
</div>
</div>
<!-- 知识产权搜索结果表格 -->
<div class="heng" v-if="activeTab === 'knowledge'"></div>
<div class="result-area" v-if="activeTab === 'knowledge'">
<div class="result-title">搜索到 | {{ knowledgeTableData.length }}</div>
<el-table
:data="knowledgeTableData"
:header-cell-style="{ background: '#EDEFFE', color: '#363636' }"
border
style="width: 100%"
>
<el-table-column type="index" label="序号" width="60" align="center"></el-table-column>
<el-table-column prop="name" label="名称" min-width="200" show-overflow-tooltip></el-table-column>
<el-table-column prop="type" label="类型" width="150" align="center"></el-table-column>
<el-table-column prop="category" label="种类" width="100" align="center"></el-table-column>
<el-table-column prop="acquisitionDate" label="获得日期" width="120" align="center"></el-table-column>
<el-table-column prop="acquisitionMethod" label="获得方式" width="120" align="center"></el-table-column>
<el-table-column label="操作" width="100" align="center">
<template slot-scope="scope">
<el-button type="text" size="small" style="color: #5165f7;" @click="handleKnowledgeDetail(scope.row)">详情</el-button>
</template>
</el-table-column>
</el-table>
</div>
<!-- 论文筛选 -->
<div class="filter-area" v-if="activeTab === 'paper'">
<div class="filter-row">
<span class="filter-label">期刊类型:</span>
<div class="filter-buttons">
<div
class="filter-btn"
:class="{ 'active': paperSelectedType === 'all' }"
@click="paperSelectedType = 'all'"
>
全部
</div>
<div
class="filter-btn"
:class="{ 'active': paperSelectedType === 'general' }"
@click="paperSelectedType = 'general'"
>
普通期刊
</div>
<div
class="filter-btn"
:class="{ 'active': paperSelectedType === 'core' }"
@click="paperSelectedType = 'core'"
>
一般核心
</div>
<div
class="filter-btn"
:class="{ 'active': paperSelectedType === 'important' }"
@click="paperSelectedType = 'important'"
>
重要核心
</div>
<div
class="filter-btn"
:class="{ 'active': paperSelectedType === 'authoritative' }"
@click="paperSelectedType = 'authoritative'"
>
权威核心
</div>
</div>
</div>
<div class="filter-row">
<span class="filter-label">更多筛选:</span>
<el-select v-model="paperFilterForm.publicationYear" placeholder="发表年度" size="small" class="filter-select">
<el-option label="全部" value=""></el-option>
<el-option label="2024" value="2024"></el-option>
<el-option label="2023" value="2023"></el-option>
<el-option label="2022" value="2022"></el-option>
</el-select>
<el-select v-model="paperFilterForm.firstAuthor" placeholder="第一作者" size="small" class="filter-select">
<el-option label="全部" value=""></el-option>
<el-option label="作者1" value="author1"></el-option>
<el-option label="作者2" value="author2"></el-option>
</el-select>
<el-select v-model="paperFilterForm.correspondingAuthor" placeholder="通信作者" size="small" class="filter-select">
<el-option label="全部" value=""></el-option>
<el-option label="作者1" value="author1"></el-option>
<el-option label="作者2" value="author2"></el-option>
</el-select>
</div>
<div class="filter-row">
<el-button type="primary" size="small" @click="handlePaperSearch" class="search-btn">搜索</el-button>
<el-button size="small" @click="handlePaperReset" class="reset-btn">重置</el-button>
</div>
</div>
<!-- 论文搜索结果表格 -->
<div class="heng" v-if="activeTab === 'paper'"></div>
<div class="result-area" v-if="activeTab === 'paper'">
<div class="result-title">搜索到 | {{ paperTableData.length }}</div>
<el-table
:data="paperTableData"
:header-cell-style="{ background: '#EDEFFE', color: '#363636' }"
border
style="width: 100%"
>
<el-table-column type="index" label="序号" width="60" align="center"></el-table-column>
<el-table-column prop="name" label="名称" min-width="200" show-overflow-tooltip></el-table-column>
<el-table-column prop="journalType" label="期刊类型" width="120" align="center"></el-table-column>
<el-table-column prop="publicationYear" label="发表年度" width="120" align="center"></el-table-column>
<el-table-column prop="firstAuthor" label="第一作者" width="120" align="center"></el-table-column>
<el-table-column prop="correspondingAuthor" label="通信作者" width="120" align="center"></el-table-column>
<el-table-column label="操作" width="100" align="center">
<template slot-scope="scope">
<el-button type="text" size="small" style="color: #5165f7;" @click="handlePaperDetail(scope.row)">详情</el-button>
</template>
</el-table-column>
</el-table>
</div>
<!-- 标准制定筛选 -->
<div class="filter-area" v-if="activeTab === 'standard'">
<div class="filter-row">
<span class="filter-label">标准类型:</span>
<div class="filter-buttons">
<div
class="filter-btn"
:class="{ 'active': standardSelectedType === 'all' }"
@click="standardSelectedType = 'all'"
>
全部
</div>
<div
class="filter-btn"
:class="{ 'active': standardSelectedType === 'international' }"
@click="standardSelectedType = 'international'"
>
国际
</div>
<div
class="filter-btn"
:class="{ 'active': standardSelectedType === 'national' }"
@click="standardSelectedType = 'national'"
>
国家
</div>
<div
class="filter-btn"
:class="{ 'active': standardSelectedType === 'industry' }"
@click="standardSelectedType = 'industry'"
>
行业
</div>
<div
class="filter-btn"
:class="{ 'active': standardSelectedType === 'local' }"
@click="standardSelectedType = 'local'"
>
地方
</div>
<div
class="filter-btn"
:class="{ 'active': standardSelectedType === 'group' }"
@click="standardSelectedType = 'group'"
>
团体
</div>
</div>
</div>
<div class="filter-row">
<span class="filter-label">更多筛选:</span>
<el-select v-model="standardFilterForm.participationMethod" placeholder="参与方式" size="small" class="filter-select">
<el-option label="全部" value=""></el-option>
<el-option label="主导" value="leading"></el-option>
<el-option label="参与" value="participating"></el-option>
</el-select>
<el-select v-model="standardFilterForm.publicationYear" placeholder="发布年度" size="small" class="filter-select">
<el-option label="全部" value=""></el-option>
<el-option label="2024" value="2024"></el-option>
<el-option label="2023" value="2023"></el-option>
<el-option label="2022" value="2022"></el-option>
</el-select>
<el-select v-model="standardFilterForm.standardStatus" placeholder="标准状态" size="small" class="filter-select">
<el-option label="全部" value=""></el-option>
<el-option label="已发布" value="published"></el-option>
<el-option label="制定中" value="drafting"></el-option>
<el-option label="已废止" value="abolished"></el-option>
</el-select>
</div>
<div class="filter-row">
<el-button type="primary" size="small" @click="handleStandardSearch" class="search-btn">搜索</el-button>
<el-button size="small" @click="handleStandardReset" class="reset-btn">重置</el-button>
</div>
</div>
<!-- 标准制定搜索结果表格 -->
<div class="heng"></div>
<div class="result-area" v-if="activeTab === 'standard'">
<div class="result-title">搜索到 | {{ standardTableData.length }}</div>
<el-table
:data="standardTableData"
:header-cell-style="{ background: '#EDEFFE', color: '#363636' }"
border
style="width: 100%"
>
<el-table-column type="index" label="序号" width="60" align="center"></el-table-column>
<el-table-column prop="standardName" label="标准名称" min-width="200" show-overflow-tooltip></el-table-column>
<el-table-column prop="standardNumber" label="标准号" width="150" align="center"></el-table-column>
<el-table-column prop="standardType" label="标准类型" width="120" align="center"></el-table-column>
<el-table-column prop="releaseDate" label="发布日期" width="120" align="center"></el-table-column>
<el-table-column prop="standardStatus" label="标准状态" width="120" align="center"></el-table-column>
<el-table-column prop="participationMethod" label="参与方式" width="120" align="center"></el-table-column>
<el-table-column label="操作" width="100" align="center">
<template slot-scope="scope">
<el-button type="text" size="small" style="color: #5165f7;" @click="handleStandardDetail(scope.row)">详情</el-button>
</template>
</el-table-column>
</el-table>
</div>
</div>
</div>
</template>
<script>
export default {
data(){
return{
activeTab: 'knowledge',
selectedType: 'all',
filterForm: {
acquisitionMethod: '',
acquisitionYear: '',
category: ''
},
paperSelectedType: 'all',
paperFilterForm: {
publicationYear: '',
firstAuthor: '',
correspondingAuthor: ''
},
standardSelectedType: 'all',
standardFilterForm: {
participationMethod: '',
publicationYear: '',
standardStatus: ''
},
// 知识产权表格数据
knowledgeTableData: [
{
name: '一种多源特征数据融合的隧道智能调光方法及系统',
type: '发明专利',
category: 'I类',
acquisitionDate: '2024-12-10',
acquisitionMethod: '自主研发'
},
{
name: '管理元数据的方法',
type: '集成电路布图',
category: 'I类',
acquisitionDate: '2024-12-10',
acquisitionMethod: '自主研发'
},
{
name: '管理元数据的方法',
type: '软件著作权',
category: 'II类',
acquisitionDate: '2024-12-10',
acquisitionMethod: '自主研发'
},
{
name: '管理元数据的方法',
type: '商标信息',
category: '-',
acquisitionDate: '2024-12-10',
acquisitionMethod: '-'
},
{
name: '管理元数据的方法',
type: '商标信息',
category: '-',
acquisitionDate: '2024-12-10',
acquisitionMethod: '-'
},
{
name: '管理元数据的方法',
type: '商标信息',
category: '-',
acquisitionDate: '2024-12-10',
acquisitionMethod: '-'
},
{
name: '管理元数据的方法',
type: '商标信息',
category: '-',
acquisitionDate: '2024-12-10',
acquisitionMethod: '-'
}
],
// 论文表格数据
paperTableData: [
{
name: '基于深度学习的图像识别方法研究',
journalType: '权威核心',
publicationYear: '2024',
firstAuthor: '张三',
correspondingAuthor: '李四'
},
{
name: '人工智能在医疗诊断中的应用',
journalType: '重要核心',
publicationYear: '2024',
firstAuthor: '王五',
correspondingAuthor: '赵六'
},
{
name: '大数据分析技术研究',
journalType: '一般核心',
publicationYear: '2023',
firstAuthor: '孙七',
correspondingAuthor: '周八'
},
{
name: '云计算架构优化方案',
journalType: '普通期刊',
publicationYear: '2023',
firstAuthor: '吴九',
correspondingAuthor: '郑十'
}
],
// 标准制定表格数据
standardTableData: [
{
standardName: '工业互联网电力装备标识数据安全保护规范',
standardNumber: 'T/GSIA 002—2023',
standardType: '团体标准',
releaseDate: '2024-12-10',
standardStatus: '现行',
participationMethod: '主持'
},
{
standardName: '高速公路机电设备数字化管理关键技术研究',
standardNumber: 'T/GSIA 002—2023',
standardType: '团体标准',
releaseDate: '2024-12-10',
standardStatus: '废止',
participationMethod: '主持'
}
]
}
},
methods: {
handleSearch() {
console.log('搜索', this.filterForm, this.selectedType)
},
handleReset() {
this.selectedType = 'all'
this.filterForm = {
acquisitionMethod: '',
acquisitionYear: '',
category: ''
}
},
handlePaperSearch() {
console.log('论文搜索', this.paperFilterForm, this.paperSelectedType)
},
handlePaperReset() {
this.paperSelectedType = 'all'
this.paperFilterForm = {
publicationYear: '',
firstAuthor: '',
correspondingAuthor: ''
}
},
handleStandardSearch() {
console.log('标准制定搜索', this.standardFilterForm, this.standardSelectedType)
},
handleStandardReset() {
this.standardSelectedType = 'all'
this.standardFilterForm = {
participationMethod: '',
publicationYear: '',
standardStatus: ''
}
},
handleKnowledgeDetail(row) {
console.log('查看知识产权详情', row)
// TODO: 跳转到详情页面
},
handlePaperDetail(row) {
console.log('查看论文详情', row)
// TODO: 跳转到详情页面
},
handleStandardDetail(row) {
console.log('查看标准制定详情', row)
// TODO: 跳转到详情页面
}
}
}
</script>
<style scoped>
.content{
background: white;
width: 100%;
margin-top: 12px;
padding: 20px;
}
.tabs-area {
display: flex;
border-bottom: 1px solid #E4E7ED;
margin-bottom: 20px;
}
.tab-item {
padding: 12px 24px;
cursor: pointer;
color: #606266;
font-size: 14px;
position: relative;
margin-right: 20px;
}
.tab-item.active {
color: #5165f7;
font-weight: 500;
}
.tab-item.active::after {
content: '';
position: absolute;
bottom: -1px;
left: 0;
right: 0;
height: 2px;
background-color: #5165f7;
}
.filter-area {
padding: 20px 0;
}
.filter-row {
display: flex;
align-items: center;
margin-bottom: 16px;
}
.filter-label {
font-size: 14px;
color: #606266;
margin-right: 12px;
min-width: 80px;
}
.heng{
width: 100vw;
height: 20px;
background: #f8f8f8;
margin-left: -40px;
}
.filter-buttons {
display: flex;
flex-wrap: wrap;
gap: 8px;
flex: 1;
}
.filter-btn {
padding: 6px 16px;
border: 1px solid #DCDFE6;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
color: #606266;
background: white;
transition: all 0.3s;
}
.filter-btn:hover {
border-color: #5165f7;
color: #5165f7;
}
.filter-btn.active {
background-color: #5165f7;
color: white;
border-color: #5165f7;
}
.filter-select {
width: 150px;
margin-right: 12px;
}
.search-btn {
background-color: #5165f7;
border-color: #5165f7;
margin-right: 12px;
}
.reset-btn {
background: white;
border: 1px solid #DCDFE6;
color: #606266;
}
::v-deep .filter-select .el-input__inner {
border: 1px solid #DCDFE6 !important;
}
::v-deep .filter-select .el-input {
border: 1px solid #DCDFE6;
}
::v-deep .el-select .el-input__inner {
border: 1px solid #DCDFE6 !important;
}
.result-area {
margin-top: 20px;
}
.result-title {
font-size: 14px;
color: #606266;
margin-bottom: 16px;
font-weight: 500;
}
::v-deep .el-table {
border: 1px solid #EBEEF5;
}
::v-deep .el-table th {
background-color: #EDEFFE !important;
color: #363636 !important;
font-weight: 500;
}
::v-deep .el-table td {
padding: 12px 0;
}
::v-deep .el-table .el-button--text {
padding: 0;
}
</style>

661
src/views/login/index.vue Normal file
View File

@@ -0,0 +1,661 @@
<template>
<div class="login-container">
<div class="login-left">
<div class="logo-section">
<div class="logo">
<div class="logo-icon">TS</div>
<div class="logo-text">
<div class="logo-chinese">数通达</div>
<div class="logo-english">DIGITAL ACCESS</div>
</div>
</div>
</div>
<div class="welcome-section">
<!-- <div class="welcome-title">Hi, 欢迎进入</div>
<div class="welcome-subtitle">数智科创·通达未来</div> -->
<img style="width: 88%;" src="@/assets/ziti.png" alt="">
</div>
<div class="description-section">
<div class="description-line">深耕智能化科创服务</div>
<div class="description-line">构建数据驱动+技术赋能的一站式科创云平台</div>
</div>
</div>
<div class="login-right">
<div class="login-card">
<div class="login-title">Hi, 请登录</div>
<div class="login-tabs">
<div
class="tab-item"
:class="{ active: activeTab === 'password' }"
@click="activeTab = 'password'"
>
密码登录
</div>
<div
class="tab-item"
:class="{ active: activeTab === 'phone' }"
@click="activeTab = 'phone'"
>
手机登录
</div>
</div>
<div class="login-form">
<div class="form-item">
<el-input
v-model="loginForm.username"
:placeholder="activeTab === 'password' ? '请输入账号...' : '请输入手机号'"
size="large"
prefix-icon="el-icon-user"
></el-input>
</div>
<div class="form-item" v-if="activeTab === 'password'">
<el-input
v-model="loginForm.password"
type="password"
placeholder="请输入密码..."
size="large"
prefix-icon="el-icon-lock"
:show-password="true"
></el-input>
</div>
<div class="form-item" v-if="activeTab === 'phone'">
<el-input
v-model="loginForm.phoneCode"
placeholder="请输入验证码"
size="large"
prefix-icon="el-icon-message"
>
<template slot="append">
<el-button @click="sendCode" :disabled="codeCountdown > 0">
{{ codeCountdown > 0 ? `${codeCountdown}` : '获取验证码' }}
</el-button>
</template>
</el-input>
</div>
<div class="verification-section" v-if="activeTab === 'password'">
<div
class="slider-verification"
@mousedown="startDrag"
@mousemove="onDrag"
@mouseup="endDrag"
@mouseleave="endDrag"
>
<div class="slider-track">
<div
class="slider-handle"
:class="{ 'verified': isVerified }"
:style="{ left: isVerified ? 'calc(100% - 50px)' : sliderPosition + 'px' }"
>
<i class="el-icon-right" v-if="!isVerified"></i>
<i class="el-icon-check" v-if="isVerified"></i>
</div>
<span class="slider-text" :class="{ 'hidden': isVerified || sliderPosition > 0 }">请拖动滑动验证</span>
<span class="slider-success" v-if="isVerified">验证通过</span>
</div>
</div>
</div>
<div class="form-item login-btn-item">
<el-button
type="primary"
class="login-btn"
@click="handleLogin"
:loading="loading"
>
登录
</el-button>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { login, smsLogin, sendSmsCode, details } from '@/api/login/login'
import { setToken, getToken, setEnterpriseLogo } from '@/utils/auth'
export default {
name: 'Login',
data() {
return {
activeTab: 'password',
loginForm: {
username: '18286593512',
password: 'admin',
phoneCode: ''
},
isVerified: false,
codeCountdown: 0,
loading: false,
sliderPosition: 0,
isDragging: false
}
},
methods: {
startDrag(e) {
if (this.isVerified) return
this.isDragging = true
this.onDrag(e)
},
onDrag(e) {
if (!this.isDragging || this.isVerified) return
const slider = e.currentTarget
const rect = slider.getBoundingClientRect()
const x = e.clientX - rect.left
const maxX = rect.width - 50
this.sliderPosition = Math.max(0, Math.min(x, maxX))
// 如果拖到最右边,自动完成验证
if (this.sliderPosition >= maxX - 5) {
this.isVerified = true
this.sliderPosition = maxX
this.$message.success('验证通过')
this.isDragging = false
}
},
endDrag() {
if (!this.isDragging) return
this.isDragging = false
// 如果没有完成验证,滑块回到起始位置
if (!this.isVerified) {
this.sliderPosition = 0
}
},
async sendCode() {
if (this.codeCountdown > 0) return
if (!this.loginForm.username) {
this.$message.warning('请输入手机号')
return
}
try {
await sendSmsCode({ phone: this.loginForm.username })
this.$message.success('验证码已发送')
this.codeCountdown = 60
const timer = setInterval(() => {
this.codeCountdown--
if (this.codeCountdown <= 0) {
clearInterval(timer)
}
}, 1000)
} catch (error) {
// 错误信息已在响应拦截器中处理
console.error('发送验证码失败:', error)
}
},
async handleLogin() {
if (this.activeTab === 'password') {
if (!this.loginForm.username || !this.loginForm.password) {
this.$message.warning('请输入用户名和密码')
return
}
if (!this.isVerified) {
this.$message.warning('请先完成验证')
return
}
} else {
if (!this.loginForm.username || !this.loginForm.phoneCode) {
this.$message.warning('请输入手机号和验证码')
return
}
}
this.loading = true
try {
let response
if (this.activeTab === 'password') {
// 密码登录
response = await login({
username: this.loginForm.username,
password: this.loginForm.password
})
} else {
// 短信验证码登录
response = await smsLogin({
phone: this.loginForm.username,
code: this.loginForm.phoneCode
})
}
// 登录成功保存token
// 响应结构: { code: 1, msg: "登陆成功!", data: { code: 1, data: { token: "...", user_id: 1, expire_time: 0, nickname: "...", logo: "..." } } }
if (response && response.code === 1 && response.data) {
// 处理嵌套的data结构
let userData = response.data
// 如果data里面还有data取内层的data
if (userData.data && userData.data.token) {
userData = userData.data
}
// 保存token
if (userData.token) {
setToken(userData.token)
}
// 保存登录状态
localStorage.setItem('isLogin', 'true')
// 可选保存用户ID
if (userData.user_id) {
localStorage.setItem('userId', userData.user_id)
}
// 保存用户昵称
if (userData.nickname) {
localStorage.setItem('userNickname', userData.nickname)
}
// 保存消息数量
if (userData.msgCount !== undefined) {
localStorage.setItem('msgCount', userData.msgCount)
}
// 保存企业LOGO
if (userData.logo) {
setEnterpriseLogo(userData.logo)
}
// 调用 details 接口获取用户详细信息(包括手机号)
if (userData.user_id) {
try {
const detailRes = await details(userData.user_id)
if (detailRes && detailRes.code === 1 && detailRes.data) {
// 保存手机号
if (detailRes.data.phone) {
localStorage.setItem('userPhone', detailRes.data.phone)
}
// 如果详情接口返回了logo也保存可能更准确
if (detailRes.data.logo) {
setEnterpriseLogo(detailRes.data.logo)
}
}
} catch (error) {
console.error('获取用户详情失败:', error)
}
}
// 清除上一次的路由和菜单状态,确保登录后显示正确的菜单
localStorage.removeItem('lastRoute')
localStorage.removeItem('activeItemIndex')
localStorage.removeItem('activeMenu')
localStorage.removeItem('openedMenus')
// 显示成功消息
this.$message.success(response.msg || '登录成功')
// 跳转到主页
this.$router.push('/home')
} else {
// 登录失败
this.$message.error(response?.msg || '登录失败,请重试')
}
} catch (error) {
// 错误信息已在响应拦截器中处理
console.error('登录失败:', error)
} finally {
this.loading = false
}
}
},
mounted() {
// 如果已经登录,直接跳转
if (getToken()) {
this.$router.push('/home')
}
}
}
</script>
<style scoped>
/* 引入字体 - 当字体文件准备好后取消注释 */
/*
@font-face {
font-family: 'Fontquan-XinYiGuanHeiTi-Regular';
src: url('../../assets/fonts/Fontquan-XinYiGuanHeiTi-Regular.woff2') format('woff2'),
url('../../assets/fonts/Fontquan-XinYiGuanHeiTi-Regular.woff') format('woff'),
url('../../assets/fonts/Fontquan-XinYiGuanHeiTi-Regular.ttf') format('truetype'),
url('../../assets/fonts/Fontquan-XinYiGuanHeiTi-Regular.otf') format('opentype');
font-weight: normal;
font-style: normal;
font-display: swap;
}
*/
.login-container {
display: flex;
width: 100%;
height: 100vh;
overflow: hidden;
position: relative;
background-image: url('../../assets/banner.jpg');
background-size: cover;
background-position: center;
background-repeat: no-repeat;
}
.login-left {
flex: 1;
position: relative;
flex-direction: column;
padding: 60px 80px;
color: white;
overflow: hidden;
}
.login-left::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(135deg, rgba(81, 101, 247, 0.85) 0%, rgba(61, 79, 216, 0.85) 100%);
z-index: -1;
}
.background-pattern {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-image:
linear-gradient(45deg, rgba(255, 255, 255, 0.05) 25%, transparent 25%),
linear-gradient(-45deg, rgba(255, 255, 255, 0.05) 25%, transparent 25%),
linear-gradient(45deg, transparent 75%, rgba(255, 255, 255, 0.05) 75%),
linear-gradient(-45deg, transparent 75%, rgba(255, 255, 255, 0.05) 75%);
background-size: 60px 60px;
background-position: 0 0, 0 30px, 30px -30px, -30px 0px;
opacity: 0.3;
z-index: 2;
}
.logo-section {
position: relative;
z-index: 3;
}
.logo {
display: flex;
align-items: center;
gap: 12px;
}
.logo-icon {
width: 60px;
height: 60px;
background: transparent;
border-radius: 0;
display: flex;
align-items: center;
justify-content: center;
font-size: 36px;
font-weight: bold;
color: white;
font-family: 'Arial', sans-serif;
letter-spacing: -2px;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
line-height: 1;
}
.logo-text {
display: flex;
flex-direction: column;
}
.logo-chinese {
font-size: 28px;
font-weight: bold;
line-height: 1.2;
}
.logo-english {
font-size: 14px;
opacity: 0.9;
letter-spacing: 2px;
margin-top: 4px;
}
.welcome-section {
position: relative;
z-index: 3;
margin-top: 120px;
}
.welcome-title {
font-size: 48px;
font-weight: 300;
margin-bottom: 16px;
line-height: 1.2;
/* 字体文件准备好后取消注释 */
/* font-family: 'Fontquan-XinYiGuanHeiTi-Regular', sans-serif; */
}
.welcome-subtitle {
font-size: 32px;
font-weight: 500;
line-height: 1.2;
/* 字体文件准备好后取消注释 */
/* font-family: 'Fontquan-XinYiGuanHeiTi-Regular', sans-serif; */
}
.description-section {
position: relative;
z-index: 3;
margin-top: 32px;
}
.description-line {
font-size: 16px;
line-height: 1.8;
opacity: 0.9;
margin-bottom: 8px;
}
.login-right {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
padding: 40px;
position: relative;
z-index: 2;
}
.login-card {
width: 100%;
max-width: 480px;
background: white;
border-radius: 16px;
padding: 48px 40px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
}
.login-title {
font-size: 28px;
font-weight: 500;
color: #303133;
margin-bottom: 32px;
text-align: center;
}
.login-tabs {
display: flex;
border-bottom: 2px solid #e4e7ed;
margin-bottom: 32px;
}
.tab-item {
flex: 1;
text-align: center;
padding: 12px 0;
font-size: 16px;
color: #909399;
cursor: pointer;
transition: all 0.3s;
position: relative;
}
.tab-item:hover {
color: #5165f7;
}
.tab-item.active {
color: #5165f7;
font-weight: 500;
}
.tab-item.active::after {
content: '';
position: absolute;
bottom: -2px;
left: 0;
right: 0;
height: 2px;
background: #5165f7;
}
.login-form {
width: 100%;
}
.form-item {
margin-bottom: 24px;
}
.form-item:last-child {
margin-bottom: 0;
}
::v-deep .el-input__inner {
height: 48px;
line-height: 48px;
border-radius: 8px;
border: 1px solid #dcdfe6 !important;
font-size: 14px;
}
::v-deep .el-input__inner:focus {
border-color: #5165f7;
}
::v-deep .el-input__prefix {
left: 16px;
}
::v-deep .el-input--prefix .el-input__inner {
padding-left: 48px;
}
.verification-section {
margin-bottom: 24px;
}
.slider-verification {
width: 100%;
height: 48px;
position: relative;
cursor: grab;
user-select: none;
}
.slider-verification:active {
cursor: grabbing;
}
.slider-track {
width: 88%;
height: 100%;
background: #f5f7fa;
border: 1px solid #e4e7ed;
border-radius: 8px;
position: relative;
display: flex;
align-items: center;
justify-content: flex-start;
padding-left: 60px;
overflow: hidden;
}
.slider-handle {
position: absolute;
left: 0;
top: 0;
width: 50px;
height: 100%;
background: #5165f7;
border-radius: 8px 0 0 8px;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-size: 20px;
transition: all 0.3s ease;
z-index: 2;
cursor: grab;
}
.slider-handle:active {
cursor: grabbing;
}
.slider-handle.verified {
background: #67c23a;
border-radius: 8px;
left: calc(100% - 50px) !important;
}
.slider-text {
font-size: 14px;
color: #909399;
transition: opacity 0.3s;
z-index: 1;
white-space: nowrap;
}
.slider-text.hidden {
opacity: 0;
}
.slider-success {
position: absolute;
right: 16px;
font-size: 14px;
color: #67c23a;
font-weight: 500;
z-index: 1;
}
.login-btn-item {
margin-top: 32px;
}
.login-btn {
width: 100%;
height: 48px;
border-radius: 8px;
font-size: 16px;
background: #5165f7;
border: none;
}
.login-btn:hover {
background: #3d4fd8;
}
::v-deep .el-input-group__append {
background: #5165f7;
color: white;
border: none;
border-radius: 0 8px 8px 0;
padding: 0 20px;
}
::v-deep .el-input-group__append .el-button {
color: white;
border: none;
background: transparent;
}
::v-deep .el-input-group__append .el-button:hover {
background: rgba(255, 255, 255, 0.1);
}
::v-deep .el-input-group__append .el-button:disabled {
color: rgba(255, 255, 255, 0.6);
}
</style>

439
src/views/message/index.vue Normal file
View File

@@ -0,0 +1,439 @@
<template>
<div class="message-center">
<div class="message-header">
<div class="header-tabs">
<div class="tabs-left">
<div
class="tab-item"
:class="{ active: activeTab === 'unread' }"
@click="activeTab = 'unread'"
>
未读
</div>
<div
class="tab-item"
:class="{ active: activeTab === 'read' }"
@click="activeTab = 'read'"
style="border:1px solid #dcdcdc"
>
已读
</div>
</div>
<el-button
v-if="activeTab === 'unread'"
type="primary"
size="small"
style="background-color: #5165f7; border: 1px solid #5165f7;"
@click="markAllAsRead"
>
全部设为已处理
</el-button>
</div>
</div>
<div class="message-content">
<el-table
:data="messageList"
style="width: 100%"
border
v-loading="loading"
>
<el-table-column
type="index"
label="序号"
width="80"
align="center"
:index="getIndex">
</el-table-column>
<el-table-column
prop="title"
label="消息标题"
min-width="200">
</el-table-column>
<el-table-column
prop="content"
label="消息内容"
min-width="300">
</el-table-column>
<el-table-column
label="推送时间"
width="180"
align="center">
<template slot-scope="scope">
{{ scope.row.pushTime || scope.row.push_time || scope.row.create_time || '-' }}
</template>
</el-table-column>
<el-table-column
label="操作"
width="120"
align="center">
<template slot-scope="scope">
<el-button
type="text"
style="color: #5165f7;"
@click="handleMessage(scope.row)"
>
{{ activeTab === 'unread' ? '去处理' : '查看' }}
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<div class="pagination-wrapper">
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="pagination.currentPage"
:page-sizes="[10, 20, 50, 100]"
:page-size="pagination.pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="pagination.total">
</el-pagination>
</div>
</div>
<!-- 消息详情对话框 -->
<el-dialog
title="消息详情"
:visible.sync="detailDialogVisible"
width="60%"
:close-on-click-modal="false"
class="message-detail-dialog">
<div class="detail-content" v-loading="detailLoading">
<div class="detail-card">
<div class="detail-item" v-if="messageDetail.title">
<div class="detail-label">
<i class="el-icon-document"></i>
<span>消息标题</span>
</div>
<div class="detail-value">{{ messageDetail.title }}</div>
</div>
<div class="detail-item" v-if="messageDetail.content">
<div class="detail-label">
<i class="el-icon-edit-outline"></i>
<span>消息内容</span>
</div>
<div class="detail-value content-text">{{ messageDetail.content }}</div>
</div>
<div class="detail-item" v-if="messageDetail.pushTime || messageDetail.push_time || messageDetail.create_time">
<div class="detail-label">
<i class="el-icon-time"></i>
<span>推送时间</span>
</div>
<div class="detail-value">{{ messageDetail.pushTime || messageDetail.push_time || messageDetail.create_time }}</div>
</div>
</div>
</div>
<div slot="footer" class="dialog-footer">
<el-button type="primary" style="background-color: #5165f7;" @click="detailDialogVisible = false">关闭</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import {list,details,messagedo} from '@/api/system/message/index'
export default {
name: 'MessageCenter',
data() {
return {
activeTab: 'unread',
loading: false,
messageList: [],
pagination: {
currentPage: 1,
pageSize: 10,
total: 0
},
detailDialogVisible: false,
detailLoading: false,
messageDetail: {}
}
},
watch: {
activeTab() {
// 切换标签时重置分页
this.pagination.currentPage = 1
this.getMessageList()
}
},
mounted() {
this.getMessageList()
},
methods: {
async getMessageList() {
// 调用接口获取消息列表
this.loading = true
const params = {
page: this.pagination.currentPage,
limit: this.pagination.pageSize,
is_read: this.activeTab === 'unread' ? 2 : 1 // 1: 已读, 2: 未读
}
try {
const res = await list(params)
if (res && res.code === 1) {
// 根据接口返回的数据结构处理
if (res.data) {
// 如果返回的是分页对象
if (res.data.data){
this.messageList = res.data.data
this.pagination.total = res.data.total
} else if (Array.isArray(res.data)) {
// 如果直接返回数组
this.messageList = res.data
this.pagination.total = res.data.length
} else {
this.messageList = []
this.pagination.total = 0
}
} else {
this.messageList = []
this.pagination.total = 0
}
} else {
this.$message.error(res.msg || '获取消息列表失败')
this.messageList = []
this.pagination.total = 0
}
} catch (error) {
console.error('获取消息列表失败:', error)
this.messageList = []
this.pagination.total = 0
// 错误信息已在响应拦截器中处理
} finally {
this.loading = false
}
},
handleSizeChange(val) {
// 每页条数改变
this.pagination.pageSize = val
this.pagination.currentPage = 1
this.getMessageList()
},
handleCurrentChange(val) {
// 当前页改变
this.pagination.currentPage = val
this.getMessageList()
},
getIndex(index) {
// 计算序号,考虑分页
return (this.pagination.currentPage - 1) * this.pagination.pageSize + index + 1
},
async handleMessage(row) {
if (this.activeTab === 'unread') {
// 未读消息:去处理
console.log('处理消息:', row)
this.$message.info('跳转到处理页面')
} else {
// 已读消息:查看详情
this.detailDialogVisible = true
this.detailLoading = true
this.messageDetail = {}
try {
const messageId = row.id || row.message_id
if (!messageId) {
this.$message.error('消息ID不存在')
this.detailDialogVisible = false
return
}
const res = await details(messageId)
if (res && res.code === 1) {
this.messageDetail = res.data || {}
} else {
this.$message.error(res.msg || '获取消息详情失败')
this.detailDialogVisible = false
}
} catch (error) {
console.error('获取消息详情失败:', error)
this.$message.error('获取消息详情失败,请稍后重试')
this.detailDialogVisible = false
} finally {
this.detailLoading = false
}
}
},
async markAllAsRead() {
// 调用接口将所有消息标记为已读
this.$confirm('确认将所有消息标记为已处理吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(async () => {
try {
const res = await messagedo({})
if (res && res.code === 1) {
this.$message.success(res.msg || '已全部标记为已处理')
this.activeTab = 'read'
this.getMessageList()
} else {
this.$message.error(res.msg || '操作失败')
}
} catch (error) {
console.error('标记消息为已处理失败:', error)
this.$message.error('操作失败,请稍后重试')
}
}).catch(() => {})
}
}
}
</script>
<style scoped>
.message-center {
padding: 20px;
background: #fff;
min-height: calc(100vh - 90px);
}
.message-header {
margin-bottom: 20px;
}
.header-title {
font-size: 20px;
font-weight: 500;
color: #303133;
margin-bottom: 16px;
position: relative;
padding-bottom: 8px;
}
.header-title::after {
content: '';
position: absolute;
bottom: 0;
left: 0;
width: 60px;
height: 3px;
background: #5165f7;
}
.header-tabs {
display: flex;
align-items: center;
justify-content: space-between;
}
.tabs-left {
display: flex;
align-items: center;
gap: 0;
}
.tab-item {
padding: 8px 20px;
font-size: 14px;
color: #606266;
cursor: pointer;
transition: all 0.3s;
}
.tab-item:hover {
color: #5165f7;
}
.tab-item.active {
background: #5165f7;
color: #fff;
}
.message-content {
background: #fff;
}
.pagination-wrapper {
margin-top: 20px;
display: flex;
justify-content: flex-end;
padding: 20px 0;
}
/* 消息详情对话框样式 */
.message-detail-dialog ::v-deep .el-dialog__header {
padding: 20px 20px 15px;
border-bottom: 1px solid #EBEEF5;
background: #F7F7FA;
text-align: center;
}
.message-detail-dialog ::v-deep .el-dialog__title {
font-size: 18px;
font-weight: 600;
color: #303133;
}
.message-detail-dialog ::v-deep .el-dialog__body {
padding: 30px;
background: #fafafa;
}
.detail-content {
min-height: 200px;
}
.detail-card {
background: #fff;
border-radius: 8px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
overflow: hidden;
}
.detail-item {
display: flex;
align-items: flex-start;
padding: 20px 24px;
border-bottom: 1px solid #F0F0F0;
transition: background-color 0.3s;
}
.detail-item:last-child {
border-bottom: none;
}
.detail-item:hover {
background-color: #F9F9F9;
}
.detail-label {
display: flex;
align-items: center;
font-weight: 600;
color: #606266;
min-width: 140px;
margin-right: 20px;
font-size: 14px;
}
.detail-label i {
margin-right: 8px;
font-size: 16px;
color: #5165f7;
}
.detail-value {
flex: 1;
color: #303133;
word-break: break-word;
line-height: 1.6;
font-size: 14px;
}
.detail-value.content-text {
padding: 12px 16px;
background: #F7F7FA;
border-radius: 6px;
border-left: 3px solid #5165f7;
min-height: 60px;
white-space: pre-wrap;
}
</style>

View File

@@ -0,0 +1,3 @@
<template>
<div>经营项目</div>
</template>

View File

@@ -0,0 +1,851 @@
<template>
<div>
<div class="headers">
<div class="headers-left">
<div class="imgs">
</div>
<div class="img-right">
<div class="name-title">微育科技</div>
<div class="right-name">数智科创 · 通达未来 </div>
</div>
</div>
<div class="headers-right">
<div class="rights">
<div class="rights-names" @click="btnShang">
<span>上一级 < </span> <span style="color:#3333;">主页</span>
</div>
</div>
</div>
</div>
<div class="contents">
<div class="content-left">
<div class="content-lefts">
<div class="leftss">
<div class="leftss-header">
<div>高速公路管道与光缆</div>
<div @click="btnEdint">
<el-button size="small" type="danger" plain @click="closeguan">删除</el-button>
<el-button size="small" style="background-color: #5165f7;color:white;">编辑</el-button>
</div>
</div>
<div class="table-area">
<div class="table-header">
<div>
<div class="shu"></div> <span class="times"> 合同信息 </span>
</div>
</div>
</div>
</div>
<div class="content-table">
<div class="content-areas">
<div class="contents-left">
<span style="margin-left: 20px;">合同项目/费用名称</span>
</div>
<div class="contents-right">
<span style="margin-left: 20px;">高速公路管道与光缆</span>
</div>
</div>
<div class="content-areas content-areas2">
<div class="contents-left">
<span class="table-name">高速公路管道与光缆</span>
</div>
<div class="contents-right">
<div class="rightss rightss1"><span class="table-name">2023-11-14</span></div>
<div class="rightss rightss2"><span class="table-name">合同编号</span></div>
<div class="rightss rightss3"><span class="table-name">WY129871</span></div>
</div>
</div>
<div class="content-areas content-areas2" style="top: 4px;">
<div class="contents-left" style="border-top: none;">
<span class="table-name">合同类型</span>
</div>
<div class="contents-right" style="border: none;">
<div class="rightss rightss1"><span class="table-name">
技术合同
</span></div>
<div class="rightss rightss2" style="border-top: none;"><span
class="table-name">合同金额</span></div>
<div class="rightss rightss3"><span class="table-name">
1,600.00
</span></div>
</div>
</div>
<div class="content-areas content-areas2" style="top: 5px;">
<div class="contents-left" style="border-top: none;">
<span class="table-name">合计支出金额</span>
</div>
<div class="contents-right" style="border: none;">
<div class="rightss rightss1"><span class="table-name">
1,600.00
</span></div>
<div class="rightss rightss2" style="border-top: none;"><span
class="table-name">付款截止期限</span></div>
<div class="rightss rightss3"><span class="table-name">
2023-11-14
</span></div>
</div>
</div>
<div class="content-areas" style="position: relative;top: 5px;">
<div class="contents-left">
<span style="margin-left: 20px;">乙方名称承接方</span>
</div>
<div class="contents-right" style="border-top: none;">
<span style="margin-left: 20px;">单位名称</span>
</div>
</div>
<div class="content-areas" style="position: relative;top: 5px;">
<div class="contents-left">
<span style="margin-left: 20px;">备注</span>
</div>
<div class="contents-right" style="border-top: none;">
<span style="margin-left: 20px;">xxxxxxx</span>
</div>
</div>
</div>
<div class="tabless">
<div class="table-area">
<div class="table-header">
<div>
<div class="shu"></div> <span class="times"> 支付信息 <span><i style="color: #D6D8EA;" class="el-icon-info"></i></span> </span>
</div>
</div>
<div style="margin-top: 10px;">
<el-table
:data="tableData"
border
style="width: 100%">
<el-table-column
align="center"
prop="date"
label="序号"
width="80">
</el-table-column>
<el-table-column
align="center"
prop="date"
label="付款时间"
width="180">
</el-table-column>
<el-table-column
prop="name"
label="摘要信息"
>
</el-table-column>
<el-table-column
align="center"
prop="address"
label="凭证号"
width="180">
</el-table-column>
<el-table-column
align="center"
prop="address"
label="支出金额(元)"
width="180">
</el-table-column>
</el-table>
</div>
</div>
</div>
</div>
</div>
<div class="content-right">
<div class="leftss-header right-header">
<div class="header-area">
<div class="area-name" v-for="(item, index) in listDate" :key="index" @click="btnNmae(index)"
:class="{ 'active': active == index }">
{{ item.name }}
</div>
</div>
<div> <el-button size="small" style="color:#5165f7;">
<i class="el-icon-download"></i> 下载</el-button>
</div>
</div>
<div class="right-area"></div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
active: 0,
listDate: [
{
name: '合同资料'
},
{
name: '支付凭证'
},
],
value1: "",
yuanright: 0,
tables: [
{
name: '有效'
},
{
name: '无效'
},
],
shu: 0,
lastActiveKey: 'headerActiveIndex',
tableData: [
{
date: "其中",
name: "",
address: "",
children: [
{ date: "2024", name: "年度审计报告及财务情况说明书", address: "8000" },
{ date: "2025", name: "年度审计报告及财务情况说明书", address: "7500" },
],
},
{ date: "其他项目", name: "5000", address: "4000" },
],
tableData2: [
{ date: "2025", name: "年度审计报告及财务情况说明书", address: "7500" },]
}
},
created() {
},
watch: {
},
methods: {
//取消
closeguan() {
},
btnNmae(e) {
this.active = e
},
//切换时效性
btnYuan(e) {
this.yuanright = e
},
//编辑跳转
btnEdint() {
this.$router.push('/hetongmingxin')
},
btnShang() {
this.$router.go(-1)
}
}
}
</script>
<style>
.el-tooltip__popper.is-dark {
color: #F04B4B !important;
background: #FCF1EB !important;
}
.el-tooltip__popper .popper__arrow {
border-top-color: #FCF1EB !important;
/* 上方箭头 */
}
.el-tooltip__popper .popper__arrow::after {
border-top-color: #FCF1EB !important;
}
/* 其他方向的箭头(按需添加) */
.el-tooltip__popper[x-placement^='bottom'] .popper__arrow {
border-bottom-color: #FCF1EB !important;
}
.el-tooltip__popper[x-placement^='left'] .popper__arrow {
border-left-color: #FCF1EB !important;
}
.el-tooltip__popper[x-placement^='right'] .popper__arrow {
border-right-color: #FCF1EB !important;
}
</style>
<style scoped>
.tabless{
width: 90%;
margin: 0 auto;
margin-top: 30px;
}
.area-name {
margin-left: 30px;
cursor: pointer;
}
.active {
border-bottom: 3px solid #5165f7;
height: 45px;
}
.header-area {
display: flex;
position: relative;
left: -30px;
}
.rightss3 {
border-right: none;
border-left: none;
}
.table-name {
margin-left: 20px;
}
.rightss2 {
background: #EDEFFE;
}
.rightss1 {
border-left: none !important;
border-right: none !important;
}
.rightss {
height: 100%;
border: 1px solid #DCE0FD;
width: 100%;
border-top: none;
}
.content-areas2 {
position: relative;
top: 1px;
}
.contents-right {
flex: 1;
border: 1px solid #DCE0FD;
line-height: 50px;
font-size: 14px;
color: #363636;
display: flex
}
.contents-left {
width: 30%;
border: 1px solid #DCE0FD;
background: #EDEFFE;
;
line-height: 50px;
font-size: 14px;
color: #363636;
}
.content-areas {
display: flex;
height: 50px;
flex-wrap: wrap;
}
.tab-area {
margin-top: 24px;
}
.namess {
color: #5B5E72;
font-size: 13px;
margin-left: 12px;
}
.names {
font-size: 14px;
color: #363636;
}
:deep .el-tooltip__popper.is-dark {
color: #F04B4B !important;
}
.right-area {
width: 90%;
margin: 0 auto;
height: 80vh;
background: #f8f8f8;
}
.right-header {
width: 90%;
margin: 0 auto;
}
.ths {
text-align: center;
background: #DCE0FD !important;
color: #363636;
}
.tou {
height: 30px;
line-height: 30px;
color: #606266;
text-align: center;
}
.financial-table {
width: 100%;
border-collapse: collapse;
font-family: Arial, sans-serif;
font-size: 14px;
}
.financial-table th,
.financial-table td {
border: 1px solid #ddd;
padding: 8px 7px;
text-align: center;
}
.financial-table th {
background-color: #f5f5f5;
font-weight: bold;
}
.financial-table .nested-label {
text-align: center;
vertical-align: middle;
font-weight: bold;
}
.table-right {
flex: 1;
}
.table-left {
flex: 1;
}
.content-table {
width: 90%;
margin: 0 auto;
margin-top: 14px;
}
/* 默认情况(有效)左边圆角 */
.left-radius {
border-bottom-left-radius: 16px !important;
border-top-left-radius: 16px !important;
}
/* 无效情况右边圆角 */
.right-radius {
border-bottom-right-radius: 16px !important;
border-top-right-radius: 16px !important;
}
.yuan-left {
flex: 1;
text-align: center;
line-height: 30px;
background: #f8f8f8;
/* border-bottom-left-radius: 16px;
border-top-left-radius: 16px; */
cursor: pointer;
}
.yuanright {
flex: 1;
background: #5165f7;
color: white;
/* border-bottom-right-radius: 16px;
border-top-right-radius: 16px; */
text-align: center;
line-height: 30px;
cursor: pointer;
}
.youxiaos {
position: relative;
top: 6px;
left: -12px;
cursor: pointer;
}
/* 修改.yuan的样式移除外层圆角 */
.yuan {
width: 100px;
height: 30px;
background: white;
display: flex;
font-size: 14px;
overflow: hidden;
/* 关键确保内部div的圆角效果不被截断 */
}
/* 默认状态下两个按钮的外侧圆角 */
.yuan-left:first-child {
border-top-left-radius: 16px;
border-bottom-left-radius: 16px;
}
.yuan-left:last-child {
border-top-right-radius: 16px;
border-bottom-right-radius: 16px;
}
/* 选中状态样式 */
.yuanright {
background: #5165f7;
color: white;
}
.rights-names {
margin-left: 32px;
cursor: pointer;
color: #5165f7;
}
/* 选中"有效"时的样式 */
.yuan-left.left-radius {
border-top-right-radius: 0 !important;
border-bottom-right-radius: 0 !important;
}
/* 选中"无效"时的样式 */
.yuan-left.right-radius {
border-top-left-radius: 0 !important;
border-bottom-left-radius: 0 !important;
}
.times {
position: relative;
top: 3px;
}
.youxiao {
color: #5B5D76;
font-size: 13px;
}
.table-header {
display: flex;
justify-content: space-between;
margin-top: 14px;
}
.table-area {
margin-top: 12px;
font-size: 15px;
}
.leftss-header {
display: flex;
height: 60px;
line-height: 60px;
border-bottom: 1px solid #3333;
font-weight: bold;
justify-content: space-between;
}
.leftss {
width: 90%;
margin: 0 auto;
}
.content-lefts {
background: white;
height: 100%;
width: 100%;
}
.content-left {
flex: 1;
padding-right: 12px;
height: 100%;
}
.content-right {
width: 600px;
height: 100%;
background: white;
}
.contents {
width: 100%;
height: 92vh;
background: #f8f8f8;
display: flex;
margin-top: 6px;
/* flex-wrap: wrap */
}
.shu {
width: 3px;
height: 18px;
background: #5165f7;
position: relative;
display: inline-block;
top: 7px;
}
::v-deep .el-table thead {
background-color: #DCE0FD !important;
color: #363636 !important;
font-weight: bold;
}
::v-deep .el-table__header th {
background-color: #DCE0FD !important;
color: #363636 !important;
font-weight: bold;
}
.rights {
width: 96%;
height: 100%;
margin: 0 auto;
line-height: 88px;
display: flex;
position: relative;
top: -6px;
}
.name-title {
position: relative;
top: -6px;
font-weight: bold;
}
.right-name {
font-size: 12px;
}
.img-right {
font-size: 14px;
position: relative;
top: 35px;
height: 40px;
margin-left: 12px;
}
.imgs {
width: 42px;
height: 40px;
background: #5165f7;
border-radius: 6px;
position: relative;
top: 26px;
margin-left: 24px
}
.headers-right {
flex: 1;
background: white;
}
.headers-left {
width: 222px;
height: 100%;
display: flex;
background: white;
}
.headers {
width: 100%;
display: flex;
}
.patent-container {
max-width: 1000px;
margin: 0 auto;
background: white;
border-radius: 8px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
overflow: hidden;
}
.patent-header {
background: linear-gradient(135deg, #6a5acd, #8a7dff);
color: white;
padding: 20px 30px;
text-align: center;
}
.patent-header h1 {
font-size: 24px;
margin-bottom: 10px;
font-weight: 600;
}
.patent-header p {
opacity: 0.9;
font-size: 14px;
}
.search-box {
padding: 15px 30px;
background-color: #f8f9fa;
border-bottom: 1px solid #eaeaea;
}
.search-box input {
width: 100%;
padding: 10px 15px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 14px;
transition: border-color 0.3s;
}
.search-box input:focus {
outline: none;
border-color: #8a7dff;
box-shadow: 0 0 0 2px rgba(138, 125, 255, 0.2);
}
.patent-table {
width: 100%;
border-collapse: collapse;
}
.patent-table th {
background-color: #f0e6ff;
color: #5a4fcf;
padding: 12px 15px;
text-align: left;
font-weight: 600;
border-bottom: 1px solid #ddd;
}
.patent-table td {
padding: 12px 15px;
border-bottom: 1px solid #f0f0f0;
transition: background-color 0.2s;
}
.patent-table tr:hover td {
background-color: #f9f7ff;
}
.patent-table tr:last-child td {
border-bottom: none;
}
.status-badge {
display: inline-block;
padding: 4px 8px;
border-radius: 4px;
font-size: 12px;
font-weight: 500;
}
.status-paid {
background-color: #e8f5e9;
color: #2e7d32;
}
.patent-footer {
padding: 15px 30px;
text-align: center;
color: #777;
font-size: 14px;
border-top: 1px solid #eaeaea;
background-color: #fafafa;
}
.active{
color: #5165f7 !important;
}
.rights-names{
margin-left: 32px;
cursor: pointer;
}
.rights{
width: 96%;
height: 100%;
margin: 0 auto;
line-height: 94px;
display: flex;
position: relative;
left: -27px;
}
.name-title{
position: relative;
top: -6px;
font-weight: bold;
}
.right-name{
font-size: 12px;
}
.img-right{
font-size: 14px;
position: relative;
top: 40px;
height: 40px;
margin-left: 12px;
}
.imgs{
width: 45px;
height: 46px;
background: #5165f7;
border-radius: 6px;
position: relative;
top: 26px;
margin-left: 24px
}
.headers-right{
flex: 1;
background: white;
}
.headers-left{
width: 222px;
height: 100%;
display: flex;
background: white;
border-right: 1px solid #EDEFFE;
}
.headers{
width: 100%;
height: 90px;
display: flex
;
border-bottom: 1px solid #EDEFFE;
}
</style>

View File

@@ -0,0 +1,487 @@
<template>
<div>
<div class="headers">
<div class="headers-left">
<div class="imgs"></div>
<div class="img-right">
<div class="name-title">微育科技</div>
<div class="right-name">数智科创 · 通达未来</div>
</div>
</div>
<div class="headers-right">
<div class="rights">
<div class="rights-names" @click="btnBack">
<span>上一级 &lt; </span> <span style="color:#3333;">研发人员考勤明细</span>
</div>
</div>
<div class="user-info">
<div class="avatar">Y</div>
<div class="user-details">
<div>言雨天</div>
<div>13424098909</div>
</div>
</div>
</div>
</div>
<div class="contents">
<div class="content-left">
<div class="content-lefts">
<div class="attendance-container">
<div class="title-section">
<h2 class="main-title">2025年1月考勤表</h2>
<div class="headerss">
<div class="legend">
<div class="legend-item">
<span class="legend-icon checkmark"></span>
<span>出勤</span>
</div>
<div class="legend-item">
<span class="legend-icon circle">O</span>
<span>请假一天</span>
</div>
<div class="legend-item">
<span class="legend-icon halfmoon">D</span>
<span>请假半天</span>
</div>
<div class="legend-item">
<span class="legend-icon triangle"></span>
<span>出差</span>
</div>
</div>
<div class="legend-item">
<el-button @click="btnReupload" type="primary" size="small" style="background-color: #5165f7;color:white;margin-left: 15px;">重新上传</el-button>
</div>
</div>
</div>
<div class="attendance-table-wrapper">
<table class="attendance-table">
<thead>
<tr>
<th rowspan="2" class="serial-col">序号</th>
<th rowspan="2" class="name-col" >姓名</th>
<th
v-for="day in days"
:key="day.date"
:colspan="1"
:class="['day-header', { 'weekend': day.isWeekend }]">
<div class="day-row">{{ day.weekday }}</div>
<div class="date-row">{{ day.date }}</div>
</th>
</tr>
</thead>
<tbody>
<tr v-for="(employee, index) in employees" :key="index">
<td class="serial-col">{{ index + 1 }}</td>
<td class="name-col">{{ employee.name }}</td>
<td
v-for="day in days"
:key="day.date"
:class="['day-cell', { 'weekend': day.isWeekend }]"
>
<div class="cell-content">
<span v-if="getAttendanceStatus(employee, day.date) === 'attendance'" class="checkmark"></span>
<span v-else-if="getAttendanceStatus(employee, day.date) === 'leave-full'" class="circle">O</span>
<span v-else-if="getAttendanceStatus(employee, day.date) === 'leave-half'" class="halfmoon">D</span>
<span v-else-if="getAttendanceStatus(employee, day.date) === 'business-trip'" class="triangle"></span>
<span v-else-if="getAttendanceStatus(employee, day.date) === 'project'" class="project-box">WY123 4210</span>
<span v-else></span>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'ExamStatusEdit',
data() {
return {
days: this.generateDays(2025, 1),
employees: [
{ name: '徐蛟', attendance: {} },
{ name: '陈翔', attendance: {
5: 'project',
12: 'leave-full',
13: 'leave-full',
14: 'leave-full',
18: 'leave-full',
25: 'leave-half',
26: 'leave-half',
27: 'leave-half',
28: 'leave-half'
}},
{ name: '高超', attendance: {
15: 'project',
16: 'project',
17: 'project',
22: 'project'
}},
{ name: '杨雪峰', attendance: {
22: 'project'
}},
{ name: '陈翔', attendance: {
5: 'project'
}},
{ name: '高超', attendance: {
15: 'project',
16: 'project',
17: 'project',
22: 'project'
}},
{ name: '陈翔', attendance: {
5: 'project'
}},
{ name: '高超', attendance: {
22: 'project'
}},
{ name: '陈翔', attendance: {
5: 'project'
}},
{ name: '高超', attendance: {
22: 'project'
}},
{ name: '杨雪峰', attendance: {
22: 'project'
}}
]
}
},
methods: {
generateDays(year, month) {
const days = []
const daysInMonth = new Date(year, month, 0).getDate()
const weekdays = ['日', '一', '二', '三', '四', '五', '六']
for (let date = 1; date <= daysInMonth; date++) {
const day = new Date(year, month - 1, date)
const weekday = weekdays[day.getDay()]
const isWeekend = day.getDay() === 0 || day.getDay() === 6
days.push({
date,
weekday,
isWeekend
})
}
return days
},
getAttendanceStatus(employee, date) {
if (employee.attendance && employee.attendance[date]) {
return employee.attendance[date]
}
return 'attendance'
},
btnBack() {
this.$router.go(-1)
},
btnReupload() {
console.log('重新上传')
// 处理重新上传逻辑
}
}
}
</script>
<style scoped>
.headerss{
display: flex
;
width: 86%;
justify-content: space-between;
}
.headers {
width: 100%;
height: 90px;
display: flex;
border-bottom: 1px solid #EDEFFE;
}
.headers-left {
width: 222px;
height: 100%;
display: flex;
background: white;
border-right: 1px solid #EDEFFE;
}
.imgs {
width: 45px;
height: 46px;
background: #5165f7;
border-radius: 6px;
position: relative;
top: 26px;
margin-left: 24px;
}
.img-right {
font-size: 14px;
position: relative;
top: 40px;
height: 40px;
margin-left: 12px;
}
.name-title {
position: relative;
top: -6px;
font-weight: bold;
}
.right-name {
font-size: 12px;
}
.headers-right {
flex: 1;
background: white;
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 20px;
}
.rights {
display: flex;
align-items: center;
}
.rights-names {
cursor: pointer;
}
.user-info {
display: flex;
align-items: center;
}
.avatar {
width: 40px;
height: 40px;
border-radius: 50%;
background: #5165f7;
color: white;
display: flex;
align-items: center;
justify-content: center;
margin-right: 10px;
font-weight: bold;
}
.user-details {
font-size: 14px;
}
.contents {
width: 100%;
min-height: calc(100vh - 90px);
background: #f8f8f8;
padding: 20px;
}
.content-left {
width: 100%;
background: white;
border-radius: 8px;
padding: 20px;
box-sizing: border-box;
}
.content-lefts {
width: 100%;
}
.attendance-container {
width: 100%;
box-sizing: border-box;
}
.title-section {
display: flex;
align-items: center;
margin-bottom: 20px;
padding-bottom: 20px;
border-bottom: 1px solid #EDEFFE;
}
.main-title {
font-size: 20px;
font-weight: bold;
color: #363636;
margin: 0;
}
.legend {
display: flex;
gap: 20px;
margin-left: 30px;
}
.legend-item {
display: flex;
align-items: center;
gap: 5px;
font-size: 14px;
color: #363636;
}
.legend-icon {
display: inline-block;
width: 20px;
text-align: center;
}
.legend-icon.checkmark {
color: #67C23A;
font-weight: bold;
}
.legend-icon.circle {
color: #606266;
}
.legend-icon.halfmoon {
color: #606266;
}
.legend-icon.triangle {
color: #606266;
}
.attendance-table-wrapper {
width: 100%;
overflow-x: auto;
overflow-y: hidden;
-webkit-overflow-scrolling: touch;
}
.attendance-table-wrapper::-webkit-scrollbar {
height: 8px;
}
.attendance-table-wrapper::-webkit-scrollbar-track {
background: #f1f1f1;
}
.attendance-table-wrapper::-webkit-scrollbar-thumb {
background: #888;
border-radius: 4px;
}
.attendance-table-wrapper::-webkit-scrollbar-thumb:hover {
background: #555;
}
.attendance-table {
width: 100%;
border-collapse: collapse;
border: 1px solid #EBEEF5;
font-size: 14px;
table-layout: auto;
}
.attendance-table th,
.attendance-table td {
border: 1px solid #EBEEF5;
padding: 8px;
text-align: center;
vertical-align: middle;
}
.attendance-table th {
background: #EDEFFE;
color: #363636;
font-weight: bold;
}
.serial-col {
width: 60px;
}
.name-col {
width: 60px;
min-width: 60px;
}
.day-header {
width: 35px;
min-width: 35px;
padding: 0;
}
.day-header.weekend {
background: #E8F5E9;
}
.day-row {
padding: 4px;
font-size: 12px;
border-bottom: 1px solid #EBEEF5;
}
.date-row {
padding: 4px;
font-size: 12px;
}
.day-cell {
width: 35px;
min-width: 35px;
height: 40px;
padding: 4px;
}
.day-cell.weekend {
background: #E8F5E9;
}
.cell-content {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
}
.checkmark {
color: #67C23A;
font-weight: bold;
font-size: 16px;
}
.circle {
color: #606266;
font-size: 16px;
}
.halfmoon {
color: #606266;
font-size: 14px;
}
.triangle {
color: #606266;
font-size: 12px;
}
.project-box {
background: #67C23A;
color: white;
padding: 2px 6px;
border-radius: 3px;
font-size: 11px;
white-space: nowrap;
}
</style>

View File

@@ -0,0 +1,430 @@
<template>
<div>
<div class="coentent">
<div class="contents-area">
<div class="areas">
<div v-if="active==0">
<div class="headers">
<div class="headers-name">研发人员考勤情况</div>
<div>
<el-form :inline="true" :model="form" class="demo-form-inline">
<el-form-item label="年度选择" size="small" style="position: relative;top: -3px;">
<el-select v-model="form.year" placeholder="请选择" class="selects">
<el-option v-for="item in yearOptions" :key="item.value" :label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="btnDownload" size="small" class="tianjia">下载模版</el-button>
</el-form-item>
</el-form>
</div>
</div>
<div class="content-table">
<el-table
:data="tableData"
:header-cell-style="{ background: '#EDEFFE', color: '#363636', textAlign: 'center' }"
:row-style="getRowStyle"
border
style="width: 100%">
<el-table-column prop="month" label="月份" width="100" align="center"></el-table-column>
<el-table-column prop="personCount" label="人数" align="center"></el-table-column>
<el-table-column prop="attendanceDays" label="合计在勤天数" align="center"></el-table-column>
<el-table-column prop="businessTripDays" label="合计出差天数" align="center"></el-table-column>
<el-table-column prop="totalAttendanceDays" label="合计总出勤天数" align="center"></el-table-column>
<el-table-column prop="leaveDays" label="合计请假天数" align="center"></el-table-column>
<el-table-column prop="uploadStatus" label="上传情况" align="center">
<template slot-scope="scope">
<span :class="scope.row.uploadStatus === '已上传' ? 'status-uploaded' : 'status-not-uploaded'">
{{ scope.row.uploadStatus }}
</span>
</template>
</el-table-column>
<el-table-column fixed="right" label="操作" align="center" >
<template slot-scope="scope">
<el-button @click="handleDetail(scope.row)" type="text" size="small" style="color: #5165f7;">详情</el-button>
<el-button @click="handleUpload(scope.row)" type="text" size="small" style="color: #5165f7;">上传</el-button>
</template>
</el-table-column>
</el-table>
<div class="footer">
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="currentPage"
:page-sizes="[100, 200, 300, 400]"
:page-size="100"
layout="total, sizes, prev, pager, next, jumper"
:total="400">
</el-pagination>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
active: 0,
currentPage: 1,
form: {
year: '2025'
},
yearOptions: [
{
value: '2023',
label: '2023'
},
{
value: '2024',
label: '2024'
},
{
value: '2025',
label: '2025'
},
{
value: '2026',
label: '2026'
}
],
tableData: [
{
month: '一',
personCount: '30',
attendanceDays: '620',
businessTripDays: '12',
totalAttendanceDays: '632',
leaveDays: '5',
uploadStatus: '已上传'
},
{
month: '二',
personCount: '30',
attendanceDays: '660',
businessTripDays: '24',
totalAttendanceDays: '654',
leaveDays: '0',
uploadStatus: '已上传'
},
{
month: '三',
personCount: '30',
attendanceDays: '672',
businessTripDays: '28',
totalAttendanceDays: '643',
leaveDays: '0',
uploadStatus: '已上传'
},
{
month: '四',
personCount: '30',
attendanceDays: '620',
businessTripDays: '9',
totalAttendanceDays: '432',
leaveDays: '0',
uploadStatus: '已上传'
},
{
month: '五',
personCount: '30',
attendanceDays: '500',
businessTripDays: '12',
totalAttendanceDays: '500',
leaveDays: '3',
uploadStatus: '已上传'
},
{
month: '六',
personCount: '-',
attendanceDays: '-',
businessTripDays: '-',
totalAttendanceDays: '-',
leaveDays: '-',
uploadStatus: '未上传'
},
{
month: '七',
personCount: '30',
attendanceDays: '620',
businessTripDays: '8',
totalAttendanceDays: '632',
leaveDays: '0',
uploadStatus: '已上传'
},
{
month: '八',
personCount: '-',
attendanceDays: '-',
businessTripDays: '-',
totalAttendanceDays: '-',
leaveDays: '-',
uploadStatus: '未上传'
},
{
month: '九',
personCount: '-',
attendanceDays: '-',
businessTripDays: '-',
totalAttendanceDays: '-',
leaveDays: '-',
uploadStatus: '未上传'
},
{
month: '十',
personCount: '-',
attendanceDays: '-',
businessTripDays: '-',
totalAttendanceDays: '-',
leaveDays: '-',
uploadStatus: '未上传'
},
{
month: '十一',
personCount: '-',
attendanceDays: '-',
businessTripDays: '-',
totalAttendanceDays: '-',
leaveDays: '-',
uploadStatus: '未上传'
},
{
month: '十二',
personCount: '-',
attendanceDays: '-',
businessTripDays: '-',
totalAttendanceDays: '-',
leaveDays: '-',
uploadStatus: '未上传'
}
]
}
},
methods: {
getRowStyle({ row, rowIndex }) {
return {}
},
handleDetail(row) {
console.log('查看详情', row)
// 跳转到详情页面
},
handleUpload(row) {
this.$router.push('/examstatusEdint')
// 处理上传逻辑
},
btnDownload() {
console.log('下载模版')
// 处理下载模版逻辑
},
handleSizeChange() {
// 处理分页大小变化
},
handleCurrentChange() {
// 处理当前页变化
}
}
}
</script>
<style>
.el-tooltip__popper.is-dark {
color: #F04B4B !important;
background: #FCF1EB !important;
}
.el-tooltip__popper .popper__arrow {
border-top-color: #FCF1EB !important;
/* 上方箭头 */
}
.el-tooltip__popper .popper__arrow::after {
border-top-color: #FCF1EB !important;
}
/* 其他方向的箭头(按需添加) */
.el-tooltip__popper[x-placement^='bottom'] .popper__arrow {
border-bottom-color: #FCF1EB !important;
}
.el-tooltip__popper[x-placement^='left'] .popper__arrow {
border-left-color: #FCF1EB !important;
}
.el-tooltip__popper[x-placement^='right'] .popper__arrow {
border-right-color: #FCF1EB !important;
}
</style>
<style scoped>
.areas {
padding-bottom: 15px;
width: 97%;
margin: 0 auto;
padding-top: 20px;
}
.active {
color: #5165f7 !important;
}
.heng {
width: 20px;
height: 6px;
background: #5165f7;
margin: 0 auto;
margin-top: 6px;
}
.header-table {
cursor: pointer;
}
.contentss-header {
width: 100%;
display: flex;
justify-content: space-between;
width: 150px;
}
.contentss {
width: 97%;
margin: 0 auto;
padding-top: 12px;
}
.contents-area {
width: 100%;
background: white;
margin-top: 20px;
}
.header-title {
position: relative;
top: 20px;
left: 25px;
}
.numbers {
position: relative;
top: -7px;
color: #2AB95F;
}
.number-name2 {
margin-top: 8px;
font-size: 14px;
color: #979BBC;
}
.number-name {
font-weight: bold;
font-size: 25px;
color: #17192C;
}
.header-names {
display: flex;
width: 82%;
justify-content: space-between;
margin: 0 auto;
padding-top: 20px;
}
.header-area {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
width: 97%;
margin: 0 auto;
}
.content-header {
width: 100%;
background: white;
padding-bottom: 22px;
}
.footer {
display: flex;
justify-content: end;
margin-top: 20px;
}
.tianjia {
position: relative;
top: -9px;
background-color: #5065F6;
}
.tianjia2 {
position: relative;
top: -9px;
background-color: #EDEFFE;
color: #5065F6;
}
::v-deep .el-table thead {
background-color: #EDEFFE !important;
color: #363636 !important;
}
::v-deep .el-table__header th {
background-color: #EDEFFE !important;
color: #363636 !important;
}
.formitem {
position: relative;
top: -5px;
}
::deep .el-form-item__label {
font-size: 15px !important;
}
.selects {
width: 100px;
border: 1px solid #3333;
}
.headers-name {
font-size: 15px;
position: relative;
top: 14px;
}
.headers {
display: flex;
justify-content: space-between;
}
.status-uploaded {
color: #67C23A;
}
.status-not-uploaded {
background: #F56C6C;
color: white;
padding: 4px 12px;
border-radius: 4px;
display: inline-block;
}
::v-deep .el-table__body tr:hover > td {
background-color: transparent !important;
}
::v-deep .el-table__body tr.el-table__row--striped td {
background-color: transparent;
}
</style>

View File

@@ -0,0 +1,430 @@
<template>
<div>
<div class="coentent">
<div class="contents-area">
<div class="areas">
<div v-if="active==0">
<div class="headers">
<div class="headers-name">研发人员考勤情况</div>
<div>
<el-form :inline="true" :model="form" class="demo-form-inline">
<el-form-item label="年度选择" size="small" style="position: relative;top: -3px;">
<el-select v-model="form.year" placeholder="请选择" class="selects">
<el-option v-for="item in yearOptions" :key="item.value" :label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="btnDownload" size="small" class="tianjia">下载模版</el-button>
</el-form-item>
</el-form>
</div>
</div>
<div class="content-table">
<el-table
:data="tableData"
:header-cell-style="{ background: '#EDEFFE', color: '#363636', textAlign: 'center' }"
:row-style="getRowStyle"
border
style="width: 100%">
<el-table-column prop="month" label="月份" width="100" align="center"></el-table-column>
<el-table-column prop="personCount" label="人数" align="center"></el-table-column>
<el-table-column prop="attendanceDays" label="合计在勤天数" align="center"></el-table-column>
<el-table-column prop="businessTripDays" label="合计出差天数" align="center"></el-table-column>
<el-table-column prop="totalAttendanceDays" label="合计总出勤天数" align="center"></el-table-column>
<el-table-column prop="leaveDays" label="合计请假天数" align="center"></el-table-column>
<el-table-column prop="uploadStatus" label="上传情况" align="center">
<template slot-scope="scope">
<span :class="scope.row.uploadStatus === '已上传' ? 'status-uploaded' : 'status-not-uploaded'">
{{ scope.row.uploadStatus }}
</span>
</template>
</el-table-column>
<el-table-column fixed="right" label="操作" align="center" >
<template slot-scope="scope">
<el-button @click="handleDetail(scope.row)" type="text" size="small" style="color: #5165f7;">详情</el-button>
<el-button @click="handleUpload(scope.row)" type="text" size="small" style="color: #5165f7;">上传</el-button>
</template>
</el-table-column>
</el-table>
<div class="footer">
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="currentPage"
:page-sizes="[100, 200, 300, 400]"
:page-size="100"
layout="total, sizes, prev, pager, next, jumper"
:total="400">
</el-pagination>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
active: 0,
currentPage: 1,
form: {
year: '2025'
},
yearOptions: [
{
value: '2023',
label: '2023'
},
{
value: '2024',
label: '2024'
},
{
value: '2025',
label: '2025'
},
{
value: '2026',
label: '2026'
}
],
tableData: [
{
month: '一',
personCount: '30',
attendanceDays: '620',
businessTripDays: '12',
totalAttendanceDays: '632',
leaveDays: '5',
uploadStatus: '已上传'
},
{
month: '二',
personCount: '30',
attendanceDays: '660',
businessTripDays: '24',
totalAttendanceDays: '654',
leaveDays: '0',
uploadStatus: '已上传'
},
{
month: '三',
personCount: '30',
attendanceDays: '672',
businessTripDays: '28',
totalAttendanceDays: '643',
leaveDays: '0',
uploadStatus: '已上传'
},
{
month: '四',
personCount: '30',
attendanceDays: '620',
businessTripDays: '9',
totalAttendanceDays: '432',
leaveDays: '0',
uploadStatus: '已上传'
},
{
month: '五',
personCount: '30',
attendanceDays: '500',
businessTripDays: '12',
totalAttendanceDays: '500',
leaveDays: '3',
uploadStatus: '已上传'
},
{
month: '六',
personCount: '-',
attendanceDays: '-',
businessTripDays: '-',
totalAttendanceDays: '-',
leaveDays: '-',
uploadStatus: '未上传'
},
{
month: '七',
personCount: '30',
attendanceDays: '620',
businessTripDays: '8',
totalAttendanceDays: '632',
leaveDays: '0',
uploadStatus: '已上传'
},
{
month: '八',
personCount: '-',
attendanceDays: '-',
businessTripDays: '-',
totalAttendanceDays: '-',
leaveDays: '-',
uploadStatus: '未上传'
},
{
month: '九',
personCount: '-',
attendanceDays: '-',
businessTripDays: '-',
totalAttendanceDays: '-',
leaveDays: '-',
uploadStatus: '未上传'
},
{
month: '十',
personCount: '-',
attendanceDays: '-',
businessTripDays: '-',
totalAttendanceDays: '-',
leaveDays: '-',
uploadStatus: '未上传'
},
{
month: '十一',
personCount: '-',
attendanceDays: '-',
businessTripDays: '-',
totalAttendanceDays: '-',
leaveDays: '-',
uploadStatus: '未上传'
},
{
month: '十二',
personCount: '-',
attendanceDays: '-',
businessTripDays: '-',
totalAttendanceDays: '-',
leaveDays: '-',
uploadStatus: '未上传'
}
]
}
},
methods: {
getRowStyle({ row, rowIndex }) {
return {}
},
handleDetail(row) {
this.$router.push('/personnelEdint')
// 跳转到详情页面
},
handleUpload(row) {
// this.$router.push('/examstatusEdint')
// 处理上传逻辑
},
btnDownload() {
console.log('下载模版')
// 处理下载模版逻辑
},
handleSizeChange() {
// 处理分页大小变化
},
handleCurrentChange() {
// 处理当前页变化
}
}
}
</script>
<style>
.el-tooltip__popper.is-dark {
color: #F04B4B !important;
background: #FCF1EB !important;
}
.el-tooltip__popper .popper__arrow {
border-top-color: #FCF1EB !important;
/* 上方箭头 */
}
.el-tooltip__popper .popper__arrow::after {
border-top-color: #FCF1EB !important;
}
/* 其他方向的箭头(按需添加) */
.el-tooltip__popper[x-placement^='bottom'] .popper__arrow {
border-bottom-color: #FCF1EB !important;
}
.el-tooltip__popper[x-placement^='left'] .popper__arrow {
border-left-color: #FCF1EB !important;
}
.el-tooltip__popper[x-placement^='right'] .popper__arrow {
border-right-color: #FCF1EB !important;
}
</style>
<style scoped>
.areas {
padding-bottom: 15px;
width: 97%;
margin: 0 auto;
padding-top: 20px;
}
.active {
color: #5165f7 !important;
}
.heng {
width: 20px;
height: 6px;
background: #5165f7;
margin: 0 auto;
margin-top: 6px;
}
.header-table {
cursor: pointer;
}
.contentss-header {
width: 100%;
display: flex;
justify-content: space-between;
width: 150px;
}
.contentss {
width: 97%;
margin: 0 auto;
padding-top: 12px;
}
.contents-area {
width: 100%;
background: white;
margin-top: 20px;
}
.header-title {
position: relative;
top: 20px;
left: 25px;
}
.numbers {
position: relative;
top: -7px;
color: #2AB95F;
}
.number-name2 {
margin-top: 8px;
font-size: 14px;
color: #979BBC;
}
.number-name {
font-weight: bold;
font-size: 25px;
color: #17192C;
}
.header-names {
display: flex;
width: 82%;
justify-content: space-between;
margin: 0 auto;
padding-top: 20px;
}
.header-area {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
width: 97%;
margin: 0 auto;
}
.content-header {
width: 100%;
background: white;
padding-bottom: 22px;
}
.footer {
display: flex;
justify-content: end;
margin-top: 20px;
}
.tianjia {
position: relative;
top: -9px;
background-color: #5065F6;
}
.tianjia2 {
position: relative;
top: -9px;
background-color: #EDEFFE;
color: #5065F6;
}
::v-deep .el-table thead {
background-color: #EDEFFE !important;
color: #363636 !important;
}
::v-deep .el-table__header th {
background-color: #EDEFFE !important;
color: #363636 !important;
}
.formitem {
position: relative;
top: -5px;
}
::deep .el-form-item__label {
font-size: 15px !important;
}
.selects {
width: 100px;
border: 1px solid #3333;
}
.headers-name {
font-size: 15px;
position: relative;
top: 14px;
}
.headers {
display: flex;
justify-content: space-between;
}
.status-uploaded {
color: #67C23A;
}
.status-not-uploaded {
background: #F56C6C;
color: white;
padding: 4px 12px;
border-radius: 4px;
display: inline-block;
}
::v-deep .el-table__body tr:hover > td {
background-color: transparent !important;
}
::v-deep .el-table__body tr.el-table__row--striped td {
background-color: transparent;
}
</style>

View File

@@ -0,0 +1,887 @@
<template>
<div>
<div class="headers">
<div class="headers-left">
<div class="imgs">
</div>
<div class="img-right">
<div class="name-title">微育科技</div>
<div class="right-name">数智科创 · 通达未来 </div>
</div>
</div>
<div class="headers-right">
<div class="rights">
<div class="rights-names" @click="btnShang">
<span>上一级 < </span> <span style="color:#3333;">研发人员薪资明细</span>
</div>
</div>
</div>
</div>
<div class="contents">
<div class="content-left">
<div class="content-lefts">
<div class="leftss">
<div class="leftss-header">
<div>2025年1月薪资情况</div>
<div @click="btnEdint">
<el-button size="small" style="background-color: #5165f7;color:white;">保存提交</el-button>
<el-button size="small" plain @click="closeguan">取消</el-button>
</div>
</div>
<div class="table-area">
<div class="table-header">
<div class="hetong">
<div class="timess" v-for="(item,index) in listDate"
key="index"
:class="{'active2':active2 === index}"
@click="btnName(index)"
>
{{ item.name }}
</div>
</div>
<div>
<span class="times">
<el-button>重新上传工资表</el-button>
</span>
</div>
</div>
</div>
</div>
<div class="content-table">
<el-table
v-show="active2==0"
:data="tableData"
border
style="width: 100%">
<el-table-column
type="index"
label="序号"
width="50">
</el-table-column>
<el-table-column
prop="date"
label="薪资费用类型"
width="150"
>
</el-table-column>
<el-table-column
prop="name"
label="凭证号"
width="150"
>
</el-table-column>
<el-table-column
prop="province"
label="凭证记载付款时间"
width="150"
>
</el-table-column>
<el-table-column
prop="city"
label="会计凭证记载金额(元)"
width="200"
>
</el-table-column>
<el-table-column
prop="address"
label="凭证附件每类最多3个"
>
</el-table-column>
</el-table>
<el-table
v-show="active2==1"
:data="tableData"
border
style="width: 100%">
<el-table-column
type="index"
label="序号"
width="50">
</el-table-column>
<el-table-column
prop="date"
label="姓名"
>
</el-table-column>
<el-table-column
prop="name"
label="所属部门"
>
</el-table-column>
<el-table-column
prop="province"
label="电话号码"
>
</el-table-column>
<el-table-column
prop="city"
label="应发工资"
>
</el-table-column>
<el-table-column
prop="address"
label="应发奖金"
>
</el-table-column>
<el-table-column
prop="address"
label="应发绩效"
>
</el-table-column>
<el-table-column
prop="address"
label="公积金"
>
</el-table-column>
<el-table-column
prop="address"
label="养老保险"
>
</el-table-column>
<el-table-column
prop="address"
label="医疗保险"
>
</el-table-column>
<el-table-column
prop="address"
label="失业保险"
>
</el-table-column>
<el-table-column
prop="address"
label="工伤保险"
>
</el-table-column>
<el-table-column
prop="address"
label="生育保险"
>
</el-table-column>
</el-table>
<div class="footers">
以企业实际上传薪资费用类型为准展示且每月类型可不一致
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
active2:0,
active: 0,
listDate: [
{
name: '合同信息'
},
{
name: '薪资信息'
},
],
value1: "",
yuanright: 0,
tables: [
{
name: '有效'
},
{
name: '无效'
},
],
shu: 0,
lastActiveKey: 'headerActiveIndex',
tableData: [
{
date: "其中",
name: "",
address: "",
children: [
{ date: "2024", name: "年度审计报告及财务情况说明书", address: "8000" },
{ date: "2025", name: "年度审计报告及财务情况说明书", address: "7500" },
],
},
{ date: "其他项目", name: "5000", address: "4000" },
],
tableData2: [
{ date: "2025", name: "年度审计报告及财务情况说明书", address: "7500" },]
}
},
created() {
},
watch: {
},
methods: {
btnName(e){
this.active2=e
},
//取消
closeguan() {
},
btnNmae(e) {
this.active = e
},
//切换时效性
btnYuan(e) {
this.yuanright = e
},
//编辑跳转
btnEdint() {
this.$router.push('/hetongmingxin')
},
btnShang() {
this.$router.go(-1)
}
}
}
</script>
<style>
.el-tooltip__popper.is-dark {
color: #F04B4B !important;
background: #FCF1EB !important;
}
.el-tooltip__popper .popper__arrow {
border-top-color: #FCF1EB !important;
/* 上方箭头 */
}
.el-tooltip__popper .popper__arrow::after {
border-top-color: #FCF1EB !important;
}
/* 其他方向的箭头(按需添加) */
.el-tooltip__popper[x-placement^='bottom'] .popper__arrow {
border-bottom-color: #FCF1EB !important;
}
.el-tooltip__popper[x-placement^='left'] .popper__arrow {
border-left-color: #FCF1EB !important;
}
.el-tooltip__popper[x-placement^='right'] .popper__arrow {
border-right-color: #FCF1EB !important;
}
</style>
<style scoped>
.footers{
margin-top: 12px;
color: #5B5E72;
font-size: 12px;
}
.active2{
height: 26px !important;
border-bottom: 2px solid #5065F6 !important;
}
.hetong{
display: flex;
width: 140px;
justify-content: space-between;
position: relative;
top: 12px;
}
.tabless{
width: 90%;
margin: 0 auto;
margin-top: 30px;
}
.area-name {
margin-left: 30px;
cursor: pointer;
}
.active {
border-bottom: 3px solid #5165f7;
height: 45px;
}
.header-area {
display: flex;
position: relative;
left: -30px;
}
.rightss3 {
border-right: none;
border-left: none;
}
.table-name {
margin-left: 20px;
}
.rightss2 {
background: #EDEFFE;
}
.rightss1 {
border-left: none !important;
border-right: none !important;
}
.rightss {
height: 100%;
border: 1px solid #DCE0FD;
width: 100%;
border-top: none;
}
.content-areas2 {
position: relative;
top: 1px;
}
.contents-right {
flex: 1;
border: 1px solid #DCE0FD;
line-height: 50px;
font-size: 14px;
color: #363636;
display: flex
}
.contents-left {
width: 30%;
border: 1px solid #DCE0FD;
background: #EDEFFE;
;
line-height: 50px;
font-size: 14px;
color: #363636;
}
.content-areas {
display: flex;
height: 50px;
flex-wrap: wrap;
}
.tab-area {
margin-top: 24px;
}
.namess {
color: #5B5E72;
font-size: 13px;
margin-left: 12px;
}
.names {
font-size: 14px;
color: #363636;
}
:deep .el-tooltip__popper.is-dark {
color: #F04B4B !important;
}
.right-area {
width: 90%;
margin: 0 auto;
height: 80vh;
background: #f8f8f8;
}
.right-header {
width: 90%;
margin: 0 auto;
}
.ths {
text-align: center;
background: #DCE0FD !important;
color: #363636;
}
.tou {
height: 30px;
line-height: 30px;
color: #606266;
text-align: center;
}
.financial-table {
width: 100%;
border-collapse: collapse;
font-family: Arial, sans-serif;
font-size: 14px;
}
.financial-table th,
.financial-table td {
border: 1px solid #ddd;
padding: 8px 7px;
text-align: center;
}
.financial-table th {
background-color: #f5f5f5;
font-weight: bold;
}
.financial-table .nested-label {
text-align: center;
vertical-align: middle;
font-weight: bold;
}
.table-right {
flex: 1;
}
.table-left {
flex: 1;
}
.content-table {
width: 90%;
margin: 0 auto;
margin-top: 14px;
}
/* 默认情况(有效)左边圆角 */
.left-radius {
border-bottom-left-radius: 16px !important;
border-top-left-radius: 16px !important;
}
/* 无效情况右边圆角 */
.right-radius {
border-bottom-right-radius: 16px !important;
border-top-right-radius: 16px !important;
}
.yuan-left {
flex: 1;
text-align: center;
line-height: 30px;
background: #f8f8f8;
/* border-bottom-left-radius: 16px;
border-top-left-radius: 16px; */
cursor: pointer;
}
.yuanright {
flex: 1;
background: #5165f7;
color: white;
/* border-bottom-right-radius: 16px;
border-top-right-radius: 16px; */
text-align: center;
line-height: 30px;
cursor: pointer;
}
.youxiaos {
position: relative;
top: 6px;
left: -12px;
cursor: pointer;
}
/* 修改.yuan的样式移除外层圆角 */
.yuan {
width: 100px;
height: 30px;
background: white;
display: flex;
font-size: 14px;
overflow: hidden;
/* 关键确保内部div的圆角效果不被截断 */
}
/* 默认状态下两个按钮的外侧圆角 */
.yuan-left:first-child {
border-top-left-radius: 16px;
border-bottom-left-radius: 16px;
}
.yuan-left:last-child {
border-top-right-radius: 16px;
border-bottom-right-radius: 16px;
}
/* 选中状态样式 */
.yuanright {
background: #5165f7;
color: white;
}
.rights-names {
margin-left: 32px;
cursor: pointer;
color: #5165f7;
}
/* 选中"有效"时的样式 */
.yuan-left.left-radius {
border-top-right-radius: 0 !important;
border-bottom-right-radius: 0 !important;
}
/* 选中"无效"时的样式 */
.yuan-left.right-radius {
border-top-left-radius: 0 !important;
border-bottom-left-radius: 0 !important;
}
.times {
position: relative;
top: 3px;
}
.timess {
position: relative;
top: 3px;
display: inline-block;
cursor: pointer;
}
.youxiao {
color: #5B5D76;
font-size: 13px;
}
.table-header {
display: flex;
justify-content: space-between;
margin-top: 14px;
}
.table-area {
margin-top: 12px;
font-size: 15px;
}
.leftss-header {
display: flex;
height: 60px;
line-height: 60px;
border-bottom: 1px solid #3333;
font-weight: bold;
justify-content: space-between;
}
.leftss {
width: 90%;
margin: 0 auto;
}
.content-lefts {
background: white;
height: 100%;
width: 100%;
}
.content-left {
flex: 1;
padding-right: 12px;
height: 100%;
}
.content-right {
width: 600px;
height: 100%;
background: white;
}
.contents {
width: 100%;
height: 92vh;
background: #f8f8f8;
display: flex;
margin-top: 6px;
/* flex-wrap: wrap */
}
.shu {
width: 3px;
height: 18px;
background: #5165f7;
position: relative;
display: inline-block;
top: 7px;
}
::v-deep .el-table thead {
background-color: #DCE0FD !important;
color: #363636 !important;
font-weight: bold;
}
::v-deep .el-table__header th {
background-color: #DCE0FD !important;
color: #363636 !important;
font-weight: bold;
}
.rights {
width: 96%;
height: 100%;
margin: 0 auto;
line-height: 88px;
display: flex;
position: relative;
top: -6px;
}
.name-title {
position: relative;
top: -6px;
font-weight: bold;
}
.right-name {
font-size: 12px;
}
.img-right {
font-size: 14px;
position: relative;
top: 35px;
height: 40px;
margin-left: 12px;
}
.imgs {
width: 42px;
height: 40px;
background: #5165f7;
border-radius: 6px;
position: relative;
top: 26px;
margin-left: 24px
}
.headers-right {
flex: 1;
background: white;
}
.headers-left {
width: 222px;
height: 100%;
display: flex;
background: white;
}
.headers {
width: 100%;
display: flex;
}
.patent-container {
max-width: 1000px;
margin: 0 auto;
background: white;
border-radius: 8px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
overflow: hidden;
}
.patent-header {
background: linear-gradient(135deg, #6a5acd, #8a7dff);
color: white;
padding: 20px 30px;
text-align: center;
}
.patent-header h1 {
font-size: 24px;
margin-bottom: 10px;
font-weight: 600;
}
.patent-header p {
opacity: 0.9;
font-size: 14px;
}
.search-box {
padding: 15px 30px;
background-color: #f8f9fa;
border-bottom: 1px solid #eaeaea;
}
.search-box input {
width: 100%;
padding: 10px 15px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 14px;
transition: border-color 0.3s;
}
.search-box input:focus {
outline: none;
border-color: #8a7dff;
box-shadow: 0 0 0 2px rgba(138, 125, 255, 0.2);
}
.patent-table {
width: 100%;
border-collapse: collapse;
}
.patent-table th {
background-color: #f0e6ff;
color: #5a4fcf;
padding: 12px 15px;
text-align: left;
font-weight: 600;
border-bottom: 1px solid #ddd;
}
.patent-table td {
padding: 12px 15px;
border-bottom: 1px solid #f0f0f0;
transition: background-color 0.2s;
}
.patent-table tr:hover td {
background-color: #f9f7ff;
}
.patent-table tr:last-child td {
border-bottom: none;
}
.status-badge {
display: inline-block;
padding: 4px 8px;
border-radius: 4px;
font-size: 12px;
font-weight: 500;
}
.status-paid {
background-color: #e8f5e9;
color: #2e7d32;
}
.patent-footer {
padding: 15px 30px;
text-align: center;
color: #777;
font-size: 14px;
border-top: 1px solid #eaeaea;
background-color: #fafafa;
}
.active{
color: #5165f7 !important;
}
.rights-names{
margin-left: 32px;
cursor: pointer;
}
.rights{
width: 96%;
height: 100%;
margin: 0 auto;
line-height: 94px;
display: flex;
position: relative;
left: -27px;
}
.name-title{
position: relative;
top: -6px;
font-weight: bold;
}
.right-name{
font-size: 12px;
}
.img-right{
font-size: 14px;
position: relative;
top: 40px;
height: 40px;
margin-left: 12px;
}
.imgs{
width: 45px;
height: 46px;
background: #5165f7;
border-radius: 6px;
position: relative;
top: 26px;
margin-left: 24px
}
.headers-right{
flex: 1;
background: white;
}
.headers-left{
width: 222px;
height: 100%;
display: flex;
background: white;
border-right: 1px solid #EDEFFE;
}
.headers{
width: 100%;
height: 90px;
display: flex
;
border-bottom: 1px solid #EDEFFE;
}
</style>

View File

@@ -0,0 +1,887 @@
<template>
<div>
<div class="headers">
<div class="headers-left">
<div class="imgs">
</div>
<div class="img-right">
<div class="name-title">微育科技</div>
<div class="right-name">数智科创 · 通达未来 </div>
</div>
</div>
<div class="headers-right">
<div class="rights">
<div class="rights-names" @click="btnShang">
<span>上一级 < </span> <span style="color:#3333;">研发人员薪资明细</span>
</div>
</div>
</div>
</div>
<div class="contents">
<div class="content-left">
<div class="content-lefts">
<div class="leftss">
<div class="leftss-header">
<div>2025年1月薪资情况</div>
<div @click="btnEdint">
<el-button size="small" style="background-color: #5165f7;color:white;">保存提交</el-button>
<el-button size="small" plain @click="closeguan">取消</el-button>
</div>
</div>
<div class="table-area">
<div class="table-header">
<div class="hetong">
<div class="timess" v-for="(item,index) in listDate"
key="index"
:class="{'active2':active2 === index}"
@click="btnName(index)"
>
{{ item.name }}
</div>
</div>
<div>
<span class="times">
<el-button>重新上传工资表</el-button>
</span>
</div>
</div>
</div>
</div>
<div class="content-table">
<el-table
v-show="active2==0"
:data="tableData"
border
style="width: 100%">
<el-table-column
type="index"
label="序号"
width="50">
</el-table-column>
<el-table-column
prop="date"
label="薪资费用类型"
width="150"
>
</el-table-column>
<el-table-column
prop="name"
label="凭证号"
width="150"
>
</el-table-column>
<el-table-column
prop="province"
label="凭证记载付款时间"
width="150"
>
</el-table-column>
<el-table-column
prop="city"
label="会计凭证记载金额(元)"
width="200"
>
</el-table-column>
<el-table-column
prop="address"
label="凭证附件每类最多3个"
>
</el-table-column>
</el-table>
<el-table
v-show="active2==1"
:data="tableData"
border
style="width: 100%">
<el-table-column
type="index"
label="序号"
width="50">
</el-table-column>
<el-table-column
prop="date"
label="姓名"
>
</el-table-column>
<el-table-column
prop="name"
label="所属部门"
>
</el-table-column>
<el-table-column
prop="province"
label="电话号码"
>
</el-table-column>
<el-table-column
prop="city"
label="应发工资"
>
</el-table-column>
<el-table-column
prop="address"
label="应发奖金"
>
</el-table-column>
<el-table-column
prop="address"
label="应发绩效"
>
</el-table-column>
<el-table-column
prop="address"
label="公积金"
>
</el-table-column>
<el-table-column
prop="address"
label="养老保险"
>
</el-table-column>
<el-table-column
prop="address"
label="医疗保险"
>
</el-table-column>
<el-table-column
prop="address"
label="失业保险"
>
</el-table-column>
<el-table-column
prop="address"
label="工伤保险"
>
</el-table-column>
<el-table-column
prop="address"
label="生育保险"
>
</el-table-column>
</el-table>
<div class="footers">
以企业实际上传薪资费用类型为准展示且每月类型可不一致
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
active2:0,
active: 0,
listDate: [
{
name: '合同信息'
},
{
name: '薪资信息'
},
],
value1: "",
yuanright: 0,
tables: [
{
name: '有效'
},
{
name: '无效'
},
],
shu: 0,
lastActiveKey: 'headerActiveIndex',
tableData: [
{
date: "其中",
name: "",
address: "",
children: [
{ date: "2024", name: "年度审计报告及财务情况说明书", address: "8000" },
{ date: "2025", name: "年度审计报告及财务情况说明书", address: "7500" },
],
},
{ date: "其他项目", name: "5000", address: "4000" },
],
tableData2: [
{ date: "2025", name: "年度审计报告及财务情况说明书", address: "7500" },]
}
},
created() {
},
watch: {
},
methods: {
btnName(e){
this.active2=e
},
//取消
closeguan() {
},
btnNmae(e) {
this.active = e
},
//切换时效性
btnYuan(e) {
this.yuanright = e
},
//编辑跳转
btnEdint() {
this.$router.push('/hetongmingxin')
},
btnShang() {
this.$router.go(-1)
}
}
}
</script>
<style>
.el-tooltip__popper.is-dark {
color: #F04B4B !important;
background: #FCF1EB !important;
}
.el-tooltip__popper .popper__arrow {
border-top-color: #FCF1EB !important;
/* 上方箭头 */
}
.el-tooltip__popper .popper__arrow::after {
border-top-color: #FCF1EB !important;
}
/* 其他方向的箭头(按需添加) */
.el-tooltip__popper[x-placement^='bottom'] .popper__arrow {
border-bottom-color: #FCF1EB !important;
}
.el-tooltip__popper[x-placement^='left'] .popper__arrow {
border-left-color: #FCF1EB !important;
}
.el-tooltip__popper[x-placement^='right'] .popper__arrow {
border-right-color: #FCF1EB !important;
}
</style>
<style scoped>
.footers{
margin-top: 12px;
color: #5B5E72;
font-size: 12px;
}
.active2{
height: 26px !important;
border-bottom: 2px solid #5065F6 !important;
}
.hetong{
display: flex;
width: 140px;
justify-content: space-between;
position: relative;
top: 12px;
}
.tabless{
width: 90%;
margin: 0 auto;
margin-top: 30px;
}
.area-name {
margin-left: 30px;
cursor: pointer;
}
.active {
border-bottom: 3px solid #5165f7;
height: 45px;
}
.header-area {
display: flex;
position: relative;
left: -30px;
}
.rightss3 {
border-right: none;
border-left: none;
}
.table-name {
margin-left: 20px;
}
.rightss2 {
background: #EDEFFE;
}
.rightss1 {
border-left: none !important;
border-right: none !important;
}
.rightss {
height: 100%;
border: 1px solid #DCE0FD;
width: 100%;
border-top: none;
}
.content-areas2 {
position: relative;
top: 1px;
}
.contents-right {
flex: 1;
border: 1px solid #DCE0FD;
line-height: 50px;
font-size: 14px;
color: #363636;
display: flex
}
.contents-left {
width: 30%;
border: 1px solid #DCE0FD;
background: #EDEFFE;
;
line-height: 50px;
font-size: 14px;
color: #363636;
}
.content-areas {
display: flex;
height: 50px;
flex-wrap: wrap;
}
.tab-area {
margin-top: 24px;
}
.namess {
color: #5B5E72;
font-size: 13px;
margin-left: 12px;
}
.names {
font-size: 14px;
color: #363636;
}
:deep .el-tooltip__popper.is-dark {
color: #F04B4B !important;
}
.right-area {
width: 90%;
margin: 0 auto;
height: 80vh;
background: #f8f8f8;
}
.right-header {
width: 90%;
margin: 0 auto;
}
.ths {
text-align: center;
background: #DCE0FD !important;
color: #363636;
}
.tou {
height: 30px;
line-height: 30px;
color: #606266;
text-align: center;
}
.financial-table {
width: 100%;
border-collapse: collapse;
font-family: Arial, sans-serif;
font-size: 14px;
}
.financial-table th,
.financial-table td {
border: 1px solid #ddd;
padding: 8px 7px;
text-align: center;
}
.financial-table th {
background-color: #f5f5f5;
font-weight: bold;
}
.financial-table .nested-label {
text-align: center;
vertical-align: middle;
font-weight: bold;
}
.table-right {
flex: 1;
}
.table-left {
flex: 1;
}
.content-table {
width: 90%;
margin: 0 auto;
margin-top: 14px;
}
/* 默认情况(有效)左边圆角 */
.left-radius {
border-bottom-left-radius: 16px !important;
border-top-left-radius: 16px !important;
}
/* 无效情况右边圆角 */
.right-radius {
border-bottom-right-radius: 16px !important;
border-top-right-radius: 16px !important;
}
.yuan-left {
flex: 1;
text-align: center;
line-height: 30px;
background: #f8f8f8;
/* border-bottom-left-radius: 16px;
border-top-left-radius: 16px; */
cursor: pointer;
}
.yuanright {
flex: 1;
background: #5165f7;
color: white;
/* border-bottom-right-radius: 16px;
border-top-right-radius: 16px; */
text-align: center;
line-height: 30px;
cursor: pointer;
}
.youxiaos {
position: relative;
top: 6px;
left: -12px;
cursor: pointer;
}
/* 修改.yuan的样式移除外层圆角 */
.yuan {
width: 100px;
height: 30px;
background: white;
display: flex;
font-size: 14px;
overflow: hidden;
/* 关键确保内部div的圆角效果不被截断 */
}
/* 默认状态下两个按钮的外侧圆角 */
.yuan-left:first-child {
border-top-left-radius: 16px;
border-bottom-left-radius: 16px;
}
.yuan-left:last-child {
border-top-right-radius: 16px;
border-bottom-right-radius: 16px;
}
/* 选中状态样式 */
.yuanright {
background: #5165f7;
color: white;
}
.rights-names {
margin-left: 32px;
cursor: pointer;
color: #5165f7;
}
/* 选中"有效"时的样式 */
.yuan-left.left-radius {
border-top-right-radius: 0 !important;
border-bottom-right-radius: 0 !important;
}
/* 选中"无效"时的样式 */
.yuan-left.right-radius {
border-top-left-radius: 0 !important;
border-bottom-left-radius: 0 !important;
}
.times {
position: relative;
top: 3px;
}
.timess {
position: relative;
top: 3px;
display: inline-block;
cursor: pointer;
}
.youxiao {
color: #5B5D76;
font-size: 13px;
}
.table-header {
display: flex;
justify-content: space-between;
margin-top: 14px;
}
.table-area {
margin-top: 12px;
font-size: 15px;
}
.leftss-header {
display: flex;
height: 60px;
line-height: 60px;
border-bottom: 1px solid #3333;
font-weight: bold;
justify-content: space-between;
}
.leftss {
width: 90%;
margin: 0 auto;
}
.content-lefts {
background: white;
height: 100%;
width: 100%;
}
.content-left {
flex: 1;
padding-right: 12px;
height: 100%;
}
.content-right {
width: 600px;
height: 100%;
background: white;
}
.contents {
width: 100%;
height: 92vh;
background: #f8f8f8;
display: flex;
margin-top: 6px;
/* flex-wrap: wrap */
}
.shu {
width: 3px;
height: 18px;
background: #5165f7;
position: relative;
display: inline-block;
top: 7px;
}
::v-deep .el-table thead {
background-color: #DCE0FD !important;
color: #363636 !important;
font-weight: bold;
}
::v-deep .el-table__header th {
background-color: #DCE0FD !important;
color: #363636 !important;
font-weight: bold;
}
.rights {
width: 96%;
height: 100%;
margin: 0 auto;
line-height: 88px;
display: flex;
position: relative;
top: -6px;
}
.name-title {
position: relative;
top: -6px;
font-weight: bold;
}
.right-name {
font-size: 12px;
}
.img-right {
font-size: 14px;
position: relative;
top: 35px;
height: 40px;
margin-left: 12px;
}
.imgs {
width: 42px;
height: 40px;
background: #5165f7;
border-radius: 6px;
position: relative;
top: 26px;
margin-left: 24px
}
.headers-right {
flex: 1;
background: white;
}
.headers-left {
width: 222px;
height: 100%;
display: flex;
background: white;
}
.headers {
width: 100%;
display: flex;
}
.patent-container {
max-width: 1000px;
margin: 0 auto;
background: white;
border-radius: 8px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
overflow: hidden;
}
.patent-header {
background: linear-gradient(135deg, #6a5acd, #8a7dff);
color: white;
padding: 20px 30px;
text-align: center;
}
.patent-header h1 {
font-size: 24px;
margin-bottom: 10px;
font-weight: 600;
}
.patent-header p {
opacity: 0.9;
font-size: 14px;
}
.search-box {
padding: 15px 30px;
background-color: #f8f9fa;
border-bottom: 1px solid #eaeaea;
}
.search-box input {
width: 100%;
padding: 10px 15px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 14px;
transition: border-color 0.3s;
}
.search-box input:focus {
outline: none;
border-color: #8a7dff;
box-shadow: 0 0 0 2px rgba(138, 125, 255, 0.2);
}
.patent-table {
width: 100%;
border-collapse: collapse;
}
.patent-table th {
background-color: #f0e6ff;
color: #5a4fcf;
padding: 12px 15px;
text-align: left;
font-weight: 600;
border-bottom: 1px solid #ddd;
}
.patent-table td {
padding: 12px 15px;
border-bottom: 1px solid #f0f0f0;
transition: background-color 0.2s;
}
.patent-table tr:hover td {
background-color: #f9f7ff;
}
.patent-table tr:last-child td {
border-bottom: none;
}
.status-badge {
display: inline-block;
padding: 4px 8px;
border-radius: 4px;
font-size: 12px;
font-weight: 500;
}
.status-paid {
background-color: #e8f5e9;
color: #2e7d32;
}
.patent-footer {
padding: 15px 30px;
text-align: center;
color: #777;
font-size: 14px;
border-top: 1px solid #eaeaea;
background-color: #fafafa;
}
.active{
color: #5165f7 !important;
}
.rights-names{
margin-left: 32px;
cursor: pointer;
}
.rights{
width: 96%;
height: 100%;
margin: 0 auto;
line-height: 94px;
display: flex;
position: relative;
left: -27px;
}
.name-title{
position: relative;
top: -6px;
font-weight: bold;
}
.right-name{
font-size: 12px;
}
.img-right{
font-size: 14px;
position: relative;
top: 40px;
height: 40px;
margin-left: 12px;
}
.imgs{
width: 45px;
height: 46px;
background: #5165f7;
border-radius: 6px;
position: relative;
top: 26px;
margin-left: 24px
}
.headers-right{
flex: 1;
background: white;
}
.headers-left{
width: 222px;
height: 100%;
display: flex;
background: white;
border-right: 1px solid #EDEFFE;
}
.headers{
width: 100%;
height: 90px;
display: flex
;
border-bottom: 1px solid #EDEFFE;
}
</style>

View File

@@ -0,0 +1,570 @@
<template>
<div>
<div class="coentent">
<div class="contents-area">
<div class="areas">
<div v-if="active==0">
<div class="headers">
<div class="headers-name">项目工时及人工费情况</div>
<div>
<el-form :inline="true" :model="form" class="demo-form-inline">
<el-form-item label="项目名称" size="small" style="position: relative;top: -3px;">
<el-select v-model="form.projectName" placeholder="请选择" class="selects">
<el-option v-for="item in projectOptions" :key="item.value" :label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="年度选择" size="small" style="position: relative;top: -3px;">
<el-select v-model="form.year" placeholder="请选择" class="selects">
<el-option v-for="item in yearOptions" :key="item.value" :label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="btnAdd" size="small" class="tianjia">添加</el-button>
</el-form-item>
</el-form>
</div>
</div>
<div class="content-table">
<el-table
:data="tableData"
:header-cell-style="{ background: '#EDEFFE', color: '#363636', textAlign: 'center' }"
border
style="width: 100%">
<el-table-column prop="serial" label="序号" width="80" align="center"></el-table-column>
<el-table-column prop="projectCode" label="项目代号" align="center"></el-table-column>
<el-table-column prop="projectName" label="项目名称" align="center"></el-table-column>
<el-table-column prop="dateRange" label="项目起止日期" align="center"></el-table-column>
<el-table-column prop="status" label="项目状态" width="120" align="center">
<template slot-scope="scope">
<span :class="scope.row.status === '已结束' ? 'status-completed' : 'status-pending'">
{{ scope.row.status }}
</span>
</template>
</el-table-column>
<el-table-column prop="totalHours" label="合计工时(天)" align="center"></el-table-column>
<el-table-column prop="monthlyLaborCost" label="本月人工费(元)" align="center"></el-table-column>
<el-table-column fixed="right" label="操作" align="center" width="100">
<template slot-scope="scope">
<el-button @click="handleDetail(scope.row)" type="text" size="small" style="color: #5165f7;">详情</el-button>
</template>
</el-table-column>
</el-table>
<div class="footer">
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="currentPage"
:page-sizes="[100, 200, 300, 400]"
:page-size="100"
layout="total, sizes, prev, pager, next, jumper"
:total="400">
</el-pagination>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 详情弹窗 -->
<el-dialog
:title="dialogTitle"
:visible.sync="dialogVisible"
width="90%"
:close-on-click-modal="false"
class="detail-dialog">
<div class="dialog-subtitle">项目工时薪资分配情况|</div>
<div class="dialog-table-wrapper">
<el-table
:data="detailTableData"
:header-cell-style="{ background: '#EDEFFE', color: '#363636', textAlign: 'center' }"
border
style="width: 100%">
<el-table-column prop="serial" label="序号" width="80" align="center"></el-table-column>
<el-table-column prop="name" label="姓名" align="center"></el-table-column>
<el-table-column prop="projectHours" label="项目工时" align="center"></el-table-column>
<el-table-column prop="hoursPercentage" label="工时占比" align="center"></el-table-column>
<el-table-column prop="salary" label="工资" align="center"></el-table-column>
<el-table-column prop="bonus" label="奖金" align="center"></el-table-column>
<el-table-column prop="performance" label="绩效" align="center"></el-table-column>
<el-table-column prop="providentFund" label="公积金" align="center"></el-table-column>
<el-table-column prop="pensionInsurance" label="养老保险" align="center"></el-table-column>
<el-table-column prop="medicalInsurance" label="医疗保险" align="center"></el-table-column>
<el-table-column prop="unemploymentInsurance" label="失业保险" align="center"></el-table-column>
<el-table-column prop="workInjuryInsurance" label="工伤保险" align="center"></el-table-column>
<el-table-column prop="maternityInsurance" label="生育保险" align="center"></el-table-column>
</el-table>
</div>
</el-dialog>
</div>
</template>
<script>
export default {
data() {
return {
active: 0,
currentPage: 1,
dialogVisible: false,
dialogTitle: '',
currentProject: null,
form: {
projectName: '',
year: '2025'
},
projectOptions: [
{
value: '全部',
label: '全部'
},
{
value: '项目A',
label: '项目A'
},
{
value: '项目B',
label: '项目B'
}
],
yearOptions: [
{
value: '2023',
label: '2023'
},
{
value: '2024',
label: '2024'
},
{
value: '2025',
label: '2025'
},
{
value: '2026',
label: '2026'
}
],
tableData: [
{
serial: 1,
projectCode: 'Wu20249',
projectName: 'GPS车辆管理系统研发项目',
dateRange: '2022.2.12-未结束',
status: '进行中',
totalHours: '100.5',
monthlyLaborCost: '666.66'
},
{
serial: 2,
projectCode: 'Wu20249',
projectName: '高速公路低功耗可变信息情报板',
dateRange: '2022.2.12-2025.2.12',
status: '已结束',
totalHours: '0',
monthlyLaborCost: '0'
},
{
serial: 3,
projectCode: 'Wu20249',
projectName: '车辆管理系统研发项目',
dateRange: '2022.2.12-未结束',
status: '进行中',
totalHours: '112.5',
monthlyLaborCost: '666.66'
},
{
serial: 4,
projectCode: 'Wu20249',
projectName: '高速公路低功耗可变信息情报板',
dateRange: '2022.2.12-未结束',
status: '进行中',
totalHours: '无数据',
monthlyLaborCost: '无数据'
},
{
serial: 5,
projectCode: 'Wu20249',
projectName: '关于智慧管养平台开发及运用的研究',
dateRange: '2022.2.12-未结束',
status: '进行中',
totalHours: '190',
monthlyLaborCost: '无数据'
},
{
serial: 6,
projectCode: 'Wu20249',
projectName: '高速公路管道与光缆管理系统开发',
dateRange: '2022.2.12-2024.2.12',
status: '已结束',
totalHours: '0',
monthlyLaborCost: '0'
},
{
serial: 7,
projectCode: 'Wu20249',
projectName: '信息安全管理体系',
dateRange: '2022.2.12-2024.2.12',
status: '已结束',
totalHours: '0',
monthlyLaborCost: '0'
},
{
serial: 8,
projectCode: 'Wu20249',
projectName: '质量管理体系认证',
dateRange: '2022.2.12-2024.2.12',
status: '已结束',
totalHours: '0',
monthlyLaborCost: '0'
}
],
detailTableData: [
{
serial: 1,
name: '徐蛟',
projectHours: '10.5',
hoursPercentage: '30.21%',
salary: '660.00',
bonus: '660.00',
performance: '660.00',
providentFund: '660.00',
pensionInsurance: '660.00',
medicalInsurance: '660.00',
unemploymentInsurance: '660.00',
workInjuryInsurance: '660.00',
maternityInsurance: '660.00'
},
{
serial: 2,
name: '陈翔',
projectHours: '6',
hoursPercentage: '30.21%',
salary: '660.00',
bonus: '660.00',
performance: '660.00',
providentFund: '660.00',
pensionInsurance: '660.00',
medicalInsurance: '660.00',
unemploymentInsurance: '660.00',
workInjuryInsurance: '660.00',
maternityInsurance: '660.00'
},
{
serial: 3,
name: '高超',
projectHours: '6',
hoursPercentage: '30.21%',
salary: '660.00',
bonus: '660.00',
performance: '660.00',
providentFund: '660.00',
pensionInsurance: '660.00',
medicalInsurance: '660.00',
unemploymentInsurance: '660.00',
workInjuryInsurance: '660.00',
maternityInsurance: '660.00'
},
{
serial: 4,
name: '陈建华 8776',
projectHours: '6',
hoursPercentage: '30.21%',
salary: '660.00',
bonus: '660.00',
performance: '660.00',
providentFund: '660.00',
pensionInsurance: '660.00',
medicalInsurance: '660.00',
unemploymentInsurance: '660.00',
workInjuryInsurance: '660.00',
maternityInsurance: '660.00'
},
{
serial: 5,
name: '陈建华 0590',
projectHours: '6',
hoursPercentage: '30.21%',
salary: '660.00',
bonus: '660.00',
performance: '660.00',
providentFund: '660.00',
pensionInsurance: '660.00',
medicalInsurance: '660.00',
unemploymentInsurance: '660.00',
workInjuryInsurance: '660.00',
maternityInsurance: '660.00'
}
]
}
},
methods: {
getRowStyle({ row, rowIndex }) {
return {}
},
handleDetail(row) {
console.log('查看详情', row)
this.currentProject = row
// 生成弹窗标题2025年11月: GPS车辆管理系统研发项目-工时工费情况
const currentDate = new Date()
const year = currentDate.getFullYear()
const month = currentDate.getMonth() + 1
this.dialogTitle = `${year}${month}月: ${row.projectName}-工时工费情况`
this.dialogVisible = true
},
handleEdit(row) {
console.log('编辑', row)
// 跳转到编辑页面
},
btnAdd() {
console.log('添加')
// 处理添加逻辑
},
handleSizeChange() {
// 处理分页大小变化
},
handleCurrentChange() {
// 处理当前页变化
}
}
}
</script>
<style>
.el-tooltip__popper.is-dark {
color: #F04B4B !important;
background: #FCF1EB !important;
}
.el-tooltip__popper .popper__arrow {
border-top-color: #FCF1EB !important;
/* 上方箭头 */
}
.el-tooltip__popper .popper__arrow::after {
border-top-color: #FCF1EB !important;
}
/* 其他方向的箭头(按需添加) */
.el-tooltip__popper[x-placement^='bottom'] .popper__arrow {
border-bottom-color: #FCF1EB !important;
}
.el-tooltip__popper[x-placement^='left'] .popper__arrow {
border-left-color: #FCF1EB !important;
}
.el-tooltip__popper[x-placement^='right'] .popper__arrow {
border-right-color: #FCF1EB !important;
}
</style>
<style scoped>
.areas {
padding-bottom: 15px;
width: 97%;
margin: 0 auto;
padding-top: 20px;
}
.active {
color: #5165f7 !important;
}
.heng {
width: 20px;
height: 6px;
background: #5165f7;
margin: 0 auto;
margin-top: 6px;
}
.header-table {
cursor: pointer;
}
.contentss-header {
width: 100%;
display: flex;
justify-content: space-between;
width: 150px;
}
.contentss {
width: 97%;
margin: 0 auto;
padding-top: 12px;
}
.contents-area {
width: 100%;
background: white;
margin-top: 20px;
}
.header-title {
position: relative;
top: 20px;
left: 25px;
}
.numbers {
position: relative;
top: -7px;
color: #2AB95F;
}
.number-name2 {
margin-top: 8px;
font-size: 14px;
color: #979BBC;
}
.number-name {
font-weight: bold;
font-size: 25px;
color: #17192C;
}
.header-names {
display: flex;
width: 82%;
justify-content: space-between;
margin: 0 auto;
padding-top: 20px;
}
.header-area {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
width: 97%;
margin: 0 auto;
}
.content-header {
width: 100%;
background: white;
padding-bottom: 22px;
}
.footer {
display: flex;
justify-content: end;
margin-top: 20px;
}
.tianjia {
position: relative;
top: -9px;
background-color: #5065F6;
}
.tianjia2 {
position: relative;
top: -9px;
background-color: #EDEFFE;
color: #5065F6;
}
::v-deep .el-table thead {
background-color: #EDEFFE !important;
color: #363636 !important;
}
::v-deep .el-table__header th {
background-color: #EDEFFE !important;
color: #363636 !important;
}
.formitem {
position: relative;
top: -5px;
}
::deep .el-form-item__label {
font-size: 15px !important;
}
.selects {
width: 100px;
border: 1px solid #3333;
}
.headers-name {
font-size: 15px;
position: relative;
top: 14px;
}
.headers {
display: flex;
justify-content: space-between;
}
.status-completed {
color: #67C23A;
}
.status-pending {
color: #E6A23C;
}
.status-pending::before {
content: '';
display: inline-block;
width: 8px;
height: 8px;
background: #E6A23C;
border-radius: 50%;
margin-right: 5px;
}
::v-deep .el-table__body tr:hover > td {
background-color: transparent !important;
}
::v-deep .el-table__body tr.el-table__row--striped td {
background-color: transparent;
}
/* 详情弹窗样式 */
.detail-dialog ::v-deep .el-dialog__header {
padding: 20px 20px 10px;
border-bottom: 1px solid #EBEEF5;
}
.detail-dialog ::v-deep .el-dialog__title {
font-size: 16px;
font-weight: bold;
color: #303133;
}
.detail-dialog ::v-deep .el-dialog__body {
padding: 20px;
}
.dialog-subtitle {
font-size: 14px;
color: #606266;
margin-bottom: 15px;
}
.dialog-table-wrapper {
max-height: 500px;
overflow-y: auto;
}
.dialog-table-wrapper ::v-deep .el-table {
font-size: 13px;
}
.dialog-table-wrapper ::v-deep .el-table th {
padding: 10px 0;
font-weight: normal;
}
.dialog-table-wrapper ::v-deep .el-table td {
padding: 10px 0;
}
</style>

View File

@@ -0,0 +1,819 @@
<template>
<div>
<div class="headers">
<div class="headers-name">校企合作明细 2</div>
<div>
<el-form :inline="true" :model="form" class="demo-form-inline">
<el-form-item label="项目类型" size="small" style="position: relative;top: -3px;">
<el-select v-model="form.value3" placeholder="请选择" class="selects" @change="handleSearch">
<el-option v-for="item in projectTypeOptions" :key="item.value" :label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="项目状态" size="small" style="position: relative;top: -3px;">
<el-select v-model="form.value4" placeholder="请选择" class="selects" @change="handleSearch">
<el-option v-for="item in projectStatusOptions" :key="item.value" :label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="项目名称" size="small" style="position: relative;top: -3px;">
<el-input placeholder="请输入项目名称/项目编号" v-model="input3" class="input-with-select" @keyup.enter.native="handleSearch">
<el-button slot="append" icon="el-icon-search" @click="handleSearch"></el-button>
</el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="btnAdd" size="small" class="tianjia">添加项目</el-button>
</el-form-item>
</el-form>
</div>
</div>
<div class="content-table">
<el-table :data="tableData" border style="width: 100%">
<el-table-column fixed type="index" label="序号" align="center" width="80" :index="getIndex">
</el-table-column>
<el-table-column prop="project_code" label="项目代号" align="center">
</el-table-column>
<el-table-column prop="project_name" label="项目名称" width="300px">
</el-table-column>
<el-table-column prop="project_type" label="项目类型" align="center">
<template slot-scope="scope">
{{ formatProjectType(scope.row.project_type) }}
</template>
</el-table-column>
<el-table-column prop="level" label="部门" align="center">
<template slot-scope="scope">
{{ formatLevel(scope.row.level) }}
</template>
</el-table-column>
<el-table-column prop="launch_date" label="立项时间" align="center">
<template slot-scope="scope">
{{ formatDate(scope.row.launch_date) }}
</template>
</el-table-column>
<el-table-column label="项目起至时间" align="center" width="240px">
<template slot-scope="scope">
{{ formatDate(scope.row.start_date) }} {{ formatDate(scope.row.end_date) }}
</template>
</el-table-column>
<el-table-column prop="data_completeness" label="资料完整度" align="center">
</el-table-column>
<el-table-column fixed="right" label="操作" align="center" width="160">
<template slot-scope="scope">
<el-button @click="handleClick(scope.row)" type="text" size="small">主页</el-button>
<el-button @click="showDeleteDialog(scope.row)" type="text" size="small" style="color: #F56C6C;">删除</el-button>
</template>
</el-table-column>
</el-table>
<div class="footer">
<el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange"
:current-page="currentPage" :page-sizes="[100, 200, 300, 400]" :page-size="pageSize"
layout="total, sizes, prev, pager, next, jumper" :total="total">
</el-pagination>
</div>
</div>
<!-- 添加部门 -->
<el-dialog :visible.sync="dialogVisible" width="60%">
<div class="dialog-header">添加部门</div>
<div class="content-table">
<div class="content-areas">
<div class="contents-left">
<span style="margin-left: 20px;">项目名称</span>
</div>
<div class="contents-right">
<span style="margin-left: 20px;">
<el-input v-model="input" placeholder="请输入内容" style="width: 70%;"></el-input>
</span>
</div>
</div>
<div class="content-areas content-areas2" style="top: 2px;">
<div class="contents-left" style="border-top: none;">
<span class="table-name">项目代号</span>
</div>
<div class="contents-right" style="border: none;" >
<div class="rightss rightss1" ><span class="table-name">
<el-input v-model="input" placeholder="请输入内容" ></el-input>
</span></div>
<div class="rightss rightss2" style="border-top: none;"><span class="table-name">立项时间</span></div>
<div class="rightss rightss3" ><span class="table-name">
<el-date-picker
v-model="value1"
type="date"
placeholder="选择日期">
</el-date-picker>
</span></div>
</div>
</div>
<div class="content-areas content-areas2" style="top: 4px;">
<div class="contents-left" style="border-top: none;">
<span class="table-name">项目开始时间</span>
</div>
<div class="contents-right" style="border: none;">
<div class="rightss rightss1" ><span class="table-name">
<el-date-picker
v-model="value1"
type="date"
placeholder="选择日期">
</el-date-picker>
</span></div>
<div class="rightss rightss2" style="border-top: none;"><span class="table-name">项目是否结束</span></div>
<div class="rightss rightss3" ><span class="table-name">
<el-select v-model="value" placeholder="请选择" class="selects2">
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</span></div>
</div>
</div>
<div class="content-areas content-areas2" style="top: 6px;">
<div class="contents-left" style="border-top: none;">
<span class="table-name">项目结束时间</span>
</div>
<div class="contents-right" style="border: none;">
<div class="rightss rightss1" ><span class="table-name">
<el-date-picker
v-model="value1"
type="date"
placeholder="选择日期">
</el-date-picker>
</span></div>
<div class="rightss rightss2" style="border-top: none;"><span class="table-name">项目类型</span></div>
<div class="rightss rightss3" ><span class="table-name">
<el-select v-model="value5" placeholder="请选择" class="selects2">
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</span></div>
</div>
</div>
<div class="content-areas content-areas2" style="top: 8px;">
<div class="contents-left" style="border-top: none;">
<span class="table-name">部门</span>
</div>
<div class="contents-right" style="border: none;">
<div class="rightss rightss1" ><span class="table-name">
<el-select v-model="value6" placeholder="请选择" class="selects2">
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</span></div>
<div class="rightss rightss2" style="border-top: none;"><span class="table-name">级别</span></div>
<div class="rightss rightss3" ><span class="table-name">
<el-select v-model="value7" placeholder="请选择" class="selects2">
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</span></div>
</div>
</div>
</div>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false" size="small"> </el-button>
<el-button type="primary" style="background-color: #5165f7;" @click="dialogVisible = false" size="small"> </el-button>
</div>
</el-dialog>
<!-- 删除确认对话框 -->
<el-dialog :visible.sync="deleteDialogVisible" width="400px" :show-close="false" center>
<div class="delete-dialog-content">
<img src="@/assets/err.png" alt="删除" class="delete-icon" />
<div class="delete-title">确认删除</div>
<div class="delete-message">确定要删除该项目吗删除后无法恢复</div>
<div class="delete-buttons">
<el-button @click="cancelDelete">取消</el-button>
<el-button type="danger" @click="confirmDelete">确定删除</el-button>
</div>
</div>
</el-dialog>
</div>
</template>
<script>
import { list, deletes } from '@/api/projectmanagement/ProjectStatus'
export default {
data() {
return {
input3:"",
value1:"",
value4:"",
value5:"",
value6:"",
value7:"",
value:"",
listDate:[
{
value1:"",
value2:"",
value3:"",
},
{
value1:"",
value2:"",
value3:"",
}
],
performanceShow:false,
input:"",
dialogVisible: false,
currentPage: 1,
pageSize: 100,
total: 0,
tableData: [],
// 删除确认框
deleteDialogVisible: false,
deleteRow: null, // 待删除的行数据
// 项目类型选项
projectTypeOptions: [
{
value: '',
label: '全部'
},
{
value: '1',
label: '自研项目'
},
{
value: '2',
label: '科研项目'
}
],
// 项目状态选项
projectStatusOptions: [
{
value: '',
label: '全部'
},
{
value: '0',
label: '已结束'
},
{
value: '1',
label: '未结束'
}
],
options3: [
{
value: 1,
label: "有效"
},
{
value: 2,
label: "无效"
}
],
options2: [
{
value: 1,
label: "本年 (期)"
},
{
value: 2,
label: "2025"
}
],
options: [
{
value: 1,
label: "全部"
},
{
value: 2,
label: "2025"
}
],
form: {
value3: "",
value4: "",
value: "全部",
value2: "本年 (期)"
}
}
},
mounted() {
this.getList()
},
methods: {
// 获取列表数据
async getList() {
try {
const params = {
page: this.currentPage,
limit: this.pageSize,
project_type: this.form.value3 || '',
is_finished: this.form.value4 || '',
project_name: this.input3 || ''
}
const res = await list(params)
if (res && res.code === 1) {
this.tableData = res.data.data || res.data.list || []
this.total = res.data.total || 0
} else {
this.$message.error(res?.msg || '获取列表失败')
this.tableData = []
this.total = 0
}
} catch (error) {
console.error('获取列表失败:', error)
this.$message.error('获取列表失败')
this.tableData = []
this.total = 0
}
},
// 搜索
handleSearch() {
this.currentPage = 1
this.getList()
},
// 分页 - 每页条数改变
handleSizeChange(val) {
this.pageSize = val
this.currentPage = 1
this.getList()
},
// 分页 - 当前页改变
handleCurrentChange(val) {
this.currentPage = val
this.getList()
},
// 格式化项目类型
formatProjectType(type) {
if (type === 1 || type === '1') {
return '自研项目'
} else if (type === 2 || type === '2') {
return '科研项目'
}
return '--'
},
// 格式化项目级别(部门)
formatLevel(level) {
const levelMap = {
1: '科技部门国家',
2: '科技部门省部',
3: '科技部门市厅',
4: '交通运输部门国家',
5: '交通运输部门省部',
6: '交通运输部门市厅',
7: '工业和信息化部门国家',
8: '工业和信息化部门省部',
9: '工业和信息化部门市厅',
10: '大数据部门国家',
11: '大数据部门省部',
12: '大数据部门市厅',
13: '发展和改革委员会国家',
14: '发展和改革委员会省部',
15: '发展和改革委员会市厅',
16: '其他部门国家',
17: '其他部门省部',
18: '其他部门市厅'
}
if (level === null || level === undefined || level === '') {
return '--'
}
const levelNum = typeof level === 'string' ? parseInt(level) : level
return levelMap[levelNum] || '--'
},
// 格式化日期
formatDate(date) {
if (!date) return '--'
// 如果是Unix时间戳转换为毫秒
if (typeof date === 'number') {
const timestamp = date.toString().length === 10 ? date * 1000 : date
const dateObj = new Date(timestamp)
if (isNaN(dateObj.getTime())) return '--'
const year = dateObj.getFullYear()
const month = String(dateObj.getMonth() + 1).padStart(2, '0')
const day = String(dateObj.getDate()).padStart(2, '0')
return `${year}-${month}-${day}`
}
// 如果是字符串日期
if (typeof date === 'string' && date.includes('T')) {
return date.split('T')[0]
}
return date
},
// 计算序号
getIndex(index) {
return (this.currentPage - 1) * this.pageSize + index + 1
},
//添加
btnAdd(){
this.dialogVisible=true
},
// 主页/详情
handleClick(row) {
this.$emit('getDetail', row)
},
// 显示删除对话框
showDeleteDialog(row) {
this.deleteRow = row
this.deleteDialogVisible = true
},
// 取消删除
cancelDelete() {
this.deleteDialogVisible = false
this.deleteRow = null
},
// 确认删除
async confirmDelete() {
if (!this.deleteRow || !this.deleteRow.id) {
this.$message.error('删除失败:缺少必要参数')
this.deleteDialogVisible = false
return
}
try {
const res = await deletes(this.deleteRow.id)
if (res && res.code === 1) {
this.deleteDialogVisible = false
this.$message.success('删除成功')
this.deleteRow = null
this.getList()
} else {
this.$message.error(res?.msg || '删除失败')
}
} catch (error) {
console.error('删除失败:', error)
this.$message.error('删除失败')
}
}
}
}
</script>
<style>
.el-tooltip__popper.is-dark {
color: #F04B4B !important;
background: #FCF1EB !important;
}
.el-tooltip__popper .popper__arrow {
border-top-color: #FCF1EB !important;
/* 上方箭头 */
}
.el-tooltip__popper .popper__arrow::after {
border-top-color: #FCF1EB !important;
}
/* 其他方向的箭头(按需添加) */
.el-tooltip__popper[x-placement^='bottom'] .popper__arrow {
border-bottom-color: #FCF1EB !important;
}
.el-tooltip__popper[x-placement^='left'] .popper__arrow {
border-left-color: #FCF1EB !important;
}
.el-tooltip__popper[x-placement^='right'] .popper__arrow {
border-right-color: #FCF1EB !important;
}
</style>
<style scoped>
.selects2{
width: 90%;
}
.adds{
width: 30px;
height: 20px;
background: #DCE0FD;
color: #5065F6;
position: relative;
left: 54px;
font-size: 14px;
text-align: center;
line-height: 18px;
cursor: pointer;
}
.lies:hover .closes {
opacity: 1;; /* 鼠标滑过 .lies 时才显示 */
}
.closes{
background: #FCF1EB;
width: 20px;
height: 30px;
position: relative;
top: 5px;
cursor: pointer;
text-align: center;
line-height: 30px;
color: #F04B4B;
font-size: 20px;
opacity: 0;
}
.first-border{
/* border-top: 1px solid #DCE0FD */
}
.liee{
background-color: #DCE0FD;
color: #17192C;
text-align:center
}
.content-areas{
display: flex;
height: 50px;
flex-wrap: wrap;
}
.contents-left{
width: 30%;
border: 1px solid #DCE0FD;
background: #EDEFFE;;
line-height: 50px;
font-size: 14px;
color: #363636;
}
.contents-right{
flex: 1;
border: 1px solid #DCE0FD;
line-height: 50px;
font-size: 14px;
color: #363636;
display: flex
}
.content-areas2{
position: relative;
top: 1px;
}
.table-name{
margin-left: 20px;
}
.rightss2{
background: #EDEFFE;
}
.rightss1{
border-left: none !important;
border-right: none !important;
}
.rightss{
height: 100%;
border: 1px solid #DCE0FD;
width: 100%;
border-top: none;
}
.lie{
border: 1px solid #3333;
width: 100px;
height: 40px;
line-height: 40px;
border-right: none;
border: none;
border-bottom: 1px solid #EDEFFE
}
.lies{
display: flex;
/* border-bottom: 1px solid #EDEFFE */
}
.zhuyi{
color: #5165f7;
font-size: 14px;
text-align: center;
position: relative;
top: -12px;
}
:deep(.el-input__wrapper) {
box-shadow: none !important;
padding-left: 7 !important;
background: none !important;
}
/* 去掉内部输入框的padding */
:deep(.el-input__inner) {
padding-left: 7 !important;
border: none !important;
background: none !important;
}
.th1{
width: 120px; /* 设置固定宽度(可以根据需要调整) */
font-size: 13px; /* 字体大小比默认小 */
text-align: right; /* 右对齐 */
padding-right: 8px;
border-right: 1px solid #DCE0FD;
background: #EDEFFE !important;
border-bottom: 1px solid #DCE0FD !important;
}
.container {
width: 72%;
margin: 0 auto;
}
h1 {
color: #333;
text-align: center;
margin-bottom: 25px;
font-weight: 600;
font-size: 24px;
}
.department-table {
width: 100%;
border-collapse: collapse;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
}
.department-table {
width: 100%;
border-collapse: collapse;
overflow: hidden;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
}
.department-table tr{
border: 1px solid #DCE0FD;
cursor: pointer;
}
.department-table th {
/* 淡紫色表头 */
color: #5a4a6a;
font-weight: 600;
text-align: left;
padding: 16px 20px;
}
.department-table td {
background-color: white;
padding: 5px 20px;
border-bottom: 1px solid #f0f0f0;
color: #333;
}
.department-table tr:last-child td {
border-bottom: none;
}
.department-table tr:hover td {
background-color: #f9f9f9;
transition: background-color 0.2s;
}
.empty-value {
color: #999;
font-style: italic;
}
.footer {
text-align: center;
margin-top: 25px;
color: #888;
font-size: 14px;
}
.contents {
width: 90%;
margin: 0 auto;
}
:deep .el-dialog__body {
padding: 0 !important;
}
.dialog-footer {
text-align: center;
margin: 0 auto;
margin-top: 12px;
}
.dialog-header {
width: 100%;
height: 54px;
background: #F7F7FA;
text-align: center;
line-height: 54px;
position: relative;
top: -28px;
color: #363636;
font-weight: bold;
font-size: 18px
}
:deep .el-tooltip__popper.is-dark {
color: #F04B4B !important;
}
.footer {
display: flex;
justify-content: end;
margin-top: 20px;
}
.tianjia {
position: relative;
top: -9px;
background-color: #5065F6;
}
.tianjia2 {
position: relative;
top: -9px;
background-color: #EDEFFE;
color: #5065F6;
}
::v-deep .el-table thead {
background-color: #DCE0FD !important;
color: #363636 !important;
}
::v-deep .el-table__header th {
background-color: #DCE0FD !important;
color: #363636 !important;
}
.input-with-select{
border: 1px solid #3333;
}
.content-table {
display: flex;
flex-direction: column;
}
.formitem {
position: relative;
top: -5px;
}
::deep .el-form-item__label {
font-size: 15px !important;
}
.selects {
width: 100px;
border: 1px solid #3333;
}
.headers-name {
font-size: 15px;
position: relative;
top: 14px;
}
.tubiao {
position: relative;
top: 22px;
z-index: 99;
left: -20px;
cursor: pointer;
}
.headers {
display: flex;
justify-content: space-between
}
.delete-dialog-content {
display: flex;
flex-direction: column;
align-items: center;
padding: 20px;
}
.delete-icon {
margin-bottom: 16px;
}
.delete-title {
font-size: 18px;
font-weight: bold;
color: #333;
margin-bottom: 12px;
}
.delete-message {
font-size: 14px;
color: #666;
margin-bottom: 24px;
text-align: center;
}
.delete-buttons {
display: flex;
gap: 16px;
}
</style>

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