From 33d19ed2005ed8c9314c4feefc9466614d76c3fc Mon Sep 17 00:00:00 2001 From: wenlele Date: Fri, 12 Aug 2022 11:32:05 +0800 Subject: [PATCH] =?UTF-8?q?=E5=BA=94=E7=94=A8=E7=AE=A1=E7=90=86=E9=A1=B5?= =?UTF-8?q?=E9=9D=A2=E6=95=B0=E6=8D=AE=E6=8E=A5=E5=85=A5=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/lib/controllers/application/index.js | 55 +- .../application/actions/application.js | 76 +- .../application/components/applyModal.jsx | 140 ++-- .../containers/applicationCenter.jsx | 679 +++++++++--------- .../components/nvrModal.jsx | 1 - .../web/client/src/utils/webapi.js | 33 +- 6 files changed, 533 insertions(+), 451 deletions(-) diff --git a/code/VideoAccess-VCMP/api/app/lib/controllers/application/index.js b/code/VideoAccess-VCMP/api/app/lib/controllers/application/index.js index 611ef3a..3594158 100644 --- a/code/VideoAccess-VCMP/api/app/lib/controllers/application/index.js +++ b/code/VideoAccess-VCMP/api/app/lib/controllers/application/index.js @@ -29,14 +29,24 @@ async function check (ctx) { } async function edit (ctx, next) { - let errMsg = '创建应用失败' const transaction = await ctx.fs.dc.orm.transaction(); try { const { models } = ctx.fs.dc; const { userId } = ctx.fs.api const data = ctx.request.body; - if (data.id) { + let findOption = { where: { name: data.name } } + + if (data.appId) { + findOption.where.id = { $ne: data.appId } + } + + const applicationRes = await models.Application.findOne(findOption) + if (applicationRes) { + throw '已有相同应用名称' + } + + if (data.appId) { // 修改 const storageData = Object.assign({}, data,) await models.Application.update(storageData, { @@ -66,7 +76,7 @@ async function edit (ctx, next) { ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); ctx.status = 400; ctx.body = { - message: errMsg + message: typeof error == 'string' ? error : undefined } } } @@ -74,11 +84,11 @@ async function edit (ctx, next) { async function get (ctx) { try { const models = ctx.fs.dc.models; - const { userId } = ctx.fs.api + const { userId, token } = ctx.fs.api const { limit, page, orderBy, orderDirection } = ctx.query let findOption = { where: { - createUserId: userId, + // createUserId: userId, }, order: [ [orderBy || 'id', orderDirection || 'DESC'] //查询排序 @@ -91,12 +101,30 @@ async function get (ctx) { if (page && limit) { findOption.offset = page * limit } - const nvrRes = await models.Application.findAndCountAll(findOption) + const applicationRes = await models.Application.findAndCountAll(findOption) + + + let createUserIds = new Set() + let cameraIds = [] + for (let c of applicationRes.rows) { + cameraIds.push(c.id) + createUserIds.add(c.createUserId) + } + + // 查用户信息 + const createUserRes = await ctx.app.fs.authRequest.get(`user/${[...createUserIds].join(',') || -1}/message`, { query: { token } }) + + for (let { dataValues: n } of applicationRes.rows) { + const corCreateUser = createUserRes.find(u => u.id == n.createUserId) + n.createUser = { + name: corCreateUser ? corCreateUser.username : '' + } + } ctx.status = 200; ctx.body = { - total: nvrRes.count, - data: nvrRes.rows + total: applicationRes.count, + data: applicationRes.rows } } catch (error) { ctx.fs.logger.error(`path: ${ctx.path}, error: ${error}`); @@ -133,8 +161,15 @@ async function del (ctx, next) { const transaction = await ctx.fs.dc.orm.transaction(); try { const models = ctx.fs.dc.models; + const { token } = ctx.fs.api const { appId } = ctx.params + const { appKey } = await models.Application.findOne({ + where: { + id: appId + }, + }) || {} + await models.Application.destroy({ where: { id: appId @@ -142,6 +177,10 @@ async function del (ctx, next) { transaction }) + await ctx.app.fs.authRequest.delete(`oauth2/token/invalidate_all`, { + query: { token, appKey } + }) + await transaction.commit(); ctx.status = 204; } catch (error) { diff --git a/code/VideoAccess-VCMP/web/client/src/sections/application/actions/application.js b/code/VideoAccess-VCMP/web/client/src/sections/application/actions/application.js index e884e54..6472ddf 100644 --- a/code/VideoAccess-VCMP/web/client/src/sections/application/actions/application.js +++ b/code/VideoAccess-VCMP/web/client/src/sections/application/actions/application.js @@ -3,40 +3,52 @@ import { basicAction } from "@peace/utils"; import { ApiTable } from "$utils"; -export function getCamera(query) { - return (dispatch) => - basicAction({ - type: "get", - dispatch: dispatch, - actionType: "GET_APPLICATION", - query: query, - url: `${ApiTable.getCamera}`, - msg: { option: "获取摄像头列表信息" }, - reducer: { name: "applicationData", params: { noClear: true } }, - }); +export function getApplication (query) { + return (dispatch) => + basicAction({ + type: "get", + dispatch: dispatch, + actionType: "GET_APPLICATION", + query: query, + url: `${ApiTable.getApplication}`, + msg: { option: "获取应用信息" }, + reducer: { name: "applicationData", params: { noClear: true } }, + }); } -export function putForbidden(data, forbidden) { - return (dispatch) => - basicAction({ - type: "put", - dispatch: dispatch, - actionType: "PUT_APPLICATION", - data, - url: `${ApiTable.putForbidden}`, - msg: { option: forbidden ? "启用" : "禁用" }, //禁用摄像头 - reducer: {}, - }); +export function putApplication (data) { + return (dispatch) => + basicAction({ + type: "put", + dispatch: dispatch, + actionType: "PUT_APPLICATION", + data, + url: `${ApiTable.putApplication}`, + msg: { option: data?.forbidden ? "启用" : "禁用" }, //禁用摄像头 + reducer: {}, + }); } -export function delCamera(orgId) { - return (dispatch) => - basicAction({ - type: "del", - dispatch: dispatch, - actionType: "DEL_APPLICATION", - url: `${ApiTable.delCamera.replace("{cameraId}", orgId)}`, - msg: { option: "设备会被存放在“设备回收站”中,删除" }, //删除摄像头 - reducer: {}, - }); +export function delApplication (orgId) { + return (dispatch) => + basicAction({ + type: "del", + dispatch: dispatch, + actionType: "DEL_APPLICATION", + url: `${ApiTable.delApplication.replace("{appId}", orgId)}`, + msg: { option: "删除" }, //删除应用 + reducer: {}, + }); +} + +export function postApplication (data) { + return (dispatch) => + basicAction({ + type: "post", + dispatch: dispatch, + data, + actionType: "POST_CHANGE_NVR", + msg: { option: data?.appId ? "修改" : "添加" }, + url: `${ApiTable.postApplication}`, + }); } \ No newline at end of file diff --git a/code/VideoAccess-VCMP/web/client/src/sections/application/components/applyModal.jsx b/code/VideoAccess-VCMP/web/client/src/sections/application/components/applyModal.jsx index a363bb5..d73cd5c 100644 --- a/code/VideoAccess-VCMP/web/client/src/sections/application/components/applyModal.jsx +++ b/code/VideoAccess-VCMP/web/client/src/sections/application/components/applyModal.jsx @@ -2,79 +2,85 @@ import React, { useState, useEffect, useRef } from "react"; import { connect } from "react-redux"; import { Button, Form, Modal, } from "@douyinfe/semi-ui"; -const ApplyModal = ({ close, modalName, visible }) => { - const form = useRef(); +const ApplyModal = ({ dispatch, actions, close, modalName, visible, appData }) => { + const { applicationCenter } = actions; + const appDatas = appData || {} + const form = useRef(); - - const handleOk = () => { - form.current - .validate() - .then((values) => { - console.log(values); - // close() + const handleOk = () => { + form.current + .validate() + .then((values) => { + if (appDatas?.id) { + values.appId = appDatas?.id + } + dispatch(applicationCenter.postApplication(values)).then((res) => { + console.log(res); + if (res.success) { + close() + form.current.reset() + } }) + }) + } - } - - return close()} - onOk={handleOk} - > -
console.log(values)} - getFormApi={(formApi) => (form.current = formApi)} - > - - - {[{ name: 'web', id: 'web' }, { name: 'app', id: 'app' }, { name: '小程序', id: '小程序' }, { name: '其他', id: '其他' }].map((item, index) => ( - - {item.name} - - ))} - - -
+ return { close(); form.current.reset() }} + onOk={handleOk} + > +
(form.current = formApi)} + > + + + {[{ name: 'web', value: 'web' }, { name: 'app', value: 'app' }, { name: '小程序', value: 'wxapp' }, { name: '其他', value: 'other' }].map((item, index) => ( + + {item.name} + + ))} + + +
} function mapStateToProps (state) { - const { auth, global, members } = state; - return { - loading: members.isRequesting, - user: auth.user, - actions: global.actions, - global: global, - members: members.data, - }; + const { auth, global, members } = state; + return { + loading: members.isRequesting, + user: auth.user, + actions: global.actions, + global: global, + members: members.data, + }; } export default connect(mapStateToProps)(ApplyModal); diff --git a/code/VideoAccess-VCMP/web/client/src/sections/application/containers/applicationCenter.jsx b/code/VideoAccess-VCMP/web/client/src/sections/application/containers/applicationCenter.jsx index 73bffbd..5327461 100644 --- a/code/VideoAccess-VCMP/web/client/src/sections/application/containers/applicationCenter.jsx +++ b/code/VideoAccess-VCMP/web/client/src/sections/application/containers/applicationCenter.jsx @@ -3,15 +3,15 @@ import { connect } from "react-redux"; import moment from "moment"; import qs from "qs"; import { - Button, - Form, - Table, - Pagination, - Popover, - Tag, - Skeleton, - Popconfirm, - Row, + Button, + Form, + Table, + Pagination, + Popover, + Tag, + Skeleton, + Popconfirm, + Row, } from "@douyinfe/semi-ui"; import { SimpleFileDownButton, VideoPlayModal, SkeletonScreen, Setup } from "$components"; // import "../style.less"; @@ -22,349 +22,368 @@ import ApplyModal from "../components/applyModal"; import '../style.less' const ApplicationCenter = (props) => { - const { dispatch, actions, user, loading, equipmentWarehouseCamera } = props; - // const { equipmentWarehouse } = actions; - const [cameraModal, setCameraModal] = useState(false); - const [remarksModal, setRemarksModal] = useState(false); - const [videoPlay, setVideoPlay] = useState(false); - const [modalName, setModalName] = useState(false); //创建或修改 - const [setup, setSetup] = useState(false); //表格设置是否显现 - const [applyModal, setApplyModal] = useState(false); - const [cameraSetup, setcameraSetup] = useState(false); - const [setupp, setSetupp] = useState([]); - const [venderList, setvenderList] = useState([]); //厂商信息 - const [query, setQuery] = useState({ limit: 10, page: 0 }); //页码信息 - const [search, setSearch] = useState({}); //搜索条件 - const [rowId, setRowId] = useState(); //表格数据id - const [cameraData, setCameraData] = useState({}); //表格传递数据 - const [modify, setModify] = useState(false); //修改 - const [parentCamera, setParentCamera] = useState(""); //级联摄像头父级设备 - const [addNvr, setAddNvr] = useState(false); //nvr页面传递参数打开NVR摄像头添加弹框 - const [nvrNumber, setNvrNumber] = useState(); - const [videoObj, setVideoObj] = useState(); //播放条件 - const [axyData, setAxyData] = useState(); - const [cameraRemarks, setCameraRemarks] = useState([]);//备注 - const api = useRef(); - const searchData = useRef({}) - const limits = useRef(); //每页实际条数 - const page = useRef(query.page); - const deviceClickb = useRef(true) - const APPLICATION = "application"; + const { dispatch, actions, user, loading, applicationData } = props; + const { applicationCenter } = actions; + const [modalName, setModalName] = useState(false); //创建或修改 + const [setup, setSetup] = useState(false); //表格设置是否显现 + const [applyModal, setApplyModal] = useState(false); + const [setupp, setSetupp] = useState([]); + const [query, setQuery] = useState({ limit: 10, page: 0 }); //页码信息 + const [appData, setAppData] = useState(null); //应用id + const APPLICATION = 'application' + const pageLimit = useRef({ limit: 10, page: 0 }); + const limits = useRef(); //每页实际条数 + const columns = [ + { + title: "序号", + dataIndex: "", + render: (text, r, index) => { + return index + 1; + }, + }, + { + title: "应用名称", + dataIndex: "name", + key: "name", + render: (text, r, index) => { + return r?.name.length > 8 ? `${r?.name.substr(0, 8)}...` : r?.name + }, - const columns = [ - { - title: "序号", - dataIndex: "", - render: (text, r, index) => { - return index + 1; - }, - }, - { - title: "应用名称", - dataIndex: "name", - key: "name", - }, - { - title: "APPID", - dataIndex: "appId", - key: "appId", - - }, - { - title: "Secret Key", - dataIndex: "secretKey", - key: "secretKey", + }, + { + title: "APPID", + dataIndex: "appKey", + key: "appId", - }, - { - title: "操作", - width: "20%", - dataIndex: "", - render: (_, row) => { - return ( -
- - {row.forbidden ? ( - - ) : ( - { + }, + { + title: "操作", + width: "20%", + dataIndex: "", + render: (_, row) => { + return ( +
+ + {row?.forbidden ? ( + + ) : ( + 禁用后,应用系统引入的页面及能力将会暂时失效,请谨慎操作。
} + arrowPointAtCenter={false} + showArrow={true} + position="topRight" + onConfirm={() => { + dispatch(applicationCenter.putApplication({ appId: row?.id, forbidden: !row?.forbidden })).then(() => { + setQuery({ limit: pageLimit.current.limit, page: pageLimit.current.page }) + }) + }} + > + +
+ )} + 删除后,应用系统引入的页面及能力将会永久失效,请谨慎操作。
} + arrowPointAtCenter={false} + width={300} + showArrow={true} + position="topRight" + onConfirm={() => { + dispatch(applicationCenter.delApplication(row?.id)).then(() => { + if (pageLimit.current.page > 0 && limits.current < 2) { + setQuery({ limit: pageLimit.current.limit, page: pageLimit.current.page - 1 }) + } else { + setQuery({ limit: pageLimit.current.limit, page: pageLimit.current.page }) + } + }) + }} + > + + - }} - > - - - )} - { + + ); + }, + } + ]; - }} - > - - + //获取表格属性设置 + function attribute () { + const arr = localStorage.getItem(APPLICATION) + ? JSON.parse(localStorage.getItem(APPLICATION)) + : []; - - ); + const column = [ + { + title: "创建时间", + dataIndex: "createTime", + key: "createTime", + render: (_, r, index) => { + return r?.createUser?.name }, - } - ]; - - //获取表格属性设置 - function attribute () { - const arr = localStorage.getItem(APPLICATION) - ? JSON.parse(localStorage.getItem(APPLICATION)) - : []; - - const column = [ - { - title: "创建时间", - dataIndex: "createTime", - key: "createTime", + }, + { + title: "创建账号", + dataIndex: "createUserId", + key: "account", + render: (_, r, index) => { + return moment(r.createTime).format("YYYY-MM-DD HH:MM:SS"); }, - { - title: "创建账号", - dataIndex: "account", - key: "account", - + }, + { + title: "应用类型", + dataIndex: "type", + key: "applicationType", + render: (_, r, index) => { + const type = r?.type?.map((item, index) => item + ';') + return type }, - { - title: "应用类型", - dataIndex: "applicationType", - key: "applicationType", + }, + ]; - }, - ]; + for (let i = 0; i < arr.length; i++) { + let colum = column.filter((item) => { + return item.key === arr[i]; + }); + columns.splice(i + 4, 0, colum[0]); + } + setSetupp(columns); + } + const tableList = [//表格属性 + { + title: '详情信息', + list: [ + { name: "创建时间", value: "createTime" }, + { name: "创建账号", value: "account" }, + { name: "应用类型", value: "applicationType" }, + ] + }, + ]; - for (let i = 0; i < arr.length; i++) { - let colum = column.filter((item) => { - return item.key === arr[i]; - }); - columns.splice(i + 4, 0, colum[0]); - } - setSetupp(columns); - } - const tableList = [//表格属性 - { - title: '详情信息', - list: [ - { name: "创建时间", value: "createTime" }, - { name: "创建账号", value: "account" }, - { name: "应用类型", value: "applicationType" }, - ] - }, - ]; + //获取应用信息 + const details = (data) => { + pageLimit.current = query + dispatch(applicationCenter.getApplication(pageLimit.current)).then((res) => { + limits.current = res.payload.data.data.length + }); + } + useEffect(() => { + details() + }, [query]) - useEffect(() => { - //初始化表格显示设置 - localStorage.getItem(APPLICATION) == null - ? localStorage.setItem( - APPLICATION, - JSON.stringify(["createTime",]) - ) - : ""; - attribute(); - }, []) - return ( - <> -
-