From d4e5744f3df7c90b44a900d1f61f5850b199b47d Mon Sep 17 00:00:00 2001
From: zhuguifei <zhuguifei@zhuguifeideiMac.local>
Date: 星期二, 04 三月 2025 10:20:59 +0800
Subject: [PATCH] 完成维修工单评价功能

---
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/IEimsRepairFbService.java         |   68 ++
 eims-ui/apps/web-antd/src/views/eims/repair-fb/repair-fb-drawer.vue                                 |  170 ++++++
 eims-ui/apps/web-antd/src/utils/render.tsx                                                          |   40 
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/controller/EimsRepairFbController.java    |  107 ++++
 eims/ruoyi-modules/lb-eims/src/main/resources/mapper/eims/EimsRepairFbMapper.xml                    |    7 
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/mapper/EimsRepairFbMapper.java            |   15 
 eims-ui/apps/web-antd/src/api/eims/repair-fb/index.ts                                               |   61 ++
 eims-ui/apps/web-antd/src/views/eims/repair-fb/fb-preview-drawer.vue                                |   33 +
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/vo/EimsRepairFbVo.java             |  125 ++++
 eims-ui/apps/web-antd/src/views/eims/repair-fb/index.vue                                            |  231 ++++++++
 eims-ui/apps/web-antd/src/views/eims/repair-res/index.vue                                           |   51 +
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/bo/EimsRepairFbBo.java             |   90 +++
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/EimsRepairRes.java                 |    6 
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/bo/EimsRepairResBo.java            |    6 
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/vo/EimsRepairResVo.java            |    6 
 eims-ui/apps/web-antd/src/api/eims/repair-fb/model.d.ts                                             |   67 ++
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/EimsRepairFb.java                  |   95 +++
 eims-ui/apps/web-antd/src/views/eims/repair-fb/data.tsx                                             |  217 ++++++++
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/impl/EimsRepairFbServiceImpl.java |  146 +++++
 19 files changed, 1,503 insertions(+), 38 deletions(-)

diff --git a/eims-ui/apps/web-antd/src/api/eims/repair-fb/index.ts b/eims-ui/apps/web-antd/src/api/eims/repair-fb/index.ts
new file mode 100644
index 0000000..57dd174
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/eims/repair-fb/index.ts
@@ -0,0 +1,61 @@
+import type { RepairFbVO } from './model';
+
+import type { ID, IDS } from '#/api/common';
+
+import { commonExport } from '#/api/helper';
+import { requestClient } from '#/api/request';
+
+enum Api {
+  repairFbExport = '/eims/repairFb/export',
+  repairFbList = '/eims/repairFb/list',
+  root = '/eims/repairFb'
+}
+
+/**
+ * 鏌ヨ缁翠慨璇勪环鍒楄〃
+ * @param query
+ * @returns {*}
+ */
+
+export function listRepairFb(params?: any) {
+  return requestClient.get<RepairFbVO[]>(Api.repairFbList, { params });
+}
+
+/**
+ * 鏌ヨ缁翠慨璇勪环璇︾粏
+ * @param repairFbId
+ */
+export function getRepairFb(repairFbId: ID) {
+  return requestClient.get<RepairFbVO>(`${Api.root}/${repairFbId}`);
+}
+
+/**
+ * 鏂板缁翠慨璇勪环
+ * @param data
+ */
+export function addRepairFb(data: any) {
+  return requestClient.postWithMsg<void>(Api.root, data);
+}
+
+/**
+ * 淇敼缁翠慨璇勪环
+ * @param data
+ */
+export function updateRepairFb(data: any) {
+  return requestClient.putWithMsg<void>(Api.root, data);
+}
+
+/**
+ * 鍒犻櫎缁翠慨璇勪环
+ * @param repairFbId
+ */
+export function delRepairFb(repairFbId: IDS) {
+  return requestClient.deleteWithMsg<void>(`${Api.root}/${repairFbId}`);
+}
+/**
+ * 瀵煎嚭
+ * @param
+ */
+export function repairFbExport(data: any) {
+  return commonExport(Api.repairFbExport, data);
+}
diff --git a/eims-ui/apps/web-antd/src/api/eims/repair-fb/model.d.ts b/eims-ui/apps/web-antd/src/api/eims/repair-fb/model.d.ts
new file mode 100644
index 0000000..f7d3fd5
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/eims/repair-fb/model.d.ts
@@ -0,0 +1,67 @@
+export interface RepairFbVO {
+  /**
+   *
+   */
+  id: number | string;
+
+  /**
+   * 缁翠慨宸ュ崟id
+
+   */
+  resId: number | string;
+  /**
+   * 缁翠慨宸ュ崟code
+
+   */
+  resCode: string;
+
+  /**
+   * 鍙嶉缁撴灉
+   */
+  fbResult: string;
+
+  /**
+   * 鍙嶉浜�
+   */
+  fbUser: number;
+
+  /**
+   * 鍙嶉浜洪儴闂�
+   */
+  fbDept: number;
+
+  /**
+   * 鍙嶉鏃堕棿
+   */
+  fbTime: string;
+
+  /**
+   * 缁翠慨鍙婃椂鎬�(瀛楀吀)
+   */
+  repairTimeliness: number | string;
+
+  /**
+   * 鏈嶅姟鎬佸害
+   */
+  serviceAttitude: number | string;
+
+  /**
+   * 缁翠慨鐜板満6s
+   */
+  repairSs: number | string;
+
+  /**
+   * 缁翠慨婊℃剰搴�
+   */
+  repairSatisfaction: number | string;
+
+  /**
+   * 鎰忚鎴栧缓璁�
+   */
+  suggestions: string;
+
+  /**
+   * 澶囨敞
+   */
+  remark: string;
+}
diff --git a/eims-ui/apps/web-antd/src/utils/render.tsx b/eims-ui/apps/web-antd/src/utils/render.tsx
index fcc9102..667b7b6 100644
--- a/eims-ui/apps/web-antd/src/utils/render.tsx
+++ b/eims-ui/apps/web-antd/src/utils/render.tsx
@@ -22,10 +22,10 @@
   QuarkIcon,
   SafariIcon,
   UcIcon,
-  WindowsIcon,
+  WindowsIcon
 } from '@vben/icons';
 
-import { Tag } from 'ant-design-vue';
+import { Rate, Tag } from 'ant-design-vue';
 
 import { DictTag } from '#/components/dict';
 
@@ -102,7 +102,7 @@
     DELETE: 'red',
     GET: 'green',
     POST: 'blue',
-    PUT: 'orange',
+    PUT: 'orange'
   };
 
   const color = colors[method] ?? 'default';
@@ -123,12 +123,7 @@
  * @param [gap] 闂撮殧
  * @returns render
  */
