diff --git a/src/api/ElectronicMapDraftApi.ts b/src/api/ElectronicMapDraftApi.ts new file mode 100644 index 0000000..9a5105e --- /dev/null +++ b/src/api/ElectronicMapDraftApi.ts @@ -0,0 +1,138 @@ +import { api } from 'src/boot/axios'; +import { PageDto } from './ApiCommon'; +import { DraftDataType } from './DraftApi'; + +export enum LineType { + UNKNOWN, + UR = 'UR', + IR = 'IR', + CR = 'CR', +} + +export const lineTypeOption = [ + { + label: '城市轨道交通', + value: LineType.UR, + }, + { + label: '城际轨道交通', + value: LineType.IR, + }, + { + label: '市域轨道交通', + value: LineType.CR, + }, +]; + +export const searchLineTypeOption = [ + { + label: '全部', + value: LineType.UNKNOWN, + }, + ...lineTypeOption, +]; + +export interface DraftItem { + id: number; + name: string; + dataType: DraftDataType; + options: string; + data: string; + userId: number; + defaultReleaseDataId: number; + isShared: boolean; + createdAt: string; + updatedAt: string; + defaultReleaseDataName: string; + userName: string; +} +export interface LineInfoOptionsInput { + lineType: LineType; + city?: string; + lineCode?: string; +} +export interface PagingQueryParams { + paging: { + page: number; + itemsPerPage: number; + }; + query: { + dataType: DraftDataType; + options?: LineInfoOptionsInput; + name?: string; + isShared?: boolean; + userId?: number; + }; +} +export interface DraftEmDataDto { + draftData: DraftItem; + options: LineInfoOptionsInput; +} + +export async function draftPageQuery( + params: PagingQueryParams +): Promise> { + const query = ` + query userDraftEmDataPaging($paging: PageQueryDto, $query: UserDraftEmDataFilterDto) { + userDraftEmDataPaging(paging: $paging, query: $query) { + total + items { + draftData {id name dataType userName defaultReleaseDataId createdAt updatedAt isShared defaultReleaseDataName} + options {lineType city lineCode} + } + } + } +`; + const response = await api.post('', { + query, + variables: params, + }); + return response.data.data.userDraftEmDataPaging; +} + +export async function sharedDraftPageQuery( + params: PagingQueryParams +): Promise> { + const query = ` + query sharedDraftEmDataPaging($paging: PageQueryDto, $query: SharedDraftEmDataFilterDto) { + sharedDraftEmDataPaging(paging: $paging, query: $query) { + total + items { + draftData {id name dataType userName userId defaultReleaseDataId createdAt updatedAt isShared defaultReleaseDataName} + options {lineType city lineCode} + } + } + } +`; + const response = await api.post('', { + query, + variables: params, + }); + return response.data.data.sharedDraftEmDataPaging; +} + + +/** + * 创建草稿 + * @param params + * @returns + */ +interface CreateDraftEmDto { + input: { + name: string; + options: LineInfoOptionsInput; + }; +} +export function createDraft(params: CreateDraftEmDto) { + const mutation = ` + mutation createDraftEmData($input: CreateDraftEmDto) { + createDraftEmData(input: $input) { + name + } + } +`; + return api.post('', { + query: mutation, + variables: params, + }); +} diff --git a/src/api/ElectronicMapPublishApi.ts b/src/api/ElectronicMapPublishApi.ts new file mode 100644 index 0000000..d27ce59 --- /dev/null +++ b/src/api/ElectronicMapPublishApi.ts @@ -0,0 +1,63 @@ +import { api } from 'src/boot/axios'; +import { PageDto } from './ApiCommon'; +import { DraftDataType } from './DraftApi'; +import { LineInfoOptionsInput } from './ElectronicMapDraftApi'; + +export interface PublishItem { + id: number; + name: string; + dataType: DraftDataType; + options: string; + data: string; + usedVersionId: number; + userId: number; + isPublished: boolean; + createdAt: string; + updatedAt: string; + description: string; + userName: string; +} + +interface PagingQueryParams { + page: { + page: number; + itemsPerPage: number; + }; + query: { + dataType: DraftDataType; + userId?: number; + name?: string; + isPublished?: boolean; + options?: LineInfoOptionsInput; + }; +} +export interface PublishEmDataDto { + releaseData: PublishItem; + options: LineInfoOptionsInput; +} + +/** + * 分页查询 + * @param params + * @returns + */ +export async function publishPageQuery( + params: PagingQueryParams +): Promise> { + const query = ` + query releaseEmDataPaging($page: PageQueryDto, $query: ReleaseEmDataFilterDto) { + releaseEmDataPaging(page: $page, query: $query) { + total + items { + releaseData {id name dataType usedVersionId userName isPublished createdAt updatedAt description } + options {lineType city lineCode} + } + } + } +`; + const response = await api.post('', { + query, + variables: params, + }); + return response.data.data.releaseEmDataPaging; +} diff --git a/src/api/UserApi.ts b/src/api/UserApi.ts index 6ba7f64..4a07b4d 100644 --- a/src/api/UserApi.ts +++ b/src/api/UserApi.ts @@ -115,8 +115,9 @@ export async function login(userLoginDto: LoginInfo) { } export interface User { - id: string; - name: string; + id: number; + username: string; + nickname: string; mobile: string; email: string; roles: []; @@ -171,7 +172,7 @@ export async function getLoginUserInfo() { const query = ` query loginUserInfo { loginUserInfo{ - id + id username nickname mobile email roles createdAt updatedAt } } `; @@ -181,20 +182,46 @@ export async function getLoginUserInfo() { return response.data.data; } -// /** -// * 获取jwt令牌(mqtt验证) -// */ -// export async function getJwt() { -// const query = ` -// query getJwt { -// getJwt -// } -// `; -// const response = await api.post('', { -// query: query, -// }); -// return response.data.data; -// } +export enum Role { + UNKNOWN, + ADMIN = 'ADMIN', + USER = 'USER', + ORG_MANAGER = 'ORG_MANAGER', //组织管理员 + ORG_TEACHER = 'ORG_TEACHER', //组织教师 + ORG_STUDENT = 'ORG_STUDENT', //组织学生 + ORG_GUEST = 'ORG_GUEST', //组织访客 +} + +export const rolesOptions = [ + { label: '系统管理员', value: Role.ADMIN }, + { label: '普通用户', value: Role.USER }, + { label: '组织管理员', value: Role.ORG_MANAGER }, + { label: '组织教师', value: Role.ORG_TEACHER }, + { label: '组织学生', value: Role.ORG_STUDENT }, + { label: '组织访客', value: Role.ORG_GUEST }, +]; + +/** + * 更改用户角色 + * @param variables + * @returns + */ +export async function updateUserRoles(variables: { + userId: number; + roles: Role[]; +}) { + const mutation = ` + mutation updateUserRoles($userId: Int,$roles: [Role!]) { + updateUserRoles(userId: $userId,roles: $roles,){ + id + } + } +`; + return api.post('', { + query: mutation, + variables, + }); +} /** * 获取默认组织信息 diff --git a/src/drawApp/electronicMapApp.ts b/src/drawApp/electronicMapApp.ts index 4532144..6854e02 100644 --- a/src/drawApp/electronicMapApp.ts +++ b/src/drawApp/electronicMapApp.ts @@ -1,11 +1,31 @@ -import { toUint8Array } from 'js-base64'; -import { GraphicData, IDrawApp, IGraphicStorage, newDrawApp } from 'jl-graphic'; -import { getDraft } from 'src/api/DraftApi'; +import { fromUint8Array, toUint8Array } from 'js-base64'; +import { + calculateDistanceFromPointToLine, + CombinationKey, + ContextMenu, + distance2, + getRectangleCenter, + GraphicData, + IDrawApp, + IGraphicStorage, + KeyListener, + MenuItemOptions, + newDrawApp, +} from 'jl-graphic'; +import { getDraft, saveDraft } from 'src/api/DraftApi'; import { electronicMapGraphicData } from 'src/protos/electronicMap_graphic_data'; import { useDrawStore } from 'src/stores/electronicMap-draw-store'; import { PlatformDraw } from 'src/graphics/electronicMap/platform/PlatformDrawAssistant'; -import { PlatformTemplate } from 'src/graphics/electronicMap/platform/Platform'; +import { + Platform, + PlatformTemplate, +} from 'src/graphics/electronicMap/platform/Platform'; import { PlatformData } from './graphics/electronicMap/PlatformInteraction'; +import { errorNotify, successNotify } from 'src/utils/CommonNotify'; +import { common } from 'src/protos/common'; +import { toStorageTransform } from './graphics/GraphicDataBase'; +import { Section } from 'src/graphics/electronicMap/section/Section'; +import { OneClickGenerateDraw, OneClickGenerateTemplate } from 'src/graphics/electronicMap/trainWindow/oneClickDrawAssistant'; let electronicMapDrawApp: IDrawApp | null = null; @@ -20,19 +40,166 @@ export function destroyElectronicMapDrawApp(): void { } } +const UndoOptions: MenuItemOptions = { + name: '撤销', +}; +const RedoOptions: MenuItemOptions = { + name: '重做', +}; +const SelectAllOptions: MenuItemOptions = { + name: '全选', +}; + +export const DefaultEmCanvasMenu = new ContextMenu({ + name: '绘制-画布菜单', + groups: [ + { + items: [UndoOptions, RedoOptions], + }, + { + items: [SelectAllOptions], + }, + ], +}); + export function initElectronicMapDrawApp(): IDrawApp { electronicMapDrawApp = newDrawApp({ - dataLoader: loadThDrawDatas, + dataLoader: loadElectronicMapDrawDatas, }); const app = electronicMapDrawApp; - new PlatformDraw( - app, - new PlatformTemplate(new PlatformData()) + new OneClickGenerateDraw(app, new OneClickGenerateTemplate()), + new PlatformDraw(app, new PlatformTemplate(new PlatformData())); + + // 画布右键菜单 + app.registerMenu(DefaultEmCanvasMenu); + + app.canvas.on('_rightclick', (e) => { + if (app.drawing) return; + UndoOptions.disabled = !app.opRecord.hasUndo; + RedoOptions.disabled = !app.opRecord.hasRedo; + + UndoOptions.handler = () => { + app.opRecord.undo(); + }; + RedoOptions.handler = () => { + app.opRecord.redo(); + }; + SelectAllOptions.handler = () => { + app.selectAllGraphics(); + }; + DefaultEmCanvasMenu.open(e.global); + }); + app.on('destroy', () => { + generateAxleCountingConfig = + new electronicMapGraphicData.GenerateAxleCountingConfig(); + }); + app.addKeyboardListener( + new KeyListener({ + value: 'KeyS', + global: true, + combinations: [CombinationKey.Ctrl], + onPress: () => { + saveDrawToServer(saveDrawDatas(app)); + }, + }) ); + // KeyA 用于区段复制--控制生成的区段位置 + const graphicCopyPlugin = app.app.graphicCopyPlugin; + const copySectionListener = new KeyListener({ + value: 'KeyA', + global: true, + onPress: () => { + graphicCopyPlugin.updateMoveLimit('sectionPointLimit'); + }, + }); + graphicCopyPlugin.addGraphicControlers([ + { + controlerList: [copySectionListener], + check: () => { + if ( + graphicCopyPlugin.copys.length == 1 && + graphicCopyPlugin.copys[0].type == Section.Type + ) + return true; + return false; + }, + moveLimitOption: { + moveLimitName: 'sectionPointLimit', + moveLimit: (e) => { + const mousePos = app.toCanvasCoordinates(e.global); + const selectSection = app.selectedGraphics[0] as Section; + let selectSectionLeft = selectSection.localToCanvasPoint( + selectSection.getStartPoint() + ); + let selectSectionRight = selectSection.localToCanvasPoint( + selectSection.getEndPoint() + ); + [selectSectionLeft, selectSectionRight] = + selectSectionLeft.x < selectSectionRight.x + ? [selectSectionLeft, selectSectionRight] + : [selectSectionRight, selectSectionLeft]; + //要移动到目标位的区段 + const sections = app.queryStore.queryByType
(Section.Type); + const minDistanceSection = sections.reduce((prev, cur) => { + const prevDistance = calculateDistanceFromPointToLine( + prev.localToCanvasPoint(prev.getStartPoint()), + prev.localToCanvasPoint(prev.getEndPoint()), + mousePos + ); + const curDistance = calculateDistanceFromPointToLine( + cur.localToCanvasPoint(cur.getStartPoint()), + cur.localToCanvasPoint(cur.getEndPoint()), + mousePos + ); + return prevDistance > curDistance || + (prevDistance == curDistance && + distance2( + prev.localToCanvasPoint(prev.getStartPoint()), + mousePos + ) > + distance2( + cur.localToCanvasPoint(cur.getStartPoint()), + mousePos + )) + ? cur + : prev; + }); + const minDistanceRefSectionsPos = + minDistanceSection.localToCanvasPoint( + getRectangleCenter( + minDistanceSection.lineGraphic.getLocalBounds() + ) + ); + let minDistanceSectionLeft = minDistanceSection.localToCanvasPoint( + minDistanceSection.getStartPoint() + ); + let minDistanceSectionRight = minDistanceSection.localToCanvasPoint( + minDistanceSection.getEndPoint() + ); + [minDistanceSectionLeft, minDistanceSectionRight] = + minDistanceSectionLeft.x < minDistanceSectionRight.x + ? [minDistanceSectionLeft, minDistanceSectionRight] + : [minDistanceSectionRight, minDistanceSectionLeft]; + + if (mousePos.x > minDistanceRefSectionsPos.x) { + graphicCopyPlugin.container.position.x = + minDistanceSectionRight.x - selectSectionLeft.x; + graphicCopyPlugin.container.position.y = + minDistanceSectionRight.y - selectSectionLeft.y; + } else { + graphicCopyPlugin.container.position.x = + minDistanceSectionLeft.x - selectSectionRight.x; + graphicCopyPlugin.container.position.y = + minDistanceSectionLeft.y - selectSectionRight.y; + } + }, + }, + }, + ]); return electronicMapDrawApp; } -export async function loadThDrawDatas(): Promise { +export async function loadElectronicMapDrawDatas(): Promise { const drawStore = useDrawStore(); const id = drawStore.draftId; if (!id) { @@ -46,6 +213,9 @@ export async function loadThDrawDatas(): Promise { ); const datas: GraphicData[] = []; generateAxleCountingConfig = storage.generateAxleCountingConfig; + storage.Platforms.forEach((platform) => { + datas.push(new PlatformData(platform)); + }); console.log(storage, 'storage'); return Promise.resolve({ canvasProperty: storage.canvas, @@ -58,8 +228,41 @@ export async function loadThDrawDatas(): Promise { } } -export function saveDrawDatas() { - console.log(111); +export function saveDrawDatas(app: IDrawApp) { + const storage = new electronicMapGraphicData.ElectronicMapGraphicStorage(); + const canvasData = app.canvas.saveData(); + storage.canvas = new common.Canvas({ + width: canvasData.width, + height: canvasData.height, + backgroundColor: canvasData.backgroundColor, + viewportTransform: toStorageTransform(canvasData.viewportTransform), + }); + const graphics = app.queryStore.getAllGraphics(); + graphics.forEach((g) => { + if (g instanceof Platform) { + const platformData = g.saveData(); + storage.Platforms.push((platformData as PlatformData).data); + } + }); + storage.generateAxleCountingConfig = generateAxleCountingConfig; + const base64 = fromUint8Array(storage.serialize()); + console.log('保存数据', storage); + return base64; +} + +export function saveDrawToServer(base64: string) { + const drawStore = useDrawStore(); + const id = drawStore.draftId; + if (!id) { + return; + } + saveDraft({ id, data: base64 }) + .then(() => { + successNotify('保存数据成功!'); + }) + .catch((err) => { + errorNotify(err.message, err); + }); } //一键生成计轴配置 diff --git a/src/layouts/MainLayout.vue b/src/layouts/MainLayout.vue index 6925466..a407731 100644 --- a/src/layouts/MainLayout.vue +++ b/src/layouts/MainLayout.vue @@ -72,7 +72,7 @@ ID: - {{ userInfo?.id }} + {{ userInfo.id }} @@ -80,7 +80,15 @@ 用户名: - {{ userInfo?.name }} + {{ userInfo.username }} + + + + + 昵称: + + + {{ userInfo.nickname }} @@ -89,7 +97,7 @@ - {{ getRoleName(userInfo?.roles) }} + {{ getRoleName(userInfo.roles) }} @@ -98,15 +106,27 @@ 电话: - {{ userInfo?.mobile }} + {{ userInfo.mobile }} - 注册时间: + 创建时间: - {{ userInfo?.register_time }} + {{ + formatTime(userInfo.createdAt) + }} + + + + + 更新时间: + + + {{ + formatTime(userInfo.updatedAt) + }} @@ -123,10 +143,13 @@ diff --git a/src/pages/ElectronicMapDraftManage.vue b/src/pages/ElectronicMapDraftManage.vue new file mode 100644 index 0000000..0cf95fc --- /dev/null +++ b/src/pages/ElectronicMapDraftManage.vue @@ -0,0 +1,838 @@ + + + +src/api/ElectronicMapDraftApi diff --git a/src/pages/ElectronicMapPublishManage.vue b/src/pages/ElectronicMapPublishManage.vue new file mode 100644 index 0000000..828807b --- /dev/null +++ b/src/pages/ElectronicMapPublishManage.vue @@ -0,0 +1,544 @@ + + + diff --git a/src/pages/IscsDraftManage.vue b/src/pages/IscsDraftManage.vue index a5ee606..57db263 100644 --- a/src/pages/IscsDraftManage.vue +++ b/src/pages/IscsDraftManage.vue @@ -41,7 +41,14 @@ color="primary" v-if="route.name == 'iscsDraft'" label="新建" - @click="createFormShow = true" + @click="showCreateDialog" + /> + @@ -436,6 +443,11 @@ const isSharedOption = ['全部', '共享', '不共享']; //新建相关 const createFormShow = ref(false); +function showCreateDialog() { + createFormShow.value = true; + createForm.draftName = ''; + createForm.style = IscsStyle.DA_SHI_ZHI_NENG; +} const createForm = reactive({ draftName: '', style: IscsStyle.DA_SHI_ZHI_NENG, diff --git a/src/pages/IscsPublishManage.vue b/src/pages/IscsPublishManage.vue index c1f03cf..dc2f7f4 100644 --- a/src/pages/IscsPublishManage.vue +++ b/src/pages/IscsPublishManage.vue @@ -39,6 +39,7 @@ label="上下架" style="width: 130px" /> + @@ -246,7 +247,6 @@ const pagination = ref({ let allRequestData: PublishIscsDataDto[] = []; async function onRequest(props: any) { const { page, rowsPerPage } = props.pagination; - const filter = props.filter; loading.value = true; const variables = { diff --git a/src/pages/UserManage.vue b/src/pages/UserManage.vue index bc30cc2..9c02e2d 100644 --- a/src/pages/UserManage.vue +++ b/src/pages/UserManage.vue @@ -52,15 +52,71 @@ + + + + + + +
修改用户角色
+ + + + + + + +
+
+
+
diff --git a/src/router/routes.ts b/src/router/routes.ts index c34b28e..6ca18ed 100644 --- a/src/router/routes.ts +++ b/src/router/routes.ts @@ -49,8 +49,8 @@ const routes: RouteRecordRaw[] = [ }, { - path: '/dataManage', - name: 'dataManage', + path: '/iscsDataManage', + name: 'iscsDataManage', component: () => import('layouts/MainLayout.vue'), meta: { label: 'ISCS数据管理', @@ -86,6 +86,44 @@ const routes: RouteRecordRaw[] = [ }, ], }, + { + path: '/emDataManage', + name: 'emDataManage', + component: () => import('layouts/MainLayout.vue'), + meta: { + label: '电子地图数据管理', + icon: 'list_alt', + }, + children: [ + { + path: 'emDraft', + name: 'emDraft', + component: () => import('pages/ElectronicMapDraftManage.vue'), + meta: { + label: '草稿数据', + icon: 'app_registration', + }, + }, + { + path: 'emSharedDraft', + name: 'emSharedDraft', + component: () => import('pages/ElectronicMapDraftManage.vue'), + meta: { + label: '共享草稿数据', + icon: 'app_registration', + }, + }, + { + path: 'emPublish', + name: 'emPublish', + component: () => import('pages/ElectronicMapPublishManage.vue'), + meta: { + label: '发布数据', + icon: 'playlist_add_check', + }, + }, + ], + }, { path: '/iscsPainting/:id', name: 'iscsPainting', @@ -95,8 +133,8 @@ const routes: RouteRecordRaw[] = [ }, }, { - path: '/electronicMapPainting/:id', - name: 'electronicMapPainting', + path: '/emPainting/:id', + name: 'emPainting', component: () => import('layouts/electronicMapDrawLayout.vue'), meta: { hidden: true,