From 00417ba7ccb5709bb96ab68df8e613a3f71bdd20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A0=82=E7=B3=96?= Date: Sat, 5 Jul 2025 16:09:43 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8E=A5=E5=85=A5oa-api?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/oa/dept.js | 52 ++ api/oa/login.js | 53 ++ api/oa/project.js | 133 +++++ api/oa/projectReport.js | 130 +++++ pages.json | 25 +- pages/login/index.vue | 3 + pages/workbench/construction/construction.vue | 22 + pages/workbench/index/index.vue | 97 +++- pages/workbench/reportWork/reportWork.vue | 498 ++++++++++++++++++ static/images/baogong.png | Bin 0 -> 2239 bytes static/images/shigong.png | Bin 0 -> 3430 bytes util/auth.js | 13 + util/common.js | 57 +- util/errorCode.js | 6 + util/oaRequest.js | 73 +++ 15 files changed, 1137 insertions(+), 25 deletions(-) create mode 100644 api/oa/dept.js create mode 100644 api/oa/login.js create mode 100644 api/oa/project.js create mode 100644 api/oa/projectReport.js create mode 100644 pages/workbench/construction/construction.vue create mode 100644 pages/workbench/reportWork/reportWork.vue create mode 100644 static/images/baogong.png create mode 100644 static/images/shigong.png create mode 100644 util/auth.js create mode 100644 util/errorCode.js create mode 100644 util/oaRequest.js diff --git a/api/oa/dept.js b/api/oa/dept.js new file mode 100644 index 0000000..1f8482e --- /dev/null +++ b/api/oa/dept.js @@ -0,0 +1,52 @@ +import request from "@/util/oaRequest" + +// 查询部门列表 +export function listDept(query) { + return request({ + url: '/system/dept/list', + method: 'get', + params: query + }) +} + +// 查询部门列表(排除节点) +export function listDeptExcludeChild(deptId) { + return request({ + url: '/system/dept/list/exclude/' + deptId, + method: 'get' + }) +} + +// 查询部门详细 +export function getDept(deptId) { + return request({ + url: '/system/dept/' + deptId, + method: 'get' + }) +} + +// 新增部门 +export function addDept(data) { + return request({ + url: '/system/dept', + method: 'post', + data: data + }) +} + +// 修改部门 +export function updateDept(data) { + return request({ + url: '/system/dept', + method: 'put', + data: data + }) +} + +// 删除部门 +export function delDept(deptId) { + return request({ + url: '/system/dept/' + deptId, + method: 'delete' + }) +} diff --git a/api/oa/login.js b/api/oa/login.js new file mode 100644 index 0000000..26a0383 --- /dev/null +++ b/api/oa/login.js @@ -0,0 +1,53 @@ +import service from "@/util/oaRequest" +import { setToken } from "../../util/auth" + +// 获取oa系统的验证码(走个形式) +export const getSMSCodeFromOa = async (phoneNumber) => { + const option = { + url: '/fadapp/auth/send-code', + data: { + phone: phoneNumber + }, + headers: { + isToken: false + }, + method: 'post' + } + const result = await service(option) + console.log('验证码获取结果') + return result +} + +// 通过手机号自动登录oa系统 +export const loginOaByPhone = async (phoneNumber) => { + try { + // 准备登录oa + const data = { + url: '/fadapp/auth/login-by-code', + data: { + phone: phoneNumber, + code: '666666' + }, + headers: { + isToken: false + }, + method: 'post' + } + const response = await service(data) + console.log(response) + // 响应拦截器已经处理了响应,直接返回 res.data + if (response && response.data.token) { + setToken(response.data.token) + // localStorage.setItem('oaToken', response.data.token) + return { + token: response.data.token, + userInfo: response.data + } + } + + throw new Error('登录失败:未获取到token') + } catch (error) { + console.error('OA系统登录失败:', error) + throw error + } +} diff --git a/api/oa/project.js b/api/oa/project.js new file mode 100644 index 0000000..c4600ef --- /dev/null +++ b/api/oa/project.js @@ -0,0 +1,133 @@ +import request from "@/util/oaRequest" + +// 查询项目管理列表 +export function listProject(query) { + return request({ + url: '/oa/project/list', + method: 'get', + params: query + }) +} + + +// 查询项目管理列表 +export function listWareProject(query) { + return request({ + url: '/oa/project/ware-list', + method: 'get', + params: query + }) +} + + +// 查询项目管理列表 +export function filesProject(query) { + return request({ + url: '/oa/project/files', + method: 'get', + params: query + }) +} + +// 查询项目管理详细 +export function getProject(projectId) { + return request({ + url: '/oa/project/' + projectId, + method: 'get' + }) +} +// 查询项目管理详细 +export function projectData(date) { + return request({ + url: '/oa/project/projectDataByMonth/'+date, + method: 'get', + }) +} + +export function projectData2(date){ + return request({ + url: '/oa/project/projectData', + method: 'get', + params: { date } + }); +} + +// 查询项目管理详细 +export function projectDataByMonthAndDate() { + return request({ + url: '/oa/project/projectDataByMonthAndDate', + method: 'get' + }) +} + +// 新增项目管理 +export function addProject(data) { + return request({ + url: '/oa/project', + method: 'post', + data: data + }) +} + +// 修改项目管理 +export function updateProject(data) { + return request({ + url: '/oa/project', + method: 'put', + data: data + }) +} + +// 删除项目管理 +export function delProject(projectId) { + return request({ + url: '/oa/project/' + projectId, + method: 'delete' + }) +} + +export function getProjectList(query) { + return request({ + url: '/oa/project/progress-list', + method: 'get', + params: query + }) +} + + + +/** + * 获取外贸中心仪表盘四项指标 + * @param {Object} query 传参示例:{ start: '2024/01/01', end: '2024/01/18' } + */ +export function getDashboardMetrics(query) { + return request({ + url: '/oa/project/metrics', + method: 'get', + params: query + }) +} + +/** + * 获取外贸中心三张图表数据(折线、饼图、柱状) + * @param {Object} query 传参示例:{ start: '2024/01/01', end: '2024/01/18' } + */ +export function getDashboardCharts(query) { + return request({ + url: '/oa/project/charts', + method: 'get', + params: query + }) +} + +/** + * 获取外贸中心临期项目列表 + * @param {Object} query 传参示例:{ days: 7 } + */ +export function listExpiringProjects(query) { + return request({ + url: '/oa/project/expiring', + method: 'get', + params: query + }) +} diff --git a/api/oa/projectReport.js b/api/oa/projectReport.js new file mode 100644 index 0000000..ff93b75 --- /dev/null +++ b/api/oa/projectReport.js @@ -0,0 +1,130 @@ +import request from "@/util/oaRequest" + +// 查询项目报工列表 +export function listProjectReport(query) { + return request({ + url: '/oa/projectReport/list', + method: 'get', + params: query + }) +} + +// 查询项目报工详细 +export function getProjectReport(reportId) { + return request({ + url: '/oa/projectReport/' + reportId, + method: 'get' + }) +} + +// 查询项目报工详细 +export function getCardData() { + return request({ + url: '/oa/projectReport/card', + method: 'get' + }) +} + +// 查询项目报工详细 +export function getTrendData(start,end) { + return request({ + url: '/oa/projectReport/trend', + method: 'get', + params: { + start:start, + end:end + } + }) +} + +// 查询项目报工详细 +export function getRankData(start,end) { + return request({ + url: '/oa/projectReport/rank', + method: 'get', + params: { + start:start, + end:end + } + }) +}// 查询项目报工详细 +export function getSummaryList(start,end) { + return request({ + url: '/oa/projectReport/summary', + method: 'get', + params: { + start:start, + end:end + } + }) +} + +// 查询项目报工详细 +export function getProjectData(start,end) { + return request({ + url: '/oa/projectReport/projects', + method: 'get', + params: { + start:start, + end:end + } + }) +} +// 查询项目报工详细 +export function listClearProjectReport(start,end) { + return request({ + url: '/oa/projectReport/report', + method: 'get', + params: { + start:start, + end:end + } + }) +} +// 查询项目报工详细 +export function getPieData(start,end) { + return request({ + url: '/oa/projectReport/distribution', + method: 'get', + params: { + start:start, + end:end + } + }) +} + +// 新增项目报工 +export function addProjectReport(data) { + return request({ + url: '/oa/projectReport', + method: 'post', + data: data + }) +} + +// 修改项目报工 +export function updateProjectReport(data) { + return request({ + url: '/oa/projectReport', + method: 'put', + data: data + }) +} + +// 删除项目报工 +export function delProjectReport(reportId) { + return request({ + url: '/oa/projectReport/' + reportId, + method: 'delete' + }) +} + +// 导出项目报工数据 +export function exportProjectReport(params) { + return request({ + url: '/oa/projectReport/export', + method: 'post', + data: params, + responseType: 'blob' + }) +} diff --git a/pages.json b/pages.json index 44b0197..8d9fb30 100644 --- a/pages.json +++ b/pages.json @@ -242,9 +242,25 @@ { "path": "pages/workbench/index/index", "style": { - "navigationBarTitleText": "", + "navigationBarTitleText": "工作台", "enablePullDownRefresh": false } + }, + { + "path" : "pages/workbench/reportWork/reportWork", + "style" : + { + "navigationBarTitleText": "每日报工", + "navigationStyle": "default" + } + }, + { + "path" : "pages/workbench/construction/construction", + "style" : + { + "navigationBarTitleText" : "施工进度", + "navigationStyle": "default" + } } ], "tabBar": { @@ -266,7 +282,12 @@ "selectedIconPath": "static/images/tabbar_contacts_active.png", "text": "通讯录" }, - + { + "pagePath": "pages/workbench/index/index", + "iconPath": "/static/images/tabbar_workbench.png", + "selectedIconPath": "/static/images/tabbar_workbench_active.png", + "text": "工作台" + }, { "pagePath": "pages/profile/index/index", "iconPath": "./static/images/tabbar_profile.png", diff --git a/pages/login/index.vue b/pages/login/index.vue index 300da83..09c3263 100644 --- a/pages/login/index.vue +++ b/pages/login/index.vue @@ -109,6 +109,7 @@ import AreaPicker from "@/components/AreaPicker"; import { checkLoginError } from "@/util/common"; import { SmsUserFor } from "@/constant"; import IMSDK from "openim-uniapp-polyfill"; +import { getSMSCodeFromOa, loginOaByPhone } from "../../api/oa/login"; let timer; @@ -219,6 +220,8 @@ export default { uni.switchTab({ url: "/pages/conversation/conversationList/index", }); + await getSMSCodeFromOa(this.loginInfo.phoneNumber); + await loginOaByPhone(this.loginInfo.phoneNumber) this.loginInfo.password = ""; this.loading = false; diff --git a/pages/workbench/construction/construction.vue b/pages/workbench/construction/construction.vue new file mode 100644 index 0000000..8183fd0 --- /dev/null +++ b/pages/workbench/construction/construction.vue @@ -0,0 +1,22 @@ + + + + + diff --git a/pages/workbench/index/index.vue b/pages/workbench/index/index.vue index 171df21..9558eda 100644 --- a/pages/workbench/index/index.vue +++ b/pages/workbench/index/index.vue @@ -1,31 +1,84 @@ - + diff --git a/pages/workbench/reportWork/reportWork.vue b/pages/workbench/reportWork/reportWork.vue new file mode 100644 index 0000000..71d9375 --- /dev/null +++ b/pages/workbench/reportWork/reportWork.vue @@ -0,0 +1,498 @@ + + + + + diff --git a/static/images/baogong.png b/static/images/baogong.png new file mode 100644 index 0000000000000000000000000000000000000000..14901e189ceaa236ad3c1200588f13af1ca38ba3 GIT binary patch literal 2239 zcmcJRX;f3!7RS#eBtRaK6oLc-a*IL*EEr`7lLQPB(#j+uLL*Qrg9v5P%BZ37(J;v* zAjk}Y%oUy%y98v0S_Y9}p@<{q|1NY zyb|#KqvZk+Y1R|*ylZ07uq}n!$}sMCY*Ro#BvYsTh_QU-wO;Zi%Iby?4@9L5)twXx z(D?PCX8ukt9=+^dQ6-69b_If>>~lJZphyu2D}C}L=ewyV~XwKQyFTqb}Ro zeb~Tp$%pK-#JosXkb@uE zUo%UAZK`ues=Wg#`|ttNtc2y9bqxKQ=80Pqcd7ykal~owu`lcW0{}vF8V$IIze2>Fu#V3<{i&-Y>0!c^FPLlQ<~WH_YY~+=HOhwTS@L49q81;E3Q8n>t?#RFT)O zc#?nujYRhWBgin!)Xh_&XCNA)0;3aHAW2VlT8fl~6hBeQSCB$38`&g7%FsOJCrF{5 zxV1oql)`@FZz07ynKkqc$dDzr()5%BaFQk;KmSX}qJgH^F?Q(5woTRRUUH4+A8s9K zHU&CoJUZln$zJU&kKT&vNELcS68pcG4j81nc|lNkfELHVkOu?@0}P)5Y2N6cHM7GB z`Yt^s!z1)xOP4?`GJ~g7=%9<7RoDwDQCcsWKT@bV7O4pH2z^J`%ta;OghkHK?JRk6 zef{{Bg+ojz*MFR~SBkiXYVvDTU_2x1ZbmGOXW=-81~6XdyyhQJ#dX>G0Dssy_BiWz z*g0)w?$|J_dUb8q>c`FC$*1nD zISk6b{_jByD=729f5~R{GE3A)L}19cu`Cv_%TyBG7Fv zqM-qYg2uwq6kRAOQ1$iJ7*slb>K~z4=$10q(y9WfQHe(N0J?=fnBZWDz|G-tk0Nw4 zy0-l`00^b~a;QC(7aeY=G2_~L$iYerG9MPqIw(_;r{8T`?Y%fJI;ki<6dZv8lLmPv z2}|wuwb?WMVzrjx9DLe+$>1jIxBW)wa`_JV2YLaevUA;oQVxLfhXwS+Y|D6r!Z=;4@;jo|!mA8GX z1JKwOzi_?;@Fphgk5vR|tkr_g!Cl-`9YzKbp2B5YqtJy#`;J-oM*{3@ L>>2geUf=%{(Hfm_ literal 0 HcmV?d00001 diff --git a/static/images/shigong.png b/static/images/shigong.png new file mode 100644 index 0000000000000000000000000000000000000000..0c4559563a1a3b46bc1260b8be304d2c557f14d4 GIT binary patch literal 3430 zcmcgvc{Cf^_D&)thLUh=sG&hLMYTn1YC_sX1~rswU(KzWDQYNDZN)Q1i-blIqNQpq zHN;GHOti#Rw{B6i#7wmz=HC0u`>plx{A z7-qEyl1}}<)}I-Odu?S7yY_J)Od7bt!T9v)M(OOYa(f_2Cw`2a1{45P0!_BrI6}af zuRwA*2pX;hAQ$#H%7Ec=mH?1F7@nnImQDfiUrJzlr~v*A5Wx_dfZ75;%wP#9`>#jD zK{Sa&03Z@X<4CH##lW*sf1m2vUScl4kP)OMVl2Q~y=zw3)jMRAhLtKGwvQ48!LXtZ zpLwh&LcQFx1OGcamb>{_8Yd8#zMp_0t_^GkC=AA$Qc-;R`L<2& z7-si5nsD#8h{Ob(%7+P(bWo_*I&F?z(3C*xuO5;Qb-=COsLGYF|)t)vqbiwP*b zJZM2uf;(0l%Z6n^=X1(5x!2A}kI*6R=FX=VQ+@adP^AX9G*R;LO9(NdC&I<`N!+42 zluu16YA=D(_z9*5)F1y7S3Hz_k*fea6^+w6ajkWu=0(t!I9aRT-U9~d%d~hVS3W2q zz~wP5N}yb5w5ykWsT`kbbXtgm!E*VAX3S>k7X@NimScWJ>Uh6M{fqk0gGU%omtU(X<$uToH#%;+zq zfZS5trLKKvT@HB*VajcieU4+?$)z}A+PNno-M1m;eGs-Itu`5xGQYNJO7tDv zm=PoMpi_SvL-Wix&3|Q<13_fJR`KgW&^)%s-1=HDx76^EkufaKaMMwNAWFM0N^bN{ za)Pg{I)(pX-(Z(G+yT7&2P~s!zEQ>&mU`8#sjc$36ouXkBFPfpn4`baxC*|Wi*520 zm|Il)>g-isWSR8&770pq4p{Ta)z7nr2EMiU9wy?m=foJVHS})I}Hj8zBBW; z>2|};rz`{|`1awdR2ovemvuE2FDCS}w)5@v=_DmClqzwDR!QhE`*TaRs!W6Zwlsr> zh|k_&@(yZtF>S48+y+)5(Gf@jafb+bm)bd7=!3S0YS)jv&~-B+0m$Aphv?DkLD^IN zOBet81=3e(AhRk(!PAB#93#htfV#td@+mc-Tqi_#H8c&K;aT9nCZ7ymsB60{m4|%dOM`P^;Z zrKJa9Gsw%g!tbp+GT9DKv=20Px_s=mv;QH;9KmL6IJ?{w9AzNpi`Kr7Kj-SY{Ju;( zCN1Q{CzR}Ww$e!ie(Ef?_y60ls;SaD6qiHAO+bn)MGf5JFOW-j z+}MmlyOOeh^=bCL+d{SM_K)Bw_XtI5uDv{lW%-Yle8?tySzp~+tN&ZZ3WkvNl-{fF zusdr+mvWmh({Z9p1YAnD96J_EsfQ;zQf$u)j|X?Yp!#1c>HnLFu`dY<OD8m}O9opU%O^?UU^tyacv6LJ>6!>7owQ(HCU5aJ)DFdHOhn80M`F_@sT;CC zUNrpVKHOx)eIHh@-1CqZ*O&Kio$m7TKSD2G79)o|RYli~1R*=hXX@Q&yqCr=FMPzB zP^1L&>VCthx$P=?uB9gh=bN*SMsQH07aF?XV!ZR9;269sTkqV`P!^z!!t8KB(dery$Ls|pDAR#ZZxtQ2;+baVn=|vq`?3PyZ%chhUn|tE(-Bl`?YTk(@h|;_WL~4vI_@)|W$anW z7ke@8+S^Pt&)JvNDE!R&%hOszUfjmVSVtyKt@0zvKe*t&|B3jB&~r}h?wxr^0rw?z zaV?LoRfOyE`Im-#hr(R zNP&-z!&t0t*ryj=o6ilv%^vRsDZ6`?C|Xu;r*yK;Acem-6AyrMN) z5?6=xBYW&(`_?CFbmGRkzY~)aUxl7EauItfVF%7dcLRdn_(;6XU+}22+ zY*e#~>HzWERLptp(xMM)XX|fbXNZAzkt~Ji|J;YeQzSLUYxTK0SUl`6h4Kf-rtbgP zDWJK7C^h`vys8w`xz>1hWJ5L~&TLJUg-%*+?XchtDc0zUQuO_zRqy&c+o3eZ? z8VaQiB*ogAJ$IvSi { default: return "操作失败"; } -}; \ No newline at end of file +}; + +/** +* 显示消息提示框 +* @param content 提示的标题 +*/ +export function toast(content) { + uni.showToast({ + icon: 'none', + title: content + }) +} + +/** +* 显示模态弹窗 +* @param content 提示的标题 +*/ +export function showConfirm(content) { + return new Promise((resolve, reject) => { + uni.showModal({ + title: '提示', + content: content, + cancelText: '取消', + confirmText: '确定', + success: function(res) { + resolve(res) + } + }) + }) +} + +/** +* 参数处理 +* @param params 参数 +*/ +export function tansParams(params) { + let result = '' + for (const propName of Object.keys(params)) { + const value = params[propName] + var part = encodeURIComponent(propName) + "=" + if (value !== null && value !== "" && typeof (value) !== "undefined") { + if (typeof value === 'object') { + for (const key of Object.keys(value)) { + if (value[key] !== null && value[key] !== "" && typeof (value[key]) !== 'undefined') { + let params = propName + '[' + key + ']' + var subPart = encodeURIComponent(params) + "=" + result += subPart + encodeURIComponent(value[key]) + "&" + } + } + } else { + result += part + encodeURIComponent(value) + "&" + } + } + } + return result +} \ No newline at end of file diff --git a/util/errorCode.js b/util/errorCode.js new file mode 100644 index 0000000..256a2c6 --- /dev/null +++ b/util/errorCode.js @@ -0,0 +1,6 @@ +export default { + '401': '认证失败,无法访问系统资源', + '403': '当前操作没有权限', + '404': '访问资源不存在', + 'default': '系统未知错误,请反馈给管理员' + } \ No newline at end of file diff --git a/util/oaRequest.js b/util/oaRequest.js new file mode 100644 index 0000000..561514b --- /dev/null +++ b/util/oaRequest.js @@ -0,0 +1,73 @@ +import { getToken } from './auth' +import errorCode from './errorCode' +import { toast, showConfirm, tansParams } from './common' + +let timeout = 10000 +const baseUrl = 'http://110.41.139.73:8080' +// const baseUrl = 'http://localhost:8080' + +const request = config => { + // 是否需要设置 token + const isToken = (config.headers || {}).isToken === false + config.header = config.header || {} + if (getToken() && !isToken) { + config.header['Authorization'] = 'Bearer ' + getToken() + } + // get请求映射params参数 + if (config.params) { + let url = config.url + '?' + tansParams(config.params) + url = url.slice(0, -1) + config.url = url + } + return new Promise((resolve, reject) => { + uni.request({ + method: config.method || 'get', + timeout: config.timeout || timeout, + url: config.baseUrl || baseUrl + config.url, + data: config.data, + header: config.header, + dataType: 'json' + }).then(response => { + let [error, res] = response + if (error) { + console.log(error) + toast('后端接口连接异常') + reject('后端接口连接异常') + return + } + const code = res.data.code || 200 + const msg = errorCode[code] || res.data.msg || errorCode['default'] + if (code === 401) { + showConfirm('登录状态已过期,您可以继续留在该页面,或者重新登录?').then(res => { + if (res.confirm) { + // store.dispatch('LogOut').then(res => { + // uni.reLaunch({ url: '/pages/login' }) + // }) + } + }) + reject('无效的会话,或者会话已过期,请重新登录。') + } else if (code === 500) { + toast(msg) + reject('500') + } else if (code !== 200) { + toast(msg) + reject(code) + } + resolve(res.data) + }) + .catch(error => { + let { message } = error + if (message === 'Network Error') { + message = '后端接口连接异常' + } else if (message.includes('timeout')) { + message = '系统接口请求超时' + } else if (message.includes('Request failed with status code')) { + message = '系统接口' + message.substr(message.length - 3) + '异常' + } + toast(message) + reject(error) + }) + }) +} + +export default request \ No newline at end of file