feat(iot): 新增设备管理卡片展示功能
- 添加设备列表页面,支持查询、重置功能 - 实现设备详情页面,展示设备信息和扩展属性 - 新增设备编辑组件,支持创建和修改设备 - 重构公告卡片组件,改为设备卡片样式
This commit is contained in:
parent
dfd9d165ca
commit
a45b8985b6
@ -36,6 +36,17 @@ const IOT: AppRouteRecordRaw = {
|
||||
permissions: ['iot:device'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'deviceCard',
|
||||
name: 'DeviceCard',
|
||||
component: () => import('@/views/iot/deviceCard/index.vue'),
|
||||
meta: {
|
||||
locale: '设备管理(卡片)',
|
||||
title: '设备管理(卡片)',
|
||||
requiresAuth: true,
|
||||
permissions: ['iot:device'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'product/:id',
|
||||
name: 'productDetail',
|
||||
|
@ -43,7 +43,7 @@ const NOTIFICATION: AppRouteRecordRaw = {
|
||||
title: '公告详情',
|
||||
requiresAuth: true,
|
||||
showInMenu: false,
|
||||
permissions: ['message:bulletin:query'],
|
||||
permissions: ['message:bulletin'],
|
||||
},
|
||||
},
|
||||
],
|
||||
|
@ -44,17 +44,6 @@ const USER: AppRouteRecordRaw = {
|
||||
permissions: ['*'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'bulletinCard',
|
||||
name: 'BulletinCard',
|
||||
component: () => import('@/views/user/bulletin-card/index.vue'),
|
||||
meta: {
|
||||
locale: '公告通知(卡片)',
|
||||
title: '公告通知(卡片)',
|
||||
requiresAuth: true,
|
||||
permissions: ['*'],
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'messages',
|
||||
name: 'Messages',
|
||||
|
@ -20,11 +20,11 @@
|
||||
{{ createBy }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="创建时间">
|
||||
{{ dayjs(publishTime).format('YYYY-MM-DD HH:mm:ss') }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="备注">
|
||||
{{ remark }}
|
||||
{{ dayjs(createTime).format('YYYY-MM-DD HH:mm:ss') }}
|
||||
</a-descriptions-item>
|
||||
<!-- <a-descriptions-item label="备注">-->
|
||||
<!-- {{ remark }}-->
|
||||
<!-- </a-descriptions-item>-->
|
||||
</a-descriptions>
|
||||
</template>
|
||||
</a-card-meta>
|
||||
@ -32,9 +32,17 @@
|
||||
<template #actions>
|
||||
<div>
|
||||
<a-space>
|
||||
<a-button type="outline" @click="handleDetail(id)">
|
||||
<a-button type="outline" status="success" @click="openDetail(id)">
|
||||
详情
|
||||
</a-button>
|
||||
<DeviceEdit
|
||||
ref="editUserRef"
|
||||
:id="id"
|
||||
:is-create="false"
|
||||
/>
|
||||
<a-button type="outline" status="danger" @click="handleDelete(id)">
|
||||
删除
|
||||
</a-button>
|
||||
</a-space>
|
||||
</div>
|
||||
</template>
|
||||
@ -46,6 +54,9 @@
|
||||
|
||||
import router from '@/router';
|
||||
import dayjs from 'dayjs';
|
||||
import { deleteDevice } from '@/api/device';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
import DeviceEdit from '@/views/iot/deviceCard/components/device-edit.vue';
|
||||
|
||||
const props = defineProps({
|
||||
loading: {
|
||||
@ -72,14 +83,28 @@
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
publishTime: {
|
||||
createTime: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
});
|
||||
// 详情
|
||||
const handleDetail = async (id: number) => {
|
||||
await router.push({ name: 'Details', params: { id } });
|
||||
// 打开详情
|
||||
function openDetail(id:number): void{
|
||||
const url = router.resolve({
|
||||
name: 'deviceDetail',
|
||||
params: {id}
|
||||
}).href;
|
||||
router.push(url);
|
||||
}
|
||||
// 删除
|
||||
const handleDelete = async (id: number) => {
|
||||
const res = await deleteDevice(id);
|
||||
if (res.status === 200) {
|
||||
Message.success({
|
||||
content: '删除成功',
|
||||
duration: 5 * 1000,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
</script>
|
102
src/views/iot/deviceCard/components/device-detail.vue
Normal file
102
src/views/iot/deviceCard/components/device-detail.vue
Normal file
@ -0,0 +1,102 @@
|
||||
<template>
|
||||
<div class="container">
|
||||
<Breadcrumb :items="['物联网管理', '设备管理', '设备详情']" />
|
||||
<a-card class="general-card" title=" ">
|
||||
<a-descriptions v-model="renderData" size="large">
|
||||
<template #title><h3 style="margin-top: -15px">设备详情</h3></template>
|
||||
<a-descriptions-item label="设备名称">{{renderData.name }}</a-descriptions-item>
|
||||
<a-descriptions-item label="硬件版本">{{renderData.hardwareVersion }}</a-descriptions-item>
|
||||
<a-descriptions-item label="固件版本">{{renderData.firmwareVersion }}</a-descriptions-item>
|
||||
<a-descriptions-item label="所属产品">{{renderData.productId }}</a-descriptions-item>
|
||||
<!-- <a-descriptions-item label="备注">{{renderData.remark }}</a-descriptions-item>-->
|
||||
<a-descriptions-item label="创建时间">{{dayjs(renderData.createTime).format('YYYY-MM-DD HH:mm:ss') }}</a-descriptions-item>
|
||||
</a-descriptions>
|
||||
</a-card>
|
||||
<a-card class="general-card" style="margin-top: 10px">
|
||||
<a-tabs :active-key="activeKey" @tab-click="handleMenuClick" style="padding-top: 20px">
|
||||
<a-tab-pane key="1" tab="参数" title="扩展属性">
|
||||
<a-table :columns="columns" :data="renderData.extendParams" />
|
||||
</a-tab-pane>
|
||||
<a-tab-pane key="2" tab="基本信息" title="基本信息">
|
||||
基本信息
|
||||
</a-tab-pane>
|
||||
<a-tab-pane key="3" tab="执行服务" title="执行服务"> 执行服务内容 </a-tab-pane>
|
||||
</a-tabs>
|
||||
</a-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import dayjs from 'dayjs';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { queryDeviceDetail } from '@/api/device';
|
||||
|
||||
const route = useRoute();
|
||||
const id = Number(route.params.id);
|
||||
const columns = [
|
||||
{
|
||||
title: '参数名称',
|
||||
dataIndex: 'name',
|
||||
slotName: 'name',
|
||||
},
|
||||
{
|
||||
title: '参数标识',
|
||||
dataIndex: 'identifier',
|
||||
slotName: 'identifier',
|
||||
},
|
||||
{
|
||||
title: '数据类型',
|
||||
dataIndex: 'dataType',
|
||||
slotName: 'dataType',
|
||||
},
|
||||
{
|
||||
title: '参数类型',
|
||||
dataIndex: 'type',
|
||||
slotName: 'type',
|
||||
},
|
||||
];
|
||||
const activeKey = ref('1');
|
||||
const renderData = ref([]);
|
||||
const fetchData = async (Id: number) => {
|
||||
const res = await queryDeviceDetail(Id);
|
||||
renderData.value = res.data;
|
||||
};
|
||||
const handleMenuClick = (e: any) => {
|
||||
activeKey.value = e;
|
||||
};
|
||||
onMounted(() => {
|
||||
fetchData(id);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.container {
|
||||
padding: 0 20px 20px 20px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 24px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.meta span {
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.attachments li {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.attachments a {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 14px;
|
||||
color: #1890ff;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.attachments a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
</style>
|
415
src/views/iot/deviceCard/components/device-edit.vue
Normal file
415
src/views/iot/deviceCard/components/device-edit.vue
Normal file
@ -0,0 +1,415 @@
|
||||
<template>
|
||||
<!-- <a-button v-permission="['iot:device:create']" v-if="props.isCreate" type="primary" @click="handleClick">-->
|
||||
<!-- <template #icon>-->
|
||||
<!-- <icon-plus />-->
|
||||
<!-- </template>-->
|
||||
<!-- 新建-->
|
||||
<!-- </a-button>-->
|
||||
<a-col
|
||||
v-permission="['iot:device:create']"
|
||||
v-if="props.isCreate"
|
||||
@click="handleClick"
|
||||
:xs="12"
|
||||
:sm="12"
|
||||
:md="12"
|
||||
:lg="6"
|
||||
:xl="6"
|
||||
:xxl="6"
|
||||
class="list-col"
|
||||
>
|
||||
<div class="card-wrap empty-wrap">
|
||||
<a-card :bordered="false" hoverable>
|
||||
<a-result :status="null" title="点击创建设备">
|
||||
<template #icon>
|
||||
<icon-plus style="font-size: 20px" />
|
||||
</template>
|
||||
</a-result>
|
||||
</a-card>
|
||||
</div>
|
||||
</a-col>
|
||||
<a-button
|
||||
v-permission="['iot:device:update']"
|
||||
v-if="!props.isCreate"
|
||||
type="outline"
|
||||
size="small"
|
||||
@click="handleClick"
|
||||
>
|
||||
<!-- <template #icon><icon-edit /></template>-->
|
||||
修改
|
||||
</a-button>
|
||||
|
||||
<a-modal
|
||||
width="900px"
|
||||
height="500px"
|
||||
:visible="visible"
|
||||
@cancel="handleCancel"
|
||||
>
|
||||
<template #title>{{ modalTitle }}</template>
|
||||
<a-form
|
||||
ref="CreateRef"
|
||||
:model="formData"
|
||||
:style="{ width: '800px', height: '420px' }"
|
||||
>
|
||||
<!-- 产品id -->
|
||||
<a-form-item
|
||||
field="productName"
|
||||
label="产品名称"
|
||||
:rules="[{ required: true, message: '产品名称不能为空' }]"
|
||||
:validate-trigger="['change']"
|
||||
>
|
||||
<a-select
|
||||
v-model="formData.productName"
|
||||
placeholder="请选择产品名称"
|
||||
:loading="loading"
|
||||
:filter-option="false"
|
||||
allow-search
|
||||
@search="handleSearch"
|
||||
>
|
||||
<a-option v-for="item of options" :key="item.id" :value="item.name">{{
|
||||
item.name
|
||||
}}</a-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<!-- 设备名称 -->
|
||||
<a-form-item
|
||||
field="name"
|
||||
label="设备名称"
|
||||
:rules="[{ required: true, message: '设备名称不能为空' }]"
|
||||
:validate-trigger="['change']"
|
||||
>
|
||||
<a-input v-model="formData.name" placeholder="请输入设备名称" />
|
||||
</a-form-item>
|
||||
<!-- 硬件版本 -->
|
||||
<a-form-item
|
||||
field="hardwareVersion"
|
||||
label="硬件版本"
|
||||
:rules="[{ required: true, message: '硬件版本不能为空' }]"
|
||||
:validate-trigger="['change']"
|
||||
>
|
||||
<a-input
|
||||
v-model="formData.hardwareVersion"
|
||||
placeholder="请输入硬件版本"
|
||||
/>
|
||||
</a-form-item>
|
||||
<!-- 固件版本 -->
|
||||
<a-form-item
|
||||
field="firmwareVersion"
|
||||
label="固件版本"
|
||||
:rules="[{ required: true, message: '固件版本不能为空' }]"
|
||||
:validate-trigger="['change']"
|
||||
>
|
||||
<a-input
|
||||
v-model="formData.firmwareVersion"
|
||||
placeholder="请输入固件版本"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
field="remark"
|
||||
label="备注"
|
||||
>
|
||||
<a-textarea
|
||||
v-model="formData.remark"
|
||||
placeholder="请输入描述"
|
||||
/>
|
||||
</a-form-item>
|
||||
<!-- 扩展属性 -->
|
||||
<a-form-item field="extendParams" label="扩展属性">
|
||||
<!-- <a-input-->
|
||||
<!-- v-model="formData.extendParams"-->
|
||||
<!-- placeholder='请输入扩展属性'-->
|
||||
<!-- />-->
|
||||
<div style="width: 100%">
|
||||
<div style="width: 100%; margin-bottom: 5px">
|
||||
<a-space
|
||||
v-for="(param, index) in paramsData"
|
||||
:key="index"
|
||||
style="margin-bottom: 5px"
|
||||
>
|
||||
<a-input v-model="param.name" placeholder="名称" allow-clear />
|
||||
<a-input
|
||||
v-model="param.identifier"
|
||||
placeholder="标识"
|
||||
allow-clear
|
||||
/>
|
||||
<a-select
|
||||
v-model="param.dataType"
|
||||
:options="dataTypeOptions"
|
||||
allow-search
|
||||
placeholder="数据类型"
|
||||
style="width: 140px"
|
||||
/>
|
||||
<a-select
|
||||
v-model="param.type"
|
||||
:options="typeOptions"
|
||||
allow-search
|
||||
placeholder="类型"
|
||||
style="width: 140px"
|
||||
/>
|
||||
<a-button type="text" @click="handleDeleteParams(index)"
|
||||
><icon-minus-circle
|
||||
/></a-button>
|
||||
</a-space>
|
||||
</div>
|
||||
<a-button type="outline" @click="handleAddParams" style="width: 100%">
|
||||
<icon-plus />
|
||||
</a-button>
|
||||
</div>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
|
||||
<template #footer>
|
||||
<a-button class="editor-button" @click="handleCancel">取消</a-button>
|
||||
<a-button class="editor-button" type="primary" @click="handleSubmit"
|
||||
>确定</a-button
|
||||
>
|
||||
</template>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import useVisible from '@/hooks/visible';
|
||||
import {
|
||||
computed,
|
||||
defineEmits,
|
||||
PropType,
|
||||
ref,
|
||||
shallowRef,
|
||||
onBeforeUnmount,
|
||||
} from 'vue';
|
||||
import { CreateRecord } from '@/api/user';
|
||||
import { FormInstance } from '@arco-design/web-vue/es/form';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
import '@wangeditor/editor/dist/css/style.css';
|
||||
import { createDevice, queryDeviceByName, queryDeviceDetail, updateDevice } from '@/api/device';
|
||||
import type { SelectOptionData } from '@arco-design/web-vue/es/select/interface';
|
||||
import { queryProductDetail } from '@/api/product';
|
||||
|
||||
const props = defineProps({
|
||||
id: {
|
||||
type: Number,
|
||||
default: -1,
|
||||
},
|
||||
isCreate: Boolean,
|
||||
});
|
||||
const paramsData = ref([
|
||||
{
|
||||
name: '',
|
||||
identifier: '',
|
||||
dataType: '',
|
||||
type: '',
|
||||
},
|
||||
]);
|
||||
const dataTypeOptions = computed<SelectOptionData[]>(() => [
|
||||
{
|
||||
label: '整型',
|
||||
value: 'INT',
|
||||
},
|
||||
{
|
||||
label: '单精度浮点型',
|
||||
value: 'FLOAT',
|
||||
},
|
||||
{
|
||||
label: '双精度浮点型',
|
||||
value: 'DOUBLE',
|
||||
},
|
||||
{
|
||||
label: '布尔型',
|
||||
value: 'BOOLEAN',
|
||||
},
|
||||
{
|
||||
label: '字符串',
|
||||
value: 'STRING',
|
||||
},
|
||||
{
|
||||
label: '日期型',
|
||||
value: 'DATE',
|
||||
},
|
||||
{
|
||||
label: '透传',
|
||||
value: 'RAW',
|
||||
},
|
||||
]);
|
||||
const typeOptions = computed<SelectOptionData[]>(() => [
|
||||
{
|
||||
label: '输入',
|
||||
value: 'INPUT',
|
||||
},
|
||||
{
|
||||
label: '输出',
|
||||
value: 'OUTPUT',
|
||||
},
|
||||
{
|
||||
label: '读写属性',
|
||||
value: 'RW',
|
||||
},
|
||||
]);
|
||||
const emit = defineEmits(['refresh']);
|
||||
const modalTitle = computed(() => {
|
||||
return props.isCreate ? '创建设备' : '编辑设备';
|
||||
});
|
||||
const { visible, setVisible } = useVisible(false);
|
||||
const checkKeys = ref<number[]>([]);
|
||||
|
||||
const CreateRef = ref<FormInstance>();
|
||||
const formData = ref<any>({});
|
||||
const editorRef = shallowRef();
|
||||
const options = ref();
|
||||
const loading = ref(false);
|
||||
|
||||
// 搜索
|
||||
const handleSearch = (value: any) => {
|
||||
if (value) {
|
||||
loading.value = true;
|
||||
options.value = [];
|
||||
window.setTimeout(async () => {
|
||||
const res = await queryDeviceByName({
|
||||
name: value,
|
||||
page:1,
|
||||
size: 10,
|
||||
});
|
||||
options.value = res.data.records.map((item: any) => {
|
||||
return {
|
||||
id: item.id,
|
||||
name: item.name,
|
||||
};
|
||||
});
|
||||
loading.value = false;
|
||||
}, 1000);
|
||||
} else {
|
||||
options.value = [];
|
||||
}
|
||||
};
|
||||
|
||||
// 点击添加参数
|
||||
const handleAddParams = () => {
|
||||
// paramsVisible.value = true;
|
||||
paramsData.value.push({
|
||||
name: '',
|
||||
identifier: '',
|
||||
dataType: '',
|
||||
type: '',
|
||||
});
|
||||
};
|
||||
// 删除参数
|
||||
const handleDeleteParams = (record: number) => {
|
||||
if (record !== -1) {
|
||||
paramsData.value.splice(record, 1);
|
||||
}
|
||||
};
|
||||
// 组件被点击
|
||||
const handleClick = async () => {
|
||||
setVisible(true);
|
||||
|
||||
if (!props.isCreate) {
|
||||
queryDeviceDetail(props.id).then((res) => {
|
||||
formData.value = res.data;
|
||||
paramsData.value = res.data.extendParams;
|
||||
console.log('formData:', formData.value);
|
||||
|
||||
const ID = formData.value.productId;
|
||||
return queryProductDetail(ID);
|
||||
}).then((res) => {
|
||||
formData.value.productName = res.data.name;
|
||||
}).catch((error) => {
|
||||
console.error('Error fetching data:', error);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 提交
|
||||
const handleSubmit = async () => {
|
||||
const valid = await CreateRef.value?.validate();
|
||||
// formData.value.productId = formData.value.productId.id;
|
||||
if (!valid) {
|
||||
// 新增
|
||||
formData.value.extendParams = paramsData.value;
|
||||
const productId = await queryDeviceByName(formData.value.productName);
|
||||
formData.value.productId = productId.data.records[0].id;
|
||||
|
||||
if (props.isCreate) {
|
||||
// formData.value.username = formData.value.email;
|
||||
const res = await createDevice(formData.value);
|
||||
if (res.status === 200) {
|
||||
Message.success({
|
||||
content: '新建成功',
|
||||
duration: 5 * 1000,
|
||||
});
|
||||
emit('refresh');
|
||||
setVisible(false);
|
||||
}
|
||||
CreateRef.value?.resetFields();
|
||||
} else {
|
||||
// 编辑
|
||||
const res = await updateDevice(formData.value);
|
||||
if (res.status === 200) {
|
||||
Message.success({
|
||||
content: '修改成功',
|
||||
duration: 5 * 1000,
|
||||
});
|
||||
emit('refresh');
|
||||
setVisible(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 组件销毁时,也及时销毁编辑器
|
||||
onBeforeUnmount(() => {
|
||||
const editor = editorRef.value;
|
||||
if (editor == null) return;
|
||||
editor.destroy();
|
||||
});
|
||||
|
||||
// 关闭
|
||||
const handleCancel = async () => {
|
||||
checkKeys.value = [];
|
||||
setVisible(false);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.editor-button {
|
||||
position: static;
|
||||
}
|
||||
.card-wrap {
|
||||
height: 100%;
|
||||
transition: all 0.3s;
|
||||
border: 1px solid var(--color-neutral-3);
|
||||
&:hover {
|
||||
transform: translateY(-4px);
|
||||
}
|
||||
:deep(.arco-card-meta-description) {
|
||||
color: rgb(var(--gray-6));
|
||||
.arco-descriptions-item-label-inline {
|
||||
font-weight: normal;
|
||||
font-size: 12px;
|
||||
color: rgb(var(--gray-6));
|
||||
}
|
||||
.arco-descriptions-item-value-inline {
|
||||
color: rgb(var(--gray-8));
|
||||
}
|
||||
}
|
||||
}
|
||||
.empty-wrap {
|
||||
height: 210px;
|
||||
border-radius: 4px;
|
||||
:deep(.arco-card) {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 4px;
|
||||
.arco-result-title {
|
||||
color: rgb(var(--gray-6));
|
||||
}
|
||||
}
|
||||
}
|
||||
:deep(.list-wrap) {
|
||||
.list-row {
|
||||
align-items: stretch;
|
||||
.list-col {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="container">
|
||||
<Breadcrumb :items="['个人中心', '公告通知']" />
|
||||
<Breadcrumb :items="['系统管理', '公告设置']" />
|
||||
<a-card class="general-card" title=" ">
|
||||
<a-row>
|
||||
<a-col :flex="1">
|
||||
@ -12,39 +12,48 @@
|
||||
>
|
||||
<a-row :gutter="18">
|
||||
<a-col :span="9">
|
||||
<a-form-item field="title" label="标题">
|
||||
<a-form-item
|
||||
field="name"
|
||||
label='名称'
|
||||
>
|
||||
<a-input
|
||||
v-model="formModel.title"
|
||||
v-model="formModel.name"
|
||||
style="width: 360px"
|
||||
placeholder="请输入标题"
|
||||
placeholder='请输入设备名称'
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="10">
|
||||
<a-form-item field="Time" label="时间">
|
||||
<a-range-picker
|
||||
show-time
|
||||
format="YYYY-MM-DD HH:mm"
|
||||
@ok="timeRangs"
|
||||
<a-form-item field="status" label='状态'>
|
||||
<a-input
|
||||
v-model="formModel.status"
|
||||
style="width: 360px"
|
||||
placeholder='请输入设备状态'
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<!-- <a-col :span="9">-->
|
||||
<!-- <a-form-item field="isRead" label="状态">-->
|
||||
<!-- <a-select-->
|
||||
<!-- v-model="formModel.isRead"-->
|
||||
<!-- style="width: 360px"-->
|
||||
<!-- placeholder="请选择状态"-->
|
||||
<!-- :options="statusOptions"-->
|
||||
<!-- />-->
|
||||
<!-- </a-form-item>-->
|
||||
<!-- </a-col>-->
|
||||
<a-col :span="9">
|
||||
<a-form-item
|
||||
field="isOnline"
|
||||
label='在线'
|
||||
>
|
||||
<a-select
|
||||
v-model="formModel.isOnline"
|
||||
style="width: 360px"
|
||||
placeholder='请选择是否在线'
|
||||
:options="statusOptions"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
|
||||
|
||||
|
||||
</a-row>
|
||||
</a-form>
|
||||
</a-col>
|
||||
<!-- <a-divider style="height: 84px" direction="vertical" />-->
|
||||
<a-col :flex="'46px'" style="text-align: right">
|
||||
<a-space :size="18">
|
||||
<a-divider style="height: 84px" direction="vertical" />
|
||||
<a-col :flex="'86px'" style="text-align: right">
|
||||
<a-space direction="vertical" :size="18">
|
||||
<a-button type="primary" @click="search">
|
||||
<template #icon>
|
||||
<icon-search />
|
||||
@ -77,10 +86,9 @@
|
||||
<CardWrap
|
||||
:loading="loading"
|
||||
:id="item.id"
|
||||
:title="item.title"
|
||||
:remark="item.remark"
|
||||
:title="item.name"
|
||||
:createBy="item.createBy"
|
||||
:publishTime="item.publishTime"
|
||||
:createTime="item.createTime"
|
||||
open-txt="详情"
|
||||
>
|
||||
<template #skeleton>
|
||||
@ -94,29 +102,30 @@
|
||||
</template>
|
||||
</CardWrap>
|
||||
</a-col>
|
||||
<a-col
|
||||
:xs="12"
|
||||
:sm="12"
|
||||
:md="12"
|
||||
:lg="6"
|
||||
:xl="6"
|
||||
:xxl="6"
|
||||
class="list-col"
|
||||
>
|
||||
<div class="card-wrap empty-wrap">
|
||||
<a-card :bordered="false" hoverable>
|
||||
<a-result :status="null" title="点击创建设备">
|
||||
<template #icon>
|
||||
<icon-plus style="font-size: 20px" />
|
||||
</template>
|
||||
</a-result>
|
||||
</a-card>
|
||||
</div>
|
||||
</a-col>
|
||||
<DeviceEdit ref="createUserRef" :is-create="true" />
|
||||
<!-- <a-col-->
|
||||
<!-- :xs="12"-->
|
||||
<!-- :sm="12"-->
|
||||
<!-- :md="12"-->
|
||||
<!-- :lg="6"-->
|
||||
<!-- :xl="6"-->
|
||||
<!-- :xxl="6"-->
|
||||
<!-- class="list-col"-->
|
||||
<!-- >-->
|
||||
<!-- <div class="card-wrap empty-wrap">-->
|
||||
<!-- <a-card :bordered="false" hoverable>-->
|
||||
<!-- <a-result :status="null" title="点击创建设备">-->
|
||||
<!-- <template #icon>-->
|
||||
<!-- <icon-plus style="font-size: 20px" />-->
|
||||
<!-- </template>-->
|
||||
<!-- </a-result>-->
|
||||
<!-- </a-card>-->
|
||||
<!-- </div>-->
|
||||
<!-- </a-col>-->
|
||||
</a-row>
|
||||
</div>
|
||||
<a-pagination
|
||||
style="float: right; position: relative; right: 1px; bottom: 25px"
|
||||
style="float: right; position: relative; right: 1px; bottom: 25px; margin-top: 10px"
|
||||
:total="pagination.total"
|
||||
show-total
|
||||
show-jumper
|
||||
@ -129,41 +138,48 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
import useLoading from '@/hooks/loading';
|
||||
import { useBulletinsStore } from '@/store';
|
||||
import usePagination from '@/hooks/pagination';
|
||||
import { BulletinsList, BulletinsRecord } from '@/api/bulletins';
|
||||
import type { SelectOptionData } from '@arco-design/web-vue/es/select/interface';
|
||||
import { DeviceRecord, queryDeviceList } from '@/api/device';
|
||||
import DeviceEdit from '@/views/iot/deviceCard/components/device-edit.vue';
|
||||
import CardWrap from './components/card-wrap.vue';
|
||||
|
||||
const generateFormModel = () => {
|
||||
return {
|
||||
title: '',
|
||||
state: '',
|
||||
publishTimeBegin: '',
|
||||
publishTimeEnd: '',
|
||||
name:'',
|
||||
status:'',
|
||||
isOnline:'',
|
||||
};
|
||||
};
|
||||
|
||||
const { loading, setLoading } = useLoading(true);
|
||||
const renderData = ref<BulletinsList[]>([]);
|
||||
const { pagination,setPagination } = usePagination();
|
||||
const renderData = ref<[]>([]);
|
||||
const formModel = ref(generateFormModel());
|
||||
const { pagination, setPagination} = usePagination();
|
||||
|
||||
|
||||
const bulletinsStore = useBulletinsStore();
|
||||
const statusOptions = computed<SelectOptionData[]>(() => [
|
||||
{
|
||||
label: '是',
|
||||
value: 'true',
|
||||
},
|
||||
{
|
||||
label: '否',
|
||||
value: 'false',
|
||||
},
|
||||
]);
|
||||
|
||||
|
||||
// 获取公告列表
|
||||
// 获取设备列表
|
||||
const fetchData = async (
|
||||
params: BulletinsRecord = { size: 8, current: 1 }
|
||||
params = { size: 10, current: 1 }
|
||||
) => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const res = await bulletinsStore.getBulletinsList(params);
|
||||
const res: any = await queryDeviceList(params);
|
||||
renderData.value = res.data.records;
|
||||
setPagination(res.data);
|
||||
console.log(pagination.value.total);
|
||||
} catch (err) {
|
||||
// you can report use errorHandler or other
|
||||
} finally {
|
||||
@ -171,45 +187,56 @@
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// 时间范围
|
||||
const timeRangs = (dateString: string[]) => {
|
||||
// eslint-disable-next-line prefer-destructuring
|
||||
formModel.value.publishTimeBegin = dateString[0];
|
||||
// eslint-disable-next-line prefer-destructuring
|
||||
formModel.value.publishTimeEnd = dateString[1];
|
||||
};
|
||||
|
||||
|
||||
// 查询
|
||||
const search = () => {
|
||||
fetchData({
|
||||
...pagination.value,
|
||||
...formModel.value,
|
||||
} as unknown as BulletinsRecord);
|
||||
} as unknown as DeviceRecord);
|
||||
};
|
||||
|
||||
// 分页发生改变
|
||||
const onPageChange = (current: number) => {
|
||||
pagination.value.page = current;
|
||||
pagination.value.current = current;
|
||||
search();
|
||||
};
|
||||
|
||||
// 数据条数改变
|
||||
const onSizeChange = (total: number) => {
|
||||
pagination.value.total = total;
|
||||
console.log(pagination.value.total);
|
||||
const onSizeChange = (Size: number) => {
|
||||
pagination.value.size = Size;
|
||||
search();
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
search();
|
||||
})
|
||||
|
||||
// 重置
|
||||
const reset = () => {
|
||||
formModel.value = generateFormModel();
|
||||
};
|
||||
|
||||
// // 打开详情
|
||||
// function openDetail(id:number): void{
|
||||
// const url = router.resolve({
|
||||
// name: 'deviceDetail',
|
||||
// params: {id}
|
||||
// }).href;
|
||||
// router.push(url);
|
||||
// }
|
||||
|
||||
// // 删除
|
||||
// const handleDelete = async (id: number) => {
|
||||
// const res = await deleteDevice(id);
|
||||
// if (res.status === 200) {
|
||||
// Message.success({
|
||||
// content: '删除成功',
|
||||
// duration: 5 * 1000,
|
||||
// });
|
||||
// search();
|
||||
// }
|
||||
// };
|
||||
onMounted(() => {
|
||||
search();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
@ -257,4 +284,38 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style scoped lang="less">
|
||||
.container {
|
||||
padding: 0 20px 20px 20px;
|
||||
}
|
||||
|
||||
:deep(.arco-table-th) {
|
||||
&:last-child {
|
||||
.arco-table-th-item-title {
|
||||
margin-left: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.action-icon {
|
||||
margin-left: 12px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.active {
|
||||
color: #0960bd;
|
||||
background-color: #e3f4fc;
|
||||
}
|
||||
|
||||
.setting {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 200px;
|
||||
|
||||
.title {
|
||||
margin-left: 12px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,208 +0,0 @@
|
||||
<template>
|
||||
<a-button v-if="props.isCreate" type="primary">
|
||||
<template #icon><icon-plus /></template>
|
||||
新建
|
||||
</a-button>
|
||||
<a-button
|
||||
v-if="!props.isCreate"
|
||||
type="outline"
|
||||
size="small"
|
||||
:style="{ marginRight: '10px', padding: '7px' }"
|
||||
>
|
||||
<template #icon><icon-edit /></template>
|
||||
修改
|
||||
</a-button>
|
||||
|
||||
<a-modal
|
||||
width="700px"
|
||||
:visible="visible"
|
||||
@ok="handleSubmit"
|
||||
@cancel="handleCancel"
|
||||
>
|
||||
<template #title>{{ modalTitle }}</template>
|
||||
<a-form ref="CreateRef" :model="formData" :style="{ width: '650px' }">
|
||||
<a-form-item
|
||||
field="title"
|
||||
:label="$t('标题')"
|
||||
:validate-trigger="['change', 'input']"
|
||||
:rules="[
|
||||
{ required: true, message: '' },
|
||||
{
|
||||
match: /^[a-zA-Z0-9\u4e00-\u9fa5]{1,20}$/,
|
||||
message: '',
|
||||
},
|
||||
]"
|
||||
>
|
||||
<a-input v-model="formData.title" :placeholder="$t('请输入公告标题')" />
|
||||
<!-- v-if="props.isCreate"-->
|
||||
<!-- <div v-else>{{ formData.title }}</div>-->
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
field="email"
|
||||
:label="$t('作者')"
|
||||
:rules="[
|
||||
{
|
||||
required: true,
|
||||
type: 'email',
|
||||
message: t('user.info.email.required'),
|
||||
},
|
||||
]"
|
||||
:validate-trigger="['change', 'input']"
|
||||
>
|
||||
<a-input v-model="formData.email" :placeholder="$t('请输入作者')" />
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
field="phone"
|
||||
:label="$t('发布范围')"
|
||||
:rules="[
|
||||
{ required: true, message: t('user.info.phone.required') },
|
||||
{ match: /^1[3-9]\d{9}$/, message: t('user.info.phone.format') },
|
||||
]"
|
||||
:validate-trigger="['change', 'input']"
|
||||
>
|
||||
<a-input v-model="formData.phone" :placeholder="$t('请选择范围')" />
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
field="password"
|
||||
:label="$t('发布时间')"
|
||||
:validate-trigger="['change', 'input']"
|
||||
:rules="[{ required: true, message: t('user.info.password.required') }]"
|
||||
>
|
||||
<!-- v-if="isCreate"-->
|
||||
<a-input
|
||||
v-model="formData.password"
|
||||
:placeholder="$t('请选择发布时间')"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item field="nickName" :label="$t('公告内容')">
|
||||
<a-textarea
|
||||
default-value="请输入内容"
|
||||
:auto-size="{
|
||||
minRows: 2,
|
||||
maxRows: 5,
|
||||
}"
|
||||
style="margin-top: 20px"
|
||||
v-model="formData.content"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import useVisible from '@/hooks/visible';
|
||||
import { computed, PropType, ref } from 'vue';
|
||||
import { CreateRecord } from '@/api/user';
|
||||
import { FormInstance } from '@arco-design/web-vue/es/form';
|
||||
import { deptList } from '@/api/dept';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
import { useUserStore } from '@/store';
|
||||
|
||||
const props = defineProps({
|
||||
prem: {
|
||||
type: Object as PropType<CreateRecord>,
|
||||
},
|
||||
isCreate: Boolean,
|
||||
});
|
||||
const { t } = useI18n();
|
||||
const modalTitle = computed(() => {
|
||||
return props.isCreate ? t('新增公告') : t('编辑公告');
|
||||
});
|
||||
const { visible, setVisible } = useVisible(false);
|
||||
const checkKeys = ref<number[]>([]);
|
||||
|
||||
const CreateRef = ref<FormInstance>();
|
||||
|
||||
const formData = ref<any>({});
|
||||
|
||||
let formDifer = {};
|
||||
const userStore = useUserStore();
|
||||
|
||||
// 部门数据
|
||||
const deptOptions = ref();
|
||||
const getDeptData = async () => {
|
||||
const res = await deptList();
|
||||
deptOptions.value = res.data.records;
|
||||
};
|
||||
// 角色数据
|
||||
// const roleOptions = ref();
|
||||
// const getRoleData = async () => {
|
||||
// const res = await queryRoleList('');
|
||||
// roleOptions.value = res.data.records.filter((item: any) => {
|
||||
// return item.enabled !== false;
|
||||
// });
|
||||
// };
|
||||
|
||||
// 组件被点击
|
||||
// const handleClick = () => {
|
||||
// getDeptData();
|
||||
// // getRoleData();
|
||||
// const userId = props.prem?.id;
|
||||
// // 编辑
|
||||
// if (!props.isCreate && userId) {
|
||||
// formData.value = props.prem;
|
||||
// formDifer = { ...props.prem };
|
||||
// }
|
||||
// setVisible(true);
|
||||
// };
|
||||
|
||||
// 做出只修改的部分
|
||||
const diffDataForm = (newData: any, oldData: any) => {
|
||||
const result = {}; // 报错修改的字段内容
|
||||
Object.keys(oldData).forEach((key) => {
|
||||
if (oldData[key] !== newData[key]) {
|
||||
result[key] = newData[key];
|
||||
}
|
||||
});
|
||||
return result;
|
||||
};
|
||||
|
||||
// 提交
|
||||
const handleSubmit = async () => {
|
||||
const valid = await CreateRef.value?.validate();
|
||||
if (!valid) {
|
||||
formData.value.permissionIds = checkKeys.value;
|
||||
// 新增
|
||||
if (props.isCreate) {
|
||||
// formData.value.username = formData.value.email;
|
||||
const res = await userStore.createUser(formData.value);
|
||||
if (res.status === 200) {
|
||||
Message.success({
|
||||
content: t('create.sucess'),
|
||||
duration: 5 * 1000,
|
||||
});
|
||||
}
|
||||
CreateRef.value?.resetFields();
|
||||
} else {
|
||||
// 编辑
|
||||
formDifer = diffDataForm(formData.value, formDifer);
|
||||
if (Object.keys(formDifer).length === 0) {
|
||||
Message.success({
|
||||
content: t('unmodified'),
|
||||
duration: 3 * 1000,
|
||||
});
|
||||
} else {
|
||||
formDifer.id = formData.value.id;
|
||||
const res = await userStore.updateUser(formDifer);
|
||||
if (res.status === 200) {
|
||||
Message.success({
|
||||
content: t('modify.sucess'),
|
||||
duration: 5 * 1000,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
checkKeys.value = [];
|
||||
setVisible(false);
|
||||
}
|
||||
};
|
||||
|
||||
// 关闭
|
||||
const handleCancel = async () => {
|
||||
checkKeys.value = [];
|
||||
setVisible(false);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
@ -1,445 +0,0 @@
|
||||
<template>
|
||||
<div class="container">
|
||||
<Breadcrumb :items="['系统管理', '公告设置']" />
|
||||
<a-card class="general-card" title=" ">
|
||||
<a-row>
|
||||
<a-col :flex="1">
|
||||
<a-form
|
||||
:model="formModel"
|
||||
:label-col-props="{ span: 6 }"
|
||||
:wrapper-col-props="{ span: 18 }"
|
||||
label-align="right"
|
||||
>
|
||||
<a-row :gutter="18">
|
||||
<a-col :span="9">
|
||||
<a-form-item field="title" :label="$t('标题')">
|
||||
<a-input
|
||||
v-model="formModel.title"
|
||||
style="width: 360px"
|
||||
:placeholder="$t('请输入标题')"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="9">
|
||||
<a-form-item field="enable" :label="$t('状态')">
|
||||
<a-select
|
||||
v-model="formModel.states"
|
||||
style="width: 360px"
|
||||
:placeholder="$t('请选择状态')"
|
||||
:options="statusOptions"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
|
||||
<a-col :span="9">
|
||||
<a-form-item field="publishTimeBegin" :label="$t('开始时间')">
|
||||
<a-date-picker
|
||||
v-model="formModel.publishTimeBegin"
|
||||
style="width: 360px"
|
||||
show-time
|
||||
:time-picker-props="{ defaultValue: '09:09:06' }"
|
||||
format="YYYY-MM-DD HH:mm"
|
||||
:allow-clear="false"
|
||||
@select="onSelect"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="9">
|
||||
<a-form-item field="publishTimeEnd" :label="$t('结束时间')">
|
||||
<a-date-picker
|
||||
v-model="formModel.publishTimeEnd"
|
||||
style="width: 360px"
|
||||
show-time
|
||||
:time-picker-props="{ defaultValue: '09:09:06' }"
|
||||
format="YYYY-MM-DD HH:mm"
|
||||
:allow-clear="false"
|
||||
@select="onSelect"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-form>
|
||||
</a-col>
|
||||
<a-divider style="height: 84px" direction="vertical" />
|
||||
<a-col :flex="'86px'" style="text-align: right">
|
||||
<a-space direction="vertical" :size="18">
|
||||
<a-button type="primary" @click="search">
|
||||
<template #icon>
|
||||
<icon-search />
|
||||
</template>
|
||||
查询
|
||||
</a-button>
|
||||
<a-button @click="reset">
|
||||
<template #icon>
|
||||
<icon-refresh />
|
||||
</template>
|
||||
重置
|
||||
</a-button>
|
||||
</a-space>
|
||||
</a-col>
|
||||
</a-row>
|
||||
|
||||
<a-divider style="margin-top: 0" />
|
||||
<a-row>
|
||||
<a-col :span="12">
|
||||
<a-space>
|
||||
<NoticeEdit
|
||||
ref="createUserRef"
|
||||
:is-create="true"
|
||||
@refresh="search"
|
||||
/>
|
||||
</a-space>
|
||||
<a-button style="margin-left: 20px" @click="generateExcel">
|
||||
<template #icon>
|
||||
<icon-download size="18" />
|
||||
</template>
|
||||
导出
|
||||
</a-button>
|
||||
</a-col>
|
||||
<a-col
|
||||
:span="12"
|
||||
style="
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: end;
|
||||
padding-bottom: 20px;
|
||||
"
|
||||
>
|
||||
<a-tooltip :content="$t('刷新')">
|
||||
<div class="action-icon" @click="search">
|
||||
<icon-refresh size="18" />
|
||||
</div>
|
||||
</a-tooltip>
|
||||
|
||||
<a-dropdown @select="handleSelectDensity">
|
||||
<a-tooltip :content="$t('密度')">
|
||||
<div class="action-icon"><icon-line-height size="18" /></div>
|
||||
</a-tooltip>
|
||||
<template #content>
|
||||
<a-doption
|
||||
v-for="item in densityList"
|
||||
:key="item.value"
|
||||
:value="item.value"
|
||||
:class="{ active: item.value === sizeof }"
|
||||
>
|
||||
<span>{{ item.name }}</span>
|
||||
</a-doption>
|
||||
</template>
|
||||
</a-dropdown>
|
||||
|
||||
<a-tooltip :content="$t('列设置')">
|
||||
<a-popover
|
||||
trigger="click"
|
||||
position="bl"
|
||||
@popup-visible-change="popupVisibleChange"
|
||||
>
|
||||
<div class="action-icon"><icon-settings size="18" /></div>
|
||||
<template #content>
|
||||
<div id="tableSetting">
|
||||
<div
|
||||
v-for="(item, index) in showColumns"
|
||||
:key="item.dataIndex"
|
||||
class="setting"
|
||||
>
|
||||
<div style="margin-right: 4px; cursor: move">
|
||||
<icon-drag-arrow />
|
||||
</div>
|
||||
<div>
|
||||
<a-checkbox
|
||||
v-model="item.checked"
|
||||
@change="
|
||||
handleChange($event, item as TableColumnData, index)
|
||||
"
|
||||
>
|
||||
</a-checkbox>
|
||||
</div>
|
||||
<div class="title">
|
||||
{{ item.title === '#' ? '序列号' : item.title }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</a-popover>
|
||||
</a-tooltip>
|
||||
</a-col>
|
||||
</a-row>
|
||||
|
||||
<a-table
|
||||
row-key="id"
|
||||
:loading="loading"
|
||||
:pagination="false"
|
||||
:columns="(cloneColumns as TableColumnData[])"
|
||||
:data="renderData"
|
||||
:bordered="false"
|
||||
:size="size"
|
||||
style="margin-bottom: 40px"
|
||||
:filter-icon-align-left="alignLeft"
|
||||
@change="handleSortChange"
|
||||
@page-change="onPageChange"
|
||||
>
|
||||
<template #index="{ rowIndex }">
|
||||
{{ rowIndex + 1 + (pagination.current - 1) * pagination.size }}
|
||||
</template>
|
||||
<template #enabled="{ record }">
|
||||
<a-switch
|
||||
:model-value="record.enabled"
|
||||
:checked-value="true"
|
||||
:unchecked-value="false"
|
||||
@change="enabledStatus(record)"
|
||||
/>
|
||||
</template>
|
||||
<template #operations="{ record }">
|
||||
<a-button
|
||||
type="outline"
|
||||
size="small"
|
||||
status="success"
|
||||
style="padding: 7px; margin-right: 10px"
|
||||
>
|
||||
<template #icon><icon-list /></template>
|
||||
详情
|
||||
</a-button>
|
||||
|
||||
<NoticeEdit
|
||||
ref="editUserRef"
|
||||
:prem="record"
|
||||
:is-create="false"
|
||||
@refresh="fetchData"
|
||||
/>
|
||||
<a-button
|
||||
type="outline"
|
||||
size="small"
|
||||
status="danger"
|
||||
style="padding: 7px"
|
||||
>
|
||||
<template #icon><icon-delete /></template>
|
||||
删除
|
||||
</a-button>
|
||||
</template>
|
||||
</a-table>
|
||||
<a-pagination
|
||||
style="float: right; position: relative; right: 1px; bottom: 25px"
|
||||
:total="pagination.total"
|
||||
:size="size"
|
||||
show-total
|
||||
show-jumper
|
||||
show-page-size
|
||||
@page-size-change="onSizeChange"
|
||||
@change="onPageChange"
|
||||
/>
|
||||
</a-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import useLoading from '@/hooks/loading';
|
||||
import { UserRecord, UserParams } from '@/api/user';
|
||||
import { Pagination } from '@/types/global';
|
||||
import type { SelectOptionData } from '@arco-design/web-vue/es/select/interface';
|
||||
import type { TableColumnData } from '@arco-design/web-vue/es/table/interface';
|
||||
import { useUserStore } from '@/store';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
import useTableOption from '@/hooks/table-option';
|
||||
import NoticeEdit from './components/notice-edit.vue';
|
||||
|
||||
const generateFormModel = () => {
|
||||
return {
|
||||
title: '',
|
||||
states: '',
|
||||
publishTimeBegin: '',
|
||||
publishTimeEnd: '',
|
||||
};
|
||||
};
|
||||
|
||||
const { loading, setLoading } = useLoading(true);
|
||||
const { t } = useI18n();
|
||||
const renderData = ref<UserRecord[]>([]);
|
||||
const formModel = ref(generateFormModel());
|
||||
|
||||
const {
|
||||
cloneColumns,
|
||||
showColumns,
|
||||
densityList,
|
||||
handleSelectDensity,
|
||||
handleChange,
|
||||
popupVisibleChange,
|
||||
deepClone,
|
||||
} = useTableOption();
|
||||
const sizeof = useTableOption().size;
|
||||
|
||||
const userStore = useUserStore();
|
||||
|
||||
const pagination: Pagination = {
|
||||
page: 1,
|
||||
size: 10,
|
||||
current: 1,
|
||||
total: null,
|
||||
};
|
||||
|
||||
const columns = computed<TableColumnData[]>(() => [
|
||||
{
|
||||
title: '序号',
|
||||
dataIndex: 'index',
|
||||
slotName: 'index',
|
||||
width: 60,
|
||||
},
|
||||
{
|
||||
title: '标题',
|
||||
dataIndex: 'title',
|
||||
sortable: {
|
||||
sortDirections: ['ascend', 'descend'],
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t('时间'),
|
||||
dataIndex: 'publishTimeBegin',
|
||||
sortable: {
|
||||
sortDirections: ['ascend', 'descend'],
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t('状态'),
|
||||
dataIndex: 'states',
|
||||
sortable: {
|
||||
sortDirections: ['ascend', 'descend'],
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'operations',
|
||||
slotName: 'operations',
|
||||
},
|
||||
]);
|
||||
const statusOptions = computed<SelectOptionData[]>(() => [
|
||||
{
|
||||
label: t('已发布'),
|
||||
value: 'true',
|
||||
},
|
||||
{
|
||||
label: t('未发布'),
|
||||
value: 'false',
|
||||
},
|
||||
]);
|
||||
|
||||
// 获取公告列表
|
||||
const fetchData = async (
|
||||
params: UserParams = { page: 1, size: 10, current: 1 }
|
||||
) => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const res = await userStore.getUserList(params);
|
||||
renderData.value = res.data.records;
|
||||
pagination.page = res.data.page;
|
||||
pagination.current = res.data.current;
|
||||
pagination.total = res.data.total;
|
||||
pagination.size = res.data.size;
|
||||
} catch (err) {
|
||||
// you can report use errorHandler or other
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// 查询
|
||||
const search = () => {
|
||||
fetchData({
|
||||
...pagination,
|
||||
...formModel.value,
|
||||
} as unknown as UserParams);
|
||||
};
|
||||
|
||||
// 分页发生改变
|
||||
const onPageChange = (current: number) => {
|
||||
pagination.page = current;
|
||||
pagination.current = current;
|
||||
search();
|
||||
};
|
||||
|
||||
// 数据条数改变
|
||||
const onSizeChange = (size: number) => {
|
||||
pagination.size = size;
|
||||
search();
|
||||
};
|
||||
|
||||
search();
|
||||
|
||||
// 重置
|
||||
const reset = () => {
|
||||
formModel.value = generateFormModel();
|
||||
};
|
||||
|
||||
// 表格内部排序
|
||||
const alignLeft = ref(false);
|
||||
const handleSortChange = (
|
||||
data: any,
|
||||
extra: any,
|
||||
currentDataSource: any
|
||||
) => {};
|
||||
|
||||
// 是否启用
|
||||
const enabledStatus = async (record: string) => {
|
||||
record.enabled = !record.enabled;
|
||||
const res = await userStore.enabledUser(record.id);
|
||||
if (res.status === 200) {
|
||||
Message.success({
|
||||
content: t('modify.status.sucess'),
|
||||
duration: 3 * 1000,
|
||||
});
|
||||
} else {
|
||||
Message.error({
|
||||
content: t('modify.status.fail'),
|
||||
duration: 3 * 1000,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 删除
|
||||
// const handleDelete = async (record: UserRecord) => {
|
||||
// const res = await userStore.removeUser(record.id);
|
||||
// if (res.status === 200) {
|
||||
// Message.success({
|
||||
// content: '删除成功',
|
||||
// duration: 5 * 1000,
|
||||
// });
|
||||
// search();
|
||||
// }
|
||||
// };
|
||||
|
||||
watch(() => columns.value, deepClone, { deep: true, immediate: true });
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.container {
|
||||
padding: 0 20px 20px 20px;
|
||||
}
|
||||
|
||||
:deep(.arco-table-th) {
|
||||
&:last-child {
|
||||
.arco-table-th-item-title {
|
||||
margin-left: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.action-icon {
|
||||
margin-left: 12px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.active {
|
||||
color: #0960bd;
|
||||
background-color: #e3f4fc;
|
||||
}
|
||||
|
||||
.setting {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 200px;
|
||||
|
||||
.title {
|
||||
margin-left: 12px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,148 +0,0 @@
|
||||
<template>
|
||||
<div class="container">
|
||||
<Breadcrumb :items="['个人中心', '公告通知','公告详情']" />
|
||||
<a-card class="general-card" title=" ">
|
||||
<div class="announcement-detail">
|
||||
<div class="header">
|
||||
<h1>{{ renderData.title }}</h1>
|
||||
<div class="meta">
|
||||
<span>作者: {{ renderData.createBy }}</span>
|
||||
<span
|
||||
>时间: {{ dayjs(renderData.publishTime).format('YYYY-MM-DD') }}</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<a-divider style="margin-top: 0" />
|
||||
<div v-html="renderData.content" class="content"></div>
|
||||
<div>
|
||||
<ul class="attachments">
|
||||
<li v-for="(item, index) in renderData.attachments" :key="index">
|
||||
<a
|
||||
:href="item.url"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<icon-download />
|
||||
{{ item.fileName }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</a-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import dayjs from 'dayjs';
|
||||
import { useBulletinStore } from '@/store';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { onMounted, ref } from 'vue';
|
||||
|
||||
const bulletinStore = useBulletinStore();
|
||||
const route = useRoute();
|
||||
const id = Number(route.params.id);
|
||||
const renderData = ref<any>([]);
|
||||
// const attachmentList = ref<any>([]);
|
||||
const fetchData = async (Id: number) => {
|
||||
const res = await bulletinStore.queryBulletinDetail(Id);
|
||||
// attachmentList.value = await bulletinStore.queryAttachmentInfo(
|
||||
// '28452d83420650425d45110c6417bf693b966b29'
|
||||
// );
|
||||
// eslint-disable-next-line prefer-destructuring
|
||||
renderData.value = res.data;
|
||||
};
|
||||
onMounted(() => {
|
||||
fetchData(id);
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped>
|
||||
.container {
|
||||
padding: 0 20px 20px 20px;
|
||||
}
|
||||
|
||||
.announcement-detail {
|
||||
min-width: 800px;
|
||||
max-width: 800px;
|
||||
margin: auto;
|
||||
padding: 20px;
|
||||
border: 1px solid #ddd;
|
||||
background-color: #fff; /* 白色背景,与淡蓝色背景区分开来 */
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
h1 {
|
||||
font-size: 24px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.meta {
|
||||
margin-bottom: 20px;
|
||||
color: #777;
|
||||
}
|
||||
|
||||
.meta span {
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.content {
|
||||
line-height: 1.6;
|
||||
}
|
||||
.attachments li {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.attachments a {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 14px;
|
||||
color: #1890ff;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.attachments a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.attachments .arco-icon {
|
||||
margin-right: 8px;
|
||||
color: #1890ff;
|
||||
}
|
||||
.layout-demo :deep(.arco-layout-header),
|
||||
.layout-demo :deep(.arco-layout-footer),
|
||||
.layout-demo :deep(.arco-layout-sider-children),
|
||||
.layout-demo :deep(.arco-layout-content) {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
color: var(--color-white);
|
||||
font-size: 16px;
|
||||
font-stretch: condensed;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.layout-demo :deep(.arco-layout-header),
|
||||
.layout-demo :deep(.arco-layout-footer) {
|
||||
height: 64px;
|
||||
background-color: var(--color-primary-light-4);
|
||||
}
|
||||
|
||||
.layout-demo :deep(.arco-layout-sider) {
|
||||
width: 206px;
|
||||
background-color: var(--color-primary-light-3);
|
||||
}
|
||||
|
||||
.layout-demo :deep(.arco-layout-content) {
|
||||
background-color: rgb(var(--arcoblue-6));
|
||||
}
|
||||
</style>
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user