-export function renderDictTags(
-  value: string[],
-  dicts: DictData[],
-  wrap = true,
-  gap = 1,
-) {
+export function renderDictTags(value: string[], dicts: DictData[], wrap = true, gap = 1) {
   if (!Array.isArray(value)) {
     return <div>{value}</div>;
   }
@@ -151,12 +146,7 @@
   const dictInfo = getDict(dictName);
   return renderDictTag(value, dictInfo);
 }
-export function renderIconSpan(
-  icon: ComponentType,
-  value: string,
-  center = false,
-  marginLeft = '2px',
-) {
+export function renderIconSpan(icon: ComponentType, value: string, center = false, marginLeft = '2px') {
   const justifyCenter = center ? 'justify-center' : '';
 
   return (
@@ -172,7 +162,7 @@
   { icon: LinuxIcon, value: 'linux' },
   { icon: OSXIcon, value: 'osx' },
   { icon: AndroidIcon, value: 'android' },
-  { icon: IPhoneIcon, value: 'iphone' },
+  { icon: IPhoneIcon, value: 'iphone' }
 ];
 
 /**
@@ -191,16 +181,14 @@
   { icon: QQIcon, value: 'qq' },
   { icon: DingtalkIcon, value: 'dingtalk' },
   { icon: UcIcon, value: 'uc' },
-  { icon: BaiduIcon, value: 'baidu' },
+  { icon: BaiduIcon, value: 'baidu' }
 ];
 
 export function renderOsIcon(os: string, center = false) {
   if (!os) {
     return;
   }
-  let current = osOptions.find((item) =>
-    os.toLocaleLowerCase().includes(item.value),
-  );
+  let current = osOptions.find((item) => os.toLocaleLowerCase().includes(item.value));
   // windows瑕佺壒娈婂鐞�
   if (os.toLocaleLowerCase().includes('windows')) {
     current = osOptions[0];
@@ -217,9 +205,7 @@
   if (!browser) {
     return;
   }
-  const current = browserOptions.find((item) =>
-    browser.toLocaleLowerCase().includes(item.value),
-  );
+  const current = browserOptions.find((item) => browser.toLocaleLowerCase().includes(item.value));
   if (current) {
     return renderIconSpan(current.icon, browser, center, '5px');
   }
@@ -227,3 +213,11 @@
   const defaultIcon = DefaultBrowserIcon;
   return renderIconSpan(defaultIcon, browser, center, '5px');
 }
+
+export function renderRate(value: string) {
+  if (!value) {
+    return null;
+  }
+
+  return <Rate disabled value={Number(value)}></Rate>;
+}
diff --git a/eims-ui/apps/web-antd/src/views/eims/repair-fb/data.tsx b/eims-ui/apps/web-antd/src/views/eims/repair-fb/data.tsx
new file mode 100644
index 0000000..524a811
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/eims/repair-fb/data.tsx
@@ -0,0 +1,217 @@
+import type { VxeGridProps } from '#/adapter/vxe-table';
+import type { DescItem } from '#/components/description';
+
+import { getPopupContainer } from '@vben/utils';
+
+import { Rate } from 'ant-design-vue';
+
+import { type FormSchemaGetter } from '#/adapter/form';
+
+export const querySchema: FormSchemaGetter = () => [
+  {
+    component: 'Input',
+    fieldName: 'resCode',
+    label: '缁翠慨鍗曞彿'
+  },
+  {
+    component: 'TreeSelect',
+    // 鍦╠rawer閲屾洿鏂� 杩欓噷涓嶉渶瑕侀粯璁ょ殑componentProps
+    defaultValue: undefined,
+    fieldName: 'resDept',
+    label: '缁翠慨閮ㄩ棬'
+    // rules: 'selectRequired',
+  },
+  {
+    component: 'Select',
+    componentProps: {
+      showSearch: true,
+      allowClear: true,
+      getPopupContainer
+    },
+    fieldName: 'resUser',
+    label: '缁翠慨浜�'
+  }
+];
+
+export const columns: VxeGridProps['columns'] = [
+  { type: 'checkbox', width: 60, fixed: 'left' },
+  {
+    title: '缁翠慨鍗曞彿',
+    field: 'resCode',
+    minWidth: 160,
+    fixed: 'left'
+  },
+  {
+    title: '缁撴灉',
+    field: 'fbResult',
+    minWidth: 200
+  },
+  {
+    field: 'action',
+    fixed: 'right',
+    slots: { default: 'action' },
+    title: '鎿嶄綔',
+    width: 200
+  }
+];
+
+export const drawerSchema: FormSchemaGetter = () => [
+  {
+    component: 'Input',
+    dependencies: {
+      show: () => false,
+      triggerFields: ['']
+    },
+    fieldName: 'id'
+  },
+  {
+    component: 'Input',
+    dependencies: {
+      show: () => false,
+      triggerFields: ['']
+    },
+    fieldName: 'resId'
+  },
+  {
+    component: 'Input',
+    fieldName: 'resCode',
+    componentProps: {
+      readonly: true
+    },
+    label: '缁翠慨宸ュ崟'
+  },
+  {
+    component: 'Textarea',
+    formItemClass: 'items-baseline',
+    fieldName: 'fbResult',
+    label: '缁撴灉鍙嶉'
+  },
+  {
+    component: 'Rate',
+    fieldName: 'repairSatisfaction',
+    label: '缁翠慨婊℃剰搴�'
+  },
+  {
+    component: 'Rate',
+    fieldName: 'repairTimeliness',
+    label: '缁翠慨鍙婃椂鎬�'
+  },
+  {
+    component: 'Rate',
+    fieldName: 'serviceAttitude',
+    label: '缁翠慨鍙婃�佸害'
+  },
+  {
+    component: 'Rate',
+    fieldName: 'repairSs',
+    label: '缁翠慨鐜板満6S'
+  },
+  {
+    component: 'Textarea',
+    formItemClass: 'items-baseline',
+    fieldName: 'suggestions',
+    label: '鎰忚鎴栧缓璁�'
+  },
+  {
+    component: 'TreeSelect',
+    // 鍦╠rawer閲屾洿鏂� 杩欓噷涓嶉渶瑕侀粯璁ょ殑componentProps
+    defaultValue: undefined,
+    fieldName: 'fbDept',
+    label: '璇勪环浜洪儴闂�',
+    rules: 'selectRequired'
+  },
+  {
+    component: 'Select',
+    componentProps: {
+      showSearch: true,
+      allowClear: true,
+      getPopupContainer
+    },
+    fieldName: 'fbUser',
+    label: '璇勪环浜�',
+    rules: 'selectRequired'
+  },
+  {
+    component: 'DatePicker',
+    componentProps: {
+      format: 'YYYY-MM-DD HH:mm:ss',
+      showTime: true,
+      valueFormat: 'YYYY-MM-DD HH:mm:ss',
+      getPopupContainer
+    },
+    fieldName: 'fbTime',
+    label: '璇勪环鏃堕棿'
+  }
+];
+
+export const descSchema: DescItem[] = [
+  {
+    field: 'resCode',
+    label: '缁翠慨宸ュ崟',
+    labelMinWidth: 80
+  },
+  {
+    field: 'fbResult',
+    label: '缁撴灉鍙嶉'
+  },
+  {
+    field: 'repairSatisfaction',
+    label: '缁翠慨婊℃剰搴�',
+    render(value) {
+      return (
+        <div class="flex items-center">
+          <Rate disabled value={Number(value)}></Rate>
+        </div>
+      );
+    }
+  },
+  {
+    field: 'repairTimeliness',
+    label: '缁翠慨鍙婃椂鎬�',
+    render(value) {
+      return (
+        <div class="flex items-center">
+          <Rate disabled value={Number(value)}></Rate>
+        </div>
+      );
+    }
+  },
+  {
+    field: 'serviceAttitude',
+    label: '缁翠慨鍙婃�佸害',
+    render(value) {
+      return (
+        <div class="flex items-center">
+          <Rate disabled value={Number(value)}></Rate>
+        </div>
+      );
+    }
+  },
+  {
+    field: 'repairSs',
+    label: '缁翠慨鐜板満6s',
+    render(value) {
+      return (
+        <div class="flex items-center">
+          <Rate disabled value={Number(value)}></Rate>
+        </div>
+      );
+    }
+  },
+  {
+    field: 'suggestions',
+    label: '鎰忚鎴栧缓璁�'
+  },
+  {
+    field: 'fbDeptName',
+    label: '璇勪环浜洪儴闂�'
+  },
+  {
+    field: 'fbUserName',
+    label: '璇勪环浜�'
+  },
+  {
+    field: 'fbTime',
+    label: '璇勪环鏃堕棿'
+  }
+];
diff --git a/eims-ui/apps/web-antd/src/views/eims/repair-fb/fb-preview-drawer.vue b/eims-ui/apps/web-antd/src/views/eims/repair-fb/fb-preview-drawer.vue
new file mode 100644
index 0000000..ca7cc62
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/eims/repair-fb/fb-preview-drawer.vue
@@ -0,0 +1,33 @@
+<script setup lang="ts">
+import { useVbenDrawer } from '@vben/common-ui';
+
+import { getRepairFb } from '#/api/eims/repair-fb';
+import { Description, useDescription } from '#/components/description';
+import { descSchema } from '#/views/eims/repair-fb/data';
+
+const [BasicDrawer, drawerApi] = useVbenDrawer({
+  onOpenChange: handleOpenChange
+});
+
+const [registerDescription, { setDescProps }] = useDescription({
+  column: 1,
+  schema: descSchema
+});
+
+async function handleOpenChange(open: boolean) {
+  if (!open) {
+    return null;
+  }
+  const { id } = drawerApi.getData() as { id?: number | string };
+  if (id) {
+    const record = await getRepairFb(id);
+    setDescProps({ data: record }, true);
+  }
+}
+</script>
+
+<template>
+  <BasicDrawer :footer="false" class="w-[600px]" title="璇勪环鏄庣粏">
+    <Description @register="registerDescription" />
+  </BasicDrawer>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/eims/repair-fb/index.vue b/eims-ui/apps/web-antd/src/views/eims/repair-fb/index.vue
new file mode 100644
index 0000000..387c1f1
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/eims/repair-fb/index.vue
@@ -0,0 +1,231 @@
+<script setup lang="ts">
+import type { Recordable } from '@vben/types';
+
+import { onMounted } from 'vue';
+
+import { Page, useVbenDrawer, type VbenFormProps } from '@vben/common-ui';
+import { $t } from '@vben/locales';
+import { addFullName, getPopupContainer, getVxePopupContainer } from '@vben/utils';
+
+import { Modal, Popconfirm, Space } from 'ant-design-vue';
+
+import { useVbenVxeGrid, vxeCheckboxChecked, type VxeGridProps, vxeSortEvent } from '#/adapter/vxe-table';
+import { delRepairFb, listRepairFb, repairFbExport } from '#/api/eims/repair-fb';
+import { getDeptTree, userList } from '#/api/system/user';
+import { commonDownloadExcel } from '#/utils/file/download';
+
+import { columns, querySchema } from './data';
+import repairFbDrawer from './repair-fb-drawer.vue';
+
+const formOptions: VbenFormProps = {
+  commonConfig: {
+    labelWidth: 80,
+    componentProps: {
+      allowClear: true
+    }
+  },
+  schema: querySchema(),
+  collapsed: true,
+  wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4',
+  // 鏃ユ湡閫夋嫨鏍煎紡鍖�
+  fieldMappingTime: [['startTime', ['params[beginStartTime]', 'params[endStartTime]'], ['YYYY-MM-DD 00:00:00', 'YYYY-MM-DD 23:59:59']]]
+};
+
+const gridOptions: VxeGridProps = {
+  checkboxConfig: {
+    // 楂樹寒
+    highlight: true,
+    // 缈婚〉鏃朵繚鐣欓�変腑鐘舵��
+    reserve: true
+    // 鐐瑰嚮琛岄�変腑
+    // trigger: 'row'
+  },
+  columns,
+  height: 'auto',
+  keepSource: true,
+  pagerConfig: {},
+  proxyConfig: {
+    ajax: {
+      query: async ({ page }, formValues = {}) => {
+        return await listRepairFb({
+          pageNum: page.currentPage,
+          pageSize: page.pageSize,
+          ...formValues
+        });
+      }
+    }
+  },
+  rowConfig: {
+    isHover: true,
+    keyField: 'id'
+  },
+  sortConfig: {
+    // 杩滅▼鎺掑簭
+    remote: true,
+    // 鏀寔澶氬瓧娈垫帓搴� 榛樿鍏抽棴
+    multiple: true
+  },
+  id: 'eims-repair-fb-index'
+};
+
+const [BasicTable, tableApi] = useVbenVxeGrid({
+  formOptions,
+  gridOptions,
+  gridEvents: {
+    sortChange: (sortParams) => vxeSortEvent(tableApi, sortParams),
+    cellClick: (e: any) => {
+      const { row } = e;
+    }
+  }
+});
+
+const [RepairFbDrawer, repairFbDrawerApi] = useVbenDrawer({
+  connectedComponent: repairFbDrawer
+});
+
+function handleAdd() {
+  repairFbDrawerApi.setData({ });
+  repairFbDrawerApi.open();
+}
+
+async function handleEdit(record: Recordable<any>) {
+  repairFbDrawerApi.setData({ id: record.id });
+  repairFbDrawerApi.open();
+}
+
+async function handleDelete(row: Recordable<any>) {
+  await delRepairFb(row.id);
+  await tableApi.query();
+}
+
+function handleMultiDelete() {
+  const rows = tableApi.grid.getCheckboxRecords();
+  const ids = rows.map((row: any) => row.id);
+  Modal.confirm({
+    title: '鎻愮ず',
+    okType: 'danger',
+    content: `纭鍒犻櫎閫変腑鐨�${ids.length}鏉¤褰曞悧锛焋,
+    onOk: async () => {
+      await delRepairFb(ids);
+      await tableApi.query();
+    }
+  });
+}
+
+function handleDownloadExcel() {
+  commonDownloadExcel(repairFbExport, '缁翠慨璇勪环璁板綍', tableApi.formApi.form.values, {
+    fieldMappingTime: formOptions.fieldMappingTime
+  });
+}
+
+onMounted(async () => {
+  await setupDeptSelect();
+});
+
+/**
+ * 鐢ㄦ埛鐨勫姞杞�
+ */
+async function setupUserOptions(deptId: any) {
+  const params = { deptId };
+  const userPageResult = await userList({
+    pageNum: 1,
+    pageSize: 500,
+    ...params
+  });
+  const options = userPageResult.rows.map((item) => ({
+    label: item.nickName || item.userName,
+    value: item.userId
+  }));
+  // 绛涢��
+  const filterOption = (input: string, option: any) => {
+    return option.label.toLowerCase().includes(input.toLowerCase());
+  };
+
+  const placeholder = options.length > 0 ? '璇烽�夋嫨' : '璇ラ儴闂ㄤ笅鏆傛棤鐢ㄦ埛';
+  tableApi.formApi.updateSchema([
+    {
+      componentProps: { options, placeholder, filterOption },
+      fieldName: 'resUser'
+    }
+  ]);
+}
+
+/**
+ * 鍒濆鍖栭儴闂ㄩ�夋嫨
+ */
+async function setupDeptSelect() {
+  // updateSchema
+  const deptTree = await getDeptTree();
+  // 閫変腑鍚庢樉绀哄湪杈撳叆妗嗙殑鍊� 鍗崇埗鑺傜偣 / 瀛愯妭鐐�
+  addFullName(deptTree, 'label', ' / ');
+  tableApi.formApi.updateSchema([
+    {
+      componentProps: (formModel) => ({
+        class: 'w-full',
+        fieldNames: {
+          key: 'id',
+          value: 'id',
+          children: 'children'
+        },
+        getPopupContainer,
+        async onSelect(deptId: number | string) {
+          /** 鏍规嵁閮ㄩ棬ID鍔犺浇鐢ㄦ埛 */
+          await setupUserOptions(deptId);
+          /** 鍙樺寲鍚庨渶瑕侀噸鏂伴�夋嫨鐢ㄦ埛 */
+          formModel.reqUser = undefined;
+        },
+        placeholder: '璇烽�夋嫨',
+        showSearch: true,
+        treeData: deptTree,
+        treeDefaultExpandAll: true,
+        treeLine: { showLeafIcon: false },
+        // 绛涢�夌殑瀛楁
+        treeNodeFilterProp: 'label',
+        // 閫変腑鍚庢樉绀哄湪杈撳叆妗嗙殑鍊�
+        treeNodeLabelProp: 'fullName'
+      }),
+      fieldName: 'resDept'
+    }
+  ]);
+}
+</script>
+
+<template>
+  <Page :auto-content-height="true">
+    <div class="flex h-full gap-[8px]">
+      <BasicTable class="flex-1 overflow-hidden" table-title="缁翠慨宸ュ崟鍒楄〃">
+        <template #toolbar-tools>
+          <Space>
+            <a-button v-access:code="['eims:repairFb:export']" @click="handleDownloadExcel">
+              {{ $t('pages.common.export') }}
+            </a-button>
+            <a-button
+              :disabled="!vxeCheckboxChecked(tableApi)"
+              danger
+              type="primary"
+              v-access:code="['eims:repairFb:remove']"
+              @click="handleMultiDelete"
+            >
+              {{ $t('pages.common.delete') }}
+            </a-button>
+            <a-button type="primary" v-access:code="['eims:repairFb:add']" @click="handleAdd"> {{ $t('pages.common.add') }}</a-button>
+          </Space>
+        </template>
+
+        <template #action="{ row }">
+          <Space>
+            <ghost-button v-access:code="['eims:repairFb:edit']" @click.stop="handleEdit(row)">
+              {{ $t('pages.common.edit') }}
+            </ghost-button>
+            <Popconfirm :get-popup-container="getVxePopupContainer" placement="left" title="纭鍒犻櫎锛�" @confirm="handleDelete(row)">
+              <ghost-button danger v-access:code="['eims:repairFb:remove']" @click.stop="">
+                {{ $t('pages.common.delete') }}
+              </ghost-button>
+            </Popconfirm>
+          </Space>
+        </template>
+      </BasicTable>
+    </div>
+    <RepairFbDrawer @reload="tableApi.query()" />
+  </Page>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/eims/repair-fb/repair-fb-drawer.vue b/eims-ui/apps/web-antd/src/views/eims/repair-fb/repair-fb-drawer.vue
new file mode 100644
index 0000000..f11a3fb
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/eims/repair-fb/repair-fb-drawer.vue
@@ -0,0 +1,170 @@
+<script setup lang="ts">
+import type { RepairFbVO } from '#/api/eims/repair-fb/model';
+
+import { computed, ref } from 'vue';
+
+import { useVbenDrawer } from '@vben/common-ui';
+import { $t } from '@vben/locales';
+import { addFullName, cloneDeep, getPopupContainer } from '@vben/utils';
+
+import { useVbenForm } from '#/adapter/form';
+import { addRepairFb, getRepairFb, updateRepairFb } from '#/api/eims/repair-fb';
+import { getDeptTree, userList } from '#/api/system/user';
+
+import { drawerSchema } from './data';
+
+const emit = defineEmits<{ reload: [] }>();
+
+const isUpdate = ref(false);
+const title = computed(() => {
+  return isUpdate.value ? `${$t('pages.common.edit')}璇勪环` : `${$t('pages.common.add')}璇勪环`;
+});
+
+const [BasicForm, formApi] = useVbenForm({
+  commonConfig: {
+    formItemClass: 'col-span-2',
+    componentProps: {
+      class: 'w-full'
+    },
+    labelWidth: 120
+  },
+  schema: drawerSchema(),
+  showDefaultActions: false,
+  wrapperClass: 'grid-cols-2'
+});
+
+const [BasicDrawer, drawerApi] = useVbenDrawer({
+  onCancel: handleCancel,
+  onConfirm: handleConfirm,
+  async onOpenChange(isOpen) {
+    if (!isOpen) {
+      return null;
+    }
+
+    drawerApi.drawerLoading(true);
+    const { id } = drawerApi.getData() as { id?: number | string };
+    // 鏁版嵁浠� repair_res index 浼犺繃鏉�
+    const repairFb = drawerApi.getData() as RepairFbVO;
+    if (repairFb?.fbDept) {
+      await setupUserOptions(repairFb.fbDept);
+    }
+    if (repairFb) {
+      await formApi.setValues(repairFb);
+    }
+    isUpdate.value = !!id;
+    // 鍒濆鍖�
+    await setupDeptSelect();
+
+    // 鏇存柊 && 璧嬪��
+    if (isUpdate.value && id) {
+      const record = await getRepairFb(id);
+      if (record.fbDept) {
+        await setupUserOptions(record.fbDept);
+      }
+      record.repairSatisfaction = Number(record.repairSatisfaction);
+      record.repairSs = Number(record.repairSs);
+      record.serviceAttitude = Number(record.serviceAttitude);
+      record.repairTimeliness = Number(record.repairTimeliness);
+      await formApi.setValues(record);
+    }
+
+    drawerApi.drawerLoading(false);
+  }
+});
+
+/**
+ * 鐢ㄦ埛鐨勫姞杞�
+ */
+async function setupUserOptions(deptId: any) {
+  const params = { deptId };
+  const userPageResult = await userList({
+    pageNum: 1,
+    pageSize: 500,
+    ...params
+  });
+  const options = userPageResult.rows.map((item) => ({
+    label: item.nickName || item.userName,
+    value: item.userId
+  }));
+  // 绛涢��
+  const filterOption = (input: string, option: any) => {
+    return option.label.toLowerCase().includes(input.toLowerCase());
+  };
+
+  const placeholder = options.length > 0 ? '璇烽�夋嫨' : '璇ラ儴闂ㄤ笅鏆傛棤鐢ㄦ埛';
+  formApi.updateSchema([
+    {
+      componentProps: { options, placeholder, filterOption },
+      fieldName: 'fbUser'
+    }
+  ]);
+}
+
+/**
+ * 鍒濆鍖栭儴闂ㄩ�夋嫨
+ */
+async function setupDeptSelect() {
+  // updateSchema
+  const deptTree = await getDeptTree();
+  // 閫変腑鍚庢樉绀哄湪杈撳叆妗嗙殑鍊� 鍗崇埗鑺傜偣 / 瀛愯妭鐐�
+  addFullName(deptTree, 'label', ' / ');
+  formApi.updateSchema([
+    {
+      componentProps: (formModel) => ({
+        class: 'w-full',
+        fieldNames: {
+          key: 'id',
+          value: 'id',
+          children: 'children'
+        },
+        getPopupContainer,
+        async onSelect(deptId: number | string) {
+          /** 鏍规嵁閮ㄩ棬ID鍔犺浇鐢ㄦ埛 */
+          await setupUserOptions(deptId);
+          /** 鍙樺寲鍚庨渶瑕侀噸鏂伴�夋嫨鐢ㄦ埛 */
+          formModel.fbUser = undefined;
+        },
+        placeholder: '璇烽�夋嫨',
+        showSearch: true,
+        treeData: deptTree,
+        treeDefaultExpandAll: true,
+        treeLine: { showLeafIcon: false },
+        // 绛涢�夌殑瀛楁
+        treeNodeFilterProp: 'label',
+        // 閫変腑鍚庢樉绀哄湪杈撳叆妗嗙殑鍊�
+        treeNodeLabelProp: 'fullName'
+      }),
+      fieldName: 'fbDept'
+    }
+  ]);
+}
+
+async function handleConfirm() {
+  try {
+    drawerApi.drawerLoading(true);
+    const { valid } = await formApi.validate();
+    if (!valid) {
+      return;
+    }
+    const data = cloneDeep(await formApi.getValues());
+    await (isUpdate.value ? updateRepairFb(data) : addRepairFb(data));
+    emit('reload');
+    await handleCancel();
+  } catch (error) {
+    console.error(error);
+  } finally {
+    drawerApi.drawerLoading(false);
+  }
+}
+
+async function handleCancel() {
+  drawerApi.close();
+  await formApi.resetForm();
+}
+</script>
+
+<template>
+  <BasicDrawer :close-on-click-modal="false" :title="title" class="w-[600px]">
+    <BasicForm />
+  </BasicDrawer>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/eims/repair-res/index.vue b/eims-ui/apps/web-antd/src/views/eims/repair-res/index.vue
index b2b4668..5a7d45b 100644
--- a/eims-ui/apps/web-antd/src/views/eims/repair-res/index.vue
+++ b/eims-ui/apps/web-antd/src/views/eims/repair-res/index.vue
@@ -12,7 +12,7 @@
 import { Modal, Popconfirm, Space } from 'ant-design-vue';
 
 import { useVbenVxeGrid, vxeCheckboxChecked, type VxeGridProps, vxeSortEvent } from '#/adapter/vxe-table';
-import { delRepairRes, listRepairRes, repairResExport, updateRepairRes } from '#/api/eims/repair-res';
+import { delRepairRes, listRepairRes, repairResExport } from '#/api/eims/repair-res';
 import { getDeptTree, userList } from '#/api/system/user';
 import { REPAIR_RES_STATUS } from '#/constants/dict';
 import { commonDownloadExcel } from '#/utils/file/download';
@@ -20,6 +20,9 @@
 import RepairRecord from '../repair-record/index.vue';
 import { columns, querySchema } from './data';
 import repairResDrawer from './repair-res-drawer.vue';
+
+import repairFbDrawer from '../repair-fb/repair-fb-drawer.vue'
+import fbPreviewDrawer from '../repair-fb/fb-preview-drawer.vue'
 
 const userStore = useUserStore();
 const userId = userStore.userInfo?.userId;
@@ -94,6 +97,25 @@
   connectedComponent: repairResDrawer
 });
 
+const [RepairFbDrawer, repairFbDrawerApi] = useVbenDrawer({
+  connectedComponent: repairFbDrawer
+});
+
+const [FbPreviewDrawer, fbPreviewDrawerApi] = useVbenDrawer({
+  connectedComponent: fbPreviewDrawer
+});
+
+function handleAddFb(record: Recordable<any>) {
+  repairFbDrawerApi.setData({ resId: record.id, resCode: record.resCode, fbUser: userId, fbDept: deptId});
+  repairFbDrawerApi.open();
+}
+
+function handleDetailFb(record: Recordable<any>) {
+  fbPreviewDrawerApi.setData({ id: record.fbId });
+  fbPreviewDrawerApi.open();
+}
+
+
 function handleAdd() {
   repairResDrawerApi.setData({ resUser: userId, resDept: deptId });
   repairResDrawerApi.open();
@@ -112,17 +134,21 @@
 const { hasAccessByRoles } = useAccess();
 const isSuperAdmin = computed(() => hasAccessByRoles(['superadmin']));
 
+
+function pingjiaAdd(row: any) {
+  return (isSuperAdmin.value || row.reqUser === userId) && row.status === REPAIR_RES_STATUS.WANCHENG && !row.fbId;
+}
+
+function pingjiaDetail(row: any) {
+  return (isSuperAdmin.value || row.reqUser === userId) && row.status === REPAIR_RES_STATUS.WANCHENG && row.fbId;
+}
+
 function weixiu(row: any) {
   return (isSuperAdmin.value || row.resUser === userId) && row.status === REPAIR_RES_STATUS.YIJIEDAN;
 }
 
 function wancheng(row: any) {
   return (isSuperAdmin.value || row.resUser === userId) && row.status === REPAIR_RES_STATUS.WEIXIU;
-}
-
-async function handleRepairStatus(record: Recordable<any>, status: string) {
-  record.status = status;
-  handleConfirm(record);
 }
 
 async function handleDelete(row: Recordable<any>) {
@@ -148,15 +174,6 @@
   commonDownloadExcel(repairResExport, '缁翠慨宸ュ崟璁板綍', tableApi.formApi.form.values, {
     fieldMappingTime: formOptions.fieldMappingTime
   });
-}
-
-async function handleConfirm(data: any) {
-  try {
-    await updateRepairRes(data);
-  } catch (error) {
-    console.error(error);
-  } finally {
-  }
 }
 
 onMounted(async () => {
@@ -255,6 +272,8 @@
 
         <template #action="{ row }">
           <Space>
+            <ghost-button v-if="pingjiaAdd(row)" class="btn-success" v-access:code="['eims:repairRes:edit']" @click.stop="handleAddFb(row)"> 璇勪环 </ghost-button>
+            <ghost-button v-if="pingjiaDetail(row)" class="btn-success" v-access:code="['eims:repairRes:edit']" @click.stop="handleDetailFb(row)"> 闃呰瘎 </ghost-button>
             <ghost-button
               v-if="weixiu(row)"
               class="btn-success"
@@ -287,5 +306,7 @@
       <RepairRecord :res-id="resId" class="h-1/3" table-title="缁翠慨璁板綍" />
     </div>
     <RepairResDrawer @reload="tableApi.query()" />
+    <RepairFbDrawer @reload="tableApi.query()" />
+    <FbPreviewDrawer />
   </Page>
 </template>
diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/controller/EimsRepairFbController.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/controller/EimsRepairFbController.java
new file mode 100644
index 0000000..a93ac8d
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/controller/EimsRepairFbController.java
@@ -0,0 +1,107 @@
+package org.dromara.eims.controller;
+
+import java.util.List;
+
+import lombok.RequiredArgsConstructor;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.constraints.*;
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import org.dromara.eims.service.IEimsRepairResService;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.validation.annotation.Validated;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.excel.utils.ExcelUtil;
+import org.dromara.eims.domain.vo.EimsRepairFbVo;
+import org.dromara.eims.domain.bo.EimsRepairFbBo;
+import org.dromara.eims.service.IEimsRepairFbService;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+
+/**
+ * 缁翠慨璇勪环
+ *
+ * @author zhuguifei
+ * @date 2025-02-28
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/eims/repairFb")
+public class EimsRepairFbController extends BaseController {
+
+    private final IEimsRepairFbService eimsRepairFbService;
+    private final IEimsRepairResService repairResService;
+
+    /**
+     * 鏌ヨ缁翠慨璇勪环鍒楄〃
+     */
+    @SaCheckPermission("eims:repairFb:list")
+    @GetMapping("/list")
+    public TableDataInfo<EimsRepairFbVo> list(EimsRepairFbBo bo, PageQuery pageQuery) {
+        return eimsRepairFbService.queryPageList(bo, pageQuery);
+    }
+
+    /**
+     * 瀵煎嚭缁翠慨璇勪环鍒楄〃
+     */
+    @SaCheckPermission("eims:repairFb:export")
+    @Log(title = "缁翠慨璇勪环", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(EimsRepairFbBo bo, HttpServletResponse response) {
+        List<EimsRepairFbVo> list = eimsRepairFbService.queryList(bo);
+        ExcelUtil.exportExcel(list, "缁翠慨璇勪环", EimsRepairFbVo.class, response);
+    }
+
+    /**
+     * 鑾峰彇缁翠慨璇勪环璇︾粏淇℃伅
+     *
+     * @param id 涓婚敭
+     */
+    @SaCheckPermission("eims:repairFb:query")
+    @GetMapping("/{id}")
+    public R<EimsRepairFbVo> getInfo(@NotNull(message = "涓婚敭涓嶈兘涓虹┖")
+                                     @PathVariable Long id) {
+        return R.ok(eimsRepairFbService.queryById(id));
+    }
+
+    /**
+     * 鏂板缁翠慨璇勪环
+     */
+    @SaCheckPermission("eims:repairFb:add")
+    @Log(title = "缁翠慨璇勪环", businessType = BusinessType.INSERT)
+    @RepeatSubmit()
+    @PostMapping()
+    public R<Void> add(@Validated(AddGroup.class) @RequestBody EimsRepairFbBo bo) {
+        return toAjax(eimsRepairFbService.insertByBo(bo));
+    }
+
+    /**
+     * 淇敼缁翠慨璇勪环
+     */
+    @SaCheckPermission("eims:repairFb:edit")
+    @Log(title = "缁翠慨璇勪环", businessType = BusinessType.UPDATE)
+    @RepeatSubmit()
+    @PutMapping()
+    public R<Void> edit(@Validated(EditGroup.class) @RequestBody EimsRepairFbBo bo) {
+        return toAjax(eimsRepairFbService.updateByBo(bo));
+    }
+
+    /**
+     * 鍒犻櫎缁翠慨璇勪环
+     *
+     * @param ids 涓婚敭涓�
+     */
+    @SaCheckPermission("eims:repairFb:remove")
+    @Log(title = "缁翠慨璇勪环", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public R<Void> remove(@NotEmpty(message = "涓婚敭涓嶈兘涓虹┖")
+                          @PathVariable Long[] ids) {
+        return toAjax(eimsRepairFbService.deleteWithValidByIds(List.of(ids), true));
+    }
+}
diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/EimsRepairFb.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/EimsRepairFb.java
new file mode 100644
index 0000000..96cc974
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/EimsRepairFb.java
@@ -0,0 +1,95 @@
+package org.dromara.eims.domain;
+
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+
+import java.io.Serial;
+
+/**
+ * 缁翠慨璇勪环瀵硅薄 eims_repair_fb
+ *
+ * @author zhuguifei
+ * @date 2025-02-28
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("eims_repair_fb")
+public class EimsRepairFb extends BaseEntity {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     *
+     */
+    @TableId(value = "id")
+    private Long id;
+
+    /**
+     * 缁翠慨宸ュ崟id
+
+     */
+    private Long resId;
+
+    /**
+     * 缁翠慨宸ュ崟code
+
+     */
+    private String resCode;
+
+    /**
+     * 鍙嶉缁撴灉
+     */
+    private String fbResult;
+
+    /**
+     * 鍙嶉浜�
+     */
+    private Long fbUser;
+
+    /**
+     * 鍙嶉浜洪儴闂�
+     */
+    private Long fbDept;
+
+    /**
+     * 鍙嶉鏃堕棿
+     */
+    private Date fbTime;
+
+    /**
+     * 缁翠慨鍙婃椂鎬�(瀛楀吀)
+     */
+    private String repairTimeliness;
+
+    /**
+     * 鏈嶅姟鎬佸害
+     */
+    private String serviceAttitude;
+
+    /**
+     * 缁翠慨鐜板満6s
+     */
+    private String repairSs;
+
+    /**
+     * 缁翠慨婊℃剰搴�
+     */
+    private String repairSatisfaction;
+
+    /**
+     * 鎰忚鎴栧缓璁�
+     */
+    private String suggestions;
+
+    /**
+     * 澶囨敞
+     */
+    private String remark;
+
+
+}
diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/EimsRepairRes.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/EimsRepairRes.java
index 32c55c9..b1f1899 100644
--- a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/EimsRepairRes.java
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/EimsRepairRes.java
@@ -101,4 +101,10 @@
     private String remark;
 
 
+    /**
+     * 璇勪环id
+     */
+    private Long fbId;
+
+
 }
diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/bo/EimsRepairFbBo.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/bo/EimsRepairFbBo.java
new file mode 100644
index 0000000..18021c5
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/bo/EimsRepairFbBo.java
@@ -0,0 +1,90 @@
+package org.dromara.eims.domain.bo;
+
+import org.dromara.eims.domain.EimsRepairFb;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import jakarta.validation.constraints.*;
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+
+/**
+ * 缁翠慨璇勪环涓氬姟瀵硅薄 eims_repair_fb
+ *
+ * @author zhuguifei
+ * @date 2025-02-28
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = EimsRepairFb.class, reverseConvertGenerate = false)
+public class EimsRepairFbBo extends BaseEntity {
+
+    /**
+     *
+     */
+    @NotNull(message = "涓嶈兘涓虹┖", groups = { EditGroup.class })
+    private Long id;
+
+    /**
+     * 缁翠慨宸ュ崟id
+
+     */
+    private Long resId;
+
+    private String resCode;
+
+    /**
+     * 鍙嶉缁撴灉
+     */
+    private String fbResult;
+
+    /**
+     * 鍙嶉浜�
+     */
+    private Long fbUser;
+
+    /**
+     * 鍙嶉浜洪儴闂�
+     */
+    private Long fbDept;
+
+    /**
+     * 鍙嶉鏃堕棿
+     */
+    private Date fbTime;
+
+    /**
+     * 缁翠慨鍙婃椂鎬�(瀛楀吀)
+     */
+    private String repairTimeliness;
+
+    /**
+     * 鏈嶅姟鎬佸害
+     */
+    private String serviceAttitude;
+
+    /**
+     * 缁翠慨鐜板満6s
+     */
+    private String repairSs;
+
+    /**
+     * 缁翠慨婊℃剰搴�
+     */
+    private String repairSatisfaction;
+
+    /**
+     * 鎰忚鎴栧缓璁�
+     */
+    private String suggestions;
+
+    /**
+     * 澶囨敞
+     */
+    private String remark;
+
+
+}
diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/bo/EimsRepairResBo.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/bo/EimsRepairResBo.java
index 1b373af..5ddb4c2 100644
--- a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/bo/EimsRepairResBo.java
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/bo/EimsRepairResBo.java
@@ -100,6 +100,12 @@
     private String remark;
 
 
+    /**
+     * 璇勪环id
+     */
+    private Long fbId;
+
+
     //杈呭姪瀛楁
     /**
      * 闇�瑕佹壒閲忔坊鍔犵殑鎶ヤ慨鍗曞彿
diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/vo/EimsRepairFbVo.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/vo/EimsRepairFbVo.java
new file mode 100644
index 0000000..609e24a
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/vo/EimsRepairFbVo.java
@@ -0,0 +1,125 @@
+package org.dromara.eims.domain.vo;
+
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import org.dromara.common.translation.annotation.Translation;
+import org.dromara.common.translation.constant.TransConstant;
+import org.dromara.eims.domain.EimsRepairFb;
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import org.dromara.common.excel.annotation.ExcelDictFormat;
+import org.dromara.common.excel.convert.ExcelDictConvert;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+
+
+/**
+ * 缁翠慨璇勪环瑙嗗浘瀵硅薄 eims_repair_fb
+ *
+ * @author zhuguifei
+ * @date 2025-02-28
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = EimsRepairFb.class)
+public class EimsRepairFbVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     *
+     */
+    @ExcelProperty(value = "")
+    private Long id;
+
+    /**
+     * 缁翠慨宸ュ崟id
+
+     */
+    @ExcelProperty(value = "缁翠慨宸ュ崟id")
+    private Long resId;
+
+    /**
+     * 缁翠慨宸ュ崟code
+
+     */
+    @ExcelProperty(value = "缁翠慨宸ュ崟code")
+    private String resCode;
+
+    /**
+     * 鍙嶉缁撴灉
+     */
+    @ExcelProperty(value = "鍙嶉缁撴灉")
+    private String fbResult;
+
+    /**
+     * 鍙嶉浜�
+     */
+    @ExcelProperty(value = "鍙嶉浜�")
+    private Long fbUser;
+
+
+    @Translation(type = TransConstant.USER_ID_TO_NICKNAME, mapper = "fbUser")
+    private String fbUserName;
+
+    /**
+     * 鍙嶉浜洪儴闂�
+     */
+    @ExcelProperty(value = "鍙嶉浜洪儴闂�")
+    private Long fbDept;
+
+
+
+    @Translation(type = TransConstant.DEPT_ID_TO_NAME, mapper = "fbDept")
+    private String fbDeptName;
+
+    /**
+     * 鍙嶉鏃堕棿
+     */
+    @ExcelProperty(value = "鍙嶉鏃堕棿")
+    private Date fbTime;
+
+    /**
+     * 缁翠慨鍙婃椂鎬�(瀛楀吀)
+     */
+    @ExcelProperty(value = "缁翠慨鍙婃椂鎬�(瀛楀吀)")
+    private String repairTimeliness;
+
+    /**
+     * 鏈嶅姟鎬佸害
+     */
+    @ExcelProperty(value = "鏈嶅姟鎬佸害")
+    private String serviceAttitude;
+
+    /**
+     * 缁翠慨鐜板満6s
+     */
+    @ExcelProperty(value = "缁翠慨鐜板満6s")
+    private String repairSs;
+
+    /**
+     * 缁翠慨婊℃剰搴�
+     */
+    @ExcelProperty(value = "缁翠慨婊℃剰搴�")
+    private String repairSatisfaction;
+
+    /**
+     * 鎰忚鎴栧缓璁�
+     */
+    @ExcelProperty(value = "鎰忚鎴栧缓璁�")
+    private String suggestions;
+
+    /**
+     * 澶囨敞
+     */
+    @ExcelProperty(value = "澶囨敞")
+    private String remark;
+
+
+}
diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/vo/EimsRepairResVo.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/vo/EimsRepairResVo.java
index 397e720..856a25f 100644
--- a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/vo/EimsRepairResVo.java
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/vo/EimsRepairResVo.java
@@ -127,6 +127,11 @@
      */
     @ExcelProperty(value = "澶囨敞")
     private String remark;
+    
+    /**
+     * 璇勪环id
+     */
+    private Long fbId;
 
 
     // 鍏宠仈琛ㄥ瓧娈�
@@ -143,4 +148,5 @@
     private String reqCode;//鎶ヤ慨缂栫爜
 
 
+
 }
diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/mapper/EimsRepairFbMapper.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/mapper/EimsRepairFbMapper.java
new file mode 100644
index 0000000..6a714df
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/mapper/EimsRepairFbMapper.java
@@ -0,0 +1,15 @@
+package org.dromara.eims.mapper;
+
+import org.dromara.eims.domain.EimsRepairFb;
+import org.dromara.eims.domain.vo.EimsRepairFbVo;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+
+/**
+ * 缁翠慨璇勪环Mapper鎺ュ彛
+ *
+ * @author zhuguifei
+ * @date 2025-02-28
+ */
+public interface EimsRepairFbMapper extends BaseMapperPlus<EimsRepairFb, EimsRepairFbVo> {
+
+}
diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/IEimsRepairFbService.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/IEimsRepairFbService.java
new file mode 100644
index 0000000..dbaf971
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/IEimsRepairFbService.java
@@ -0,0 +1,68 @@
+package org.dromara.eims.service;
+
+import org.dromara.eims.domain.vo.EimsRepairFbVo;
+import org.dromara.eims.domain.bo.EimsRepairFbBo;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.mybatis.core.page.PageQuery;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 缁翠慨璇勪环Service鎺ュ彛
+ *
+ * @author zhuguifei
+ * @date 2025-02-28
+ */
+public interface IEimsRepairFbService {
+
+    /**
+     * 鏌ヨ缁翠慨璇勪环
+     *
+     * @param id 涓婚敭
+     * @return 缁翠慨璇勪环
+     */
+    EimsRepairFbVo queryById(Long id);
+
+    /**
+     * 鍒嗛〉鏌ヨ缁翠慨璇勪环鍒楄〃
+     *
+     * @param bo        鏌ヨ鏉′欢
+     * @param pageQuery 鍒嗛〉鍙傛暟
+     * @return 缁翠慨璇勪环鍒嗛〉鍒楄〃
+     */
+    TableDataInfo<EimsRepairFbVo> queryPageList(EimsRepairFbBo bo, PageQuery pageQuery);
+
+    /**
+     * 鏌ヨ绗﹀悎鏉′欢鐨勭淮淇瘎浠峰垪琛�
+     *
+     * @param bo 鏌ヨ鏉′欢
+     * @return 缁翠慨璇勪环鍒楄〃
+     */
+    List<EimsRepairFbVo> queryList(EimsRepairFbBo bo);
+
+    /**
+     * 鏂板缁翠慨璇勪环
+     *
+     * @param bo 缁翠慨璇勪环
+     * @return 鏄惁鏂板鎴愬姛
+     */
+    Boolean insertByBo(EimsRepairFbBo bo);
+
+    /**
+     * 淇敼缁翠慨璇勪环
+     *
+     * @param bo 缁翠慨璇勪环
+     * @return 鏄惁淇敼鎴愬姛
+     */
+    Boolean updateByBo(EimsRepairFbBo bo);
+
+    /**
+     * 鏍¢獙骞舵壒閲忓垹闄ょ淮淇瘎浠蜂俊鎭�
+     *
+     * @param ids     寰呭垹闄ょ殑涓婚敭闆嗗悎
+     * @param isValid 鏄惁杩涜鏈夋晥鎬ф牎楠�
+     * @return 鏄惁鍒犻櫎鎴愬姛
+     */
+    Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
+}
diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/impl/EimsRepairFbServiceImpl.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/impl/EimsRepairFbServiceImpl.java
new file mode 100644
index 0000000..de5fb8a
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/impl/EimsRepairFbServiceImpl.java
@@ -0,0 +1,146 @@
+package org.dromara.eims.service.impl;
+
+import org.dromara.common.core.service.RepairResService;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import lombok.RequiredArgsConstructor;
+import org.dromara.eims.domain.EimsRepairRes;
+import org.dromara.eims.mapper.EimsRepairResMapper;
+import org.springframework.stereotype.Service;
+import org.dromara.eims.domain.bo.EimsRepairFbBo;
+import org.dromara.eims.domain.vo.EimsRepairFbVo;
+import org.dromara.eims.domain.EimsRepairFb;
+import org.dromara.eims.mapper.EimsRepairFbMapper;
+import org.dromara.eims.service.IEimsRepairFbService;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Collection;
+
+/**
+ * 缁翠慨璇勪环Service涓氬姟灞傚鐞�
+ *
+ * @author zhuguifei
+ * @date 2025-02-28
+ */
+@RequiredArgsConstructor
+@Service
+public class EimsRepairFbServiceImpl implements IEimsRepairFbService {
+
+    private final EimsRepairFbMapper baseMapper;
+    private final EimsRepairResMapper repairResMapper;
+
+    /**
+     * 鏌ヨ缁翠慨璇勪环
+     *
+     * @param id 涓婚敭
+     * @return 缁翠慨璇勪环
+     */
+    @Override
+    public EimsRepairFbVo queryById(Long id){
+        return baseMapper.selectVoById(id);
+    }
+
+    /**
+     * 鍒嗛〉鏌ヨ缁翠慨璇勪环鍒楄〃
+     *
+     * @param bo        鏌ヨ鏉′欢
+     * @param pageQuery 鍒嗛〉鍙傛暟
+     * @return 缁翠慨璇勪环鍒嗛〉鍒楄〃
+     */
+    @Override
+    public TableDataInfo<EimsRepairFbVo> queryPageList(EimsRepairFbBo bo, PageQuery pageQuery) {
+        LambdaQueryWrapper<EimsRepairFb> lqw = buildQueryWrapper(bo);
+        Page<EimsRepairFbVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
+        return TableDataInfo.build(result);
+    }
+
+    /**
+     * 鏌ヨ绗﹀悎鏉′欢鐨勭淮淇瘎浠峰垪琛�
+     *
+     * @param bo 鏌ヨ鏉′欢
+     * @return 缁翠慨璇勪环鍒楄〃
+     */
+    @Override
+    public List<EimsRepairFbVo> queryList(EimsRepairFbBo bo) {
+        LambdaQueryWrapper<EimsRepairFb> lqw = buildQueryWrapper(bo);
+        return baseMapper.selectVoList(lqw);
+    }
+
+    private LambdaQueryWrapper<EimsRepairFb> buildQueryWrapper(EimsRepairFbBo bo) {
+        Map<String, Object> params = bo.getParams();
+        LambdaQueryWrapper<EimsRepairFb> lqw = Wrappers.lambdaQuery();
+        lqw.eq(bo.getResId() != null, EimsRepairFb::getResId, bo.getResId());
+        lqw.eq(bo.getFbUser() != null, EimsRepairFb::getFbUser, bo.getFbUser());
+        lqw.eq(bo.getFbDept() != null, EimsRepairFb::getFbDept, bo.getFbDept());
+        lqw.eq(bo.getFbTime() != null, EimsRepairFb::getFbTime, bo.getFbTime());
+        lqw.eq(StringUtils.isNotBlank(bo.getRepairTimeliness()), EimsRepairFb::getRepairTimeliness, bo.getRepairTimeliness());
+        lqw.eq(StringUtils.isNotBlank(bo.getServiceAttitude()), EimsRepairFb::getServiceAttitude, bo.getServiceAttitude());
+        lqw.eq(StringUtils.isNotBlank(bo.getRepairSs()), EimsRepairFb::getRepairSs, bo.getRepairSs());
+        lqw.eq(StringUtils.isNotBlank(bo.getRepairSatisfaction()), EimsRepairFb::getRepairSatisfaction, bo.getRepairSatisfaction());
+        return lqw;
+    }
+
+    /**
+     * 鏂板缁翠慨璇勪环
+     *
+     * @param bo 缁翠慨璇勪环
+     * @return 鏄惁鏂板鎴愬姛
+     */
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public Boolean insertByBo(EimsRepairFbBo bo) {
+        EimsRepairFb add = MapstructUtils.convert(bo, EimsRepairFb.class);
+        validEntityBeforeSave(add);
+        boolean flag = baseMapper.insert(add) > 0;
+        if (flag) {
+            bo.setId(add.getId());
+            //鏂板鏃舵洿鏂皉epair_res琛ㄨ瘎浠穒d
+            EimsRepairRes eimsRepairRes = repairResMapper.selectById(bo.getResId());
+            eimsRepairRes.setFbId(add.getId());
+            repairResMapper.updateById(eimsRepairRes);
+        }
+        return flag;
+    }
+
+    /**
+     * 淇敼缁翠慨璇勪环
+     *
+     * @param bo 缁翠慨璇勪环
+     * @return 鏄惁淇敼鎴愬姛
+     */
+    @Override
+    public Boolean updateByBo(EimsRepairFbBo bo) {
+        EimsRepairFb update = MapstructUtils.convert(bo, EimsRepairFb.class);
+        validEntityBeforeSave(update);
+        return baseMapper.updateById(update) > 0;
+    }
+
+    /**
+     * 淇濆瓨鍓嶇殑鏁版嵁鏍¢獙
+     */
+    private void validEntityBeforeSave(EimsRepairFb entity){
+        //TODO 鍋氫竴浜涙暟鎹牎楠�,濡傚敮涓�绾︽潫
+    }
+
+    /**
+     * 鏍¢獙骞舵壒閲忓垹闄ょ淮淇瘎浠蜂俊鎭�
+     *
+     * @param ids     寰呭垹闄ょ殑涓婚敭闆嗗悎
+     * @param isValid 鏄惁杩涜鏈夋晥鎬ф牎楠�
+     * @return 鏄惁鍒犻櫎鎴愬姛
+     */
+    @Override
+    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
+        if(isValid){
+            //TODO 鍋氫竴浜涗笟鍔′笂鐨勬牎楠�,鍒ゆ柇鏄惁闇�瑕佹牎楠�
+        }
+        return baseMapper.deleteByIds(ids) > 0;
+    }
+}
diff --git a/eims/ruoyi-modules/lb-eims/src/main/resources/mapper/eims/EimsRepairFbMapper.xml b/eims/ruoyi-modules/lb-eims/src/main/resources/mapper/eims/EimsRepairFbMapper.xml
new file mode 100644
index 0000000..816c72c
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/resources/mapper/eims/EimsRepairFbMapper.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.eims.mapper.EimsRepairFbMapper">
+
+</mapper>

--
Gitblit v1.9.3