优化高德地图,修改首页图片,修改事件处理视频

This commit is contained in:
wenxin 2024-12-24 19:46:43 +08:00
parent 7babd0fec6
commit 220d8ffb5e
27 changed files with 340 additions and 218 deletions

View File

@ -1,23 +0,0 @@
const BASE_API = {
// SERVER_IP: 'http://www.linxyun.com',
SERVER_IP: 'http://39.101.75.113:8088',
// SERVER_IP: 'http://121.229.160.133:8088',
GetFileConfigUrl: '/smartroadlamp/genFileConfig.action',
// 部署时是否要加前缀后端API地址需要统计加上这串当部署不需要时该串配置成空串就可以
URL_PRE: '',
// 显示的项目名称
PROJECT_NAME: '智慧路灯',
PROJECT_URI: '/smartroadlamp',
ContainCustmerID: '0',
CustomerType: 1,
// 项目ID
ENT_CODE: '56',
SubSysID: '2',
// 提示消息显示时长
MSG_SHOW_TIME: 3000,
IS_TEST: false,
// 是否开启国际化
I18N: false,
// 管理员角色编码
MANAGER_ROLE: '2101',
}

View File

@ -13,7 +13,7 @@
content="vue-next-admin基于 vue3 + CompositionAPI + typescript + vite + element plus适配手机、平板、pc 的后台开源免费管理系统模板vue-prev-admin基于 vue2 + element ui适配手机、平板、pc 的后台开源免费管理系统模板!"
/>
<link rel="icon" href="/favicon.ico" />
<script src="./config.js"></script>
<script src="./public/config.js"></script>
<title>智慧路灯</title>
</head>
<body>

View File

