Ver Código Fonte

油站信息

miaofuhao 3 meses atrás
pai
commit
674fed04a3

+ 2 - 12
apps/web-ele/src/adapter/component/index.ts

@@ -180,18 +180,8 @@ async function initComponentAdapter() {
180 180
             options.map((option, index) => {
181 181
               // 确保每个选项都有正确的value和label属性
182 182
               const optionProps = {
183
-                label:
184
-                  option.value === undefined
185
-                    ? option.label === undefined
186
-                      ? option
187
-                      : option.label)
188
-                    : option.value,
189
-                value:
190
-                  option.value === undefined
191
-                    ? option.label === undefined
192
-                      ? option
193
-                      : option.label)
194
-                    : option.value,
183
+                label: option.value === undefined ? option.label === undefined ? option : option.label : option.value,
184
+                value: option.value === undefined ? option.label === undefined ? option : option.label : option.value,
195 185
                 ...option,
196 186
               };
197 187
               return h(isButton ? ElRadioButton : ElRadio, optionProps);

+ 78 - 0
apps/web-ele/src/api/system/infoEntry/districtInfo/districtInfo.ts

@@ -0,0 +1,78 @@
1
+import type { DistrictInfoModel } from './model';
2
+
3
+import type { BaseResult } from '#/api/base-result';
4
+
5
+import { commonExport } from '#/api/helper';
6
+import { requestClient } from '#/api/request';
7
+
8
+// API路径常量枚举
9
+enum Api {
10
+  // 导出
11
+  export = '/sysStationArea/area/export',
12
+  // 列表查询
13
+  list = '/sysStationArea/area/list',
14
+  // 基础路径
15
+  root = '/sysStationArea/area',
16
+}
17
+
18
+/**
19
+ * 查询片区信息列表
20
+ * @param params 查询参数
21
+ * @returns 分页结果
22
+ */
23
+export function districtInfoList(params: any) {
24
+  return requestClient.get<BaseResult<DistrictInfoModel[]>>(Api.list, {
25
+    params,
26
+  });
27
+}
28
+
29
+/**
30
+ * 获取片区信息详细信息
31
+ * @param id 片区信息ID
32
+ * @returns 片区信息详情
33
+ */
34
+export function getDistrictInfoDetail(id: number) {
35
+  return requestClient.get<DistrictInfoModel>(`${Api.root}/${id}`);
36
+}
37
+
38
+/**
39
+ * 新增片区信息
40
+ * @param data 片区信息数据
41
+ * @returns 操作结果
42
+ */
43
+export function addDistrictInfo(data: DistrictInfoModel) {
44
+  return requestClient.post(Api.root, data, {
45
+    successMessageMode: 'message',
46
+  });
47
+}
48
+
49
+/**
50
+ * 修改片区信息
51
+ * @param data 片区信息数据
52
+ * @returns 操作结果
53
+ */
54
+export function updateDistrictInfo(data: DistrictInfoModel) {
55
+  return requestClient.put(Api.root, data, {
56
+    successMessageMode: 'message',
57
+  });
58
+}
59
+
60
+/**
61
+ * 删除片区信息
62
+ * @param ids 片区信息ID数组
63
+ * @returns 操作结果
64
+ */
65
+export function deleteDistrictInfo(ids: number[]) {
66
+  return requestClient.delete(`${Api.root}/${ids.join(',')}`, {
67
+    successMessageMode: 'message',
68
+  });
69
+}
70
+
71
+/**
72
+ * 导出片区信息列表
73
+ * @param data 导出参数
74
+ * @returns 导出结果
75
+ */
76
+export function exportDistrictInfo(data: Partial<DistrictInfoModel>) {
77
+  return commonExport(Api.export, data);
78
+}

+ 18 - 0
apps/web-ele/src/api/system/infoEntry/districtInfo/model.ts

@@ -0,0 +1,18 @@
1
+export interface DistrictInfoModel {
2
+  // 主键ID
3
+  id?: number;
4
+  // 片区编码
5
+  areaCode?: string;
6
+  // 片区名称
7
+  areaName?: string;
8
+  // 详细地址
9
+  address?: string;
10
+  // 联系电话
11
+  contactPhone?: string;
12
+  // 片区负责人
13
+  manager?: string;
14
+  // 状态:0-禁用,1-启用
15
+  status?: number;
16
+  // 修改时间
17
+  updatedAt?: string;
18
+}

+ 18 - 0
apps/web-ele/src/api/system/infoEntry/stationInfo/model.ts

@@ -0,0 +1,18 @@
1
+export interface StationInfoModel {
2
+  // 主键ID
3
+  id?: number;
4
+  // 所属片区ID
5
+  areaId?: number;
6
+  // 创建人
7
+  createdBy?: string;
8
+  // 油站名称
9
+  stationName?: string;
10
+  // 状态:0-禁用,1-启用
11
+  status?: number;
12
+  // 场站类型编号
13
+  typeCode?: string;
14
+  // 修改时间
15
+  updateTime?: string;
16
+  // 创建时间
17
+  createTime?: string;
18
+}

+ 89 - 0
apps/web-ele/src/api/system/infoEntry/stationInfo/stationInfo.ts

@@ -0,0 +1,89 @@
1
+import type { StationInfoModel } from './model';
2
+
3
+import type { BaseResult } from '#/api/base-result';
4
+
5
+import { commonExport } from '#/api/helper';
6
+import { requestClient } from '#/api/request';
7
+
8
+// API路径常量枚举
9
+enum Api {
10
+  // 导出
11
+  export = '/sysStation/station/export',
12
+  // 列表查询
13
+  list = '/sysStation/station/list',
14
+  // 基础路径
15
+  root = '/sysStation/station',
16
+  // 查询所有片区信息
17
+  selectAllSysStationList = '/sysStationArea/area/selectAllSysStationAreaList',
18
+}
19
+
20
+
21
+
22
+/**
23
+ * 查询所有油站信息
24
+ * @returns 油站列表
25
+ */
26
+export function selectAllSysStationAreaList() {
27
+  return requestClient.get<BaseResult<StationInfoModel[]>>(Api.selectAllSysStationList);
28
+}
29
+/**
30
+ * 查询油站信息列表
31
+ * @param params 查询参数
32
+ * @returns 分页结果
33
+ */
34
+export function stationInfoList(params: any) {
35
+  return requestClient.get<BaseResult<StationInfoModel[]>>(Api.list, {
36
+    params,
37
+  });
38
+}
39
+
40
+/**
41
+ * 获取油站详细信息
42
+ * @param id 油站ID
43
+ * @returns 油站详情
44
+ */
45
+export function getStationInfoDetail(id: number) {
46
+  return requestClient.get<StationInfoModel>(`${Api.root}/${id}`);
47
+}
48
+
49
+/**
50
+ * 新增油站
51
+ * @param data 油站数据
52
+ * @returns 操作结果
53
+ */
54
+export function addStationInfo(data: StationInfoModel) {
55
+  return requestClient.post(Api.root, data, {
56
+    successMessageMode: 'message',
57
+  });
58
+}
59
+
60
+/**
61
+ * 修改油站
62
+ * @param data 油站数据
63
+ * @returns 操作结果
64
+ */
65
+export function updateStationInfo(data: StationInfoModel) {
66
+  return requestClient.put(Api.root, data, {
67
+    successMessageMode: 'message',
68
+  });
69
+}
70
+
71
+/**
72
+ * 删除油站信息
73
+ * @param ids 油站ID数组
74
+ * @returns 操作结果
75
+ */
76
+export function deleteStationInfo(ids: number[]) {
77
+  return requestClient.delete(`${Api.root}/${ids.join(',')}`, {
78
+    successMessageMode: 'message',
79
+  });
80
+}
81
+
82
+/**
83
+ * 导出油站信息列表
84
+ * @param data 导出参数
85
+ * @returns 导出结果
86
+ */
87
+export function exportStationInfo(data: Partial<StationInfoModel>) {
88
+  return commonExport(Api.export, data);
89
+}

+ 136 - 0
apps/web-ele/src/views/system/infoEntry/districtInfo/districtInfo-data.tsx

@@ -0,0 +1,136 @@
1
+import type { FormSchemaGetter } from '#/adapter/form';
2
+import type { VxeGridProps } from '#/adapter/vxe-table';
3
+
4
+// 状态选项
5
+type StatusOption = { label: string; value: number };
6
+
7
+const getStatusOptions = (): StatusOption[] => [
8
+  { label: '启用', value: 1 },
9
+  { label: '禁用', value: 0 },
10
+];
11
+
12
+export const queryFormSchema: FormSchemaGetter = () => [
13
+  {
14
+    component: 'Input',
15
+    fieldName: 'areaName',
16
+    label: '片区',
17
+    componentProps: {
18
+      placeholder: '请输入片区名称',
19
+    },
20
+  },
21
+];
22
+
23
+export const tableColumns: VxeGridProps['columns'] = [
24
+  {
25
+    type: 'checkbox',
26
+    width: 80,
27
+  },
28
+  {
29
+    field: 'areaName',
30
+    title: '片区名称',
31
+    minWidth: 150,
32
+  },
33
+  {
34
+    field: 'address',
35
+    title: '详细地址',
36
+    minWidth: 200,
37
+  },
38
+  {
39
+    field: 'contactPhone',
40
+    title: '联系电话',
41
+    minWidth: 120,
42
+  },
43
+  {
44
+    field: 'manager',
45
+    title: '片区负责人',
46
+    minWidth: 120,
47
+  },
48
+  {
49
+    field: 'status',
50
+    title: '状态',
51
+    minWidth: 100,
52
+    formatter: (params: { cellValue: number; column: any; row: any }) => {
53
+      if (params.cellValue === undefined || params.cellValue === null) {
54
+        return '-';
55
+      }
56
+      const options = getStatusOptions();
57
+      const option = options.find((item) => item.value === params.cellValue);
58
+      const color = params.cellValue === 1 ? 'success' : 'danger';
59
+      return `<el-tag type="${color}">${option ? option.label : params.cellValue}</el-tag>`;
60
+    },
61
+  },
62
+  {
63
+    field: 'updatedAt',
64
+    title: '修改时间',
65
+    minWidth: 150,
66
+  },
67
+  {
68
+    field: 'action',
69
+    fixed: 'right',
70
+    slots: { default: 'action' },
71
+    title: '操作',
72
+    width: 150,
73
+  },
74
+];
75
+
76
+export const drawerFormSchema: FormSchemaGetter = () => [
77
+  {
78
+    component: 'Input',
79
+    dependencies: {
80
+      show: () => false,
81
+      triggerFields: [''],
82
+    },
83
+    fieldName: 'id',
84
+  },
85
+  {
86
+    component: 'Input',
87
+    fieldName: 'areaName',
88
+    label: '片区名称',
89
+    componentProps: {
90
+      placeholder: '请输入片区名称',
91
+      maxlength: 100,
92
+    },
93
+    rules: 'required',
94
+  },
95
+  {
96
+    component: 'Input',
97
+    fieldName: 'address',
98
+    label: '详细地址',
99
+    componentProps: {
100
+      placeholder: '请输入详细地址',
101
+      maxlength: 200,
102
+    },
103
+    rules: 'required',
104
+  },
105
+  {
106
+    component: 'Input',
107
+    fieldName: 'contactPhone',
108
+    label: '联系电话',
109
+    componentProps: {
110
+      placeholder: '请输入联系电话',
111
+      maxlength: 20,
112
+    },
113
+    rules: 'required'
114
+  },
115
+  {
116
+    component: 'Input',
117
+    fieldName: 'manager',
118
+    label: '片区负责人',
119
+    componentProps: {
120
+      placeholder: '请输入片区负责人',
121
+      maxlength: 20,
122
+    },
123
+    rules: 'required',
124
+  },
125
+  {
126
+    component: 'RadioGroup',
127
+    componentProps: {
128
+      options: getStatusOptions(),
129
+      isButton: true,
130
+    },
131
+    fieldName: 'status',
132
+    defaultValue: 1,
133
+    label: '状态',
134
+    required: false,
135
+  },
136
+];

+ 79 - 0
apps/web-ele/src/views/system/infoEntry/districtInfo/districtInfo-drawer.vue

@@ -0,0 +1,79 @@
1
+<script setup lang="ts">
2
+import { ref } from 'vue';
3
+import { useVbenDrawer, useVbenForm } from '@vben/common-ui';
4
+
5
+import {
6
+  addDistrictInfo,
7
+  getDistrictInfoDetail,
8
+  updateDistrictInfo,
9
+} from '#/api/system/infoEntry/districtInfo/districtInfo';
10
+
11
+import { drawerFormSchema } from './districtInfo-data';
12
+
13
+const emit = defineEmits<{
14
+  reload: [];
15
+}>();
16
+
17
+const [Form, formApi] = useVbenForm({
18
+  showDefaultActions: false,
19
+  schema: drawerFormSchema(),
20
+});
21
+
22
+const isUpdateRef = ref<boolean>(false);
23
+const confirmLoading = ref<boolean>(false);
24
+
25
+const [Drawer, drawerApi] = useVbenDrawer({
26
+  async onOpenChange(isOpen) {
27
+    if (!isOpen) {
28
+      return;
29
+    }
30
+    try {
31
+      drawerApi.drawerLoading(true);
32
+      const { id, isUpdate } = drawerApi.getData();
33
+      isUpdateRef.value = isUpdate;
34
+      if (isUpdate && id) {
35
+        const res = await getDistrictInfoDetail(id);
36
+        console.log('获取片区详情数据:', res);
37
+        // 确保从正确的响应结构中获取数据
38
+        const detailData = res?.data || res;
39
+        await formApi.setValues(detailData);
40
+      }
41
+    } catch (error) {
42
+      console.error('获取片区详情失败:', error);
43
+    } finally {
44
+      drawerApi.drawerLoading(false);
45
+    }
46
+  },
47
+
48
+  async onConfirm() {
49
+    try {
50
+      confirmLoading.value = true;
51
+      const { valid } = await formApi.validate();
52
+      if (!valid) {
53
+        return;
54
+      }
55
+      const data = await formApi.getValues();
56
+      console.log('提交数据:', data);
57
+      await (isUpdateRef.value
58
+        ? updateDistrictInfo(data)
59
+        : addDistrictInfo(data));
60
+      emit('reload');
61
+      drawerApi.close();
62
+    } catch (error) {
63
+      console.error('保存片区信息失败:', error);
64
+    } finally {
65
+      confirmLoading.value = false;
66
+    }
67
+  },
68
+
69
+  onClosed() {
70
+    formApi.resetForm();
71
+  },
72
+});
73
+</script>
74
+
75
+<template>
76
+  <Drawer :title="isUpdateRef ? '编辑片区' : '新增片区'">
77
+    <Form />
78
+  </Drawer>
79
+</template>

+ 187 - 0
apps/web-ele/src/views/system/infoEntry/districtInfo/index.vue

@@ -0,0 +1,187 @@
1
+<script setup lang="ts">
2
+import type { VbenFormProps } from '@vben/common-ui';
3
+import type { VxeGridProps } from '#/adapter/vxe-table';
4
+
5
+import { ref } from 'vue';
6
+
7
+import { Page, useVbenDrawer } from '@vben/common-ui';
8
+import { ElMessageBox } from 'element-plus';
9
+
10
+import { useVbenVxeGrid } from '#/adapter/vxe-table';
11
+import {
12
+  deleteDistrictInfo,
13
+  districtInfoList,
14
+  exportDistrictInfo,
15
+} from '#/api/system/infoEntry/districtInfo/districtInfo';
16
+import { commonDownloadExcel } from '#/utils/file/download';
17
+
18
+import { queryFormSchema, tableColumns } from './districtInfo-data';
19
+import DistrictInfoDrawerComp from './districtInfo-drawer.vue';
20
+
21
+const formOptions: VbenFormProps = {
22
+  commonConfig: {
23
+    labelWidth: 80,
24
+    componentProps: {
25
+      allowClear: true,
26
+    },
27
+  },
28
+  schema: queryFormSchema(),
29
+  wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-4',
30
+};
31
+
32
+const gridOptions: VxeGridProps = {
33
+  checkboxConfig: {
34
+    highlight: true,
35
+    reserve: true,
36
+    trigger: 'default',
37
+  },
38
+  columns: tableColumns,
39
+  size: 'medium',
40
+  height: 'auto',
41
+  proxyConfig: {
42
+    ajax: {
43
+      query: async ({ page }, formValues = {}) => {
44
+        const resp = await districtInfoList({
45
+          ...formValues,
46
+          pageNum: page.currentPage,
47
+          pageSize: page.pageSize,
48
+        });
49
+        return { items: resp.data?.rows || resp.rows || [], total: resp.data?.total || resp.total || 0 };
50
+      },
51
+    },
52
+  },
53
+  rowConfig: {
54
+    keyField: 'id',
55
+  },
56
+  toolbarConfig: {
57
+    custom: true,
58
+    refresh: true,
59
+    zoom: true,
60
+  },
61
+  id: 'system-districtInfo-index',
62
+};
63
+
64
+const [BasicTable, basicTableApi] = useVbenVxeGrid({
65
+  formOptions,
66
+  gridOptions,
67
+});
68
+
69
+const [DistrictInfoDrawer, drawerApi] = useVbenDrawer({
70
+  connectedComponent: DistrictInfoDrawerComp,
71
+});
72
+
73
+// 状态选项
74
+const statusOptions = ref([
75
+  { label: '启用', value: 1 },
76
+  { label: '禁用', value: 0 },
77
+]);
78
+
79
+// 新增片区
80
+function openDrawer() {
81
+  drawerApi.setData({ isUpdate: false }).open();
82
+}
83
+
84
+// 编辑片区
85
+function handleEdit(row: any) {
86
+  drawerApi.setData({ ...row, isUpdate: true }).open();
87
+}
88
+
89
+// 单个删除片区
90
+async function confirmEvent(row: any) {
91
+  await deleteDistrictInfo([row.id]);
92
+  await basicTableApi.reload();
93
+}
94
+
95
+// 批量删除片区
96
+function deleteHandle() {
97
+  const checkRecords = basicTableApi.grid.getCheckboxRecords();
98
+  const ids = checkRecords.map((item: any) => item.id);
99
+  if (ids.length <= 0) {
100
+    return;
101
+  }
102
+
103
+  ElMessageBox.confirm(`确认删除选中的${ids.length}条数据吗?`, '提示', {
104
+    confirmButtonText: '确定',
105
+    cancelButtonText: '取消',
106
+    type: 'warning',
107
+  }).then(async () => {
108
+    await deleteDistrictInfo(ids);
109
+    await basicTableApi.reload();
110
+  });
111
+}
112
+
113
+// 导出片区数据
114
+async function exportHandle() {
115
+  await commonDownloadExcel(
116
+    exportDistrictInfo,
117
+    '片区信息数据',
118
+    basicTableApi.formApi.form.values
119
+  );
120
+}
121
+</script>
122
+
123
+<template>
124
+  <Page :auto-content-height="true">
125
+    <BasicTable table-title="片区信息列表">
126
+      <template #toolbar-tools>
127
+        <el-space>
128
+          <el-button
129
+            @click="exportHandle"
130
+            v-access:code="['system:districtInfo:export']"
131
+          >
132
+            导出
133
+          </el-button>
134
+          <el-button
135
+            type="danger"
136
+            :disabled="
137
+              !(basicTableApi?.grid?.getCheckboxRecords?.()?.length > 0)
138
+            "
139
+            @click="deleteHandle"
140
+            v-access:code="['system:districtInfo:remove']"
141
+          >
142
+            批量删除
143
+          </el-button>
144
+          <el-button
145
+            type="primary"
146
+            @click="openDrawer"
147
+            v-access:code="['system:districtInfo:add']"
148
+          >
149
+            新增片区
150
+          </el-button>
151
+        </el-space>
152
+      </template>
153
+      <template #action="{ row }">
154
+        <el-space>
155
+          <el-button
156
+            size="small"
157
+            type="primary"
158
+            plain
159
+            @click="handleEdit(row)"
160
+            v-access:code="['system:districtInfo:edit']"
161
+          >
162
+            编辑
163
+          </el-button>
164
+          <el-popconfirm title="确认删除" @confirm="confirmEvent(row)">
165
+            <template #reference>
166
+              <el-button
167
+                size="small"
168
+                type="danger"
169
+                plain
170
+                v-access:code="['system:districtInfo:remove']"
171
+              >
172
+                删除
173
+              </el-button>
174
+            </template>
175
+          </el-popconfirm>
176
+        </el-space>
177
+      </template>
178
+    </BasicTable>
179
+    <DistrictInfoDrawer @reload="basicTableApi.reload()" />
180
+  </Page>
181
+</template>
182
+
183
+<style scoped lang="scss">
184
+:deep(.el-tooltip__trigger:focus) {
185
+  outline: none;
186
+}
187
+</style>

+ 277 - 0
apps/web-ele/src/views/system/infoEntry/stationInfo/index.vue

@@ -0,0 +1,277 @@
1
+<script setup lang="ts">
2
+import type { VbenFormProps } from '@vben/common-ui';
3
+import type { VxeGridProps } from '#/adapter/vxe-table';
4
+
5
+import { onMounted, ref, computed } from 'vue';
6
+import { Page, useVbenDrawer } from '@vben/common-ui';
7
+import { ElMessageBox } from 'element-plus';
8
+
9
+import { useVbenVxeGrid } from '#/adapter/vxe-table';
10
+import { deleteStationInfo, exportStationInfo, stationInfoList, selectAllSysStationAreaList } from '#/api/system/infoEntry/stationInfo/stationInfo';
11
+import { getDictOptions } from '#/utils/dict';
12
+import { commonDownloadExcel } from '#/utils/file/download';
13
+
14
+import { queryFormSchema, tableColumns } from './stationInfo-data';
15
+import StationInfoDrawerComp from './stationInfo-drawer.vue';
16
+
17
+// 字典标识常量
18
+const DICT_KEYS = {
19
+  // 状态字典标识
20
+  STATUS: 'status',
21
+  // 场站类型字典标识
22
+  STATION_TYPE: 'station_type',
23
+};
24
+
25
+// 片区列表选项
26
+const areaOptions = ref<any[]>([]);
27
+// 场站类型选项
28
+const stationTypeOptions = ref<any[]>([]);
29
+// 状态选项
30
+const statusOptions = ref<any[]>([]);
31
+
32
+// 创建响应式的表单选项,方便后续更新
33
+const formOptions = ref<VbenFormProps>({
34
+  commonConfig: {
35
+    labelWidth: 80,
36
+    componentProps: {
37
+      allowClear: true,
38
+    },
39
+  },
40
+  schema: queryFormSchema(),
41
+  wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-4',
42
+});
43
+
44
+const gridOptions: VxeGridProps = {
45
+  checkboxConfig: {
46
+    highlight: true,
47
+    reserve: true,
48
+    trigger: 'default',
49
+  },
50
+  columns: tableColumns,
51
+  size: 'medium',
52
+  height: 'auto',
53
+  proxyConfig: {
54
+    ajax: {
55
+      query: async ({ page }, formValues = {}) => {
56
+        const resp = await stationInfoList({
57
+          ...formValues,
58
+          pageNum: page.currentPage,
59
+          pageSize: page.pageSize,
60
+        });
61
+        return { 
62
+          items: resp?.rows || [], 
63
+          total: resp?.total || 0 
64
+        };
65
+      },
66
+    },
67
+  },
68
+  rowConfig: {
69
+    keyField: 'id',
70
+  },
71
+  toolbarConfig: {
72
+    custom: true,
73
+    refresh: true,
74
+    zoom: true,
75
+  },
76
+  id: 'system-infoEntry-stationInfo-index',
77
+};
78
+
79
+const [BasicTable, basicTableApi] = useVbenVxeGrid({
80
+  formOptions: formOptions.value,
81
+  gridOptions,
82
+});
83
+
84
+const [StationInfoDrawer, drawerApi] = useVbenDrawer({
85
+  connectedComponent: StationInfoDrawerComp,
86
+  props: {
87
+    areaOptions: computed(() => areaOptions.value),
88
+  },
89
+});
90
+
91
+// 根据areaId获取片区名称
92
+const getAreaName = (areaId: number) => {
93
+  const area = areaOptions.value.find((item) => item.value === areaId);
94
+  return area ? area.label : areaId || '';
95
+};
96
+
97
+// 根据typeCode获取场站类型名称
98
+const getStationTypeName = (typeCode: string) => {
99
+  const type = stationTypeOptions.value.find((item) => item.value === typeCode);
100
+  return type ? type.label : typeCode;
101
+};
102
+
103
+// 根据status获取状态名称
104
+const getStatusName = (status: number) => {
105
+  const statusItem = statusOptions.value.find((item) => String(item.value) === String(status));
106
+  return statusItem ? statusItem.label : status;
107
+};
108
+
109
+// 加载字典和片区数据
110
+const loadData = async () => {
111
+  try {
112
+    // 获取片区列表
113
+    const areaListResp = await selectAllSysStationAreaList();
114
+    areaOptions.value = (areaListResp?.data || []).map((item: any) => ({
115
+      label: item.areaName,
116
+      value: item.id,
117
+    }));
118
+    
119
+    // 更新表单中的片区选项
120
+    // 使用响应式方式更新schema
121
+    const updatedSchema = [...formOptions.value.schema];
122
+    const areaFieldIndex = updatedSchema.findIndex((item) => item.fieldName === 'areaId');
123
+    if (areaFieldIndex !== -1) {
124
+      updatedSchema[areaFieldIndex] = {
125
+        ...updatedSchema[areaFieldIndex],
126
+        componentProps: {
127
+          ...updatedSchema[areaFieldIndex].componentProps,
128
+          options: areaOptions.value,
129
+        },
130
+      };
131
+      formOptions.value = {
132
+        ...formOptions.value,
133
+        schema: updatedSchema,
134
+      };
135
+    }
136
+    
137
+    // 获取字典数据
138
+    stationTypeOptions.value = getDictOptions(DICT_KEYS.STATION_TYPE) || [];
139
+    statusOptions.value = getDictOptions(DICT_KEYS.STATUS) || [
140
+      { label: '启用', value: '1' },
141
+      { label: '禁用', value: '0' },
142
+    ];
143
+  } catch (error) {
144
+    console.error('加载数据失败:', error);
145
+  }
146
+};
147
+
148
+onMounted(() => {
149
+  loadData();
150
+});
151
+
152
+// 新增场站
153
+function openDrawer() {
154
+  drawerApi.setData({ isUpdate: false }).open();
155
+}
156
+
157
+// 编辑场站
158
+function handleEdit(row: any) {
159
+  drawerApi.setData({ ...row, isUpdate: true }).open();
160
+}
161
+
162
+// 单个删除场站
163
+async function confirmEvent(row: any) {
164
+  await deleteStationInfo([row.id]);
165
+  await basicTableApi.reload();
166
+}
167
+
168
+// 批量删除场站
169
+function deleteHandle() {
170
+  const checkRecords = basicTableApi.grid.getCheckboxRecords();
171
+  const ids = checkRecords.map((item: any) => item.id);
172
+  if (ids.length <= 0) {
173
+    return;
174
+  }
175
+
176
+  ElMessageBox.confirm(`确认删除选中的${ids.length}条数据吗?`, '提示', {
177
+    confirmButtonText: '确定',
178
+    cancelButtonText: '取消',
179
+    type: 'warning',
180
+  }).then(async () => {
181
+    await deleteStationInfo(ids);
182
+    await basicTableApi.reload();
183
+  });
184
+}
185
+
186
+// 导出场站数据
187
+async function exportHandle() {
188
+  await commonDownloadExcel(
189
+    exportStationInfo,
190
+    '场站信息数据',
191
+    basicTableApi.formApi.form.values,
192
+    {}
193
+  );
194
+}
195
+</script>
196
+
197
+<template>
198
+  <Page :auto-content-height="true">
199
+    <BasicTable table-title="场站信息列表">
200
+      <template #toolbar-tools>
201
+        <ElSpace>
202
+          <ElButton
203
+            @click="exportHandle"
204
+            v-access:code="['system:infoEntry:stationInfo:export']"
205
+          >
206
+            导出
207
+          </ElButton>
208
+          <ElButton
209
+            type="danger"
210
+            :disabled="
211
+              !(basicTableApi?.grid?.getCheckboxRecords?.()?.length > 0)
212
+            "
213
+            @click="deleteHandle"
214
+            v-access:code="['system:infoEntry:stationInfo:remove']"
215
+          >
216
+            批量删除
217
+          </ElButton>
218
+          <ElButton
219
+            type="primary"
220
+            @click="openDrawer"
221
+            v-access:code="['system:infoEntry:stationInfo:add']"
222
+          >
223
+            新增场站
224
+          </ElButton>
225
+        </ElSpace>
226
+      </template>
227
+      <template #areaId="{ row }">
228
+        <span>{{ getAreaName(row.areaId) }}</span>
229
+      </template>
230
+      <template #typeCode="{ row }">
231
+        <ElTag>{{ getStationTypeName(row.typeCode) }}</ElTag>
232
+      </template>
233
+      <template #status="{ row }">
234
+        <ElTag
235
+          :type="row.status === 1 ? 'success' : 'danger'"
236
+        >
237
+          {{ getStatusName(row.status) }}
238
+        </ElTag>
239
+      </template>
240
+      <template #action="{ row }">
241
+        <ElSpace>
242
+          <ElButton
243
+            size="small"
244
+            type="primary"
245
+            plain
246
+            @click="handleEdit(row)"
247
+            v-access:code="['system:infoEntry:stationInfo:edit']"
248
+          >
249
+            编辑
250
+          </ElButton>
251
+          <ElPopconfirm title="确认删除" @confirm="confirmEvent(row)">
252
+            <template #reference>
253
+              <ElButton
254
+                size="small"
255
+                type="danger"
256
+                plain
257
+                v-access:code="['system:infoEntry:stationInfo:remove']"
258
+              >
259
+                删除
260
+              </ElButton>
261
+            </template>
262
+          </ElPopconfirm>
263
+        </ElSpace>
264
+      </template>
265
+    </BasicTable>
266
+    <StationInfoDrawer
267
+      :area-options="areaOptions"
268
+      @reload="basicTableApi.reload()"
269
+    />
270
+  </Page>
271
+</template>
272
+
273
+<style scoped lang="scss">
274
+:deep(.el-tooltip__trigger:focus) {
275
+  outline: none;
276
+}
277
+</style>

+ 193 - 0
apps/web-ele/src/views/system/infoEntry/stationInfo/stationInfo-data.tsx

@@ -0,0 +1,193 @@
1
+import type { FormSchemaGetter } from '#/adapter/form';
2
+import type { VxeGridProps } from '#/adapter/vxe-table';
3
+
4
+import { getDictOptions } from '#/utils/dict';
5
+import { selectAllSysStationAreaList } from '#/api/system/infoEntry/stationInfo/stationInfo';
6
+
7
+// 字典标识常量
8
+const DICT_KEYS = {
9
+  // 状态字典标识
10
+  STATUS: 'status',
11
+  // 场站类型字典标识
12
+  STATION_TYPE: 'station_type',
13
+};
14
+
15
+// 获取状态字典选项
16
+const getStatusOptions = () =>
17
+  getDictOptions(DICT_KEYS.STATUS) || [
18
+    { label: '启用', value: '1' },
19
+    { label: '禁用', value: '0' },
20
+  ];
21
+
22
+// 获取场站类型字典选项
23
+const getStationTypeOptions = () =>
24
+  getDictOptions(DICT_KEYS.STATION_TYPE) || [];
25
+
26
+// 获取片区列表选项
27
+const getAreaOptions = async () => {
28
+  try {
29
+    const resp = await selectAllSysStationAreaList();
30
+    console.log('获取片区列表响应:', resp);
31
+    // 确保正确处理响应数据结构
32
+    const data = resp || resp || [];
33
+    return Array.isArray(data) ? data.map((item: any) => ({
34
+      label: item.areaName,
35
+      value: item.id,
36
+    })) : [];
37
+  } catch (error) {
38
+    console.error('获取片区列表失败:', error);
39
+    return [];
40
+  }
41
+};
42
+
43
+// 查询表单schema
44
+export const queryFormSchema: FormSchemaGetter = () => [
45
+  {
46
+    component: 'Input',
47
+    fieldName: 'stationName',
48
+    label: '场站名称',
49
+    componentProps: {
50
+      placeholder: '请输入场站名称',
51
+    },
52
+  },
53
+  {
54
+    component: 'Select',
55
+    componentProps: {
56
+      placeholder: '请选择所属片区',
57
+      options: [], // 将在组件中动态加载
58
+    },
59
+    fieldName: 'areaId',
60
+    label: '所属片区',
61
+  },
62
+];
63
+
64
+// 表格列配置
65
+export const tableColumns: VxeGridProps['columns'] = [
66
+  {
67
+    type: 'checkbox',
68
+    width: 80,
69
+  },
70
+  {
71
+    field: 'stationName',
72
+    title: '场站名称',
73
+    minWidth: 150,
74
+  },
75
+  {
76
+    field: 'areaId',
77
+    title: '所属片区',
78
+    minWidth: 120,
79
+    // 修改后
80
+    slots: 'areaId', // 使用插槽进行格式化,避免在formatter中进行异步操作
81
+    // formatter函数不应该包含异步操作,保留基本功能
82
+    formatter: (params: { cellValue: number; column: any; row: any }) => {
83
+      // 这里将在index.vue中通过插槽进行实际格式化
84
+      const options = getAreaOptions();
85
+      console.log('areaId 格式化选项:', options);
86
+      const option = options.find((item) => item.value === params.cellValue);
87
+      return option ? option.label : params.cellValue;
88
+    },
89
+  },
90
+  {
91
+    field: 'typeCode',
92
+    title: '场站类型',
93
+    minWidth: 120,
94
+    formatter: (params: { cellValue: string; column: any; row: any }) => {
95
+      const options = getStationTypeOptions();
96
+      const option = options.find((item) => item.value === params.cellValue);
97
+      return option ? option.label : params.cellValue;
98
+    },
99
+  },
100
+  {
101
+    field: 'status',
102
+    title: '状态',
103
+    minWidth: 100,
104
+    formatter: (params: { cellValue: string; column: any; row: any }) => {
105
+      const options = getStatusOptions();
106
+      const option = options.find((item) => item.value === params.cellValue);
107
+      const color = params.cellValue === '1' ? 'success' : 'danger';
108
+      return `<el-tag type="${color}">${option ? option.label : params.cellValue}</el-tag>`;
109
+    },
110
+  },
111
+  {
112
+    field: 'createTime',
113
+    title: '创建时间',
114
+    minWidth: 150,
115
+  },
116
+  {
117
+    field: 'updateTime',
118
+    title: '修改时间',
119
+    minWidth: 150,
120
+  },
121
+  {
122
+    field: 'createdBy',
123
+    title: '创建人',
124
+    minWidth: 100,
125
+  },
126
+  {
127
+    field: 'updatedBy',
128
+    title: '更新人',
129
+    minWidth: 100,
130
+  },
131
+  {
132
+    field: 'action',
133
+    fixed: 'right',
134
+    slots: { default: 'action' },
135
+    title: '操作',
136
+    width: 150,
137
+  },
138
+];
139
+
140
+// 抽屉表单schema
141
+export const drawerFormSchema: FormSchemaGetter = () => [
142
+   {
143
+    component: 'Input',
144
+    dependencies: {
145
+      show: () => false,
146
+      triggerFields: [''],
147
+    },
148
+    fieldName: 'id',
149
+  },
150
+  {
151
+    component: 'Input',
152
+    fieldName: 'stationName',
153
+    label: '场站名称',
154
+    componentProps: {
155
+      placeholder: '请输入场站名称',
156
+      maxlength: 100,
157
+    },
158
+    rules: 'required',
159
+  },
160
+  {
161
+    component: 'Select',
162
+    componentProps: {
163
+      placeholder: '请选择所属片区',
164
+      options: [], // 将在组件中动态加载,不要在schema定义中使用异步操作
165
+    },
166
+    fieldName: 'areaId',
167
+    label: '所属片区',
168
+    rules: 'required',
169
+  },
170
+  {
171
+    component: 'Select',
172
+    componentProps: {
173
+      placeholder: '请选择场站类型',
174
+      options: getStationTypeOptions(),
175
+    },
176
+    fieldName: 'typeCode',
177
+    label: '场站类型',
178
+    rules: 'required',
179
+  },
180
+  {
181
+    component: 'RadioGroup',
182
+    componentProps: {
183
+      options: [
184
+        { label: '启用', value: 1 },
185
+        { label: '禁用', value: 0 },
186
+      ],
187
+      isButton: true,
188
+    },
189
+    fieldName: 'status',
190
+    defaultValue: 1,
191
+    label: '状态',
192
+  },
193
+];

+ 132 - 0
apps/web-ele/src/views/system/infoEntry/stationInfo/stationInfo-drawer.vue

@@ -0,0 +1,132 @@
1
+<script setup lang="ts">
2
+import { onMounted, ref, nextTick } from 'vue';
3
+import { useVbenDrawer, useVbenForm } from '@vben/common-ui';
4
+
5
+import { addStationInfo, getStationInfoDetail, updateStationInfo, selectAllSysStationAreaList } from '#/api/system/infoEntry/stationInfo/stationInfo';
6
+import { drawerFormSchema } from './stationInfo-data';
7
+
8
+const emit = defineEmits<{
9
+  reload: [];
10
+}>();
11
+
12
+const confirmLoading = ref(false);
13
+const isUpdateRef = ref<boolean>(false);
14
+
15
+// 获取片区列表的函数,将在index.vue中传入
16
+const props = defineProps<{
17
+  areaOptions?: any[];
18
+}>();
19
+
20
+// 本地片区选项缓存
21
+const localAreaOptions = ref<any[]>([]);
22
+
23
+// 创建响应式schema引用
24
+const formSchema = ref(drawerFormSchema());
25
+
26
+const [Form, formApi] = useVbenForm({
27
+  showDefaultActions: false,
28
+  schema: formSchema.value,
29
+  autoSubmitOnEnter: false,
30
+});
31
+
32
+const [Drawer, drawerApi] = useVbenDrawer({
33
+  async onOpenChange(isOpen) {
34
+    if (!isOpen) {
35
+      return;
36
+    }
37
+    try {
38
+      drawerApi.drawerLoading(true);
39
+      const { id, isUpdate } = drawerApi.getData();
40
+      isUpdateRef.value = isUpdate;
41
+      
42
+      // 加载片区选项
43
+      await loadAreaOptions();
44
+      
45
+      if (isUpdate && id) {
46
+        const res = await getStationInfoDetail(id);
47
+        const detailData = res;
48
+        await formApi.setValues(detailData);
49
+      } else {
50
+        await formApi.resetForm();
51
+        await nextTick();
52
+        await formApi.setValueByField('status', 1); // 默认启用状态
53
+      }
54
+    } catch (error) {
55
+      console.error('获取场站详情失败:', error);
56
+    } finally {
57
+      drawerApi.drawerLoading(false);
58
+    }
59
+  },
60
+
61
+  async onConfirm() {
62
+    try {
63
+      confirmLoading.value = true;
64
+      const { valid } = await formApi.validate();
65
+      if (!valid) {
66
+        return;
67
+      }
68
+      const data = await formApi.getValues();
69
+      
70
+      console.log('提交数据:', data);
71
+      await (isUpdateRef.value
72
+        ? updateStationInfo(data)
73
+        : addStationInfo(data));
74
+      emit('reload');
75
+      drawerApi.close();
76
+    } catch (error) {
77
+      console.error('保存场站信息失败:', error);
78
+    } finally {
79
+      confirmLoading.value = false;
80
+    }
81
+  },
82
+
83
+  onClosed() {
84
+    formApi.resetForm();
85
+  },
86
+});
87
+
88
+// 加载片区选项
89
+const loadAreaOptions = async () => {
90
+  try {
91
+    // 优先使用props传入的选项,如果没有则从API获取
92
+    if (props.areaOptions && props.areaOptions.length > 0) {
93
+      localAreaOptions.value = props.areaOptions;
94
+    } else {
95
+      const resp = await selectAllSysStationAreaList();
96
+      console.log('获取片区列表响应:', resp);
97
+      
98
+      // 确保正确处理响应数据结构
99
+      const data = resp || resp || [];
100
+      localAreaOptions.value = Array.isArray(data) ? data.map((item: any) => ({
101
+        label: item.areaName,
102
+        value: item.id,
103
+      })) : [];
104
+      console.log('转换后的片区选项:', localAreaOptions.value);
105
+    }
106
+    
107
+    // 更新表单中的片区选项
108
+    const schema = formApi.getSchema();
109
+    const areaField = schema.find((item) => item.fieldName === 'areaId');
110
+    if (areaField) {
111
+      areaField.componentProps.options = localAreaOptions.value;
112
+    }
113
+  } catch (error) {
114
+    console.error('加载片区选项失败:', error);
115
+  }
116
+};
117
+
118
+// 监听props变化,更新表单选项
119
+const updateOptions = async () => {
120
+  await loadAreaOptions();
121
+};
122
+
123
+onMounted(async () => {
124
+  await updateOptions();
125
+});
126
+</script>
127
+
128
+<template>
129
+  <Drawer :title="isUpdateRef ? '编辑场站' : '新增场站'" :confirm-loading="confirmLoading">
130
+    <Form />
131
+  </Drawer>
132
+</template>