userName 2025-04-03 17:02:51 +08:00
commit 2be2382c44
19 changed files with 1439 additions and 62 deletions

View File

@ -124,6 +124,7 @@
"mars3d": "~3.8.8",
"mars3d-cesium": "~1.124.0",
"mockjs": "^1.1.0",
"moment": "^2.30.1",
"monaco-editor": "^0.33.0",
"monaco-editor-core": "^0.46.0",
"naive-ui": "2.34.3",

View File

@ -26,6 +26,9 @@ import { useChartDataFetch } from '@/hooks';
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore';
import { EventBus } from '@/utils/eventBus';
import { replaceSqlParams } from '@/utils/sqlHandler';
const props = defineProps({
chartConfig: {
type: Object as PropType<CreateComponentType>,
@ -33,6 +36,9 @@ const props = defineProps({
}
})
const { w, h } = toRefs(props.chartConfig.attr)
const {
colors,
@ -45,37 +51,31 @@ const {
console.log("props.chartConfig",props.chartConfig.option.showColumns);
onMounted(()=>{
const sql = JSON.parse(JSON.stringify(props.chartConfig.request.requestSQLContent)).sql;
const sql = props.chartConfig.request?.requestSQLContent?.sql;
//
EventBus.on(props.chartConfig.id+'dataupdate', (data) => {
props.chartConfig.request.requestSQLContent.sql = replaceSqlParams(sql,{Id:data.id})
// callback
useChartDataFetch(props.chartConfig, useChartEditStore, (resData: any) => {
props.chartConfig.request.requestSQLContent.sql = replaceSqlParams(sql,{Id:data.id})
// props.chartConfig.option.dataset = resData;
let data = [];
// callback
useChartDataFetch(props.chartConfig, useChartEditStore, (resData: any) => {
// props.chartConfig.option.dataset = resData;
let data = [];
props.chartConfig.option.showColumns?.forEach((item,index)=>{
let info = {
title:item.zh_name,
desc:resData[0][firstLetterToLowerCase(item.en_name)]
}
data.push(info);
})
props.chartConfig.option.dataset.data = data;
});
props.chartConfig.option.showColumns?.forEach((item,index)=>{
let info = {
title:item.zh_name,
desc:resData[0][firstLetterToLowerCase(item.en_name)]
}
data.push(info);
})
props.chartConfig.option.dataset.data = data;
});
});
})
function firstLetterToLowerCase(str) {
@ -87,17 +87,6 @@ const handlerShowColumns = ()=> {
}
function replaceSqlParams(sql, params) {
return sql.replace(/#\{([^}]+)\}/g, (match, p1) => {
if (params.hasOwnProperty(p1)) {
//
return typeof params[p1] === 'string' ? `'${params[p1]}'` : params[p1];
}
throw new Error(`缺少参数: ${p1}`);
});
}
</script>
<style lang="scss" scoped>

20
src/utils/sqlHandler.ts Normal file
View File

@ -0,0 +1,20 @@
/**
sql : select * from tableName where 'Id' = #{id} and 'state' = #{state}
params : {id:12343,state:1}
select * from tableName where 'Id' = 12343 and 'state' = 1
*/
export function replaceSqlParams(sql, params) {
return sql.replace(/#\{([^}]+)\}/g, (match, p1) => {
if (params.hasOwnProperty(p1)) {
return typeof params[p1] === 'string' ? `'${params[p1]}'` : params[p1];
}
throw new Error(`缺少参数: ${p1}`);
});
}

View File

@ -0,0 +1,160 @@
<template>
<div class="user-task m-4">
<a-form
ref="formRef"
:model="addForm"
labelAlign="left"
:rules="data.rules"
:label-col="labelCol"
:wrapper-col="wrapperCol"
>
<a-form-item label="防火站点名称" name="siteName">
<a-input v-model:value="addForm.siteName" placeholder="请输入" />
</a-form-item>
<a-form-item label="防火站点地址" name="siteAddress">
<a-space>
<a-input v-model:value="addForm.siteAddress" placeholder="请输入" />
<a-button type="primary" @click="mapVisible = true">选择</a-button>
</a-space>
</a-form-item>
<a-form-item label="站点负责人姓名" name="director">
<a-input v-model:value="addForm.director" placeholder="请输入" />
</a-form-item>
<a-form-item label="负责人电话" name="phone">
<a-input v-model:value="addForm.phone" placeholder="请输入" />
</a-form-item>
<a-form-item label="是否有人值守" name="isonduty">
<a-radio-group name="radioGroup" v-model:value="addForm.isonduty">
<a-radio :value="true"></a-radio>
<a-radio :value="false"></a-radio>
</a-radio-group>
</a-form-item>
<a-form-item label="是否接收进山消息" name="isreceive">
<a-radio-group name="radioGroup" v-model:value="addForm.isreceive">
<a-radio :value="true"></a-radio>
<a-radio :value="false"></a-radio>
</a-radio-group>
</a-form-item>
<a-space>
<span>消息接收人员扫码信息消息接收人员</span>
<a-button danger @click="addPerson"></a-button>
</a-space>
<a-table :columns="data.columns" :data-source="accountList" bordered :pagination="false">
<template #bodyCell="{ column, text, record }">
<template v-if="['name'].includes(column.dataIndex)">
<div>
{{ text }}
</div>
</template>
<template v-else-if="['account'].includes(column.dataIndex)">
<div>
{{ text }}
</div>
</template>
<template v-else-if="column.dataIndex === 'operation'">
<a-button danger @click="onDelete(record.id)" size="small" class="ml-2">删除</a-button>
</template>
</template>
</a-table>
</a-form>
<a-modal
width="60%"
v-model:open="accountVisible"
title="选择人员"
@ok="handleFormulaOk"
:destroyOnClose="true"
>
<SelectAccount ref="SelectAccountRef" />
</a-modal>
<a-modal
width="60%"
v-model:open="mapVisible"
title="选择位置"
@ok="handlePostionOk"
:destroyOnClose="true"
>
<Map ref="PostionRef" />
</a-modal>
</div>
</template>
<script lang="ts" setup>
import { SelectAccount } from './page';
import { reactive, ref, onMounted, watch, defineProps } from 'vue';
import { Map } from './page';
const labelCol = { span: 3 };
const wrapperCol = { span: 6 };
const SelectAccountRef = ref<any>();
const accountVisible = ref(false);
const mapVisible = ref(false);
const accountList = ref([]);
const addForm: any = ref({});
const formRef = ref<any>();
const data = reactive({
rules: {
siteName: [{ required: true, message: '防火站点名称不能为空' }],
siteAddress: [{ required: true, message: '防火站点地址不能为空' }],
director: [{ required: true, message: '站点负责人姓名不能为空' }],
phone: [{ required: true, message: '负责人电话不能为空' }],
},
columns: [
{ title: '用户姓名', dataIndex: 'name' },
{ title: '联系电话', dataIndex: 'account' },
{ title: '操作', dataIndex: 'operation' },
],
tableData: [],
});
const PostionRef = ref();
onMounted(() => {});
const addPerson = () => {
accountVisible.value = true;
};
function onDelete(id) {
const index = accountList.value.findIndex((item) => item.id === id);
accountList.value.splice(index, 1);
}
const handleFormulaOk = () => {
const list = SelectAccountRef.value.getRow();
accountList.value = list;
accountVisible.value = false;
};
const handlePostionOk = () => {
const data = PostionRef.value.getPosition();
console.log(data);
mapVisible.value = false;
};
const createSite = () => {
const params = {
...addForm.value,
accountList: accountList.value,
};
return params;
};
//
function validateForm() {
formRef.value
.validate()
.then(async () => {
return true;
})
.catch(async () => {
return false;
});
}
defineExpose({
createSite,
validateForm,
});
</script>
<style scoped>
::v-deep .ant-alert-info {
margin-bottom: 20px;
}
::v-deep .ant-table-wrapper {
margin-top: 20px;
}
</style>

View File

@ -0,0 +1,70 @@
<template>
<div class="m-4">
<a-descriptions bordered class="mt-4">
<a-descriptions-item label="站点名称"> {{ detailInfo.siteName }}</a-descriptions-item>
<a-descriptions-item label="站点状态">
<a-tag
:color="
detailInfo.state == '未审核'
? 'orange'
: detailInfo.state == '审核通过'
? 'green'
: 'red'
"
size="mini"
>{{ detailInfo.state }}</a-tag
>
</a-descriptions-item>
<a-descriptions-item label="负责人">{{ detailInfo.director }}</a-descriptions-item>
<a-descriptions-item label="负责人电话"> {{ detailInfo.phone }}</a-descriptions-item>
<a-descriptions-item label="是否有人值守">
<a-tag size="mini" v-if="detailInfo.isonduty"></a-tag>
<a-tag size="mini" color="red" v-else></a-tag>
</a-descriptions-item>
<a-descriptions-item label="是否接收进山消息推送">
<a-tag size="mini" v-if="detailInfo.isreceive"></a-tag>
<a-tag size="mini" color="red" v-else></a-tag>
</a-descriptions-item>
<a-descriptions-item label="站点图片">{{ detailInfo.siteImg }}</a-descriptions-item>
<a-descriptions-item label="站点地址">{{ detailInfo.siteAddress }}</a-descriptions-item>
</a-descriptions>
<a-descriptions bordered class="mt-4">
<a-descriptions-item label="接收消息人员">
<a-table :dataSource="dataSource" :columns="columns" />
</a-descriptions-item>
</a-descriptions>
<div class="mt-4">
<a-input style="width: 50%" v-model:value="form.content" placeholder="审核说明" />
<a-button style="margin: 0 20px" type="primary" @click="examine(2)" danger>拒绝</a-button>
<a-button type="primary" @click="examine(1)"></a-button>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
const detailInfo: any = ref({});
const dataSource = ref([]);
const columns = ref([
{
title: '人员名称',
dataIndex: 'name',
key: 'name',
},
{
title: '手机号',
dataIndex: 'account',
key: 'account',
},
]);
const form = ref({
content: '',
});
const examine = (status: number) => {
const params = {
status,
};
console.log(params);
};
</script>

View File

@ -0,0 +1,289 @@
<template>
<div style="position: relative; height: 100%" ref="vChartRef" id="mars3d-container"></div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import * as mars3d from 'mars3d';
let map: mars3d.Map; //
const vChartRef = ref<HTMLElement>();
onMounted(() => {
let options = {
scene: {
center: {
lat: 35.362625,
lng: 118.033886,
alt: 8306.3,
heading: 360,
pitch: -45,
},
scene3DOnly: false,
shadows: false,
removeDblClick: true,
sceneMode: 3,
showSun: true,
showMoon: true,
showSkyBox: true,
showSkyAtmosphere: true,
fog: true,
fxaa: true,
requestRenderMode: true,
contextOptions: {
requestWebgl1: false,
webgl: {
preserveDrawingBuffer: true,
alpha: false,
stencil: true,
powerPreference: 'high-performance',
},
},
globe: {
depthTestAgainstTerrain: false,
baseColor: '#546a53',
showGroundAtmosphere: true,
enableLighting: false,
},
cameraController: {
zoomFactor: 3,
minimumZoomDistance: 1,
maximumZoomDistance: 50000000,
enableRotate: true,
enableTranslate: true,
enableTilt: true,
enableZoom: true,
enableCollisionDetection: true,
minimumCollisionTerrainHeight: 15000,
},
},
control: {
homeButton: false,
baseLayerPicker: false,
sceneModePicker: false,
vrButton: false,
fullscreenButton: false,
navigationHelpButton: false,
animation: false,
timeline: false,
infoBox: false,
geocoder: false,
selectionIndicator: false,
showRenderLoopErrors: true,
contextmenu: {
hasDefault: true,
},
mouseDownView: true,
zoom: {
insertIndex: 1,
},
},
method: {
templateValues: {
dataServer: '//data.mars3d.cn',
gltfServerUrl: '//data.mars3d.cn/gltf',
},
},
terrain: {
url: '//data.mars3d.cn/terrain',
show: true,
clip: true,
},
basemaps: [
{
id: 10,
name: '地图底图',
type: 'group',
opacity: 1,
},
{
id: 2021,
pid: 10,
name: '天地图影像',
icon: 'https://data.mars3d.cn/img/thumbnail/basemap/tdt_img.png',
type: 'group',
layers: [
{
name: '底图',
type: 'tdt',
layer: 'img_d',
eventParent: {
id: 2021,
pid: 10,
name: '天地图影像',
icon: 'https://data.mars3d.cn/img/thumbnail/basemap/tdt_img.png',
type: 'group',
layers: [
{
name: '底图',
type: 'tdt',
layer: 'img_d',
show: true,
},
{
name: '注记',
type: 'tdt',
layer: 'img_z',
show: true,
},
],
show: true,
},
private: false,
id: 'm-a57ecb7d-ba05-47a3-b1be-2e28411a5954',
opacity: 1,
pid: 2021,
parent: {
id: 2021,
pid: 10,
name: '天地图影像',
icon: 'https://data.mars3d.cn/img/thumbnail/basemap/tdt_img.png',
type: 'group',
layers: [
{
name: '底图',
type: 'tdt',
layer: 'img_d',
show: true,
},
{
name: '注记',
type: 'tdt',
layer: 'img_z',
show: true,
},
],
show: true,
},
zIndex: 1,
},
{
name: '注记',
type: 'tdt',
layer: 'img_z',
eventParent: {
id: 2021,
pid: 10,
name: '天地图影像',
icon: 'https://data.mars3d.cn/img/thumbnail/basemap/tdt_img.png',
type: 'group',
layers: [
{
name: '底图',
type: 'tdt',
layer: 'img_d',
show: true,
},
{
name: '注记',
type: 'tdt',
layer: 'img_z',
show: true,
},
],
show: true,
},
private: false,
id: 'm-671f9d42-dda7-45ec-9d0f-4259c915b2cb',
opacity: 1,
pid: 2021,
parent: {
id: 2021,
pid: 10,
name: '天地图影像',
icon: 'https://data.mars3d.cn/img/thumbnail/basemap/tdt_img.png',
type: 'group',
layers: [
{
name: '底图',
type: 'tdt',
layer: 'img_d',
show: true,
},
{
name: '注记',
type: 'tdt',
layer: 'img_z',
show: true,
},
],
show: true,
},
zIndex: 2,
},
],
show: true,
opacity: 1,
},
],
layers: [],
};
initMap(options);
});
const isFirstLoad = ref(true);
const idNum = ref(0);
let graphicLayer = null;
const pointGraphic = ref();
const pointData = ref();
const initMap = (newData: any) => {
//
if (isFirstLoad.value) {
map = new mars3d.Map(vChartRef.value, newData);
} else {
//
// map.setOptions(newData);
map.setSceneOptions(newData.scene);
}
isFirstLoad.value = false;
//
handlerInitEntityLayer();
//
const pointLayer = new mars3d.layer.GraphicLayer({
name: 'PointLayer',
hasEdit: false,
isAutoEditing: false,
});
map.addLayer(pointLayer);
map.on(mars3d.EventType.click, function (event) {
console.log('click', event);
var point = mars3d.LngLatPoint.fromCartesian(event.cartesian); //
point.format(); //
pointData.value = point;
console.log('鼠标单击坐标', point);
console.log('经度:' + point.lng + '\n' + '纬度:' + point.lat + '\n' + '高度:' + point._alt);
if (idNum.value > 0) {
pointLayer.removeGraphic(pointGraphic.value);
}
//
const coordinates = [point.lng, point.lat];
//
// Mars3D ()
pointGraphic.value = new mars3d.graphic.BillboardEntity({
position: coordinates,
attr: point,
style: {
pixelSize: 100,
scale: 0.5,
image: '/positioning.png',
},
});
//
pointLayer.addGraphic(pointGraphic.value);
idNum.value = idNum.value + 1;
});
};
//
const handlerInitEntityLayer = () => {
if (graphicLayer == null) {
graphicLayer = new mars3d.layer.GraphicLayer({ id: 999 });
}
};
const getPosition = () => {
return pointData.value;
};
defineExpose({
getPosition,
});
</script>
<style lang="less" scoped></style>

View File

@ -0,0 +1,57 @@
<template>
<div class="select-account">
<BasicTable @register="registerTable" :searchInfo="searchInfo" />
</div>
</template>
<script lang="ts" setup>
import { reactive } from 'vue';
import { BasicTable, useTable } from '@/components/Table';
import { getAccountList } from '@/api/demo/system';
import { SelectColumns, SelectSearchFormSchema } from './data';
defineOptions({ name: 'AccountManagement' });
const searchInfo = reactive<Recordable>({});
const [registerTable, { reload, updateTableDataRecord, getSelectRows, clearSelectedRowKeys }] =
useTable({
title: '用户列表',
api: getAccountList,
rowKey: 'id',
columns: SelectColumns,
formConfig: {
labelWidth: 120,
schemas: SelectSearchFormSchema,
autoSubmitOnEnter: true,
},
rowSelection: {
//
type: 'checkbox',
},
useSearchForm: true,
showTableSetting: false,
bordered: true,
tableSetting: { fullScreen: true },
isCanResizeParent: true,
handleSearchInfoFn(info) {
console.log('handleSearchInfoFn', info);
return info;
},
});
function getRow() {
let rows = getSelectRows();
console.log(rows);
return rows;
}
defineExpose({
getRow,
});
</script>
<style scoped>
.select-account {
display: flex;
height: 100%;
}
</style>

View File

@ -0,0 +1,186 @@
import { BasicColumn, FormSchema } from '@/components/Table';
import { h } from 'vue';
import { Tag } from 'ant-design-vue';
import { getPosGroupList } from '@/api/demo/system';
export const columns: BasicColumn[] = [
{
title: '站点名称',
dataIndex: 'siteName',
},
{
title: '站点地址',
dataIndex: 'siteAddress',
},
{
title: '站点名称',
dataIndex: 'siteName',
},
{
title: '排序',
dataIndex: 'sortNo',
},
{
title: '审核状态',
dataIndex: 'state',
width: 80,
customRender: ({ record }) => {
const status = record.state;
let color = '';
const text = status;
if (status == '未审核') {
color = 'orange';
} else if (status == '审核通过') {
color = 'green';
} else {
color = 'red';
}
return h(Tag, { color: color }, () => text);
},
},
{
title: '负责人',
dataIndex: 'director',
},
{
title: '负责人电话',
dataIndex: 'phone',
},
];
export const searchFormSchema: FormSchema[] = [
{
field: 'state',
label: '审核状态',
component: 'Select',
colProps: { span: 8 },
defaultValue: 3,
componentProps: {
options: [
{
value: 0,
label: '未审核',
},
{
value: 1,
label: '审核通过',
},
{
value: 2,
label: '未通过',
},
{
value: 3,
label: '全部',
},
],
},
},
{
field: 'siteName',
label: '站点名称',
component: 'Input',
colProps: { span: 8 },
},
];
export const formGroupSchema: FormSchema[] = [
{
field: 'posGroupId',
component: 'ApiSelect',
label: '职级组',
required: true,
componentProps: ({ formActionType, formModel }) => {
return {
api: getPosGroupList, // 接口
// 接口参数
resultField: 'result',
labelField: 'name',
valueField: 'id',
};
},
},
];
export const formSchema: FormSchema[] = [
{
field: 'id',
label: '部门id',
component: 'Input',
ifShow: true,
},
{
field: 'name',
label: '部门名称',
component: 'Input',
required: true,
},
{
field: 'parentId',
label: '上级部门',
component: 'TreeSelect',
componentProps: {
fieldNames: {
label: 'name',
key: 'id',
value: 'id',
},
onChange: (value) => {
console.log(value);
},
getPopupContainer: () => document.body,
},
// required: true,
},
// {
// field: 'orderNo',
// label: '排序',
// component: 'InputNumber',
// required: true,
// },
{
field: 'status',
label: '状态',
component: 'RadioButtonGroup',
defaultValue: 0,
componentProps: {
options: [
{ label: '启用', value: 0 },
{ label: '停用', value: 1 },
],
},
required: true,
},
// {
// label: '备注',
// field: 'remark',
// component: 'InputTextArea',
// },
];
export const SelectColumns: BasicColumn[] = [
{
title: '用户名',
dataIndex: 'account',
width: 120,
},
{
title: '昵称',
dataIndex: 'name',
width: 120,
},
{
title: '所属部门',
dataIndex: 'organizations',
// customRender: ({ value }) => {
// return deptMap[value];
// },
},
];
export const SelectSearchFormSchema: FormSchema[] = [
{
field: 'account',
label: '用户名',
component: 'Input',
colProps: { span: 8 },
},
];

View File

@ -0,0 +1,158 @@
<template>
<PageWrapper dense contentFullHeight fixedHeight contentClass="flex">
<BasicTable @register="registerTable" :searchInfo="searchInfo">
<template #toolbar>
<PermissionBtn @btn-event="onBtnClicked" />
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'action'">
<TableAction
:actions="[
{
// icon: 'ant-design:ellipsis-outlined',
label: '详情',
onClick: viewDetail.bind(null, record),
},
]"
/>
</template>
</template>
</BasicTable>
<a-modal
v-model:visible="addModelVisible"
title="站点信息"
wrap-class-name="full-modal"
width="80%"
@ok="handleOk"
>
<AddModal ref="AddModalRef" />
</a-modal>
<a-modal
v-model:visible="detailModelVisible"
title="站点信息"
wrap-class-name="full-modal"
width="80%"
:footer="null"
>
<Detail @close="closeDetail" />
</a-modal>
</PageWrapper>
</template>
<script lang="ts" setup>
import { reactive, ref } from 'vue';
import { BasicTable, useTable, TableAction } from '@/components/Table';
import { getOrgList, deleteDept } from '@/api/demo/system';
import { PageWrapper } from '@/components/Page';
import { useMessage } from '@/hooks/web/useMessage';
import { AddModal, Detail } from './page';
import { PermissionBtn } from '@/components/PermissionBtn/index';
import { columns, searchFormSchema } from './data';
defineOptions({ name: 'DeptManagement' });
const { createConfirm, createMessage } = useMessage();
const AddModalRef = ref();
const searchInfo = reactive<Recordable>({});
const addModelVisible = ref(false);
const detailModelVisible = ref(false);
const [registerTable, { reload, getSelectRows, clearSelectedRowKeys }] = useTable({
//
title: '站点列表',
//
api: getOrgList,
// BasicColumn[]
columns,
rowKey: 'id',
formConfig: {
labelWidth: 120,
schemas: searchFormSchema,
},
// 使
useSearchForm: true,
//
showTableSetting: true,
//
bordered: true,
//
showIndexColumn: false,
//
rowSelection: {
//
// type: 'checkbox',
type: 'radio',
},
//
handleSearchInfoFn(info) {
return info;
},
actionColumn: {
width: 80,
title: '操作',
dataIndex: 'action',
// slots: { customRender: 'action' },
fixed: undefined,
},
});
const childRef = ref<any>();
function handleCreate() {
addModelVisible.value = true;
}
function handleEdit() {
let rows = getSelectRows();
if (rows.length == 0) {
return createMessage.warn('请选择一个站点进行编辑');
}
const record = rows[0];
addModelVisible.value = true;
}
function onBtnClicked(domId) {
switch (domId) {
case 'btnAdd':
handleCreate();
break;
case 'btnEdit':
handleEdit();
break;
case 'btnExport':
break;
default:
break;
}
}
function handleSuccess() {
clearSelectedRowKeys();
childRef.value.fetch();
reload();
}
const handleOk = () => {
AddModalRef.value.validateForm();
const params = AddModalRef.value.createSite();
console.log('params', params);
};
const viewDetail = (record: any) => {
console.log('record', record);
detailModelVisible.value = true;
};
const closeDetail = () => {
detailModelVisible.value = false;
};
</script>
<style lang="less">
.full-modal {
.ant-modal {
max-width: 80%;
}
.ant-modal-content {
height: calc(80vh);
}
.ant-modal-body {
height: 100%;
}
}
</style>

View File

@ -0,0 +1,4 @@
export { default as AddModal } from './AddModal.vue';
export { default as SelectAccount } from './SelectAccount.vue';
export { default as Map } from './Map.vue';
export { default as Detail } from './Detail.vue';

View File

@ -0,0 +1,139 @@
<template>
<BasicModal v-bind="$attrs" @register="registerModal" :title="getTitle" @ok="handleSubmit">
<BasicForm @register="registerForm">
<template #areaId="{ model, field }">
<a-tree-select
show-search
style="width: 100%"
v-model:value="model[field]"
:tree-data="treeData"
:field-names="{ label: 'name', value: 'id' }"
placeholder="请选择"
allow-clear
multiple
/>
</template>
<template #time="{ model, field }">
<div>
<div class="flex mt-1" v-for="(item, index) in timeslot" :key="index">
<a-time-picker
placeholder="开始时间"
@change="(time, timeString) => beginTimeChange(time, timeString, index)"
v-model:value="item.beginTime"
/>
~
<a-time-picker
placeholder="结束时间"
@change="(time, timeString) => endTimeChange(time, timeString, index)"
v-model:value="item.endTime"
/>
<CloseCircleOutlined style="margin-left: 10px" @click="delTime(index)" />
</div>
<a-button type="primary" style="margin-top: 10px" @click="addTime"></a-button>
</div>
</template>
</BasicForm>
</BasicModal>
</template>
<script lang="ts" setup>
import { ref, computed, unref, onMounted } from 'vue';
import { BasicModal, useModalInner } from '@/components/Modal';
import { BasicForm, useForm } from '@/components/Form';
import { formSchema } from './data';
import { CloseCircleOutlined } from '@ant-design/icons-vue';
import { addRole, updateRole, getDeptList } from '@/api/demo/system';
import { useMessage } from '@/hooks/web/useMessage';
import moment from 'moment';
const { createMessage } = useMessage();
const treeData: any = ref([]);
const timeslot: any = ref([]);
const timeList: any = ref([]);
defineOptions({ name: 'DeptModal' });
onMounted(() => {
getTreeList();
});
const emit = defineEmits(['success', 'register']);
const isUpdate = ref(true);
const [registerForm, { resetFields, setFieldsValue, validate }] = useForm({
labelWidth: 100,
baseColProps: { span: 24 },
schemas: formSchema,
showActionButtonGroup: false,
});
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
resetFields();
setModalProps({ confirmLoading: false });
isUpdate.value = !!data?.isUpdate;
if (unref(isUpdate)) {
setFieldsValue({
...data.record,
});
}
});
const getTitle = computed(() => (!unref(isUpdate) ? '新增角色' : '编辑角色'));
async function handleSubmit() {
try {
const values = await validate();
let query = values;
//
if (!unref(isUpdate)) {
const data = await addRole(query);
if (data) {
setModalProps({ confirmLoading: true });
// TODO custom api
closeModal();
emit('success');
return createMessage.success('新增成功');
} else {
return createMessage.error('新增失败');
}
} else {
const data = await updateRole(query);
if (data) {
setModalProps({ confirmLoading: true });
// TODO custom api
closeModal();
emit('success');
return createMessage.success('编辑成功');
} else {
return createMessage.error('编辑失败');
}
}
} finally {
setModalProps({ confirmLoading: false });
}
}
const getTreeList = async () => {
getDeptList().then((res) => {
treeData.value = res;
});
};
const delTime = (index) => {
timeslot.value.splice(index, 1);
timeList.value.splice(index, 1);
};
const addTime = () => {
timeslot.value.push({
beginTime: '',
endTime: '',
});
timeList.value.push({
beginTime: '',
endTime: '',
});
};
const beginTimeChange = (time, timeString, index) => {
timeList.value[index].beginTime = timeString;
};
const endTimeChange = (time, timeString, index) => {
timeList.value[index].endTime = timeString;
};
</script>

