[tag] 实现基本功能demo

This commit is contained in:
LYC 2025-04-26 23:11:00 +08:00
parent 76e92b461d
commit fd0d380ae9
10 changed files with 379 additions and 74 deletions

View File

@ -1,7 +1,7 @@
# backend service base url, prod environment
VITE_SERVICE_BASE_URL=http://localhost:8080
VITE_SERVICE_BASE_URL=http://154.219.110.17:8080
# other backend service base url, prod environment
VITE_OTHER_SERVICE_BASE_URL= `{
"demo": "http://localhost:9529"
}`
# VITE_OTHER_SERVICE_BASE_URL= `{
# "demo": "http://localhost:9529"
# }`

View File

@ -109,7 +109,8 @@ export const generatedRoutes: GeneratedRoute[] = [
title: 'function',
i18nKey: 'route.function',
icon: 'icon-park-outline:all-application',
order: 6
order: 6,
hideInMenu: true
},
children: [
{

View File

@ -7,46 +7,22 @@ export {}
/* prettier-ignore */
declare module 'vue' {
export interface GlobalComponents {
ABreadcrumb: typeof import('ant-design-vue/es')['Breadcrumb']
ABreadcrumbItem: typeof import('ant-design-vue/es')['BreadcrumbItem']
AButton: typeof import('ant-design-vue/es')['Button']
ACard: typeof import('ant-design-vue/es')['Card']
ACheckbox: typeof import('ant-design-vue/es')['Checkbox']
ACol: typeof import('ant-design-vue/es')['Col']
ADescriptions: typeof import('ant-design-vue/es')['Descriptions']
ADescriptionsItem: typeof import('ant-design-vue/es')['DescriptionsItem']
ADivider: typeof import('ant-design-vue/es')['Divider']
ADrawer: typeof import('ant-design-vue/es')['Drawer']
ADropdown: typeof import('ant-design-vue/es')['Dropdown']
AEmpty: typeof import('ant-design-vue/es')['Empty']
AForm: typeof import('ant-design-vue/es')['Form']
AFormItem: typeof import('ant-design-vue/es')['FormItem']
AInput: typeof import('ant-design-vue/es')['Input']
AInputNumber: typeof import('ant-design-vue/es')['InputNumber']
AInputPassword: typeof import('ant-design-vue/es')['InputPassword']
AInputSearch: typeof import('ant-design-vue/es')['InputSearch']
AList: typeof import('ant-design-vue/es')['List']
AListItem: typeof import('ant-design-vue/es')['ListItem']
AListItemMeta: typeof import('ant-design-vue/es')['ListItemMeta']
AMenu: typeof import('ant-design-vue/es')['Menu']
AMenuDivider: typeof import('ant-design-vue/es')['MenuDivider']
AMenuItem: typeof import('ant-design-vue/es')['MenuItem']
AModal: typeof import('ant-design-vue/es')['Modal']
APopconfirm: typeof import('ant-design-vue/es')['Popconfirm']
APopover: typeof import('ant-design-vue/es')['Popover']
APagination: typeof import('ant-design-vue/es')['Pagination']
AppProvider: typeof import('./../components/common/app-provider.vue')['default']
ARadio: typeof import('ant-design-vue/es')['Radio']
ARadioGroup: typeof import('ant-design-vue/es')['RadioGroup']
ARow: typeof import('ant-design-vue/es')['Row']
ASegmented: typeof import('ant-design-vue/es')['Segmented']
ASelect: typeof import('ant-design-vue/es')['Select']
ASelectOption: typeof import('ant-design-vue/es')['SelectOption']
ASpace: typeof import('ant-design-vue/es')['Space']
AStatistic: typeof import('ant-design-vue/es')['Statistic']
ASwitch: typeof import('ant-design-vue/es')['Switch']
ATable: typeof import('ant-design-vue/es')['Table']
ATag: typeof import('ant-design-vue/es')['Tag']
ATooltip: typeof import('ant-design-vue/es')['Tooltip']
ATree: typeof import('ant-design-vue/es')['Tree']
AWatermark: typeof import('ant-design-vue/es')['Watermark']
BetterScroll: typeof import('./../components/custom/better-scroll.vue')['default']
@ -55,21 +31,6 @@ declare module 'vue' {
DarkModeContainer: typeof import('./../components/common/dark-mode-container.vue')['default']
ExceptionBase: typeof import('./../components/common/exception-base.vue')['default']
FullScreen: typeof import('./../components/common/full-screen.vue')['default']
IconAntDesignReloadOutlined: typeof import('~icons/ant-design/reload-outlined')['default']
IconAntDesignSettingOutlined: typeof import('~icons/ant-design/setting-outlined')['default']
IconCarbonAdd: typeof import('~icons/carbon/add')['default']
IconGridiconsFullscreen: typeof import('~icons/gridicons/fullscreen')['default']
IconGridiconsFullscreenExit: typeof import('~icons/gridicons/fullscreen-exit')['default']
'IconIc:roundPlus': typeof import('~icons/ic/round-plus')['default']
IconIcRoundDelete: typeof import('~icons/ic/round-delete')['default']
IconIcRoundPlus: typeof import('~icons/ic/round-plus')['default']
IconIcRoundRefresh: typeof import('~icons/ic/round-refresh')['default']
IconIcRoundRemove: typeof import('~icons/ic/round-remove')['default']
IconIcRoundSearch: typeof import('~icons/ic/round-search')['default']
IconLocalBanner: typeof import('~icons/local/banner')['default']
IconLocalLogo: typeof import('~icons/local/logo')['default']
IconMdiDrag: typeof import('~icons/mdi/drag')['default']
IconMdiRefresh: typeof import('~icons/mdi/refresh')['default']
LangSwitch: typeof import('./../components/common/lang-switch.vue')['default']
LookForward: typeof import('./../components/custom/look-forward.vue')['default']
MenuToggler: typeof import('./../components/common/menu-toggler.vue')['default']

View File

@ -3,17 +3,39 @@ import axios from 'axios';
import { localStg } from '@/utils/storage';
// 封装网络请求的接口
export const apiRequest = async (path: string, data: any) => {
let url = "http://localhost:8080" + path;
const token = localStg.get('token'); // 获取 token
try {
const response = await axios.post(url, data, {
headers: {
Authorization: `Bearer ${token}`, // 添加 Authorization 头
},
});
return response.data; // 返回响应数据
} catch (error) {
throw new Error('请求失败'); // 抛出错误
}
};
export const apiRequest = async (method: 'GET' | 'POST' | 'PUT' | 'DELETE', path: string, data?: any) => {
let url = "http://localhost:8080" + path;
const token = localStg.get('token'); // 获取 token
try {
const response = await axios({
method,
url,
data,
headers: {
Authorization: `Bearer ${token}`, // 添加 Authorization 头
},
});
return response.data; // 返回响应数据
} catch (error) {
throw new Error('请求失败'); // 抛出错误
}
};
export const apiRequestGet = async (path: string) => {
let url = "http://localhost:8080" + path;
const token = localStg.get('token'); // 获取 token
try {
return axios.get(
url,
{
headers: {
Authorization: `Bearer ${token}`, // 添加 Authorization 头
},
}
);
} catch (error) {
throw new Error('请求失败'); // 抛出错误
}
};
export default apiRequest;

View File

@ -35,7 +35,7 @@ const services = ref([
id: 1,
name: '图像识别模型',
status: 'Running',
responseTime: 120,
responseTime: Math.floor(Math.random() * 500),
health: 'Healthy',
lastUpdated: new Date().toLocaleTimeString(),
},
@ -43,7 +43,7 @@ const services = ref([
id: 2,
name: '大语言模型',
status: 'Running',
responseTime: 0,
responseTime: Math.floor(Math.random() * 500),
health: 'Healthy',
lastUpdated: new Date().toLocaleTimeString(),
}

View File

@ -74,7 +74,8 @@
import { ref, onMounted } from 'vue';
import { message, Modal } from 'ant-design-vue';
import axios from 'axios';
import { apiRequestGet } from '@/utils/api'
import { localStg } from '@/utils/storage';
//
const treeData = ref([]);
//
@ -96,7 +97,8 @@ const selectedKeys = ref([]);
//
const fetchDepartments = async () => {
try {
const response = await axios.get('http://localhost:8080/api/departments');
const response = await apiRequestGet('/api/department/allDepartment');
if (response.data.success) {
//
const deptMap = new Map();

View File

@ -1,7 +1,151 @@
<script setup lang="ts"></script>
<!-- fac.vue -->
<template>
<div>facility</div>
<div class="facility-management">
<a-card title="设施管理" :bordered="false">
<!-- 搜索和操作区域 -->
<div class="search-bar" style="margin-bottom: 16px;">
<a-form
:model="searchForm"
layout="inline"
class="search-form"
>
<a-form-item label="设施编号">
<a-input v-model:value="searchForm.code" placeholder="请输入设施编号" />
</a-form-item>
<a-form-item label="设施类型">
<a-select
v-model:value="searchForm.type"
placeholder="请选择类型"
style="width: 200px"
>
<a-select-option value="PIPELINE">管道</a-select-option>
<!-- 可以根据需求添加更多类型 -->
</a-select>
</a-form-item>
<a-form-item>
<a-button type="primary" @click="fetchData">查询</a-button>
<a-button style="margin-left: 8px" @click="resetForm">重置</a-button>
</a-form-item>
</a-form>
</div>
<!-- 表格展示 -->
<a-table
:columns="columns"
:data-source="dataSource"
:loading="loading"
:pagination="pagination"
row-key="id"
@change="handleTableChange"
>
<template #status="{ record }">
<a-tag :color="getStatusColor(record.status)">
{{ statusText(record.status) }}
</a-tag>
</template>
</a-table>
</a-card>
</div>
</template>
<style scoped></style>
<script setup>
import { ref, reactive, onMounted } from 'vue';
import { message } from 'ant-design-vue';
import axios from 'axios';
import {apiRequestGet} from '@/utils/api'
//
const columns = [
{ title: '设施编号', dataIndex: 'code', key: 'code' },
{ title: '设施类型', dataIndex: 'type', key: 'type' },
{ title: '区域', dataIndex: 'area', key: 'area' },
{ title: '状态', dataIndex: 'status', key: 'status', slots: { customRender: 'status' } },
{ title: '安装日期', dataIndex: 'installDate', key: 'installDate' },
{ title: '上次维护日期', dataIndex: 'lastMaintainDate', key: 'lastMaintainDate' },
];
//
const dataSource = ref([]);
const loading = ref(false);
//
const pagination = reactive({
current: 1,
pageSize: 10,
total: 0,
});
//
const searchForm = reactive({
code: '',
type: '',
});
//
const getStatusColor = (status) => {
return status === 'NORMAL' ? 'green' : 'red';
};
const statusText = (status) => {
return status === 'NORMAL' ? '正常' : '异常';
};
//
const fetchData = async () => {
loading.value = true;
try {
const params = {
page: pagination.current,
size: pagination.pageSize,
code: searchForm.code || undefined,
type: searchForm.type || undefined,
};
const response = await apiRequestGet('/api/facilities/list', { params });
if (response.data.success) {
dataSource.value = response.data.data;
pagination.total = response.data.total || response.data.data.length;
} else {
message.error(response.data.errorMsg || '数据获取失败');
dataSource.value = [];
}
} catch (error) {
message.error('请求失败: ' + error.message);
dataSource.value = [];
} finally {
loading.value = false;
}
};
//
const resetForm = () => {
searchForm.code = '';
searchForm.type = '';
pagination.current = 1;
fetchData();
};
//
const handleTableChange = (pag) => {
pagination.current = pag.current;
pagination.pageSize = pag.pageSize;
fetchData();
};
//
onMounted(() => {
fetchData();
});
</script>
<style scoped>
.facility-management {
padding: 20px;
}
.search-bar {
display: flex;
justify-content: space-between;
}
.search-form {
flex: 1;
}
</style>

View File

@ -22,9 +22,9 @@ import CreativityBanner from './modules/creativity-banner.vue';
</ARow>
-->
<ARow :gutter="[16, 16]">
<ACol :span="24" :lg="14">
<!-- <ACol :span="24" :lg="14">
<ProjectNews />
</ACol>
</ACol> -->
<!--
<ACol :span="24" :lg="10">
<CreativityBanner />

View File

@ -1,7 +1,182 @@
<script setup lang="ts"></script>
<template>
<div>plan</div>
<div class="plan-container">
<h2>计划管理</h2>
<a-table
:columns="columns"
:data-source="planData"
:pagination="false"
:loading="loading"
:row-key="record => record.planId"
>
<template #status="{ record }">
<a-tag :color="getStatusColor(record.status)">
{{ statusMap[record.status] || record.status }}
</a-tag>
</template>
<template #createdAt="{ record }">
{{ formatDate(record.createdAt) }}
</template>
</a-table>
<div class="pagination-wrapper">
<a-pagination
v-model:current="pagination.current"
v-model:pageSize="pagination.pageSize"
:total="pagination.total"
:show-size-changer="true"
:page-size-options="['10', '20', '50', '100']"
@change="handlePageChange"
@showSizeChange="handlePageSizeChange"
/>
</div>
</div>
</template>
<style scoped></style>
<script>
import { ref, onMounted } from 'vue';
import axios from 'axios';
import dayjs from 'dayjs';
import { Tag } from 'ant-design-vue';
import { apiRequestGet } from '@/utils/api';
export default {
name: 'PlanManagement',
setup() {
//
const columns = [
{
title: '计划ID',
dataIndex: 'planId',
key: 'planId',
width: 100,
},
{
title: '区域',
dataIndex: 'area',
key: 'area',
width: 150,
},
{
title: '状态',
dataIndex: 'status',
key: 'status',
slots: { customRender: 'status' },
width: 120,
},
{
title: '创建时间',
dataIndex: 'createdAt',
key: 'createdAt',
slots: { customRender: 'createdAt' },
width: 150,
},
];
//
const planData = ref([]);
const loading = ref(false);
//
const pagination = ref({
current: 1,
pageSize: 10,
total: 0,
});
//
const statusMap = {
COMPLETED: '已完成',
CANCELLED: '已取消',
SCHEDULED: '已计划',
};
const getStatusColor = (status) => {
switch (status) {
case 'COMPLETED':
return 'green';
case 'CANCELLED':
return 'red';
case 'SCHEDULED':
return 'blue';
default:
return 'default';
}
};
//
const formatDate = (date) => {
return date ? dayjs(date).format('YYYY-MM-DD HH:mm:ss') : '-';
};
//
const fetchPlanData = async () => {
loading.value = true;
try {
//
const response = await apiRequestGet("/api/inspection-plans/employee/my-plan")
if (response.data.success) {
planData.value = response.data.data;
//
pagination.value.total = 50; // response.data.total
} else {
console.error('获取计划数据失败:', response.data.errorMsg);
}
} catch (error) {
console.error('请求失败:', error);
} finally {
loading.value = false;
}
};
//
const handlePageChange = (page) => {
pagination.value.current = page;
fetchPlanData();
};
//
const handlePageSizeChange = (current, size) => {
pagination.value.pageSize = size;
pagination.value.current = 1; //
fetchPlanData();
};
//
onMounted(() => {
fetchPlanData();
});
return {
columns,
planData,
loading,
pagination,
statusMap,
getStatusColor,
formatDate,
handlePageChange,
handlePageSizeChange,
};
},
};
</script>
<style scoped>
.plan-container {
padding: 20px;
background: #fff;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
h2 {
margin-bottom: 20px;
font-size: 20px;
color: #333;
}
.pagination-wrapper {
margin-top: 16px;
text-align: right;
}
</style>

View File

@ -1,7 +1,7 @@
<script setup lang="ts"></script>
<template>
<LookForward />
<!-- <LookForward /> -->
</template>
<style scoped></style>