@ -14,6 +14,7 @@
"@element-plus/icons-vue": "^2.3.1",
"@wangeditor/editor": "^5.1.23",
"@wangeditor/editor-for-vue": "^5.1.12",
"ali-oss": "^6.22.0",
"autofit.js": "^3.2.2",
"axios": "^1.6.8",
"coordtransform": "^2.1.2",
@ -27,7 +28,10 @@
"js-cookie": "^3.0.5",
"js-table2excel": "^1.1.2",
"jsplumb": "^2.15.6",
"localforage": "^1.10.0",
"lodash-es": "^4.17.21",
"mitt": "^3.0.1",
"monaco-editor": "^0.52.2",
"nprogress": "^0.2.0",
"pinia": "^2.1.7",
"print-js": "^1.6.0",
@ -36,12 +40,14 @@
"screenfull": "^6.0.2",
"sortablejs": "^1.15.2",
"splitpanes": "^3.1.5",
"vant": "^4.9.15",
"vue": "^3.4.21",
"vue-clipboard3": "^2.0.0",
"vue-demi": "^0.14.7",
"vue-grid-layout": "^3.0.0-beta1",
"vue-i18n": "^9.10.2",
"vue-router": "^4.3.0"
"vue-router": "^4.3.0",
"xlsx": "^0.18.5"
},
"devDependencies": {
"@types/node": "^20.11.28",

View File

@ -1,8 +1,8 @@
// import { Post, SyncPost } from '/@/api/linxyun/base/index.ts'
import IFileClient from './file_client_interface.js';
import { httpReqeustApi } from '/@/api/linxyun/base';
import { httpRequestApi } from '/@/api/linxyun/base';
const httpReqeust = httpReqeustApi();
const httpReqeust = httpRequestApi();
export default class FileClient_Eslithe extends IFileClient {
constructor(fileConfig) {
@ -40,7 +40,10 @@ export default class FileClient_Eslithe extends IFileClient {
console.log('[Debug][File][eslithe]upload file, file: ', fileName, content);
const formData = new FormData();
formData.append('file', content, fileName);
let res = await httpReqeust.SyncPost(this._fileConfig.setting.uploadUrl, null, formData);
let res = await httpReqeust.SyncPost(this._fileConfig.setting.uploadUrl, null, formData, {
'Content-Type': 'multipart/form-data'
});
console.log('yyyyyyyyyyyyyyyyyy, res: ', res);
if (!res || !res.data || res.code !== '0000') {
console.error('[Error][File][uploadFile][eslithe]Upload fail, res: ', res);

View File

@ -1,9 +1,9 @@
// import { Post, SyncPost, SyncPostOutside } from '/@/api/linxyun/base/index.ts'
import { warnTime } from './constant.js';
import IFileClient from './file_client_interface.js';
import { httpReqeustApi } from '/@/api/linxyun/base';
import { httpRequestApi } from '/@/api/linxyun/base';
const httpReqeust = httpReqeustApi();
const httpReqeust = httpRequestApi();
export default class FileClient_QN extends IFileClient {
constructor(fileConfig) {

View File

@ -2,9 +2,9 @@ import { warnTime } from './constant.js'
// import { SyncPost } from '/@/api/linxyun/base/index.ts'
import IFileClient from './file_client_interface.js'
import { getGUID } from './guid.js'
import { httpReqeustApi } from '/@/api/linxyun/base';
import { httpRequestApi } from '/@/api/linxyun/base';
const httpReqeust = httpReqeustApi();
const httpReqeust = httpRequestApi();
const COS = () => ({})

View File

@ -6,9 +6,9 @@ import FileClient_Ali from './file_client_ali.js';
// import { Message } from 'element-ui'
import { ElMessage } from 'element-plus';
// import { SyncPost } from '/@/api/linxyun/base/index.ts'
import { httpReqeustApi } from '/@/api/linxyun/base';
import { httpRequestApi } from '/@/api/linxyun/base';
const httpReqeust = httpReqeustApi();
const httpReqeust = httpRequestApi();
export default class FileIns {
_getFileConfigUrl = 'genFileConfig';

View File

@ -8,13 +8,13 @@
</template>
<script lang="ts" setup name="ImportExcel">
import uoloadExcel from './upload-excel.vue';
import { httpReqeustApi } from '/@/api/linxyun/base/index.ts';
import { httpRequestApi } from '/@/api/linxyun/base/index.ts';
import EnumOptions from '/@/components/Linxyun/Datas/enum_options.js';
import Lxy_page_event_remote from '/@/components/Linxyun/custom/CustomCommon/lxy_page_event_remote.js';
import { treeData2Optioins } from '/@/components/Linxyun/custom/CustomCommon/tools.js';
import { getVuex } from '/@/utils/formatPrivacyData.js';
import { ElMessage } from 'element-plus';
const httpRequest = httpReqeustApi();
const httpRequest = httpRequestApi();
const props = withDefaults(
defineProps<{

View File

@ -12,7 +12,7 @@ import {
} from '/@/utils/formatPrivacyData.js';
import EnumOptions from '../../Datas/enum_options.js';
import Lxy_params_mgr from '/@/components/Linxyun/custom/CustomCommon/lxy_params_mgr.js';
import { httpReqeustApi } from '/@/api/linxyun/base/index.ts';
import { httpRequestApi } from '/@/api/linxyun/base/index.ts';
import { createDDE_SA } from '/@/utils/stringUtil';
import localforage from 'localforage';
import { functions } from 'lodash';
@ -625,7 +625,7 @@ export const getPageFuncDefine = async (pageid) => {
// 页面函数
const funcs = await loadFuncFromLocal(1, pageid)
if (funcs == null) {
const res = await httpReqeustApi().SyncPost(
const res = await httpRequestApi().SyncPost(
'/eslithe/queryFunctionDefineNew.action',
{ PageID: pageid, EntCode: BASE_API.ENT_CODE, Type: 1 },
{},
@ -642,7 +642,7 @@ export const getPageFuncDefine = async (pageid) => {
// 全局函数
const glfuncs = await loadFuncFromLocal(0, -1)
if (glfuncs == null) {
const glres = await httpReqeustApi().SyncPost('/eslithe/queryFunctionDefineNew.action', { EntCode: BASE_API.ENT_CODE, Type: 0 }, {}, headers);
const glres = await httpRequestApi().SyncPost('/eslithe/queryFunctionDefineNew.action', { EntCode: BASE_API.ENT_CODE, Type: 0 }, {}, headers);
addFunction(glres, 0, -1);
} else {
if (glfuncs !== 'None') {

View File

@ -1,8 +1,8 @@
// import request from '@/utils/request'
import { httpReqeustApi } from '/@/api/linxyun/base/index.ts';
import { httpRequestApi } from '/@/api/linxyun/base/index.ts';
import lxy_event from './lxy_page_event.js';
import Lxy_params_mgr from './lxy_params_mgr.js';
const httpRequest = httpReqeustApi();
const httpRequest = httpRequestApi();
class Lxy_page_event_emit extends lxy_event {
constructor(e) {

View File

@ -1,8 +1,8 @@
// import { SyncPost } from '@/api/linxyun/base/index'
import { httpReqeustApi } from '/@/api/linxyun/base/index.ts';
import { httpRequestApi } from '/@/api/linxyun/base/index.ts';
import Lxy_params_mgr from './lxy_params_mgr.js';
import lxy_event from './lxy_page_event.js';
const httpRequest = httpReqeustApi();
const httpRequest = httpRequestApi();
// 远程调用事件;
class Lxy_page_event_remote extends lxy_event {
_uri = null; // 远程服务URI;

View File

@ -1,6 +1,6 @@
import PageItem from './page_item.js';
import localforage from 'localforage';
import { httpReqeustApi } from '/@/api/linxyun/base/index.ts';
import { httpRequestApi } from '/@/api/linxyun/base/index.ts';
import { getPageFuncDefine } from './lxy_expression.js';
const httpRequest = httpReqeustApi();

View File

@ -1,11 +1,11 @@
import { httpReqeustApi } from '/@/api/linxyun/base/index.ts';
import { httpRequestApi } from '/@/api/linxyun/base/index.ts';
import { formatStr2Obj } from './tools.js';
import EnumOptions from '/@/components/Linxyun/Datas/enum_options.js';
import { createDDE_SA } from '/@/utils/stringUtil';
const DDE_SA = createDDE_SA(BASE_API.ENT_CODE || 0, 0, 0);
const headers = { 'DDE-SA': DDE_SA, 'Content-Type': 'application/json;charset=UTF-8' };
const httpRequest = httpReqeustApi();
const headers = { 'DDE-SA': httpRequestApi, 'Content-Type': 'application/json;charset=UTF-8' };
const httpRequest = httpRequestApi();
const ColOptType_Update = 0;
const ColOptType_Delete = 1;
// const ColOptType_Details = 2

View File

@ -31,7 +31,7 @@ import { getComponent } from '/@/utils/componentFactory';
import { calcFieldValue } from '/@/components/Linxyun/custom/CustomCommon/lxy_expression.js';
import { isChinese, isEnglish } from '/@/utils/extendMethods';
import localforage from 'localforage';
import { httpReqeustApi } from '/@/api/linxyun/base';
import { httpRequestApi } from '/@/api/linxyun/base';
import { createDDE_SA } from '/@/utils/stringUtil';
const props = defineProps<{
fieldDefines: TabFieldType[];
@ -41,7 +41,7 @@ const props = defineProps<{
rowParams?: Record<string, any>;
}>();
const formItemRefs = ref<Record<string, any>>({});
const httpRequest = httpReqeustApi();
const httpRequest = httpRequestApi();
const { OpType, inputData, rowParams, fieldDefines } = toRefs(props);
const formData = reactive<Record<string, any>>({});
const located = ref('Add');

View File

@ -1,14 +1,14 @@
import { useRouter } from 'vue-router';
import { ElMessage, ElMessageBox, ElLoading } from 'element-plus';
import { ButtonDefineType, DialogType, EInputDataType, EventExcuteType, TabFieldType } from '../../DataStructs/commontype';
import { httpReqeustApi } from '/@/api/linxyun/base';
import { httpRequestApi } from '/@/api/linxyun/base';
import exportExcel from '/@/utils/exportExcel.js';
// import { calcFieldValue } from '/@/utils/formatPrivacyData.js';
import { calcFieldValue } from '/@/components/Linxyun/custom/CustomCommon/lxy_expression.js';
import type { IStateType, IPropsType } from '../type';
const httpRequest = httpReqeustApi();
const httpRequest = httpRequestApi();
export default function useBtnOperate(getData: () => void, state: IStateType, props: IPropsType) {
const router = useRouter();

View File

@ -270,7 +270,7 @@ import {
DialogConfigType,
EInputType,
} from '/@/components/Linxyun/custom/DataStructs/commontype';
import { httpReqeustApi } from '/@/api/linxyun/base';
import { httpRequestApi } from '/@/api/linxyun/base';
// import { TabPageItem } from '../CustomCommon/tab_page_item.js';
import { getComponent } from '/@/utils/componentFactory';
import { compare, getArrayIndex } from '/@/utils/extendMethods';
@ -297,7 +297,7 @@ export interface IPropsType {
}
const router = useRouter();
const route = useRoute();
const httpRequest = httpReqeustApi();
const httpRequest = httpRequestApi();
const customTableStore = useCustomTableStore();
const props = withDefaults(defineProps<IPropsType>(), {

View File

@ -1,5 +1,5 @@
import { EInputDataType, ProcessType, TabFieldType } from '/@/components/Linxyun/custom/DataStructs/commontype';
import { calcFieldValue } from '/@/components/linxyun/custom/CustomCommon/lxy_expression.js';
import { calcFieldValue } from '/@/components/Linxyun/custom/CustomCommon/lxy_expression.js';
export default function useElement(located: any, FieldItem: TabFieldType, componentVal: any, props: Record<string, any>) {
if (FieldItem?.FieldName) {
if (FieldItem.InputDataType == EInputDataType.FrontType) {

View File

@ -1,5 +1,6 @@
<template>
<el-cascader v-model="componentVal" :options="options" :key="propKey" :disabled="!activate" clearable :style="{ width: width }" @change="handleChange" />
<el-cascader v-model="componentVal" :options="options" :key="propKey" :disabled="!activate" clearable
:style="{ width: width }" @change="handleChange" />
</template>
<script lang="ts" setup>
@ -19,7 +20,7 @@ const props = withDefaults(
pageData?: Record<string, any>;
inputData?: Record<string, any>;
}>(),
{ located: 'table', filterIdx: -1, pageData: () => ({}), inputData: () => ({}), modelValue: () =>(''), FieldItem: null }
{ located: 'table', filterIdx: -1, pageData: () => ({}), inputData: () => ({}), modelValue: () => (''), FieldItem: null }
);
/**
* 目前的级联只支持tab_tree_data中的数据
@ -45,7 +46,7 @@ const propKey = ref(1);
// } else {
// tempVal.value = ''
// }
// },
// {
// immediate: true,
@ -64,42 +65,55 @@ const init = async (item: any) => {
const remoteEvent = new Lxy_page_event_remote(item.pageType ? item.dynamicOptions : item.InputDefine.event);
remoteEvent.setDataSrc(props.pageData, props.inputData, null);
const result = await remoteEvent.callEvent(null);
if (!result || !result.data) {
console.error('[Error]call remote method fail, itme: ', item.FieldName);
// return this.$set(this.loadings, item.value, false)
console.error('[Error]call remote method fail, item: ', item.FieldName);
return;
}
treeData2Optioins(result.data.Child, options);
console.log('cascader: ', options)
console.log('located.value: ', located.value)
console.log("aaaaaaaa", { options: options, tempVal: tempVal.value, })
getCascaderDataArray(options, tempVal.value);
if (tempVal.value) {
tempCpnVal.value = [];
getCascaderDataArray(options, tempVal.value);
componentVal.value = [...tempCpnVal.value];
}
};
let falg = false
watch(() => props.modelValue,
watch(
() => props.modelValue,
(newVal: string) => {
console.log('props modelValue: ', newVal)
tempCpnVal.value = []
if(newVal === ''){
console.log(11111,[...componentVal.value])
componentVal.value = []
// componentVal.length = 0
}else{
if(!falg){
console.log(2234434)
tempVal.value = newVal
// init(FieldItem.value)
if (['Add'].includes(located.value)) {
tempCpnVal.value = []
}
console.log('props modelValue: ', newVal);
falg = false;
if (newVal === '') {
componentVal.value = [];
tempCpnVal.value = [];
} else {
tempVal.value = newVal;
tempCpnVal.value = []; //
// options
if (options.length > 0) {
getCascaderDataArray(options, newVal);
componentVal.value = [...tempCpnVal.value];
} else {
// optionsoptions
nextTick(() => {
if (options.length > 0) {
getCascaderDataArray(options, newVal);
componentVal.value = [...tempCpnVal.value];
}
});
}
componentVal.value = tempCpnVal.value
}
},
{
immediate:true,
deep:true
})
immediate: true,
deep: true,
}
);
const handleChange = (val: string[]) => {
falg = true
tempCpnVal.value = []
@ -110,30 +124,45 @@ const handleChange = (val: string[]) => {
} else {
emit('update:modelValue', '');
}
};
const setActivate = (params: any) => {
activate.value = params.activate;
};
const getCascaderDataArray = (options: any[], value: string,) => {
if (!options || options.length === 0) {
return;
const getCascaderDataArray = (options: any[], value: string) => {
if (!options || options.length === 0 || !value) {
return false;
}
console.log('getCascaderDataArray', options, value, tempCpnVal.value);
for (let i = 0; i < options.length; i++) {
if (value && value.indexOf(options[i].value) === 0) {
console.log('getCascaderDataArray', options[i].value);
tempCpnVal.value.push(options[i].value);
if (options[i].children && options[i].children.length > 0) {
getCascaderDataArray(options[i].children, value);
for (const option of options) {
if (value === option.value) {
//
tempCpnVal.value.push(option.value);
return true;
}
if (option.children && option.children.length > 0) {
//
tempCpnVal.value.push(option.value);
//
const found = getCascaderDataArray(option.children, value);
if (found) {
// true
return true;
} else {
//
tempCpnVal.value.pop();
}
}
}
return false;
};
if(!['Table','Detail'].includes(located.value)){
if (!['Table', 'Detail'].includes(located.value)) {
init(FieldItem.value);
}
//

View File

@ -62,7 +62,7 @@ import { ElMessage, ElMessageBox, ElLoading } from 'element-plus';
import { DialogConfigType, DialogType, TabFieldType } from '/@/components/Linxyun/custom/DataStructs/commontype';
import Lxy_params_mgr from '../custom/CustomCommon/lxy_params_mgr.js';
import Lxy_expression from '../custom/CustomCommon/lxy_expression.js';
import { httpReqeustApi } from '/@/api/linxyun/base';
import { httpRequestApi } from '/@/api/linxyun/base';
import TableForm from '../custom/TableForm/index.vue';
import CustomTablePape from '../custom/CustomTablePape/index.vue';
import CustomPage from '../custom/CustomizePage/index.vue';
@ -86,7 +86,7 @@ const props = withDefaults(
const { dialogConfig, inputData } = toRefs(props);
const emit = defineEmits(['update:modelValue', 'getTableData', 'exportExcel', 'handleEmitEvent']);
const httpRequest = httpReqeustApi();
const httpRequest = httpRequestApi();
const showDialog = ref(false);
//

View File

@ -5,8 +5,8 @@
<script lang="ts" setup>
import { TablePageType, TabFieldType, timestampType } from '/@/components/Linxyun/custom/DataStructs/commontype';
import { ElMessage } from 'element-plus';
import { httpReqeustApi } from '/@/api/linxyun/base/index'
const httpRequest = httpReqeustApi()
import { httpRequestApi } from '/@/api/linxyun/base/index'
const httpRequest = httpRequestApi()
import { calcFieldValue } from '/@/components/Linxyun/custom/CustomCommon/lxy_expression.js';
import { randomLetter, randomNum, randomString, uuid } from '/@/utils/stringUtil'

View File

@ -2,55 +2,48 @@
<div v-if="located === 'Filter'">不支持图片过滤</div>
<template v-else>
<div>{{ FieldItem?.TipsText }}</div>
<el-upload
v-bind="attrs"
:disabled="!activate"
:file-list="fileList"
:before-upload="handleBeforeUpload"
:on-remove="handleRemove"
:on-preview="handlePreview"
:on-exceed="handleExceed"
:on-change="handleChange"
:http-request="handleUploadRequest"
class="upload"
>
<el-icon><Plus /></el-icon>
<template #file="{ file }" v-if="FieldItem?.InputType === 'video' || FieldItem?.InputDefine?.fileType === '2'">
<el-upload v-bind="attrs" :disabled="!activate" :file-list="fileList" :before-upload="handleBeforeUpload"
:on-remove="handleRemove" :on-preview="handlePreview" :on-exceed="handleExceed" :on-change="handleChange"
:http-request="handleUploadRequest" class="upload">
<el-icon>
<Plus />
</el-icon>
<template #file="{ file }"
v-if="FieldItem?.InputType === 'video' || FieldItem?.InputDefine?.fileType === '2'">
<video :src="file.url" controls height="148" width="148"></video>
<el-icon v-if="located !== 'Detail'" class="delete" :size="20" @click="handleRemove(file)"><DeleteFilled /></el-icon>
<el-icon v-if="located !== 'Detail'" class="delete" :size="20" @click="handleRemove(file)">
<DeleteFilled />
</el-icon>
</template>
<template #file="{ file }" v-else-if="FieldItem?.InputDefine?.fileType === '1'">
<div style="width: 100%; height: 100%; background-color: #409eff; display: flex; justify-content: center; align-items: center">
<div
style="width: 100%; height: 100%; background-color: #409eff; display: flex; justify-content: center; align-items: center">
<span style="color: #fff; cursor: pointer" @click="previewFile(file.url)">预览</span>
</div>
<el-icon v-if="located !== 'Detail'" class="delete" :size="20" @click="handleRemove(file)"><DeleteFilled /></el-icon>
<el-icon v-if="located !== 'Detail'" class="delete" :size="20" @click="handleRemove(file)">
<DeleteFilled />
</el-icon>
</template>
</el-upload>
<el-progress v-if="progress" :percentage="state.progressPercent" />
</template>
<el-dialog v-model="dialogVisible" destroy-on-close append-to-body>
<img v-if="FieldItem?.InputType === 'el-img'" w-full :src="dialogImageUrl" alt="Preview Image" style="width: 100%" />
<video v-else-if="FieldItem?.InputType === 'video' || FieldItem?.InputDefine?.fileType === '2'" :src="dialogImageUrl" controls></video>
<img v-if="FieldItem?.InputType === 'el-img'" w-full :src="dialogImageUrl" alt="Preview Image"
style="width: 100%" />
<video v-else-if="FieldItem?.InputType === 'video' || FieldItem?.InputDefine?.fileType === '2'"
:src="dialogImageUrl" controls></video>
</el-dialog>
<el-dialog
@close="endCropper ? '' : fileList.pop()"
width="1000px"
v-model="showCropper"
append-to-body
title="需要将图片剪切至规范大小"
:close-on-click-modal="false"
destroy-on-close
>
<cropper
:imgurl="imgurl"
@cropperClone="cropperClone"
:config="FieldItem?.pageType === 'page' ? FieldItem.attrs.cropperCfg : FieldItem!.InputDefine.cropperCfg"
></cropper>
<el-dialog @close="endCropper ? '' : fileList.pop()" width="1000px" v-model="showCropper" append-to-body
title="需要将图片剪切至规范大小" :close-on-click-modal="false" destroy-on-close>
<cropper :imgurl="imgurl" @cropperClone="cropperClone"
:config="FieldItem?.pageType === 'page' ? FieldItem.attrs.cropperCfg : FieldItem!.InputDefine.cropperCfg">
</cropper>
</el-dialog>
</template>
<script lang="ts" setup>
import { reactive, toRefs, onMounted, ref, watch, nextTick, withDefaults } from 'vue';
import { ElMessage, UploadFile, UploadFiles, UploadRawFile, UploadRequestOptions } from 'element-plus';
import { DeleteFilled } from '@element-plus/icons-vue';
import { TabFieldType, TablePageType } from '../custom/DataStructs/commontype';
@ -71,12 +64,25 @@ const props = withDefaults(
{ located: 'table', filterIdx: -1, pageData: () => ({}), inputData: () => ({}), modelValue: '', FieldItem: null }
);
const { FieldItem, located } = toRefs(props);
//
const fileTypeMap = {
'0': '.jpg,.jpeg,.png,.gif', //
'1': '.doc,.docx,.pdf,.txt,.xls,.xlsx,.ppt,.pptx', //
'2': '.mp4,.avi,.mov' //
};
// attrs
const attrs: Record<string, any> = {
listType: FieldItem.value!.InputDefine?.listType || 'picture-card',
drag: FieldItem.value!.InputDefine?.drag || false,
limit: FieldItem.value!.InputDefine?.limit || 1,
action: '#',
autoUpload: false,
autoUpload: true,
// fileType accept
accept: FieldItem.value?.InputDefine?.fileType ?
fileTypeMap[FieldItem.value.InputDefine.fileType] :
(FieldItem.value?.attrs?.fileType ? fileTypeMap[FieldItem.value.attrs.fileType] : undefined)
};
const style = ref<Record<string, any>>({
@ -114,6 +120,8 @@ const { activate, fileList, deleteList, dialogVisible, dialogImageUrl, videoArr,
const progress = ref(false);
const fileUrl = ref(null)
const fileConfig = ref();
if (localStorage.getItem('setting')) {
fileConfig.value = JSON.parse(localStorage.getItem('setting') as string);
@ -127,6 +135,7 @@ if (attrs.listType === 'picture-card') {
}
const init = async () => {
console.log('初始化 upload 组件...');
//
if (FieldItem.value?.pageType === 'page') {
FieldItem.value.InputDataType = 0;
@ -136,9 +145,21 @@ const init = async () => {
FieldItem.value.InputType = 'video';
}
}
fileClient.value = await FileIns.instance(FieldItem.value!.InputDefine);
try {
console.log('初始化 fileClient...');
console.log('InputDefine:', FieldItem.value?.InputDefine);
fileClient.value = await FileIns.instance(FieldItem.value!.InputDefine);
console.log('fileClient 初始化完成:', fileClient.value);
} catch (error) {
console.error('fileClient 初始化失败:', error);
}
};
init();
// init
onMounted(() => {
init();
});
const initFileList = () => {
for (let i = 0; i < tempModelVal.value.length; i++) {
@ -199,7 +220,20 @@ watch(
);
//
const handleBeforeUpload = (file: UploadRawFile) => {
console.log(file);
console.log('beforeUpload:', file);
const fileType = FieldItem.value?.InputDefine?.fileType || FieldItem.value?.attrs?.fileType;
if (fileType) {
const allowedTypes = fileTypeMap[fileType].split(',');
const fileExt = file.name.substring(file.name.lastIndexOf('.')).toLowerCase();
if (!allowedTypes.includes(fileExt)) {
ElMessage.error(`只允许上传${allowedTypes.join('/')}格式的文件`);
return false;
}
}
return true;
};
//
const handleRemove = (file: UploadFile) => {
@ -226,6 +260,10 @@ const handleExceed = () => {
};
//
const handleChange = (file: UploadFile, files: UploadFiles) => {
console.log('handleChange - file status:', file.status);
console.log('handleChange - file:', file);
console.log('handleChange - files:', files);
if (FieldItem?.value?.InputDefine?.cropperCfg?.isCrop || (FieldItem.value?.pageType === 'page' && FieldItem.value.attrs.cropperCfg.isCrop)) {
imgurl.value = file.url || '';
showCropper.value = true;
@ -234,15 +272,37 @@ const handleChange = (file: UploadFile, files: UploadFiles) => {
getDuration();
};
//
const handleUploadRequest = (option: UploadRequestOptions) => {
console.log('handleUploadRequest option', option);
const fileUrl = FileIns.instance().uploadFile();
if (fileUrl === null) {
const handleUploadRequest = async (option: UploadRequestOptions) => {
console.log('开始上传文件...');
console.log('upload options:', option);
console.log('fileClient:', fileClient.value); // fileClient
try {
if (!fileClient.value) {
console.error('fileClient not initialized');
onError();
return;
}
const fileUrl = await fileClient.value.uploadContent(
option.file.name,
option.file,
state
);
console.log('上传返回的 URL:', fileUrl);
if (fileUrl === null) {
console.error('上传失败:返回的 URL 为 null');
onError();
return;
}
fileUrl.value = fileUrl;
onSuccess(fileUrl, fileList.value);
} catch (error) {
console.error('上传失败:', error);
onError();
return;
}
fileList.value.push(fileUrl);
onSuccess(fileUrl, fileList.value);
};
const onSuccess = (file: string, fileList: any[]) => {
console.log('[Debug][File][Upload]success: ', file, fileList);
@ -304,7 +364,7 @@ const uploadSubmit = async () => {
}
if (!fileList.value[i].raw) {
//
item = { name: fileList.value[i].name, url: fileList.value[i].url };
item = { name: fileList.value[i].name, url: fileList.value[i].url };
resList.push(item);
continue;
}
@ -359,16 +419,18 @@ defineExpose({
:deep(.el-upload-dragger) {
padding: v-bind('style.padding');
}
:deep(.el-upload.is-drag) {
display: v-bind('style.display');
}
.delete {
position: absolute;
right: 5px;
top: 5px;
cursor: pointer;
}
// .upload:deep(.el-upload .el-upload--picture-card .is-drag .el-list-move) {
// display: v-bind('displayStyle');
// }
</style>
// }</style>

View File

@ -1,8 +1,10 @@
<template>
<div id="map-container">
<Transition>
<Component :is="popCom" :data="clickData" :visible="visible" @close="close" />
</Transition>
<div class="map-container">
<div id="map-container">
<Transition>
<Component :is="popCom" :data="clickData" :visible="visible" @close="close" />
</Transition>
</div>
</div>
</template>
<script setup>
@ -14,6 +16,7 @@ import BroadcastPopUp from '/@/components/broadcastPopUp/index.vue';
import CameraPopUp from '/@/components/cameraPopUp/index.vue';
import { useCommon } from "/@/stores/common";
import { storeToRefs } from "pinia";
import { debounce } from 'lodash-es'
const commonStore = useCommon()
const { markerData, deviceType } = storeToRefs(commonStore)
@ -52,17 +55,19 @@ import screenImage from '/@/assets/icon-screen.png';
import broadcastImage from '/@/assets/icon-broadcast.png';
const markerMap = new Map();
const currentHighlightMarker = ref(null)
const markers = ref([])
// markerData
watch(() => markerData.value, () => {
console.log('markerData.records 发生变化')
watch(() => markerData.value, debounce(() => {
console.log('markerData 发生变化')
initMarkerData()
}, { deep: true })
}, 200), { deep: true })
// center
watch(center, () => {
console.log('map center 发生变化')
map?.setCenter(center.value, false, 200)
})
watch(center, debounce(() => {
if (map && center.value) {
map.setZoomAndCenter( 15, center.value, false, 500)
}
}, 200))
const close = () => {
visible.value = false
}
@ -125,58 +130,63 @@ const clickScreen = (event) => {
const initMarkerData = async () => {
if (!map) return;
if (!markerData.value) {
console.error('markerData 不存在');
return;
}
if (!map || !markerData.value) return;
//
markers.value.forEach(marker => {
marker.off('click') //
map.remove(marker) //
})
markers.value = [] //
markerMap.clear() // Map
map.clearMap(); //
//
const newMarkers = markerData.value.map(item => {
if (!item.Lng || !item.Lat) return null;
// 使 Promise.all
await Promise.all(markerData.value.map(async (item) => {
if (!item.Lng || !item.Lat) {
console.warn('经纬度不存在', item);
return;
}
let marker = new AMap.Marker({
const marker = new AMap.Marker({
position: new AMap.LngLat(parseFloat(item.Lng), parseFloat(item.Lat)),
offset: new AMap.Pixel(0, 0), // icon [center bottom]
anchor: "bottom-center", //
offset: new AMap.Pixel(0, 0),
anchor: "bottom-center",
icon: new AMap.Icon({
size: new AMap.Size(50, 50),
image: getIcon(),
imageSize: new AMap.Size(50, 50)
})
});
var icon = new AMap.Icon({
size: new AMap.Size(50, 50),
image: getIcon(),
imageSize: new AMap.Size(50, 50)
});
//
const clickHandler = {
'lamp': clickLamp,
'camera': clickCamera,
'screen': clickScreen,
'broadcast': clickBroadcast
}[deviceType.value];
marker.setIcon(icon);
//
if (deviceType.value === 'lamp') {
marker.on('click', clickLamp);
markerMap.set(item.LampID, marker);
} else if (deviceType.value === 'camera') {
marker.on('click', clickCamera);
markerMap.set(item.CameraID, marker);
} else if (deviceType.value === 'screen') {
marker.on('click', clickScreen);
markerMap.set(item.DiaplayID, marker);
} else if (deviceType.value === 'broadcast') {
marker.on('click', clickBroadcast);
markerMap.set(item.BreakerID, marker);
if (clickHandler) {
marker.on('click', clickHandler);
}
marker.setExtData(item);
//
await new Promise((resolve) => {
map?.add(marker);
resolve();
});
}));
// ID
const markerId = item[{
'lamp': 'LampID',
'camera': 'CameraID',
'screen': 'DiaplayID',
'broadcast': 'BreakerID'
}[deviceType.value]];
if (markerId) {
markerMap.set(markerId, marker);
}
return marker;
}).filter(Boolean); //
//
map.add(newMarkers);
markers.value = newMarkers;
}
defineExpose({
@ -209,8 +219,22 @@ onMounted(() => {
});
onUnmounted(() => {
map?.destroy();
});
//
markers.value.forEach(marker => {
marker.off('click')
})
// Map
markers.value = []
markerMap.clear()
//
if (map) {
map.clearMap()
map.destroy()
map = null
}
})
</script>
<style scoped lang="scss">
@ -232,6 +256,12 @@ onUnmounted(() => {
.v-leave-to {
opacity: 0;
}
.map-container {
display: flex;
justify-content: center;
width: 100%;
background-color: #000000;
}
#map-container {
width: 100%;

View File

@ -4,7 +4,8 @@
<el-icon class="close-btn" style="font-size: 30px; color: #006CFF;" @click="close">
<Close />
</el-icon>
<video src="https://sample-videos.com/video321/mp4/720/big_buck_bunny_720p_20mb.mp4"></video>
<!-- <video src="https://sample-videos.com/video321/mp4/720/big_buck_bunny_720p_20mb.mp4"></video> -->
<img src="https://th.bing.com/th/id/R.ca3fe924bfbac323d488b382f6fbb83b?rik=vNQ3wuFYrb2zsQ&riu=http%3a%2f%2fzcgjjsjt.com%2f_20191212%2f1449129436.jpg&ehk=%2fnTSEckavCq%2fAq59QI3G00zDyJH1w9y0C4b8EgFEr%2fY%3d&risl=&pid=ImgRaw&r=0" alt="">
<div class="control">
<div class="setting-box">
<div class="top">
@ -95,7 +96,7 @@ const close = () => {
transform: translate(-50%, -50%);
.content {
padding: 0 50px;
padding: 0 40px;
display: flex;
align-items: center;
gap: 30px;
@ -113,7 +114,7 @@ const close = () => {
}
}
video {
video, img {
width: 252px;
height: 158px;
}

View File

@ -40,7 +40,7 @@ const videoRef = ref(null);
const videoUrl = ref(null);
const flvPlayer = ref(null);
var sdk = null;
var apiUrl = "http://127.0.0.1:9999"
var apiUrl = BASE_API.STREAM_URL
const getStream = async (camera_id, type) => {
try {

View File

@ -12,7 +12,7 @@
</div>
</div>
<div class="right">
<button>返回</button>
<button @click="router.push('/home')">返回</button>
<el-icon color="#fff" size="24">
<Close />
</el-icon>
@ -25,8 +25,8 @@
<div>丈八东路监控</div>
<div>2023.10.12 14:00:00</div>
</div>
<video controls autoplay
src="https://sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4"></video>
<video controls autoplay loop muted
src="/src/assets/video/test.mp4"></video>
</div>
</div>
<div class="other-box">
@ -63,7 +63,7 @@
<div class="handle-box">
<div class="internal-handle">
<div class="label">
内部处
内部处
</div>
<div class="left-icon">
<div class="content yellow">
@ -156,7 +156,7 @@
</div>
<div class="external-linkage">
<div class="label">
内部处理
外部联动
</div>
<div class="left-icon">
<div class="content yellow">
@ -242,15 +242,18 @@ onMounted(() => {
<style scoped lang="scss">
.visualization-container {
position: relative;
min-height: 1080px;
padding: 119px 27.5px 94px 27.5px;
height: 1080px;
overflow-y: hidden;
display: flex;
justify-content: center;
padding: 90px 27.5px;
background: linear-gradient(90deg, #272E42 0%, #304E7E 49%, #272E42 100%);
.data-show {
width: 1862px;
height: 934px;
border: 1px solid #0989d3;
padding: 24px 17px 34px 17px;
padding: 30px 25px;
position: relative;
.header {
@ -309,16 +312,22 @@ onMounted(() => {
height: 34px;
border: 2px solid #0670AC;
background: transparent;
transition: all 0.2s ease-in-out;
}
button:hover {
background: #0b5f8f;
cursor: pointer;
}
}
}
.monitoring-box {
display: flex;
justify-content: space-between;
gap: 35px;
.monitoring {
width: 430px;
max-width: 422px;
height: 227px;
position: relative;
@ -326,7 +335,6 @@ onMounted(() => {
position: absolute;
width: 100%;
height: 100%;
z-index: 1;
background-image: url('/@/assets/monitoring-frame.png');
background-size: 100% 100%;
}
@ -336,7 +344,10 @@ onMounted(() => {
font-size: 15.28px;
position: absolute;
top: 0;
left: 0;
left: 50%;
//
transform: translate(-50%);
height: 34.4px;
width: 100%;
color: #fff;
@ -357,7 +368,7 @@ onMounted(() => {
.other-box {
display: flex;
gap: 60px;
margin-top: 8px;
margin-top: 20px;
.monitoring-search {
width: 367px;

View File

@ -93,7 +93,7 @@ import { NextLoading } from '/@/utils/loading';
import PullDown from '/@/components/pullDown/index.vue';
import EnumOptions from '/@/components/Linxyun/Datas/enum_options.js';
import { httpRequestApi } from '/@/api/linxyun/base'
import { formatDateTimeStr, formatStrByDate } from '/@/utils/formatTime';
import { formatDateTimeStr, formatStrByDate } from '/@/utils/formatTime.ts';
import { Close } from '@element-plus/icons-vue'
const http = httpRequestApi()
const SourceTypes = EnumOptions.instance().getOptions('SourceType')

View File

@ -62,7 +62,9 @@
<span class="sub-title">在线</span>
</div>
<div class="content">
<img class="screen-img" src="https://www.yumus.cn/api/?target=img&brand=bing&ua=m" alt="">
<img class="screen-img"
src="https://bpic.588ku.com/back_origin_min_pic/20/12/01/37f1aca822d87db9356238a1571aed1b.jpg"
alt="">
<div class="control">
<div class="control-title">{{ currentScreen.content }}</div>
<div class="play">
@ -158,11 +160,12 @@ import { CirclePlus, Remove } from '@element-plus/icons-vue';
import { httpRequestApi } from '/@/api/linxyun/base/index';
import { getAllData } from '/@/api/linxyun/common';
import { ElMessage } from 'element-plus';
import { formatDateTimeStr } from '/@/utils/formatTime';
import { formatDateTimeStr } from '/@/utils/formatTime.ts';
import EnumOptions from '/@/components/Linxyun/Datas/enum_options.js';
import { storeToRefs } from 'pinia'
import { useCommon } from '/@/stores/common';
import StreamVideo from '/@/components/streamVideo/index.vue'
const EventTypes = EnumOptions.instance().getOptions('EventType')
const commonStore = useCommon()
const { deviceType, markerData, lampData, screenData, broadcastData, cameraData } = storeToRefs(commonStore)