View File

@ -0,0 +1,83 @@
import { BasicColumn, FormSchema } from '@/components/Table';
export const columns: BasicColumn[] = [
{
title: '账号',
dataIndex: 'Account',
},
{
title: '姓名',
dataIndex: 'Name',
},
{
title: '性别',
dataIndex: 'Sex',
customRender: ({ record }) => {
const status = record.Sex;
const enable = ~~status === 0;
const text = enable ? '男' : '女';
return text;
},
},
];
export const searchFormSchema: FormSchema[] = [
{
field: 'key',
label: '关键字',
component: 'Input',
colProps: { span: 8 },
},
];
export const formSchema: FormSchema[] = [
{
field: 'id',
label: '角色名称',
required: true,
component: 'Input',
ifShow: false,
},
{
field: 'name',
label: '人员姓名',
required: true,
component: 'Input',
},
{
field: 'account',
label: '账号/手机号',
required: true,
component: 'Input',
},
{
field: 'sex',
component: 'RadioGroup',
label: '人员性别',
colProps: {
span: 8,
},
componentProps: {
options: [
{
label: '男',
value: 0,
},
{
label: '女',
value: 1,
},
],
},
},
{
field: 'areaId',
label: '所属机构',
slot: 'areaId',
},
{
field: 'time',
label: '打卡时间',
slot: 'time',
},
];

