Browse Source

Merge pull request 'feat 测点管理模块' (#16) from dev-xjf into master

Reviewed-on: http://120.26.116.243:3000/root/alert-front/pulls/16
xiaojinfei-patch-1
xiaojinfei 2 months ago
parent
commit
8d26213be4
  1. 11
      .vscode/sftp.json
  2. 1
      package.json
  3. 15577
      pnpm-lock.yaml
  4. 75
      src/api/alert/exa/index.ts
  5. 1
      src/components/Container/src/LazyContainer.vue
  6. 6
      src/layouts/default/footer/index.vue
  7. 3
      src/layouts/default/header/index.vue
  8. 4
      src/locales/lang/en/action.json
  9. 4
      src/locales/lang/zh-CN/action.json
  10. 3
      src/main.ts
  11. 4
      src/utils/http/axios/index.ts
  12. 2
      src/views/config/index.vue
  13. 114
      src/views/exa/EXAHistoryLine.vue
  14. 60
      src/views/exa/config/CreateBatchModal.vue
  15. 95
      src/views/exa/config/EXAModal.vue
  16. 77
      src/views/exa/config/HistoryModal.vue
  17. 154
      src/views/exa/config/index.vue
  18. 128
      src/views/exa/exa.data.ts
  19. 240
      src/views/exa/history/PointModal.vue
  20. 260
      src/views/exa/history/index copy.vue
  21. 105
      src/views/exa/history/index.vue

11
.vscode/sftp.json

@ -0,0 +1,11 @@
{
"name": "My Server",
"host": "120.26.116.243",
"protocol": "sftp",
"port": 22,
"username": "root",
"remotePath": "/",
"uploadOnSave": false,
"useTempFile": false,
"openSsh": false
}

1
package.json

@ -61,6 +61,7 @@
"dayjs": "^1.11.10",
"echarts": "^5.4.3",
"lodash-es": "^4.17.21",
"moment": "^2.30.1",
"nprogress": "^0.2.0",
"path-to-regexp": "^6.2.1",
"pinia": "^2.1.7",

15577
pnpm-lock.yaml

File diff suppressed because it is too large

75
src/api/alert/exa/index.ts

@ -0,0 +1,75 @@
import { integer } from 'vue-types'
import { defHttp } from '@/utils/http/axios'
export interface EXAPageReqVO extends PageParam {
condition?: string
}
export interface EXAHistoryReqVO {
itemName?: string
startTime?: Date
endTime?: Date
}
export interface EXANowReqVO {
itemName?: string
}
export interface EXAPoint {
AssetCode?: string
ItemName?: string
GroupName?: string
ItemType?: number
Descriptor?: string
EngUnits?: string
Source?: string
AutoSave?: number
UpperBound?: number
LowerBound?: number
UpperLimit?: number
LowerLimit?: number
UpperUpperLimit?: number
LowerLowerLimit?: number
Comment?: string
Note?: string
}
// 查询测点列表
export function getEXAPage(params: EXAPageReqVO) {
return defHttp.get({ url: '/alert/exa/page', params })
}
// 查询实时值列表
export function getExaNowList(itemName: string) {
return defHttp.get({ url: `/alert/exa/nowList?itemName=${itemName}` })
}
export function getExaNow(itemName: string) {
return defHttp.get({ url: `/alert/exa/now?itemName=${itemName}` })
}
// 查询历史值-单点
export function getExaHistory(params: EXAHistoryReqVO) {
return defHttp.get({ url: '/alert/exa/history', params })
}
// 查询历史值-多点
export function getExaHistorys(params: EXAHistoryReqVO) {
return defHttp.get({ url: '/alert/exa/historys', params })
}
// 新增点
export function createEXAPoint(data: EXAPoint) {
return defHttp.post({ url: '/alert/exa/create', data })
}
// 获取全部组名
export function getGroup() {
return defHttp.get({ url: '/alert/exa/group' })
}
// 删除点
export function deletePoint(ItemName: string) {
return defHttp.delete({ url: `/alert/exa/delete?ItemName=${ItemName}` })
}

1
src/components/Container/src/LazyContainer.vue

@ -51,6 +51,7 @@ interface State {
}
const elRef = ref()
const state = reactive<State>({
isInit: false,
loading: false,

6
src/layouts/default/footer/index.vue

@ -39,14 +39,14 @@ const getShowLayoutFooter = computed(() => {
<template>
<Footer v-if="getShowLayoutFooter" ref="footerRef" class="text-center text-[var(--normal-text)]">
<div class="mb-2">
<!-- <div class="mb-2">
<a class="text-[var(--normal-text)] hover:text-[var(--hover-text)]" @click="openWindow(SITE_URL)">外包咨询</a>
<GithubFilled class="mx-7.5 hover:text-[var(--hover-text)]" @click="openWindow(GITHUB_URL)" />
<a class="text-[var(--normal-text)] hover:text-[var(--hover-text)]" @click="openWindow(DOC_URL)">{{
t('layout.footer.onlineDocument') }}</a>
</div>
<div>Copyright &copy;2023 {{ SITE_TITLE }}</div>
</div> -->
<div>Copyright &copy;2025 {{ SITE_TITLE }}</div>
</Footer>
</template>

3
src/layouts/default/header/index.vue

@ -96,6 +96,7 @@ const getMenuMode = computed(() => {
:theme="getHeaderTheme" :sider="false"
/>
<LayoutBreadcrumb v-if="getShowContent && getShowBread" :theme="getHeaderTheme" />
</div>
<!-- left end -->
@ -107,6 +108,8 @@ const getMenuMode = computed(() => {
<!-- action -->
<div :class="`${prefixCls}-action`">
<AppSearch v-if="getShowSearch" :class="`${prefixCls}-action__item search-item`" />
<ErrorAction v-if="getUseErrorHandle" :class="`${prefixCls}-action__item error-action`" />

4
src/locales/lang/en/action.json

@ -9,5 +9,7 @@
"more": "more",
"sync": "Sync",
"test": "Test",
"view": "View"
"view": "View",
"clearAllandClose": "ClearAllAndClose",
"createBatch": "CreateBatch"
}

4
src/locales/lang/zh-CN/action.json

@ -10,5 +10,7 @@
"send": "发送",
"sync": "同步",
"test": "测试",
"view": "查看"
"view": "查看",
"clearAllandClose": "清空并关闭",
"createBatch": "批量导入"
}

3
src/main.ts

@ -1,4 +1,6 @@
import 'uno.css'
// import Antd from 'ant-design-vue'
import 'ant-design-vue/dist/reset.css'
import './design/index.less'
@ -20,6 +22,7 @@ import '@/utils/tongji'
async function bootstrap() {
const app = createApp(App)
// app.use(Antd)
// Configure store
// 配置 store
setupStore(app)

4
src/utils/http/axios/index.ts

@ -259,7 +259,7 @@ const transform: AxiosTransform = {
// 添加自动重试机制 保险起见 只针对GET请求
if (config?.requestOptions) {
const retryRequest = new AxiosRetry()
const {isOpenRetry} = config.requestOptions.retryRequest
const { isOpenRetry } = config.requestOptions.retryRequest
config.method?.toUpperCase() === RequestEnum.GET
&& isOpenRetry
&& retryRequest.retry(axiosInstance, error)
@ -277,7 +277,7 @@ function createAxios(opt?: Partial<CreateAxiosOptions>) {
// authentication schemes,e.g: Bearer
// authenticationScheme: 'Bearer',
authenticationScheme: 'Bearer',
timeout: 10 * 1000,
timeout: 20 * 1000,
// 基础接口地址
// baseURL: globSetting.apiUrl,

2
src/views/config/index.vue

@ -0,0 +1,2 @@
<template>
</template>

114
src/views/exa/EXAHistoryLine.vue

@ -0,0 +1,114 @@
<script lang="ts" setup>
import type { Ref } from 'vue'
import { onMounted, ref, watch } from 'vue'
import type { YAXisOption } from 'echarts/types/dist/shared'
import { useECharts } from '@/hooks/web/useECharts'
import { propTypes } from '@/utils/propTypes'
const props = defineProps({
height: {
type: String,
default: propTypes.string.def('500px'),
},
name: {
type: Array<string>,
default: [],
},
data: {
type: Array<Array<number>>,
default: () => [[]],
},
width: propTypes.string.def('100%'),
// height: propTypes.string.def('70vh'),
})
const chartRef = ref<HTMLDivElement | null>(null)
const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>)
onMounted(() => {
})
// const yAxis = reactive<yAxisForm>({
// type: 'value',
// scale: true, //
// })
watch(
() => props.data,
() => {
console.log(props.data)
const yAxis = ref<YAXisOption[]>([])
const series = ref<any[]>([])
for (let i = 0; i < props.data.length; i++) {
yAxis.value.push({
type: 'value',
show: false,
scale: true, //
})
series.value.push({
name: props.name[i],
type: 'line',
smooth: true,
itemStyle: {
normal: {
lineStyle: {
width: 3, // 0.1线
},
},
},
showSymbol: false,
data: props.data[i],
yAxisIndex: i,
})
}
setOptions({
tooltip: {
trigger: 'axis',
position(pt) {
return [pt[0], '10%']
},
},
title: {
left: 'center',
text: 'Large Ara Chart',
show: false,
},
toolbox: {
feature: {
dataZoom: {
yAxisIndex: 'none',
},
restore: {},
saveAsImage: {},
},
},
xAxis: {
type: 'time',
// boundaryGap: false,
},
yAxis: yAxis.value,
legend: {
},
dataZoom: [
{
type: 'inside',
start: 0,
end: 100,
},
{
start: 0,
end: 100,
},
],
series: series.value,
})
},
{ immediate: true },
)
</script>
<template>
<div ref="chartRef" :style="{ width, height }" />
</template>

60
src/views/exa/config/CreateBatchModal.vue

@ -0,0 +1,60 @@
<script lang="ts" setup>
import { onBeforeMount, onMounted, ref, unref } from 'vue'
import { UploadDragger, message } from 'ant-design-vue'
import type { UploadChangeParam } from 'ant-design-vue'
import { InboxOutlined } from '@ant-design/icons-vue'
import { useI18n } from '@/hooks/web/useI18n'
import { useMessage } from '@/hooks/web/useMessage'
import { BasicModal, useModalInner } from '@/components/Modal'
import { createEXAPoint, getGroup } from '@/api/alert/exa'
const emit = defineEmits(['success', 'register'])
const { t } = useI18n()
const { createMessage } = useMessage()
const [registerCreateBatchModal, { setModalProps, closeModal }] = useModalInner(async () => {
})
const fileList = ref([])
function handleChange(info: UploadChangeParam) {
const status = info.file.status
if (status !== 'uploading')
console.log(info.file, info.fileList)
if (status === 'done')
message.success(`${info.file.name} file uploaded successfully.`)
else if (status === 'error')
message.error(`${info.file.name} file upload failed.`)
}
function handleDrop(e: DragEvent) {
console.log(e)
}
</script>
<template>
<BasicModal
v-bind="$attrs" :min-height="200" :title="t('action.createBatch')" @register="registerCreateBatchModal"
@ok="handleSubmit"
>
<UploadDragger
v-model:fileList="fileList"
name="file"
:multiple="true"
action="/user/import/"
@change="handleChange"
@drop="handleDrop"
>
<p class="ant-upload-drag-icon">
<inbox-outlined />
</p>
<p class="ant-upload-text">
Click or drag file to this area to upload
</p>
<p class="ant-upload-hint">
Support for a single or bulk upload. Strictly prohibit from uploading company data or other
band files
</p>
</UploadDragger>
</BasicModal>
</template>

95
src/views/exa/config/EXAModal.vue

@ -0,0 +1,95 @@
<script lang="ts" setup>
import { onBeforeMount, onMounted, ref, unref } from 'vue'
import { formSchema } from '../exa.data'
import { useI18n } from '@/hooks/web/useI18n'
import { useMessage } from '@/hooks/web/useMessage'
import { BasicForm, useForm } from '@/components/Form'
import { BasicModal, useModalInner } from '@/components/Modal'
import { createEXAPoint, getGroup } from '@/api/alert/exa'
const emit = defineEmits(['success', 'register'])
const { t } = useI18n()
const { createMessage } = useMessage()
//
const groupList = ref()
// onMounted(() => {
// getGroupListSelect()
// })
const [registerForm, { resetFields, validate, updateSchema }] = useForm({
labelWidth: 120,
baseColProps: { span: 24 },
schemas: formSchema,
showActionButtonGroup: false,
actionColOptions: { span: 23 },
})
const [registerModal, { setModalProps, closeModal }] = useModalInner(async () => {
resetFields()
setModalProps({ confirmLoading: false })
getGroupListSelect()
// isUpdate.value = !!data?.isUpdate
// if (unref(isUpdate)) {
// const res = await getRole(data.record.id)
// setFieldsValue({ ...res })
// }
})
async function getGroupListSelect() {
// {label'',value:''}
const res = await getGroup()
const list = [] as any
// //
res.forEach((item) => {
list.push({ label: item.GroupName, value: item.GroupName })
})
groupList.value = list
console.log(groupList.value)
//
updateSchema({
field: 'GroupName',
componentProps: {
options: unref(groupList.value),
},
})
}
async function handleSubmit() {
try {
const values = await validate()
setModalProps({ confirmLoading: true })
// const mergedObject = Object.assign({}, values, { AutoSave: 1 })
const createResult = await createEXAPoint(values)
closeModal()
if (createResult === '1') {
createMessage.success(t('common.successText'))
emit('success')
}
else if (createResult === '-20') {
createMessage.info('点号已存在')
}
else {
createMessage.error(t('common.errorText'))
}
}
finally {
setModalProps({ confirmLoading: false })
}
}
</script>
<template>
<BasicModal
v-bind="$attrs" :min-height="200" :title="t('action.create')" @register="registerModal"
@ok="handleSubmit"
>
<BasicForm @register="registerForm" />
</BasicModal>
</template>

77
src/views/exa/config/HistoryModal.vue

@ -0,0 +1,77 @@
<script lang="ts" setup>
import { ref } from 'vue'
import moment from 'moment'
import { Card } from 'ant-design-vue'
import { formHistory } from '../exa.data'
import EXAHistoryLine from '../EXAHistoryLine.vue'
import { BasicModal, useModalInner } from '@/components/Modal'
import { BasicForm, useForm } from '@/components/Form'
import { getExaHistorys } from '@/api/alert/exa'
const loading = ref(true)
const itemName = ref('')
const [registerForm, { getFieldsValue }] = useForm({
labelWidth: 100,
// baseColProps: { span: 24 },
schemas: formHistory,
showResetButton: false,
layout: 'horizontal',
model: { time: [moment().subtract(1, 'day').format('YYYY-MM-DD HH:mm:ss'), moment().format('YYYY-MM-DD HH:mm:ss')] },
fieldMapToTime: [
// datastartTimeendTime
['time', ['startTime', 'endTime'], 'YYYY-MM-DD HH:mm:ss'],
],
actionColOptions: { span: 2 },
})
const historyData = ref()
const legendName = ref<any[]>([])
const [registerHistoryModal, { setModalProps }] = useModalInner(async (data) => {
console.log(543)
setModalProps({ confirmLoading: false, showCancelBtn: false, showOkBtn: false })
itemName.value = data.record.itemName
legendName.value = []
legendName.value.push(`${data.record.descriptor}-${data.record.itemName}`)
handleSubmitR()
// 线
// setFieldsValue({ time: [moment().subtract(1, 'day').format('YYYY-MM-DD HH:mm:ss'), moment().format('YYYY-MM-DD HH:mm:ss')] })
// console.log(startTime, endTime, itemName)
// const historyData = getExaHistory({
// startTime,
// endTime,
// itemName: itemName.value,
// })
// isUpdate.value = !!data?.isUpdate
// if (unref(isUpdate)) {
// const res = await getUser(data.record.id)
// setFieldsValue({ ...res })
// }
})
async function handleSubmitR() {
const serachFormData = getFieldsValue()
loading.value = true
const exaHistoryReqVO = {
startTime: serachFormData.startTime,
endTime: serachFormData.endTime,
itemName: itemName.value,
}
historyData.value = await getExaHistorys(exaHistoryReqVO)
loading.value = false
}
</script>
<template>
<BasicModal v-bind="$attrs" title="历史曲线" width="80%" @register="registerHistoryModal">
<BasicForm @register="registerForm" @submit="handleSubmitR" />
<Card :loading="loading">
<EXAHistoryLine :data="historyData" :name="legendName" height="500px" />
</Card>
</BasicModal>
</template>

154
src/views/exa/config/index.vue

@ -0,0 +1,154 @@
<script lang="ts" setup>
import { onMounted, onUnmounted } from 'vue'
import { columns, searchFormSchema } from '../exa.data'
import EXAModal from './EXAModal.vue'
import CreateBatchModal from './CreateBatchModal.vue'
import HistoryModal from './HistoryModal.vue'
import { useI18n } from '@/hooks/web/useI18n'
import { useMessage } from '@/hooks/web/useMessage'
import { useModal } from '@/components/Modal'
import { IconEnum } from '@/enums/appEnum'
import { BasicTable, TableAction, useTable } from '@/components/Table'
import type { RoleExportReqVO } from '@/api/system/role'
import { deletePoint, getEXAPage, getExaNow } from '@/api/alert/exa'
defineOptions({ name: 'EXAConfig' })
const { t } = useI18n()
const { createConfirm, createMessage } = useMessage()
const [registerModal, { openModal }] = useModal()
const [registerCreateBatchModal, { openModal: openCreateBatchModal }] = useModal()
const [registerHistoryModal, { openModal: openHistoryModal }] = useModal()
const [registerTable, { getForm, reload, getDataSource, updateTableDataRecord }] = useTable({
title: '测点列表',
api: getEXAPage,
rowKey: 'serialNumber',
immediate: false,
columns,
formConfig: {
labelWidth: 150,
schemas: searchFormSchema,
showResetButton: false,
actionColOptions: {
span: 2,
},
},
useSearchForm: true,
showTableSetting: true,
showIndexColumn: false,
actionColumn: {
width: 140,
title: t('common.action'),
dataIndex: 'action',
fixed: 'right',
},
})
// function handleQuery() {
// getForm().setFieldsValue({ condition: '' })
// reload()
// }
async function getNow() {
const params = getDataSource()
params.forEach((item: any) => {
//
getExaNow(item.itemName).then((result) => {
updateTableDataRecord(item.serialNumber, Object.assign(item, { value: result }))
})
})
}
let timerId
onMounted(() => {
// 5
timerId = setInterval(() => {
getNow()
}, 5000) // 5[^1]
})
onUnmounted(() => {
//
clearInterval(timerId)
})
function handleCreate() {
openModal(true, {})
}
function handleCreateBatch() {
openCreateBatchModal(true, {})
}
function handleHistory(record: Recordable) {
openHistoryModal(true, { record })
}
async function handleExport() {
createConfirm({
title: t('common.exportTitle'),
iconType: 'warning',
content: t('common.exportMessage'),
async onOk() {
await exportRole(getForm().getFieldsValue() as RoleExportReqVO)
createMessage.success(t('common.exportSuccessText'))
},
})
}
async function handleDelete(record: Recordable) {
await deletePoint(record.itemName)
createMessage.success(t('common.delSuccessText'))
reload()
}
</script>
<template>
<div>
<BasicTable @register="registerTable">
<template #value="{ record }">
<a class="click-status" @click="handleHistory(record)">
{{ record.value }}
</a>
<!-- <SlidersOutlined class="click-status" /> -->
</template>
<template #toolbar>
<a-button v-auth="['system:role:create']" type="primary" :pre-icon="IconEnum.ADD" @click="handleCreate">
{{ t('action.create') }}
</a-button>
<a-button v-auth="['system:role:create']" type="primary" :pre-icon="IconEnum.ADD" @click="handleCreateBatch">
{{ t('action.createBatch') }}
</a-button>
<!-- <a-button v-auth="['system:role:create']" :pre-icon="IconEnum.EXPORT" @click="handleExport">
{{ t('action.export') }}
</a-button> -->
</template>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'action'">
<TableAction
:actions="[{
icon: IconEnum.DELETE,
danger: true,
label: t('action.delete'),
auth: 'alert:exa:delete',
popConfirm: {
title: t('common.delMessage'),
placement: 'left',
confirm: handleDelete.bind(null, record),
},
},
]"
/>
</template>
</template>
</BasicTable>
<EXAModal @register="registerModal" @success="reload" />
<CreateBatchModal @register="registerCreateBatchModal" />
<HistoryModal @register="registerHistoryModal" />
</div>
</template>
<style lang="less" scoped>
:deep(.value) {
font-weight:bold;
color: #0B55A4
}
</style>

128
src/views/exa/exa.data.ts

@ -0,0 +1,128 @@
import moment from 'moment'
import type { BasicColumn, FormSchema } from '@/components/Table'
import { DICT_TYPE, getDictOptions } from '@/utils/dict'
export const columns: BasicColumn[] = [
{
title: '编号',
dataIndex: 'serialNumber',
width: 80,
},
{
title: '测点编码',
dataIndex: 'itemName',
width: 150,
},
{
title: '测点名称',
dataIndex: 'descriptor',
width: 200,
},
{
title: '实时值',
dataIndex: 'value',
width: 90,
className: 'value',
slots: { customRender: 'value' },
},
{
title: '单位',
dataIndex: 'engUnits',
width: 30,
},
{
title: '组别',
dataIndex: 'groupName',
width: 50,
},
]
export const searchFormSchema: FormSchema[] = [
{
label: '测点名称或测点描述',
field: 'condition',
component: 'Input',
defaultValue: '',
required: true,
colProps: { span: 8 },
},
]
export const formSchema: FormSchema[] = [
{
label: '测点编码',
field: 'ItemName',
required: true,
component: 'Input',
},
{
label: '测点描述',
field: 'Descriptor',
required: true,
component: 'Input',
},
{
label: '单位',
field: 'EngUnits',
required: true,
component: 'Input',
},
{
label: '组名',
field: 'GroupName',
component: 'Select',
componentProps: {
options: getDictOptions(DICT_TYPE.COMMON_STATUS),
},
required: true,
},
{
label: '类型',
field: 'ItemType',
component: 'Select',
componentProps: {
options: [{ value: 1, label: 1 }, { value: 2, label: 2 }, { value: 3, label: 3 }, { value: 4, label: 4 }, { value: 5, label: 5 }],
},
required: true,
},
{
label: '自动保存',
field: 'AutoSave',
component: 'Select',
componentProps: {
options: [{ value: 1, label: '是' }, { value: 2, label: '否' }],
},
required: true,
},
{
label: '数据来源',
field: 'Source',
component: 'Input',
},
]
export const formHistory: FormSchema[] = [
{
label: '时间',
field: 'time',
show: true,
component: 'RangePicker',
componentProps: {
placeholder: ['开始时间', '结束时间'],
defaultValue: [moment().subtract(1, 'day').format('YYYY-MM-DD HH:mm:ss'), moment().format('YYYY-MM-DD HH:mm:ss')],
valueFormat: 'YYYY-MM-DD HH:mm:ss',
showTime: {
defaultValue: [moment().subtract(1, 'day').format('YYYY-MM-DD HH:mm:ss'), moment().format('YYYY-MM-DD HH:mm:ss')],
},
onChange: (e: any) => {
console.log(e)
},
},
},
]

240
src/views/exa/history/PointModal.vue

@ -0,0 +1,240 @@
<script lang="ts" setup>
import { computed, reactive, ref, watch } from 'vue'
import { columns, searchFormSchema } from '../exa.data'
import type { TableActionType } from '@/components/Table'
import { BasicTable, TableAction, useTable } from '@/components/Table'
import { getEXAPage } from '@/api/alert/exa'
import { useI18n } from '@/hooks/web/useI18n'
import { IconEnum } from '@/enums/appEnum'
import { BasicModal, useModalInner } from '@/components/Modal'
const props = defineProps({
selectedData: { type: Array<Recordable>, default: [] },
selectedRowKeys: { type: Array<number>, default: [] },
})
const emit = defineEmits(['success', 'register'])
const [registerPointModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
setModalProps({ confirmLoading: false })
})
const { t } = useI18n()
const selectedData = ref<Recordable[]>(props.selectedData)
interface RowKeys {
selectedRowKeys: number[]
}
const state = reactive<RowKeys>({
selectedRowKeys: props.selectedRowKeys,
})
const tableRef = ref<Nullable<TableActionType>>(null)
const tableRef1 = ref<Nullable<TableActionType>>(null)
const [registerTable] = useTable({
title: '测点列表',
api: getEXAPage,
immediate: false,
showTableSetting: false,
tableSetting: {
//
redo: false,
//
size: false,
//
setting: false,
//
fullScreen: false,
},
columns,
formConfig: {
labelWidth: 150,
schemas: searchFormSchema,
showResetButton: false,
actionColOptions: {
span: 2,
},
},
rowKey: 'serialNumber',
useSearchForm: true,
showIndexColumn: false,
})
// computed
const rowSelection = computed(() => {
return {
preserveSelectedRowKeys: true, // 2.
type: 'checkbox',
selectedRowKeys: state.selectedRowKeys,
onChange: onSelectChange,
}
})
// defaultChecked: record.serialNumber === 93,
watch(
() => props.selectedRowKeys,
() => {
state.selectedRowKeys = props.selectedRowKeys
selectedData.value = props.selectedData
},
)
// onBeforeMount(() => {
// console.log(props.selectedRowKeys)
// console.log(props.selectedData)
// state.selectedRowKeys = props.selectedRowKeys
// selectedData.value = props.selectedData
// console.log(state.selectedRowKeys)
// console.log(selectedData.value)
// emit('success')
// })
// const historyData = ref()
// const legendName = ref<any[]>([])
// async function getHistoryChart() {
// const pointCodeList = selectedData.value.map(item => (item.itemName))
// loading.value = true
// if (pointCodeList.length !== 0) {
// const pointCode = selectedData.value.map(item => (item.itemName)).join(',')
// const pointDesc: any[] = selectedData.value.map(item => (item.descriptor))
// const exaHistoryReqVO = {
// startTime: searchForm.publishTime[0],
// endTime: searchForm.publishTime[1],
// itemName: pointCode,
// }
// historyData.value = await getExaHistorys(exaHistoryReqVO)
// legendName.value = pointDesc
// }
// else {
// message.info('')
// }
// loading.value = false
// }
const [registerSelectedTable] = useTable({
title: '已选中测点列表',
showTableSetting: false,
tableSetting: {
//
redo: false,
//
size: false,
//
setting: false,
//
fullScreen: false,
},
columns,
formConfig: {
labelWidth: 150,
schemas: searchFormSchema,
showResetButton: false,
actionColOptions: {
span: 2,
},
},
rowKey: 'serialNumber',
useSearchForm: false,
showIndexColumn: false,
actionColumn: {
width: 140,
title: t('common.action'),
dataIndex: 'action',
fixed: 'right',
},
})
function onSelectChange(selectedRowKeys, selectedRows) {
console.log(selectedRowKeys, selectedRows)
state.selectedRowKeys = selectedRowKeys
let selectionRows: any[] = []
console.log('3', selectedData.value)
selectionRows = selectedData.value.concat(selectedRows)
console.log('2', selectionRows)
selectionRows = selectionRows.filter(item => selectedRowKeys.includes(item.serialNumber))
console.log('1', selectionRows)
//
const map = new Map()
for (const item of selectionRows) {
if (!map.has(item.serialNumber))
map.set(item.serialNumber, item)
};
selectedData.value = [...map.values()]
}
function handleOk() {
console.log('onOk:')
localStorage.setItem('pointInfo', JSON.stringify(state.selectedRowKeys))
localStorage.setItem('pointInfoList', JSON.stringify(selectedData.value))
closeModal()
emit('success')
}
async function handleDelete(record: Recordable) {
const newArr = state.selectedRowKeys.filter((value) => {
return value !== record.serialNumber
})
state.selectedRowKeys = newArr
localStorage.setItem('pointInfo', JSON.stringify(state.selectedRowKeys))
const newArrObj = selectedData.value.filter((value) => {
return value.serialNumber !== record.serialNumber
})
selectedData.value = newArrObj
}
function handleClearAndClose() {
state.selectedRowKeys = []
selectedData.value = []
localStorage.setItem('pointInfo', JSON.stringify(state.selectedRowKeys))
localStorage.setItem('pointInfoList', JSON.stringify(selectedData.value))
closeModal()
emit('success')
}
</script>
<template>
<BasicModal v-bind="$attrs" title="测点配置" width="1000px" @register="registerPointModal" @ok="handleOk">
<BasicTable
ref="tableRef" :can-resize="false" title="RefTable示例" title-help-message="使用Ref调用表格内方法"
:row-selection="rowSelection" size="small" @register="registerTable"
/>
<BasicTable
ref="tableRef1" :pagination="false" size="small" :data-source="selectedData" :can-resize="false"
title="已选中测点" title-help-message="使用Ref调用表格内方法" @register="registerSelectedTable"
>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'action'">
<TableAction
:actions="[{
icon: IconEnum.DELETE,
danger: true,
label: t('action.delete'),
auth: 'system:role:delete',
popConfirm: {
title: t('common.delMessage'),
placement: 'left',
confirm: handleDelete.bind(null, record),
},
},
]"
/>
</template>
</template>
<template #toolbar>
<a-button v-auth="['system:role:create']" type="primary" :pre-icon="IconEnum.DELETE" @click="handleClearAndClose">
{{ t('action.clearAllandClose') }}
</a-button>
<!-- <a-button v-auth="['system:role:create']" :pre-icon="IconEnum.EXPORT" @click="handleExport">
{{ t('action.export') }}
</a-button> -->
</template>
</BasicTable>
</BasicModal>
</template>

260
src/views/exa/history/index copy.vue

@ -0,0 +1,260 @@
<script lang="ts" setup>
import { computed, onMounted, reactive, ref } from 'vue'
import type { Dayjs } from 'dayjs'
import moment from 'moment'
import { Button, Card, Form, FormItem, Modal, RangePicker, Space, message } from 'ant-design-vue'
import { columns, searchFormSchema } from '../exa.data'
import EXAHistoryLine from '../EXAHistoryLine.vue'
import type { TableActionType } from '@/components/Table'
import { BasicTable, TableAction, useTable } from '@/components/Table'
import { getEXAPage, getExaHistorys } from '@/api/alert/exa'
import { useI18n } from '@/hooks/web/useI18n'
import { IconEnum } from '@/enums/appEnum'
const { t } = useI18n()
interface FormState {
publishTime: any[]
}
const searchForm = reactive<FormState>({
publishTime: [],
})
const loading = ref(true)
function onRangeChange(value: [Dayjs, Dayjs], dateString: [string, string]) {
console.log('Selected Time: ', value)
console.log('Formatted Selected Time: ', dateString)
}
function onRangeOk(value: [Dayjs, Dayjs]) {
console.log('onOk: ', value)
console.log(searchForm.publishTime)
searchForm.publishTime = value
}
const open = ref<boolean>(false)
const selectedData = ref<Recordable[]>([])
interface RowKeys {
selectedRowKeys: number[]
}
const state = reactive<RowKeys>({
selectedRowKeys: [],
})
const tableRef = ref<Nullable<TableActionType>>(null)
const tableRef1 = ref<Nullable<TableActionType>>(null)
const [registerTable] = useTable({
title: '测点列表',
api: getEXAPage,
immediate: false,
showTableSetting: false,
tableSetting: {
//
redo: false,
//
size: false,
//
setting: false,
//
fullScreen: false,
},
columns,
formConfig: {
labelWidth: 150,
schemas: searchFormSchema,
showResetButton: false,
actionColOptions: {
span: 2,
},
},
rowKey: 'serialNumber',
useSearchForm: true,
showIndexColumn: false,
})
// computed
const rowSelection = computed(() => {
return {
preserveSelectedRowKeys: true, // 2.
type: 'checkbox',
selectedRowKeys: state.selectedRowKeys,
onChange: onSelectChange,
}
})
// defaultChecked: record.serialNumber === 93,
onMounted(() => {
state.selectedRowKeys = localStorage.getItem('pointInfo') ? JSON.parse(localStorage.getItem('pointInfo') || '') : []
selectedData.value = localStorage.getItem('pointInfoList') ? JSON.parse(localStorage.getItem('pointInfoList') || '') : []
searchForm.publishTime = [moment().subtract(1, 'day').format('YYYY-MM-DD HH:mm:ss'), moment().format('YYYY-MM-DD HH:mm:ss')]
getHistoryChart()
})
const historyData = ref()
const legendName = ref<any[]>([])
async function getHistoryChart() {
const pointCodeList = selectedData.value.map(item => (item.itemName))
loading.value = true
if (pointCodeList.length !== 0) {
const pointCode = selectedData.value.map(item => (item.itemName)).join(',')
const pointDesc: any[] = selectedData.value.map(item => (item.descriptor))
const exaHistoryReqVO = {
startTime: searchForm.publishTime[0],
endTime: searchForm.publishTime[1],
itemName: pointCode,
}
historyData.value = await getExaHistorys(exaHistoryReqVO)
legendName.value = pointDesc
}
else {
message.info('暂无测点')
}
loading.value = false
}
const [registerSelectedTable] = useTable({
title: '已选中测点列表',
showTableSetting: false,
tableSetting: {
//
redo: false,
//
size: false,
//
setting: false,
//
fullScreen: false,
},
columns,
formConfig: {
labelWidth: 150,
schemas: searchFormSchema,
showResetButton: false,
actionColOptions: {
span: 2,
},
},
rowKey: 'serialNumber',
useSearchForm: false,
showIndexColumn: false,
actionColumn: {
width: 140,
title: t('common.action'),
dataIndex: 'action',
fixed: 'right',
},
})
function openModal() {
open.value = true
console.log(24)
console.log(selectedData.value)
}
function onSelectChange(selectedRowKeys, selectedRows) {
console.log(selectedRowKeys, selectedRows)
state.selectedRowKeys = selectedRowKeys
let selectionRows: any[] = []
console.log('3', selectedData.value)
selectionRows = selectedData.value.concat(selectedRows)
console.log('2', selectionRows)
selectionRows = selectionRows.filter(item => selectedRowKeys.includes(item.serialNumber))
console.log('1', selectionRows)
//
const map = new Map()
for (const item of selectionRows) {
if (!map.has(item.serialNumber))
map.set(item.serialNumber, item)
};
selectedData.value = [...map.values()]
}
function handleOk() {
console.log('onOk:')
localStorage.setItem('pointInfo', JSON.stringify(state.selectedRowKeys))
localStorage.setItem('pointInfoList', JSON.stringify(selectedData.value))
open.value = false
getHistoryChart()
}
async function handleDelete(record: Recordable) {
const newArr = state.selectedRowKeys.filter((value) => {
return value !== record.serialNumber
})
state.selectedRowKeys = newArr
localStorage.setItem('pointInfo', JSON.stringify(state.selectedRowKeys))
const newArrObj = selectedData.value.filter((value) => {
return value.serialNumber !== record.serialNumber
})
selectedData.value = newArrObj
}
</script>
<template>
<div>
<Card>
<Form layout="inline" :model="searchForm">
<FormItem label="时间范围">
<RangePicker
:model="searchForm.publishTime"
:show-time="{ format: 'HH:mm:ss' }"
:placeholder="['开始时间', '结束时间']" :default-value="[moment().subtract(1, 'day').format('YYYY-MM-DD HH:mm:ss'), moment().format('YYYY-MM-DD HH:mm:ss')]"
value-format="YYYY-MM-DD HH:mm:ss"
@change="onRangeChange"
@ok="onRangeOk"
/>
</FormItem>
<FormItem>
<Space wrap>
<Button type="primary" @click="getHistoryChart">
查看趋势
</Button>
<Button @click="openModal()">
测点配置
</Button>
</Space>
</FormItem>
</Form>
</Card>
<Card style="margin:5px" :loading="loading">
<EXAHistoryLine :data="historyData" :name="legendName" height="70vh" />
</Card>
<Modal v-model:open="open" :destroy-on-close="false" width="1000px" title="测点配置" @ok="handleOk">
<BasicTable
ref="tableRef" :can-resize="false" title="RefTable示例" title-help-message="使用Ref调用表格内方法"
:row-selection="rowSelection" size="small" @register="registerTable"
/>
<BasicTable
ref="tableRef1" :pagination="false" size="small" :data-source="selectedData" :can-resize="false"
title="已选中测点" title-help-message="使用Ref调用表格内方法" @register="registerSelectedTable"
>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'action'">
<TableAction
:actions="[{
icon: IconEnum.DELETE,
danger: true,
label: t('action.delete'),
auth: 'system:role:delete',
popConfirm: {
title: t('common.delMessage'),
placement: 'left',
confirm: handleDelete.bind(null, record),
},
},
]"
/>
</template>
</template>
</BasicTable>
</Modal>
</div>
</template>

105
src/views/exa/history/index.vue

@ -0,0 +1,105 @@
<script lang="ts" setup>
import { onMounted, reactive, ref } from 'vue'
import type { Dayjs } from 'dayjs'
import moment from 'moment'
import { Button, Card, Form, FormItem, RangePicker, Space, message } from 'ant-design-vue'
import EXAHistoryLine from '../EXAHistoryLine.vue'
import PointModal from './PointModal.vue'
import { getExaHistorys } from '@/api/alert/exa'
import { useModal } from '@/components/Modal'
interface FormState {
publishTime: any[]
}
const searchForm = reactive<FormState>({
publishTime: [],
})
const loading = ref(true)
function onRangeChange(value: [Dayjs, Dayjs], dateString: [string, string]) {
console.log('Selected Time: ', value)
console.log('Formatted Selected Time: ', dateString)
}
function onRangeOk(value: [Dayjs, Dayjs]) {
console.log('onOk: ', value)
console.log(searchForm.publishTime)
searchForm.publishTime = value
}
const selectedData = ref<Recordable[]>([])
interface RowKeys {
selectedRowKeys: number[]
}
const state = reactive<RowKeys>({
selectedRowKeys: [],
})
onMounted(() => {
getHistoryChart()
})
const historyData = ref()
const legendName = ref<any[]>([])
async function getHistoryChart() {
state.selectedRowKeys = localStorage.getItem('pointInfo') ? JSON.parse(localStorage.getItem('pointInfo') || '') : []
selectedData.value = localStorage.getItem('pointInfoList') ? JSON.parse(localStorage.getItem('pointInfoList') || '') : []
searchForm.publishTime = [moment().subtract(1, 'day').format('YYYY-MM-DD HH:mm:ss'), moment().format('YYYY-MM-DD HH:mm:ss')]
const pointCodeList = selectedData.value.map(item => (item.itemName))
loading.value = true
if (pointCodeList.length === 0)
message.info('暂无测点')
const pointCode = selectedData.value.map(item => (item.itemName)).join(',')
const pointDesc: any[] = selectedData.value.map(item => (item.descriptor))
const exaHistoryReqVO = {
startTime: searchForm.publishTime[0],
endTime: searchForm.publishTime[1],
itemName: pointCode,
}
historyData.value = await getExaHistorys(exaHistoryReqVO)
legendName.value = pointDesc
loading.value = false
}
const [registerPointModal, { openModal: openPointModal }] = useModal()
function handlePointModal() {
openPointModal(true)
}
</script>
<template>
<div>
<Card>
<Form layout="inline" :model="searchForm">
<FormItem label="时间范围">
<RangePicker
:model="searchForm.publishTime"
:show-time="{ format: 'HH:mm:ss' }"
:placeholder="['开始时间', '结束时间']" :default-value="[moment().subtract(1, 'day').format('YYYY-MM-DD HH:mm:ss'), moment().format('YYYY-MM-DD HH:mm:ss')]"
value-format="YYYY-MM-DD HH:mm:ss"
@change="onRangeChange"
@ok="onRangeOk"
/>
</FormItem>
<FormItem>
<Space wrap>
<Button type="primary" @click="getHistoryChart">
查看趋势
</Button>
<Button @click="handlePointModal">
测点配置
</Button>
</Space>
</FormItem>
</Form>
</Card>
<Card style="margin:5px" :loading="loading">
<EXAHistoryLine :data="historyData" :name="legendName" height="70vh" />
</Card>
<PointModal :selected-row-keys="state.selectedRowKeys" :selected-data="selectedData" @register="registerPointModal" @success="getHistoryChart" />
</div>
</template>
Loading…
Cancel
Save