View File

@ -0,0 +1,131 @@
<template>
<div>
<BasicTable @register="registerTable" :searchInfo="searchInfo">
<template #toolbar>
<PermissionBtn @btn-event="onBtnClicked" />
</template>
</BasicTable>
<AddModal @register="registerModal" @success="handleSuccess" />
</div>
</template>
<script lang="ts" setup>
import { reactive } from 'vue';
import { BasicTable, useTable } from '@/components/Table';
import { getRoleListByPage, deleteRole } from '@/api/demo/system';
import { useMessage } from '@/hooks/web/useMessage';
import { useModal } from '@/components/Modal';
import { AddModal } from './page';
import { PermissionBtn } from '@/components/PermissionBtn/index';
import { columns, searchFormSchema } from './data';
defineOptions({ name: 'RoleManagement' });
const { createConfirm, createMessage } = useMessage();
const [registerModal, { openModal: openRoleModal }] = useModal();
const searchInfo = reactive<Recordable>({});
const [registerTable, { reload, getSelectRows, clearSelectedRowKeys }] = useTable({
//
title: '角色列表',
//
api: getRoleListByPage,
// BasicColumn[]
columns,
rowKey: 'id',
formConfig: {
labelWidth: 120,
schemas: searchFormSchema,
},
// 使
useSearchForm: true,
//
showTableSetting: true,
//
bordered: true,
//
showIndexColumn: false,
//
rowSelection: {
//
// type: 'checkbox',
type: 'radio',
},
//
handleSearchInfoFn(info) {
return info;
},
});
function handleCreate() {
openRoleModal(true, {
isUpdate: false,
});
}
function handleEdit() {
let rows = getSelectRows();
if (rows.length == 0) {
return createMessage.warn('请勾选一个角色进行编辑');
}
const record = rows[0];
openRoleModal(true, {
record,
isUpdate: true,
});
}
async function handleDelete() {
let rows = getSelectRows();
if (rows.length == 0) {
return createMessage.warn('请勾选一个角色进行删除');
}
const query = [rows[0].id];
createConfirm({
iconType: 'info',
title: '删除',
content: '确定要删除当前角色吗',
onOk: async () => {
const data = await deleteRole(query);
if (data) {
handleSuccess();
createMessage.success('删除成功');
} else {
createMessage.error('删除失败');
}
},
});
}
function handleSuccess() {
clearSelectedRowKeys();
reload();
}
function onBtnClicked(domId) {
switch (domId) {
case 'btnAdd':
handleCreate();
break;
case 'btnEdit':
handleEdit();
break;
case 'btnDelete':
handleDelete();
break;
case 'btnModules':
let rows = getSelectRows();
if (rows.length == 0) {
return createMessage.warn('请勾选一个角色进行编辑');
}
const record = rows[0];
openModulesModal(true, {
record,
});
break;
default:
break;
}
}
</script>

View File

@ -0,0 +1 @@
export { default as AddModal } from './AddModal.vue';

View File

@ -8,12 +8,8 @@
:dropdown-style="{ maxHeight: '400px', overflow: 'auto' }"
:tree-data="treeData"
placeholder="选择行政区划"
tree-default-expand-all
>
<template #title="{ key, value }">
<span style="color: #08c" v-if="key === '0-0-1'">Child Node1 {{ value }}</span>
</template>
</a-tree-select>
:field-names="{ label: 'name', value: 'id' }"
/>
<!-- formState.isonline -->
<a-select ref="select" v-model:value="formState.isonline" style="width: 120px">
<a-select-option :value="item.value" v-for="item in stateOptions" :key="item.value">{{
@ -89,6 +85,7 @@
import { EventBus } from '@/utils/eventBus';
import { useMessage } from '@/hooks/web/useMessage';
import { getPatrolPointByTimeSubsection } from '@/api/firegrid/patrol';
import { getDeptList } from '@/api/demo/system';
const { createMessage } = useMessage();
defineOptions({ name: 'DeptModal' });
@ -97,6 +94,12 @@
online: 0,
offline: 0,
});
const treeData: any = ref([]);
const getTree = () => {
getDeptList().then((res) => {
treeData.value = res;
});
};
const routerLine = ref([]);
const [registerTable, { reload, getSelectRows, clearSelectedRowKeys, setTableData }] = useTable({
//
@ -219,6 +222,7 @@
};
onMounted(() => {
getLine();
getTree();
});
</script>
<style lang="less" scoped>

View File

@ -3,17 +3,14 @@
<div class="flex justify-around items-center form-data m-4">
<a-input v-model:value="formState.keyWord" placeholder="输入关键字" style="width: 30%" />
<a-tree-select
v-model:value="formState.orgId"
v-model:value="formState.areaid"
style="width: 30%"
:dropdown-style="{ maxHeight: '400px', overflow: 'auto' }"
:tree-data="treeData"
:field-names="{ label: 'name', value: 'id' }"
placeholder="选择行政区划"
tree-default-expand-all
>
<template #title="{ key, value }">
<span style="color: #08c" v-if="key === '0-0-1'">Child Node1 {{ value }}</span>
</template>
</a-tree-select>
allow-clear
/>
<div class="form-button">
<a-button type="primary" @click="getTaskList"></a-button>
<a-button type="primary" @click="toStatic"></a-button>
@ -21,7 +18,11 @@
</div>
</div>
<div class="table-data">
<div class="clock-item-container">
<div style="width: 100%; text-align: center; padding: 100px 0px" v-if="tasklist.length <= 0">
<img src="@/assets/images/canvas/noData.png" style="width: 140px; margin-bottom: 20px" />
<p style="color: #cfcfcf">暂无数据</p>
</div>
<div class="clock-item-container" v-else>
<div class="clock-item" v-for="(item, index) in tasklist" :key="index">
<div class="clock-item-icon">
<img src="@/assets/images/meshing/clockIn-bg.png" />
@ -90,6 +91,7 @@
import { getCheckPointList, deleteCheckPoint } from '@/api/firegrid/index';
import { useMessage } from '@/hooks/web/useMessage';
import { EventBus } from '@/utils/eventBus';
import { getDeptList } from '@/api/demo/system';
const { createMessage } = useMessage();
const emits = defineEmits(['viewHandle']);
@ -97,6 +99,7 @@
const statisticsModalVisible = ref(false);
const InspectionModelVisible = ref(false);
onMounted(() => {
getTree();
getTaskList();
EventBus.on('addCheckPoint', (data) => {
getTaskList();
@ -104,8 +107,8 @@
});
//
interface FormState {
keyWord: string;
orgId: string;
keyWord: string | null;
areaid: string | null;
}
interface listObj {
Id: number;
@ -116,16 +119,21 @@
CreateUserName: string;
}
const formState: UnwrapRef<FormState> = reactive({
keyWord: '',
orgId: '',
keyWord: null,
areaid: null,
});
const treeData = ref([]);
const treeData: any = ref([]);
//
const pageData = reactive({
total: 100,
current: 1,
pageSize: 10,
});
const getTree = () => {
getDeptList().then((res) => {
treeData.value = res;
});
};
const paginationOnChange = (page: number) => {
pageData.current = page;
getTaskList();
@ -141,7 +149,8 @@
const params = {
page: pageData.current,
limit: pageData.pageSize,
pointName: formState.orgId,
pointName: formState.keyWord,
areaid: formState.areaid,
};
EventBus.emit('getPatrolMap', params);
getCheckPointList(params).then((res) => {

View File

@ -42,6 +42,7 @@
format="YYYY-MM-DD HH:mm"
:placeholder="['开始时间', '结束时间']"
@change="timeChange"
v-model:value="value1"
/>
</div>
@ -137,6 +138,7 @@
import { getCheckInfoByPointId } from '@/api/firegrid/index';
import { getPatrolInfoByUserId } from '@/api/firegrid/patrol';
import { EventBus } from '@/utils/eventBus';
import moment from 'moment';
const props = defineProps({
itemData: Object,
@ -175,9 +177,30 @@
currentRouters.value = res;
});
};
const value1: any = ref([]);
onMounted(() => {
getPointInfo();
getPatrolInfo();
let start = new Date();
let end = new Date();
const time = [
end.getFullYear() + '-' + (end.getMonth() + 1) + '-' + end.getDate() + ' 00:00:00',
start.getFullYear() +
'-' +
(start.getMonth() + 1) +
'-' +
start.getDate() +
' ' +
start.getHours() +
':' +
start.getMinutes() +
':' +
start.getSeconds(),
];
formState.begintime = time[0];
formState.endtime = time[1];
value1.value = [moment(time[0], 'YYYY-MM-DD HH:mm'), moment(time[1], 'YYYY-MM-DD HH:mm')];
});
</script>
<style lang="less" scoped>

View File

@ -7,6 +7,7 @@
format="YYYY-MM-DD HH:mm"
:placeholder="['开始时间', '结束时间']"
@change="timeChange"
v-model:value="value1"
/>
</div>
<a-tabs v-model:activeKey="activeKey">
@ -91,6 +92,7 @@
} from '@ant-design/icons-vue';
import { getCheckInfoByUserId } from '@/api/firegrid/index';
import { getPatrolInfoByUserId } from '@/api/firegrid/patrol';
import moment from 'moment';
defineOptions({ name: 'DeptModal' });
const props = defineProps({
@ -140,9 +142,29 @@
list.value = res;
});
};
const value1: any = ref([]);
onMounted(() => {
getCheckList();
getPatrolList();
let start = new Date();
let end = new Date();
const time = [
end.getFullYear() + '-' + (end.getMonth() + 1) + '-' + end.getDate() + ' 00:00:00',
start.getFullYear() +
'-' +
(start.getMonth() + 1) +
'-' +
start.getDate() +
' ' +
start.getHours() +
':' +
start.getMinutes() +
':' +
start.getSeconds(),
];
formState.begintime = time[0];
formState.endtime = time[1];
value1.value = [moment(time[0], 'YYYY-MM-DD HH:mm'), moment(time[1], 'YYYY-MM-DD HH:mm')];
});
</script>
<style lang="less" scoped>

View File

@ -7,20 +7,17 @@
:dropdown-style="{ maxHeight: '400px', overflow: 'auto' }"
:tree-data="treeData"
placeholder="选择行政区划"
tree-default-expand-all
>
<template #title="{ key, value }">
<span style="color: #08c" v-if="key === '0-0-1'">Child Node1 {{ value }}</span>
</template>
</a-tree-select>
:field-names="{ label: 'name', value: 'id' }"
/>
<a-range-picker
:show-time="{ format: 'HH:mm' }"
format="YYYY-MM-DD HH:mm"
:placeholder="['开始时间', '结束时间']"
@change="timeChange"
v-model:value="value1"
/>
<div class="form-button">
<a-button type="primary" @click="getCount"></a-button>
<a-button type="primary" @click="inquire"></a-button>
<a-button type="primary">导出</a-button>
</div>
</div>
@ -74,7 +71,7 @@
{
// icon: 'ant-design:ellipsis-outlined',
label: '巡查轨迹',
onClick: getGuiji.bind(null,record),
onClick: getGuiji.bind(null, record),
},
]"
/>
@ -99,9 +96,17 @@
import { getStatistics, getStatisticsCount } from '@/api/firegrid/index';
import { columns } from './data';
import { PatrolTrackModel } from './index';
import { getDeptList } from '@/api/demo/system';
import moment from 'moment';
defineOptions({ name: 'DeptModal' });
const patrolTrackModelVisible = ref(false);
const treeData: any = ref([]);
const getTree = () => {
getDeptList().then((res) => {
treeData.value = res;
});
};
const [registerTable, { reload, getSelectRows, clearSelectedRowKeys }] = useTable({
//
title: '角色列表',
@ -154,6 +159,7 @@
areaid: null,
});
const timeChange = (value: any, dateString: string) => {
console.log(dateString);
formState.begintime = dateString[0];
formState.endtime = dateString[1];
};
@ -162,8 +168,33 @@
allData.value = res;
});
};
const inquire = () => {
getCount();
reload();
};
const value1: any = ref([]);
onMounted(() => {
getCount();
getTree();
let start = new Date();
let end = new Date();
const time = [
end.getFullYear() + '-' + (end.getMonth() + 1) + '-' + end.getDate() + ' 00:00:00',
start.getFullYear() +
'-' +
(start.getMonth() + 1) +
'-' +
start.getDate() +
' ' +
start.getHours() +
':' +
start.getMinutes() +
':' +
start.getSeconds(),
];
formState.begintime = time[0];
formState.endtime = time[1];
value1.value = [moment(time[0], 'YYYY-MM-DD HH:mm'), moment(time[1], 'YYYY-MM-DD HH:mm')];
});
</script>
<style lang="less" scoped>