فهرست منبع

2.0.0 去除所有bootstrap,使用antd重构

liuyanpeng 1 سال پیش
والد
کامیت
4ff35429f2
56فایلهای تغییر یافته به همراه2908 افزوده شده و 3281 حذف شده
  1. 3 2
      .eslintrc.js
  2. 126 90
      examples/App.vue
  3. 5 2
      examples/date/src/DateExample.vue
  4. 8 27
      examples/datetime/src/DateTimeExample.vue
  5. 35 0
      examples/doc-generator/DocGeneratorExample.vue
  6. 10 1
      examples/info/SearchWidgetExample.vue
  7. 59 0
      examples/modal/src/ModalExample copy.vue
  8. 40 41
      examples/modal/src/ModalExample.vue
  9. 102 0
      examples/notify/NotifyExample.vue
  10. 61 0
      examples/paginationNew/src/AntdPaginationExample.vue
  11. 10 7
      examples/print/src/PrintExample.vue
  12. 4 4
      examples/print/src/WriteEpcExample.vue
  13. 10 2
      examples/route/index.js
  14. 2 2
      examples/switches/src/SwitchesExample.vue
  15. 24 11
      examples/tree/src/TreeExample.vue
  16. 46 255
      examples/vue-monthly-picker/src/VueMonthlyPickerExample.vue
  17. 261 0
      examples/vue-monthly-picker/src/VueMonthlyPickerExampleOld.vue
  18. 12 28
      examples/year-picker/src/YearPickerExample.vue
  19. 35 0
      examples/year-picker/src/YearPickerExampleOld.vue
  20. 1 6
      index.html
  21. 1 1
      package.json
  22. 8 0
      packages/antd-pagination/index.js
  23. 97 0
      packages/antd-pagination/src/antd-pagination.vue
  24. 11 23
      packages/client-organization/src/ClientOrganization.vue
  25. 129 134
      packages/common/Notify.js
  26. 2 1
      packages/components.js
  27. 43 172
      packages/date/src/Date.vue
  28. 39 166
      packages/datetime/src/DateTime.vue
  29. 36 35
      packages/info/src/DocGenerator.vue
  30. 61 87
      packages/info/src/DocGeneratorGrid.vue
  31. 49 59
      packages/info/src/DocGeneratorSelected.vue
  32. 47 9
      packages/info/src/EnumSelectWidgetInfo.vue
  33. 2 1
      packages/info/src/InfoHeader.vue
  34. 5 0
      packages/info/src/InfoWindow.vue
  35. 124 123
      packages/info/src/MultiSearchWidget.vue
  36. 1 0
      packages/info/src/QueryCondition.vue
  37. 197 323
      packages/info/src/QueryConditionComplex.vue
  38. 11 24
      packages/info/src/QueryPage.vue
  39. 34 4
      packages/info/src/QueryPageTable.vue
  40. 71 53
      packages/info/src/SearchAutoCompleteWidget.vue
  41. 49 75
      packages/info/src/SearchWidget.vue
  42. 50 172
      packages/modal/src/Modal.vue
  43. 20 49
      packages/navbar/src/Navbar.vue
  44. 62 69
      packages/print/src/PrintEpc.vue
  45. 44 25
      packages/print/src/PrintWidget.vue
  46. 114 33
      packages/print/src/WriteEpc.vue
  47. 31 11
      packages/process/src/EnumSelectWidget.vue
  48. 121 139
      packages/process/src/ProcessReportDynamic.vue
  49. 153 114
      packages/process/src/ProcessReportResultPreview.vue
  50. 104 127
      packages/process/src/ProcessReportStatic.vue
  51. 90 53
      packages/switches/src/Switches.vue
  52. 31 35
      packages/time/src/Time.vue
  53. 69 111
      packages/tree/src/TreeViewNode.vue
  54. 23 51
      packages/upload-widget/src/UploadWidget.vue
  55. 53 445
      packages/vue-monthly-picker/src/VueMonthlyPicker.vue
  56. 72 79
      packages/year-picker/src/YearPicker.vue

+ 3 - 2
.eslintrc.js

@@ -28,8 +28,9 @@ module.exports = {
     'no-extra-semi': 'off',
     // 该规则强制使用一致的分号
     semi: ['error', 'always', { 'omitLastInOneLineBlock': false }],
-
-    
+    "vue/multi-word-component-names": ["error", {
+      "ignores": ["Date"] // 允许特定单单词名称
+    }],
     // 该规则强制使用一致的反勾号、双引号或单引号。
     quotes: ['error', 'single'],
     // 该规则旨在强制使用一致的缩进风格。默认是 4个空格。

+ 126 - 90
examples/App.vue

@@ -1,104 +1,140 @@
 <template>
-  <div class="container-fluid bs-docs-container">
-    <div class="row">
-      <div class="col-md-2">
-        <ul class="nav nav-pills nav-stacked">
-          <li>
-            <a href="#/desktop/writeEpc-example">EPC发卡</a>
-          </li>
-          <li>
-            <router-link :to="{ path: '/desktop/input-number-example'}">数字输入</router-link>
-          </li>
-          <li>
-            <router-link :to="{ path: '/desktop/date-example'}">日期控件</router-link>
-          </li>
-          <li>
-            <router-link :to="{ path: '/desktop/date-time-example'}">日期时间控件</router-link>
-          </li>
-          <li>
-            <router-link :to="{ path: '/desktop/image-preview-example'}">图片预览</router-link>
-          </li>
-          <li>
-            <router-link :to="{ path: '/desktop/loading-example'}">加载中</router-link>
-          </li>
-          <li>
-            <router-link :to="{ path: '/desktop/navbar-example'}">页面导航</router-link>
-          </li>
-          <li>
-            <router-link :to="{ path: '/desktop/page-size-select-example'}">页面大小控件</router-link>
-          </li>
-          <li>
-            <router-link :to="{ path: '/desktop/print-example'}">打印控件</router-link>
-          </li>
-          <li>
-            <router-link :to="{ path: '/desktop/scanner-example'}">扫描仪控件</router-link>
-          </li>
-          <li>
-            <router-link :to="{ path: '/desktop/switches-example'}">开关控件</router-link>
-          </li>
-          <li>
-            <router-link :to="{ path: '/desktop/time-example'}">时间控件</router-link>
-          </li>
-          <li>
-            <router-link :to="{ path: '/desktop/tree-example'}">树控件</router-link>
-          </li>
-          <li>
-            <router-link :to="{ path: '/desktop/update-widget-example'}">上传控件</router-link>
-          </li>
-          <li>
-            <router-link :to="{ path: '/desktop/pagination-example'}">分页控件</router-link>
-          </li>
-          <li>
-            <router-link :to="{ path: '/desktop/vue-monthly-picker-example'}">月份控件</router-link>
-          </li>
-          <li>
-            <router-link :to="{ path: '/desktop/year-picker-example'}">年份控件</router-link>
-          </li>
-          <li>
-            <router-link :to="{ path: '/desktop/search-widget-example'}">搜索框控件</router-link>
-          </li>
-          <li>
-            <router-link :to="{ path: '/desktop/search-input-example'}">搜索输入框控件</router-link>
-          </li>
-          <li>
-            <router-link :to="{ path: '/desktop/modal-example'}">模态框</router-link>
-          </li>
-          <li>
-            <a href="#/desktop/process-report/123456">流程报表</a>
-          </li>
-          <li>
-            <a href="#/desktop/info/040602">查询窗口</a>
-          </li>
-          <li>
-            <a href="#/doc-generator-selected">生单界面</a>
-          </li>
-        </ul>
-      </div>
-      <div class="col-md-10">
-        <router-view />
-      </div>
-    </div>
-  </div>
+  <a-layout class="app-container">
+    <a-layout-sider width="240" class="app-sider">
+      <a-menu mode="inline">
+        <a-menu-item key="writeEpc">
+          <router-link to="/desktop/writeEpc-example">EPC发卡</router-link>
+        </a-menu-item>
+        <a-menu-item key="inputNumber">
+          <router-link to="/desktop/input-number-example">数字输入</router-link>
+        </a-menu-item>
+        <a-menu-item key="date">
+          <router-link to="/desktop/date-example">日期控件</router-link>
+        </a-menu-item>
+        <a-menu-item key="dateTime">
+          <router-link to="/desktop/date-time-example">日期时间控件</router-link>
+        </a-menu-item>
+        <a-menu-item key="imagePreview">
+          <router-link to="/desktop/image-preview-example">图片预览</router-link>
+        </a-menu-item>
+        <a-menu-item key="loading">
+          <router-link to="/desktop/loading-example">加载中</router-link>
+        </a-menu-item>
+        <a-menu-item key="navbar">
+          <router-link to="/desktop/navbar-example">页面导航</router-link>
+        </a-menu-item>
+        <a-menu-item key="pageSize">
+          <router-link to="/desktop/page-size-select-example">页面大小控件</router-link>
+        </a-menu-item>
+        <a-menu-item key="print">
+          <router-link to="/desktop/print-example">打印控件</router-link>
+        </a-menu-item>
+        <a-menu-item key="scanner">
+          <router-link to="/desktop/scanner-example">扫描仪控件</router-link>
+        </a-menu-item>
+        <a-menu-item key="switches">
+          <router-link to="/desktop/switches-example">开关控件</router-link>
+        </a-menu-item>
+        <a-menu-item key="time">
+          <router-link to="/desktop/time-example">时间控件</router-link>
+        </a-menu-item>
+        <a-menu-item key="tree">
+          <router-link to="/desktop/tree-example">树控件</router-link>
+        </a-menu-item>
+        <a-menu-item key="update">
+          <router-link to="/desktop/update-widget-example">上传控件</router-link>
+        </a-menu-item>
+        <a-menu-item key="pagination">
+          <router-link to="/desktop/pagination-example">分页控件</router-link>
+        </a-menu-item>
+        <a-menu-item key="monthlyPicker">
+          <router-link to="/desktop/vue-monthly-picker-example">月份控件</router-link>
+        </a-menu-item>
+        <a-menu-item key="yearPicker">
+          <router-link to="/desktop/year-picker-example">年份控件</router-link>
+        </a-menu-item>
+        <a-menu-item key="searchWidget">
+          <router-link to="/desktop/search-widget-example">搜索框控件</router-link>
+        </a-menu-item>
+        <a-menu-item key="searchInput">
+          <router-link to="/desktop/search-input-example">搜索输入框控件</router-link>
+        </a-menu-item>
+        <a-menu-item key="modal">
+          <router-link to="/desktop/modal-example">模态框</router-link>
+        </a-menu-item>
+        <a-menu-item key="processReport">
+          <router-link to="/desktop/process-report/123456">流程报表</router-link>
+        </a-menu-item>
+        <a-menu-item key="info">
+          <router-link to="/desktop/info/040602">查询窗口</router-link>
+        </a-menu-item>
+        <a-menu-item key="docGenerator">
+          <router-link to="/desktop/doc-generator-example">生单界面</router-link>
+        </a-menu-item>
+        <a-menu-item key="notify">
+          <router-link to="/desktop/notify-example">通知</router-link>
+        </a-menu-item>
+      </a-menu>
+    </a-layout-sider>
+    <a-layout-content class="app-content">
+      <router-view />
+    </a-layout-content>
+  </a-layout>
 </template>
 
 <script>
-
+import { Layout, Menu } from 'ant-design-vue';
 
 export default {
   name: 'App',
-
   components: {
+    ALayout: Layout,
+    ALayoutSider: Layout.Sider,
+    ALayoutContent: Layout.Content,
+    AMenu: Menu,
+    AMenuItem: Menu.Item,
   },
-
   data() {
-    return {
-
-    };
-  },
-
-  methods: {
-
+    return {};
   },
+  methods: {},
 };
 </script>
 
+<style>
+.app-container {
+  min-height: 100vh;
+}
+
+.app-sider {
+  background: #fff;
+  border-right: 1px solid #f0f0f0;
+  overflow-y: auto;
+  height: 100vh;
+  position: fixed;
+  left: 0;
+}
+
+.app-content {
+  padding: 24px;
+  min-height: 100vh;
+  background: #fff;
+}
+
+:deep(.ant-menu-item) {
+  margin: 0 !important;
+}
+
+:deep(.ant-menu-item a) {
+  color: rgba(0, 0, 0, 0.85);
+  text-decoration: none;
+}
+
+:deep(.ant-menu-item-selected a) {
+  color: #1890ff;
+}
+
+:deep(.ant-menu-item:hover a) {
+  color: #1890ff;
+}
+</style>

+ 5 - 2
examples/date/src/DateExample.vue

@@ -9,7 +9,7 @@
         <label for="datetime">日期</label>
         <Date
           v-model="dateValue0"
-          @update:model-value="changedCount0++"
+          @update:model-value="getNewDate"
         />
       </div>
     </div>
@@ -91,7 +91,10 @@ export default {
   },
 
   methods: {
-
+    getNewDate(date) {
+      console.log(date);
+      this.changedCount0++;
+    },
   },
 };
 </script>

+ 8 - 27
examples/datetime/src/DateTimeExample.vue

@@ -6,10 +6,7 @@
     <div>
       <div class="form-group">
         <label for="datetime">日期时间</label>
-        <DateTime
-          v-model="dateValue1"
-          @update:model-value="changedCount1++"
-        />
+        <DateTime v-model="dateValue1" @update:model-value="changedCount1++" />
       </div>
     </div>
 
@@ -19,10 +16,7 @@
     <div>
       <div class="form-group">
         <label for="datetime">日期时间</label>
-        <DateTime
-          :model-value="dateValue1"
-          :readonly="true"
-        />
+        <DateTime :model-value="dateValue1" :readonly="true" />
       </div>
     </div>
 
@@ -30,31 +24,19 @@
     <h2>内联表单</h2>
     <div class="form-inline">
       <div class="form-group">
-        <label
-          class="control-label"
-          for="inputGroupSuccess3"
-        >日期时间</label>
-        <DateTime
-          v-model="dateValue2"
-          @update:model-value="changedCount2 ++ "
-        />
+        <label class="control-label" for="inputGroupSuccess3">日期时间</label>
+        <DateTime v-model="dateValue2" @update:model-value="changedCount2++" />
       </div>
     </div>
 
     {{ dateValue2 }} 更改次数 {{ changedCount2 }}
 
     <h2>只读</h2>
-        
+
     <div class="form-inline">
       <div class="form-group">
-        <label
-          class="control-label"
-          for="inputGroupSuccess3"
-        >日期时间</label>
-        <DateTime
-          v-model="dateValue3"
-          :readonly="true"
-        />
+        <label class="control-label" for="inputGroupSuccess3">日期时间</label>
+        <DateTime v-model="dateValue3" :readonly="true" />
       </div>
     </div>
 
@@ -93,5 +75,4 @@ export default {
 };
 </script>
 
-<style>
-</style>
+<style></style>

+ 35 - 0
examples/doc-generator/DocGeneratorExample.vue

@@ -0,0 +1,35 @@
+<template>
+  <Navbar :title="title" :is-go-back="false" />
+  <a-space>
+    <a-button type="primary" @click="generate()">确定</a-button>
+    <a-button danger @click="back()">撤销</a-button>
+  </a-space>
+  <DocGenerator ref="docGenerator" :info-window-no="infoWindowNo" @show-title="title = $event" />
+</template>
+
+<script>
+import Navbar from '../../packages/navbar/src/Navbar.vue';
+import DocGenerator from '../../packages/info/src/DocGenerator.vue';
+export default {
+  components: {
+    Navbar,
+    DocGenerator,
+  },
+  data() {
+    return {
+      title: '生单界面',
+      infoWindowNo: '301921',
+    };
+  },
+  methods: {
+    generate() {
+      const selectedDatas = this.$refs.docGenerator.getSelectedData();
+      console.log(selectedDatas, 'selectedDatas');
+    },
+    back() {
+      // window.close();
+      console.log('关闭');
+    },
+  },
+};
+</script>

+ 10 - 1
examples/info/SearchWidgetExample.vue

@@ -6,7 +6,8 @@
     info-window-no="279750"
     :field-value="fieldValue1"
     title-name="部门"
-    display-name="name"
+    display-name="organization.name"
+    :where-clause-source="whereClauseSource"
     @value-changed="fieldValue1Changed"
   />
 
@@ -99,6 +100,14 @@ export default {
         fieldType: 'Key',
       },
 
+      whereClauseSource: {
+        customerDataDimensions: [{
+          fieldName: 'client.id',
+          dataDimensionTypeNo: '202201191757',
+          defaultDataDimensionTypeValueNo: '3',
+        }],
+      },
+
       whereClauseSource2: {
         customerDataDimensions:[{
           fieldName: 'client.id',

+ 59 - 0
examples/modal/src/ModalExample copy.vue

@@ -0,0 +1,59 @@
+<template>
+  <div>
+    <h1>模态框</h1>
+    <button class="btn btn-default" @click="show">显示</button>
+    <Modal v-model:show="modal" title="hello">
+      <div>hello</div>
+    </Modal>
+
+    
+    <h1>模态框-标题+内容+结尾</h1>
+    <button class="btn btn-default" @click="show1">显示</button>
+    <Modal v-model:show="modal1" title="hello" :show-canel-button="false" :show-ok-button="false">
+      <template #header>
+        标题
+      </template>
+      <template #default>
+        内容
+      </template>
+      <template #footer>
+        结尾
+      </template>
+    </Modal>
+  </div>
+</template>
+
+<script>
+
+import Modal from '@/modal/index.js';
+
+export default {
+
+  components: {
+    'Modal': Modal,
+  },
+  data: function(){
+    return {
+      modal: false,
+      modal1: false,
+    };
+  },
+
+  mounted: function(){
+        
+  },
+
+  methods: {
+    show: function(){
+      this.modal = true;
+    },
+    show1: function(){
+      this.modal1 = true;
+    },
+  },
+};
+</script>
+
+<style scoped>
+
+</style>

+ 40 - 41
examples/modal/src/ModalExample.vue

@@ -1,21 +1,36 @@
 <template>
   <div>
-    <h1>模态框</h1>
-    <button class="btn btn-default" @click="show">显示</button>
-    <Modal v-model:show="modal" title="hello">
-      <div>hello</div>
+    <!-- 无插槽时则使用title属性 -->
+    <h1>无插槽标题+内容+默认结尾</h1>
+    <a-button type="primary" @click="open1 = true">打开</a-button>
+    <Modal v-model:show="open1" title="无插槽标题" @ok="handleOk" @cancel="handleCancel" @close="handleClose">
+      <p>标题+内容+默认结尾按钮</p>
     </Modal>
 
-    
-    <h1>模态框-标题+内容+结尾</h1>
-    <button class="btn btn-default" @click="show1">显示</button>
-    <Modal v-model:show="modal1" title="hello" :show-canel-button="false" :show-ok-button="false">
+    <!-- 有插槽时则使用插槽内容不使用title属性 -->
+    <h1>插槽标题+内容+默认结尾</h1>
+    <a-button type="primary" @click="open2 = true">打开</a-button>
+    <Modal
+      v-model:show="open2" title="插槽标题" :force="false" @ok="handleOk" @cancel="handleCancel"
+      @close="handleClose"
+    >
       <template #header>
-        标题
+        <h1>使用插槽标题</h1>
       </template>
-      <template #default>
-        内容
+      <p>标题+内容+默认结尾按钮</p>
+    </Modal>
+
+    <h1>标题+内容+自定义结尾</h1>
+    <a-button type="primary" @click="open3 = true">打开</a-button>
+    <Modal
+      v-model:show="open3" :force="true" :show-canel-button="false" :show-ok-button="false"
+      :show-top-right-close-button="true" @ok="handleOk" @cancel="handleCancel" @close="handleClose"
+    >
+      <template #header>
+        <h1>测试</h1>
       </template>
+      <p>标题+内容+自定义结尾</p>
+      <a-button @click="open1 = true">打开另一个模态框</a-button>
       <template #footer>
         结尾
       </template>
@@ -23,37 +38,21 @@
   </div>
 </template>
 
-<script>
-
-import Modal from '@/modal/index.js';
-
-export default {
+<script setup>
+import { ref } from 'vue';
+import Modal from '@/modal/src/Modal.vue';
 
-  components: {
-    'Modal': Modal,
-  },
-  data: function(){
-    return {
-      modal: false,
-      modal1: false,
-    };
-  },
+const open1 = ref(false);
+const open2 = ref(false);
+const open3 = ref(false);
 
-  mounted: function(){
-        
-  },
-
-  methods: {
-    show: function(){
-      this.modal = true;
-    },
-    show1: function(){
-      this.modal1 = true;
-    },
-  },
+const handleOk = () => {
+  console.log('handleOk');
+};
+const handleCancel = () => {
+  console.log('handleCancel');
+};
+const handleClose = () => {
+  console.log('handleClose');
 };
 </script>
-
-<style scoped>
-
-</style>

+ 102 - 0
examples/notify/NotifyExample.vue

@@ -0,0 +1,102 @@
+<template>
+  <div>
+    <h1>Notify Example</h1>
+  </div>
+  <a-space>
+    <a-button @click="show">show方法</a-button>
+    <a-button @click="notice">notice方法</a-button>
+    <a-button @click="noticeBig">noticeBig方法</a-button>
+    <a-button @click="info">info方法</a-button>
+    <a-button @click="infoBig">infoBig方法</a-button>
+    <a-button @click="success">success方法</a-button>
+    <a-button @click="error">error方法</a-button>
+    <a-button @click="open">antd原生open方法</a-button>
+  </a-space>
+</template>
+
+<script setup>
+import { h, ref } from 'vue';
+import { Button, notification, message } from 'ant-design-vue';
+import Notify from '../../packages/common/Notify.js';
+
+const test = ref('你好');
+const handleClose = () => {
+  message.success(test.value);
+};
+const show = () => {
+  Notify.show({
+    title: '提示',
+    message: '这是一个提示',
+    buttons: [
+      {
+        label: '确定',
+        cssClass: 'btn-primary',
+        action: function (dialogItself) {
+          console.log('确定', dialogItself);
+          dialogItself.close();
+          handleClose();
+        },
+      },
+      {
+        label: '取消',
+        action: function (dialogItself) {
+          console.log('取消', dialogItself);
+          dialogItself.close();
+        },
+      },
+    ],
+  });
+};
+
+const notice = () => {
+  Notify.notice('提示', '这是一个提示', 3000);
+};
+
+const noticeBig = () => {
+  Notify.noticeBig('提示', '这是一个提示');
+};
+
+const info = () => {
+  Notify.info('提示', '这是一个提示', 2000);
+};
+
+const infoBig = () => {
+  Notify.infoBig('提示', '这是一个提示', 2000);
+};
+
+const success = () => {
+  Notify.success('提示', '这是一个提示', 6000);
+};
+
+const error = () => {
+  Notify.error('提示', '这是一个提示', 2000);
+};
+
+const open = () => {
+  const key = `notify_${Date.now()}`; // 生成唯一标识 
+  notification.open({
+    message: '提示',
+    description: '这是一个提示',
+    duration: 0,
+    key,
+    btn: () =>
+
+      h(
+        Button,
+        {
+          type: 'primary',
+          size: 'small',
+          onClick: () => {
+            console.log('确认');
+            notification.close(key);
+          },
+        },
+        {
+          default: () => '确认',
+        },
+      ),
+    onClose: console.log('close'),
+  });
+};
+
+</script>

+ 61 - 0
examples/paginationNew/src/AntdPaginationExample.vue

@@ -0,0 +1,61 @@
+<template>
+  <h1>antd分页控件</h1>
+  <a-button @click="backFirstPage">回到第一页</a-button>
+  <div class="pagination-right">
+    <AntdPagination
+      ref="paginationRef"
+      :pagination="pagination" :options="options" :size="size" :disabled="disabled"
+      @get-page-params="getPageParams"
+    />
+  </div>
+</template>
+<script setup>
+import { ref, defineOptions } from 'vue';
+import AntdPagination from '@/antd-pagination/index.js';
+
+defineOptions({
+  name: 'AntdPaginationExample',
+});
+
+// 分页配置
+const pagination = ref({
+  total: 100, // 总条数
+  per_page: 20, // 每页条数
+  current_page: 1, // 当前页
+});
+
+// 分页配置
+const options = ref({
+  showTotal: true, // 显示总条数
+  showSizeChanger: true, // 显示每页条数
+  showQuickJumper: true, // 显示快速跳转
+  pageSizeOptions: ['10', '20', '50', '100', '200', '500'], // 每页条数选项
+});
+
+const size = ref('small'); // 大小
+const disabled = ref(false); // 是否禁用
+
+const paginationRef = ref(null); // 分页组件实例
+
+// 页数改变
+const getPageParams = (page, pageSize) => {
+  console.log(page, pageSize, 'getPageParams');
+  pagination.value.current_page = page;
+  pagination.value.per_page = pageSize;
+  console.log('执行查询---');
+};
+
+// 回到第一页
+const backFirstPage = () => {
+//   paginationRef.value.backFirstPage();
+  pagination.value.current_page = 1;
+  console.log('执行查询---');
+};
+
+</script>
+
+<style scoped>
+.pagination-right {
+    float: right;
+}
+</style>

+ 10 - 7
examples/print/src/PrintExample.vue

@@ -5,21 +5,21 @@
 
   <div class="form-group">
     <label>EPC</label>
-    <input v-model="epc" type="text" class="form-control" placeholder="发卡数据" />
+    <a-input v-model="epc" type="text" class="form-control" placeholder="发卡数据" />
   </div>
 
-  <button class="btn btn-default" @click="printEpc">发卡1</button>
+  <a-button class="gap-top" @click="printEpc">发卡1</a-button>
 
 
   <div class="form-group">
     <label>printPage</label>
-    <textarea v-model="printPageText" type="text" class="form-control" placeholder="发卡数据" />
+    <a-textarea v-model:value="printPageText" class="gap-top" :row="3" placeholder="发卡数据" />
   </div>
 
-  <button class="btn btn-default" @click="printPrintPage">发卡2</button>
+  <a-button class="gap-top" @click="printPrintPage">发卡2</a-button>
 
-  <button class="btn btn-default" @click="printByPrinter">打印</button>
-  <button class="btn btn-default" @click="printPreviewByPrinter">打印预览</button>
+  <a-button class="gap-top" @click="printByPrinter">打印</a-button>
+  <a-button class="gap-top" @click="printPreviewByPrinter">打印预览</a-button>
 
 
   <PrintEpc ref="printEpc" v-model:visible="printEpcVisible" :printer-name="selectedPrinter" />
@@ -103,5 +103,8 @@ export default {
 </script>
 
 <style scoped>
-
+.gap-top {
+  margin-top: 8px;
+  margin-right: 8px;
+}
 </style>

+ 4 - 4
examples/print/src/WriteEpcExample.vue

@@ -1,16 +1,16 @@
 <template>
   <h1>EPC发卡</h1>
   <div class="form-group">
-    <label>EPC</label>
-    <input
-      v-model="epc"
+    <label>EPC</label>
+    <a-input
+      v-model:value="epc"
       type="text"
       class="form-control"
       placeholder="发卡数据"
     />
   </div>
 
-  <button class="btn btn-default" @click="writeEpc">发卡</button>
+  <a-button style="margin-top: 8px;" @click="writeEpc">发卡</a-button>
 
   <WriteEpc ref="writeEpc" v-model:visible="writeEpcVisible" />
 </template>

+ 10 - 2
examples/route/index.js

@@ -17,7 +17,7 @@ const VueMonthlyPickerExample = () => import(/* webpackChunkName: "vue-monthly-p
 const YearPickerExample = () => import(/* webpackChunkName: "year-picker-example" */ '../year-picker/src/YearPickerExample.vue');
 const InputNumberExample = () => import(/* webpackChunkName: "input-number-example" */ '../input-number/src/InputNumberExample.vue');
 
-
+const AntdPaginationExample = () => import(/* webpackChunkName: "antd-pagination-example" */ '../paginationNew/src/AntdPaginationExample.vue');
 
 const LoadingExample = () => import(/* webpackChunkName: "loading-example" */ '../loading/src/LoadingExample.vue');
 const SearchWidgetExample = () => import(/* webpackChunkName: "search-widget-example" */ '../info/SearchWidgetExample.vue');
@@ -30,6 +30,9 @@ const SearchInput = () => import(/* webpackChunkName: "doc-generator-selected" *
 const SearchInputExample = () => import(/* webpackChunkName: "doc-generator-selected" */ '../search-input/SearchInputExample.vue');
 const WriteEpcExample = () => import('../print/src/WriteEpcExample.vue');
 const DocGeneratorExample = () => import('../info/DocGeneratorExample.vue');
+const DocGeneratorExample2 = () => import('../doc-generator/DocGeneratorExample.vue');
+
+const NotifyExample = () => import('../notify/NotifyExample.vue');
 
 export default {
   routes: [
@@ -104,7 +107,8 @@ export default {
 
 				
 
-        
+        /** antd分页控件 */
+        { path: 'antd-pagination-example', component: AntdPaginationExample },
 
         /** 流程报表 */
         { path: 'process-report/:no', component: ProcessReport },
@@ -119,6 +123,10 @@ export default {
         { path: 'search-input-example', component: SearchInputExample },
         // 生单例子
         { path: 'generate-document/:type/:infoWindowNo/:uuid', component: DocGeneratorExample },
+        // 生单例子
+        { path: 'doc-generator-example', component: DocGeneratorExample2 },
+        /** 通知 */
+        { path: 'notify-example', component: NotifyExample },
       ],
 
     },

+ 2 - 2
examples/switches/src/SwitchesExample.vue

@@ -39,9 +39,9 @@
   <div>{{ value4 }}</div>
 
 
-  <h1>图标</h1>
+  <h1>图标</h1>
 
-  <Switches v-model="value5" :type-bold="true" />
+  <Switches v-model="value5" :type-bold="true" :size="'small'" />
 
   <div>{{ value5 }}</div>
 </template>

+ 24 - 11
examples/tree/src/TreeExample.vue

@@ -15,8 +15,6 @@
 </template>
 
 <script>
-
-
 import TreeViewNode from '@/tree/index.js';
 
 export default {
@@ -26,7 +24,6 @@ export default {
     TreeViewNode,
   },
 
-
   data: function () {
     return {
       categories: [
@@ -37,15 +34,18 @@ export default {
             {
               id: '1-1',
               text: '树节点1-1',
-            }, {
+            },
+            {
               id: '1-2',
               text: '树节点1-2',
             },
           ],
-        }, {
+        },
+        {
           id: '2',
           text: '树节点2',
-        }, {
+        },
+        {
           id: '3',
           text: '树节点3',
         },
@@ -56,18 +56,31 @@ export default {
   },
 
   methods: {
-
     /**
-         * 类别选择发生改变
-         */
+     * 类别选择发生改变
+     */
     categorySelect: function (node) {
       node.selected = !node.selected;
       this.selectedNode = node;
     },
+    handleNodeExpand(updatedNode) {
+      // 找到并更新对应节点
+      const updateNode = nodes => {
+        return nodes.map(n => {
+          if (n.id === updatedNode.id) {
+            return { ...n, open: updatedNode.open };
+          }
+          if (n.childrenDatas) {
+            return { ...n, childrenDatas: updateNode(n.childrenDatas) };
+          }
+          return n;
+        });
+      };
 
+      this.categories = updateNode(this.categories);
+    },
   },
 };
 </script>
 
-<style>
-</style>
+<style></style>

+ 46 - 255
examples/vue-monthly-picker/src/VueMonthlyPickerExample.vue

@@ -1,261 +1,52 @@
 <template>
-  <div>
-    <h1>月份选择器</h1>
-    <h2>绑定dayjs对象</h2>
-    <div class="demo-component">
-      <vue-monthly-picker
-        v-model="selectedMonth"
-        :input-class="{'input': isDisplayInput}"
-        :disabled="isDisable"
-        :month-labels="locale"
-        :clear-option="clearOption"
-        :min="min"
-        :max="max"
-        :alignment="alignment"
-        :selected-background-color="selectedBackgroundColor"
-        @selected="handleSelect"
-      />
-    </div>
-
-    <div>选择的月份: {{ selectedMonthStr }}</div>
-
-    
-    <h2>绑定String</h2>
-    <div class="demo-component">
-      <vue-monthly-picker
-        v-model="selectedMonth1"
-        :input-class="{'input': isDisplayInput}"
-        :disabled="isDisable"
-        :month-labels="locale"
-        :clear-option="clearOption"
-        :min="min"
-        :max="max"
-        :alignment="alignment"
-        :selected-background-color="selectedBackgroundColor"
-        @selected="handleSelect"
-      />
-    </div>
-
-    <div>选择的月份: {{ selectedMonth1 }}</div>
-
-    <div>
-      <div class="form-group">
-        <label>只读</label>
-        <div class="input-group">
-          <Switches v-model="isDisable" />
-          {{ isDisable ? 'Disabled': 'Enable' }}
-        </div>
-      </div>
-      <div class="form-group">
-        <label>限制范围</label>
-        <div class="input-group">
-          <Switches v-model="isLimitRange" />
-          {{ rangeDisplay }}
-        </div>
-      </div>
-      <div class="form-group">
-        <label>显示</label>
-        <div class="input-group">
-          <Switches
-            v-model="isDisplayInput"
-            true-value="Input"
-            false-value="Label"
-          />
-          {{ isDisplayInput? 'Input': 'Label' }}
-        </div>
-      </div>
-      <div class="form-group">
-        <label>清空</label>
-        <div class="input-group">
-          <Switches v-model="clearOption" />
-          {{ clearOption ? 'Enable': 'Disabled' }}
-        </div>
-      </div>
-      <div class="form-group">
-        <label>国际化</label>
-        <select
-          v-model="locale"
-          placeholder="Select a language"
-          class="form-control"
-        >
-          <option
-            v-for="option in options"
-            :key="option.id"
-            :value="option.monthLabels"
-          >
-            {{ option.title }}
-          </option>
-        </select>
-      </div>
-      <div class="form-group">
-        <label>对齐</label>
-        <select
-          v-model="alignment"
-          placeholder="Select an alignment"
-          class="form-control"
-        >
-          <option
-            v-for="alignment1 in alignments"
-            :key="alignment1"
-            :value="alignment1"
-          >
-            {{ alignment1 }}
-          </option>
-        </select>
-      </div>
-      <div class="form-group">
-        <label>背景色</label>
-        <select
-          v-model="selectedBackgroundColor"
-          placeholder="Select an color"
-          class="form-control"
-        >
-          <option
-            v-for="color in colorExamples"
-            :key="color"
-            :value="color"
-          >
-            {{ color }}
-          </option>
-        </select>
-      </div>
-    </div>
+  <div style="margin-top: 20px;">
+    <h4>正常使用</h4>
+    <month-picker v-model="selectedMonth" :placeholder="placeholder" @selected="monthSelected" />
+    <p>当前选择:{{ selectedMonth }}</p>
+    <h4>限制范围(前后六个月)</h4>
+    <a-switch v-model:checked="isLimitRange" @change="rangeChange" />
+    <month-picker
+      v-model="selectedMonth" :placeholder="placeholder" :disabled-date="disabledDate"
+      @selected="monthSelected"
+    />
+    <h4>禁用</h4>
+    <month-picker v-model="selectedMonth" :placeholder="placeholder" :disabled="disabled" @selected="monthSelected" />
   </div>
 </template>
 
-<script>
+<script setup>
+import { ref } from 'vue';
 import dayjs from 'dayjs';
-import VueMonthlyPicker from '@/vue-monthly-picker/index.js';
-import Switches from '@/switches/index.js';
-
-export default {
-  name: 'App',
-  components: {
-    VueMonthlyPicker, Switches,
-  },
-  data() {
-    return {
-      selectedMonth: dayjs(),
-      selectedMonth1: '2024-05',
-      isDisable: false,
-      isDisplayInput: true,
-      locale: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
-      alignment: 'left',
-      selectedBackgroundColor: 'blue',
-      options: [
-        {
-          id: 1,
-          title: 'English',
-          monthLabels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
-        },
-        {
-          id: 2,
-          title: '中文',
-          monthLabels: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],
-        },
-        {
-          id: 3,
-          title: 'Korean',
-          monthLabels: ['1월', '2월', '3월', '4월', '5월', '6월', '7월', '8월', '9월', '10월', '11월', '12월'],
-        },
-      ],
-      alignments: ['left', 'center', 'right'],
-      colorExamples: ['blue', 'red', 'black'],
-      min: null,
-      max: null,
-      isLimitRange: false,
-      clearOption: true,
-    };
-  },
-  computed: {
-    rangeDisplay() {
-      if (!this.min || !this.max) {
-        return 'Disabled';
-      }
-      return this.min.format('YYYY/MM') + '-' + this.max.format('YYYY/MM');
-    },
-
-    selectedMonthStr(){
-      if(typeof this.selectedMonth === 'string'){
-        return this.selectedMonth;
-      }else{
-        return this.selectedMonth.format('YYYY-MM');
-      }
-    },
-  },
-  watch: {
-    isLimitRange(newValue) {
-      if (newValue) {
-        this.setSelectRange(dayjs().subtract(6, 'months'), dayjs().add(6, 'months'));
-      } else {
-        this.setSelectRange(null, null);
-      }
-    },
-    
-  },
-
-  mounted(){
-    this.testDayJs();
-  },
-  methods: {
-    handleSelect(value) {
-      console.log('Select', value);
-    },
-    setSelectRange(min, max) {
-      this.min = min;
-      this.max = max;
-    },
-    // 测试DayJs
-    testDayJs(){
-      // exist bug
-      console.log(dayjs('00:00:00', 'HH:mm:ss'));
-
-
-      console.log(dayjs('2024-05-09').format('YYYY-MM-DD'));
-      console.log(dayjs('2024-05-09 10:45').format('YYYY-MM-DD'));
-      console.log(dayjs('2024-05-09 10:45:01').format('YYYY-MM-DD'));
-      console.log(dayjs().format('YYYYMMDD_hhmmss'));
-
-      const nowDate = new Date();
-      const startDate = dayjs(nowDate).subtract(1, 'M').format('YYYY-MM-DD HH:mm:ss');
-      const endDate = dayjs(nowDate).add(1, 'd').format('YYYY-MM-DD HH:mm:ss');
-      console.log(startDate, endDate);
-      
-      const startDate1 = '2024-01-02';
-      const endDate1 = '2024-01-10';
-      let currentYearMonth = dayjs(startDate1).add(1, 'M').format('YYYY-MM');
-      console.log(endDate1, 'isBefore', currentYearMonth, dayjs(endDate1).isBefore(currentYearMonth));
-
-      console.log(dayjs('2024-01-25').format('YYYY-MM-DD HH:mm'));
-      console.log(dayjs('2024-01-25').format('YYYY-MM-DD'));
-      console.log(dayjs('2024-01-25').format('YYYY-MM'));
-      console.log(dayjs().format('_YYYYMMDD_hhmmss'));
-    },
-  },
+import MonthPicker from '@/vue-monthly-picker/src/VueMonthlyPicker.vue';
+
+const selectedMonth = ref('2025-06');
+const isLimitRange = ref(false);
+const min = ref(null);
+const max = ref(null);
+const placeholder = ref('请选择月份');
+const disabled = ref(true);
+
+// 月份变更
+const monthSelected = value => {
+  console.log('月份变更:', value);
 };
-</script>
-
-<style scoped>
-#app {
-    font-family: "Avenir", Helvetica, Arial, sans-serif;
-    -webkit-font-smoothing: antialiased;
-    -moz-osx-font-smoothing: grayscale;
-    text-align: center;
-    color: #2c3e50;
-    margin-top: 60px;
-}
-
-.demo-component {
-    width: 250px;
-    margin: auto;
-}
-.control-group {
-    margin-top: 100px;
-}
-.control {
-    text-align: center;
-}
-.option-list {
-    margin-top: 20px;
-}
-</style>
+// 限制日期
+const disabledDate = current => {
+  if (!current) return false;
+  const date = dayjs(current);
+
+  if (!min.value || !max.value) return false;
+  return date < min.value.startOf('month') ||
+    date > max.value.endOf('month');
+};
+// 限制范围
+const rangeChange = checked => {
+  if (checked) {
+    min.value = dayjs().subtract(6, 'month');
+    max.value = dayjs().add(6, 'month');
+  } else {
+    min.value = null;
+    max.value = null;
+  }
+};
+</script>

+ 261 - 0
examples/vue-monthly-picker/src/VueMonthlyPickerExampleOld.vue

@@ -0,0 +1,261 @@
+<template>
+  <div>
+    <h1>月份选择器</h1>
+    <h2>绑定dayjs对象</h2>
+    <div class="demo-component">
+      <vue-monthly-picker
+        v-model="selectedMonth"
+        :input-class="{'input': isDisplayInput}"
+        :disabled="isDisable"
+        :month-labels="locale"
+        :clear-option="clearOption"
+        :min="min"
+        :max="max"
+        :alignment="alignment"
+        :selected-background-color="selectedBackgroundColor"
+        @selected="handleSelect"
+      />
+    </div>
+
+    <div>选择的月份: {{ selectedMonthStr }}</div>
+
+    
+    <h2>绑定String</h2>
+    <div class="demo-component">
+      <vue-monthly-picker
+        v-model="selectedMonth1"
+        :input-class="{'input': isDisplayInput}"
+        :disabled="isDisable"
+        :month-labels="locale"
+        :clear-option="clearOption"
+        :min="min"
+        :max="max"
+        :alignment="alignment"
+        :selected-background-color="selectedBackgroundColor"
+        @selected="handleSelect"
+      />
+    </div>
+
+    <div>选择的月份: {{ selectedMonth1 }}</div>
+
+    <div>
+      <div class="form-group">
+        <label>只读</label>
+        <div class="input-group">
+          <Switches v-model="isDisable" />
+          {{ isDisable ? 'Disabled': 'Enable' }}
+        </div>
+      </div>
+      <div class="form-group">
+        <label>限制范围</label>
+        <div class="input-group">
+          <Switches v-model="isLimitRange" />
+          {{ rangeDisplay }}
+        </div>
+      </div>
+      <div class="form-group">
+        <label>显示</label>
+        <div class="input-group">
+          <Switches
+            v-model="isDisplayInput"
+            true-value="Input"
+            false-value="Label"
+          />
+          {{ isDisplayInput? 'Input': 'Label' }}
+        </div>
+      </div>
+      <div class="form-group">
+        <label>清空</label>
+        <div class="input-group">
+          <Switches v-model="clearOption" />
+          {{ clearOption ? 'Enable': 'Disabled' }}
+        </div>
+      </div>
+      <div class="form-group">
+        <label>国际化</label>
+        <select
+          v-model="locale"
+          placeholder="Select a language"
+          class="form-control"
+        >
+          <option
+            v-for="option in options"
+            :key="option.id"
+            :value="option.monthLabels"
+          >
+            {{ option.title }}
+          </option>
+        </select>
+      </div>
+      <div class="form-group">
+        <label>对齐</label>
+        <select
+          v-model="alignment"
+          placeholder="Select an alignment"
+          class="form-control"
+        >
+          <option
+            v-for="alignment1 in alignments"
+            :key="alignment1"
+            :value="alignment1"
+          >
+            {{ alignment1 }}
+          </option>
+        </select>
+      </div>
+      <div class="form-group">
+        <label>背景色</label>
+        <select
+          v-model="selectedBackgroundColor"
+          placeholder="Select an color"
+          class="form-control"
+        >
+          <option
+            v-for="color in colorExamples"
+            :key="color"
+            :value="color"
+          >
+            {{ color }}
+          </option>
+        </select>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import dayjs from 'dayjs';
+import VueMonthlyPicker from '@/vue-monthly-picker/index.js';
+import Switches from '@/switches/index.js';
+
+export default {
+  name: 'App',
+  components: {
+    VueMonthlyPicker, Switches,
+  },
+  data() {
+    return {
+      selectedMonth: dayjs(),
+      selectedMonth1: '2024-05',
+      isDisable: false,
+      isDisplayInput: true,
+      locale: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
+      alignment: 'left',
+      selectedBackgroundColor: 'blue',
+      options: [
+        {
+          id: 1,
+          title: 'English',
+          monthLabels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
+        },
+        {
+          id: 2,
+          title: '中文',
+          monthLabels: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],
+        },
+        {
+          id: 3,
+          title: 'Korean',
+          monthLabels: ['1월', '2월', '3월', '4월', '5월', '6월', '7월', '8월', '9월', '10월', '11월', '12월'],
+        },
+      ],
+      alignments: ['left', 'center', 'right'],
+      colorExamples: ['blue', 'red', 'black'],
+      min: null,
+      max: null,
+      isLimitRange: false,
+      clearOption: true,
+    };
+  },
+  computed: {
+    rangeDisplay() {
+      if (!this.min || !this.max) {
+        return 'Disabled';
+      }
+      return this.min.format('YYYY/MM') + '-' + this.max.format('YYYY/MM');
+    },
+
+    selectedMonthStr(){
+      if(typeof this.selectedMonth === 'string'){
+        return this.selectedMonth;
+      }else{
+        return this.selectedMonth.format('YYYY-MM');
+      }
+    },
+  },
+  watch: {
+    isLimitRange(newValue) {
+      if (newValue) {
+        this.setSelectRange(dayjs().subtract(6, 'months'), dayjs().add(6, 'months'));
+      } else {
+        this.setSelectRange(null, null);
+      }
+    },
+    
+  },
+
+  mounted(){
+    this.testDayJs();
+  },
+  methods: {
+    handleSelect(value) {
+      console.log('Select', value);
+    },
+    setSelectRange(min, max) {
+      this.min = min;
+      this.max = max;
+    },
+    // 测试DayJs
+    testDayJs(){
+      // exist bug
+      console.log(dayjs('00:00:00', 'HH:mm:ss'));
+
+
+      console.log(dayjs('2024-05-09').format('YYYY-MM-DD'));
+      console.log(dayjs('2024-05-09 10:45').format('YYYY-MM-DD'));
+      console.log(dayjs('2024-05-09 10:45:01').format('YYYY-MM-DD'));
+      console.log(dayjs().format('YYYYMMDD_hhmmss'));
+
+      const nowDate = new Date();
+      const startDate = dayjs(nowDate).subtract(1, 'M').format('YYYY-MM-DD HH:mm:ss');
+      const endDate = dayjs(nowDate).add(1, 'd').format('YYYY-MM-DD HH:mm:ss');
+      console.log(startDate, endDate);
+      
+      const startDate1 = '2024-01-02';
+      const endDate1 = '2024-01-10';
+      let currentYearMonth = dayjs(startDate1).add(1, 'M').format('YYYY-MM');
+      console.log(endDate1, 'isBefore', currentYearMonth, dayjs(endDate1).isBefore(currentYearMonth));
+
+      console.log(dayjs('2024-01-25').format('YYYY-MM-DD HH:mm'));
+      console.log(dayjs('2024-01-25').format('YYYY-MM-DD'));
+      console.log(dayjs('2024-01-25').format('YYYY-MM'));
+      console.log(dayjs().format('_YYYYMMDD_hhmmss'));
+    },
+  },
+};
+</script>
+
+<style scoped>
+#app {
+    font-family: "Avenir", Helvetica, Arial, sans-serif;
+    -webkit-font-smoothing: antialiased;
+    -moz-osx-font-smoothing: grayscale;
+    text-align: center;
+    color: #2c3e50;
+    margin-top: 60px;
+}
+
+.demo-component {
+    width: 250px;
+    margin: auto;
+}
+.control-group {
+    margin-top: 100px;
+}
+.control {
+    text-align: center;
+}
+.option-list {
+    margin-top: 20px;
+}
+</style>

+ 12 - 28
examples/year-picker/src/YearPickerExample.vue

@@ -1,35 +1,19 @@
 <template>
-  <h1>年份选择器</h1>
-
-  <YearPicker v-model="year" />
-
-  <div>{{ year }}</div>
+  <div>
+    <year-picker v-model="selectedYear" :placeholder="'测试年份'" @selected="yearSelected" />
+    <p>当前选择:{{ selectedYear }}</p>
+  </div>
 </template>
 
-<script>
-import YearPicker from '@/year-picker/index.js';
-
-export default {
+<script setup>
+import { ref } from 'vue';
+import dayjs from 'dayjs';
+import YearPicker from '@/year-picker/src/YearPicker.vue';
 
-  components: {
-    'YearPicker': YearPicker,
-  },
-  data: function(){
-    return {
-      year: '2022',
-    };
-  },
+const selectedYear = ref('2025');
 
-  mounted: function(){
-        
-  },
-
-  methods: {
-      
-  },
+const yearSelected = value => {
+  console.log('年份变更:', value);
 };
-</script>
-
-<style scoped>
 
-</style>
+</script>

+ 35 - 0
examples/year-picker/src/YearPickerExampleOld.vue

@@ -0,0 +1,35 @@
+<template>
+  <h1>年份选择器</h1>
+
+  <YearPicker v-model="year" />
+
+  <div>{{ year }}</div>
+</template>
+
+<script>
+import YearPicker from '@/year-picker/index.js';
+
+export default {
+
+  components: {
+    'YearPicker': YearPicker,
+  },
+  data: function(){
+    return {
+      year: '2022',
+    };
+  },
+
+  mounted: function(){
+        
+  },
+
+  methods: {
+      
+  },
+};
+</script>
+
+<style scoped>
+
+</style>

+ 1 - 6
index.html

@@ -3,15 +3,10 @@
   <head>
     <meta charset="utf-8">
     <title>pc-component-v3</title>
-    
-    <link rel="stylesheet" type="text/css" href="./bootstrap/css/bootstrap.min.css">
-    <link rel="stylesheet" type="text/css" href="./bootstrap/css/bootstrap-dialog.min.css">
 
     <script src="./bootstrap/js/jquery.min.js"></script>
     <script src="./bootstrap/js/jquery.cookie.js"></script>
-
-    <script src="./bootstrap/js/bootstrap.js"></script>
-    <script src="./bootstrap/js/bootstrap-dialog.min.js"></script>
+    <script nonce="*NONCE_TOKEN*" type="text/javascript" src="/static/table-fixer.jquery/table-fixer.jquery.js"></script>
 
 
     <script src="./dayjs/dayjs.min.js"></script>

+ 1 - 1
package.json

@@ -1,6 +1,6 @@
 {
   "name": "pc-component-v3",
-  "version": "1.1.14",
+  "version": "2.0.0",
   "description": "",
   "main": "dist/pc-component-v3.js",
   "scripts": {

+ 8 - 0
packages/antd-pagination/index.js

@@ -0,0 +1,8 @@
+
+import AntdPagination from './src/antd-pagination.vue';
+
+AntdPagination.install = function(Vue) {
+  Vue.component(AntdPagination.name, AntdPagination);
+};
+
+export default AntdPagination;

+ 97 - 0
packages/antd-pagination/src/antd-pagination.vue

@@ -0,0 +1,97 @@
+<template>
+  <a-pagination
+    v-model:current="innerCurrent" v-model:pageSize="innerPageSize" :total="total" :size="size"
+    :disabled="disabled" :show-size-changer="showSizeChanger" :show-quick-jumper="showQuickJumper"
+    :page-size-options="pageSizeOptions" :show-total="showTotal ? showTotalFormatter : undefined" @change="handleChange"
+    @show-size-change="handleSizeChange"
+  />
+</template>
+
+<script setup>
+import { ref,toRefs, computed, watch, defineProps, defineEmits, defineExpose, defineOptions } from 'vue';
+
+defineOptions({
+  name: 'AntdPagination',
+});
+
+const props = defineProps({
+  size: {
+    type: String,
+    default: 'default',
+  },
+  disabled: {
+    type: Boolean,
+    default: false,
+  },
+  pagination: {
+    type: Object,
+    default: () => ({
+      total: 0,
+      current_page: 1,
+      per_page: 10,
+    }),
+  },
+  options: {
+    type: Object,
+    default: () => ({
+      showTotal: true,
+      showSizeChanger: true,
+      showQuickJumper: true,
+      pageSizeOptions: ['10', '20', '50', '100', '200', '500'],
+    }),
+  },
+});
+
+const emit = defineEmits(['getPageParams']);
+
+const innerPageSize = ref(props.pagination.per_page);
+const innerCurrent = ref(props.pagination.current_page);
+
+// 总条数
+const total = computed(() => props.pagination.total);
+
+// 分页配置
+const { showTotal, showSizeChanger, showQuickJumper, pageSizeOptions } = toRefs(props.options);
+
+// 显示总条数
+const showTotalFormatter = (total, range) => {
+  return `第${range[0]}-${range[1]}条,共计${total}条`;
+};
+
+const isSizeChange = ref(false);
+
+// 页数改变
+const handleChange = (page, pageSize) => {
+  if(isSizeChange.value) {
+    innerCurrent.value = 1;
+    isSizeChange.value = false;
+    emit('getPageParams', 1, pageSize);
+  } else {
+    innerCurrent.value = page;
+    emit('getPageParams', page, pageSize);
+  }
+  innerPageSize.value = pageSize;
+};
+
+// 每页条数改变(会自动触发handleChange)
+const handleSizeChange = (current, size) => {
+  isSizeChange.value = true;
+};
+
+// 回到第一页
+const backFirstPage = () => {
+  emit('getPageParams', 1, innerPageSize.value);
+};
+
+defineExpose({
+  backFirstPage,
+});
+
+// 同步外部props变化
+watch(() => props.pagination, val => {
+  // console.log(val,'pagination');
+  innerCurrent.value = val.current_page;
+  innerPageSize.value = val.per_page;
+}, { deep: true });
+
+</script>

+ 11 - 23
packages/client-organization/src/ClientOrganization.vue

@@ -1,22 +1,10 @@
 <template>
   <div>
-    <div>
-      <div class="panel panel-default">
-        <div class="panel-body">
-          <div
-            v-for="clientOrganization in clientOrganizations"
-            :key="clientOrganization.id"
-          >
-            <TreeViewNode
-              :node="clientOrganization"
-              :is-root="true"
-              :is-show-check="clientOrganization.isShowCheck"
-              @node-expand="nodeExpand"
-              @node-select="nodeSelect"
-            />
-          </div>
-        </div>
-      </div>
+    <div style="user-select: none;">
+      <TreeViewNode
+        v-for="clientOrganization in clientOrganizations" :key="clientOrganization.id"
+        :node="clientOrganization" :is-root="true" :is-show-check="true" @node-select="nodeSelect"
+      />
     </div>
     <Loading v-if="loading" />
   </div>
@@ -37,7 +25,7 @@ export default {
     'whereClause': {
       type: String,
       default: '',
-    }, 
+    },
     'isSearchWidget': {
       type: Boolean,
       default: false,
@@ -86,7 +74,7 @@ export default {
 
     // 节点选择事件
     nodeSelect: function (node) {
-      console.log(node);
+
       if (!node.isClient) {
         node.selected = !node.selected;
         if (node.selected) {
@@ -133,7 +121,7 @@ export default {
           Common.addTokenToRequest(request);
         },
         success: function (data) {
-          if(data.errorCode != 0){
+          if (data.errorCode != 0) {
             Notify.error('部门查询失败', data.errorCode, false);
             return;
           }
@@ -202,13 +190,13 @@ export default {
   },
 };
 </script>
-    
+
 <style scoped>
 .clear-div {
-    clear: both;
+  clear: both;
 }
 
 .filter-button {
-    float: right;
+  float: right;
 }
 </style>

+ 129 - 134
packages/common/Notify.js

@@ -1,165 +1,160 @@
-import ModalFix from '../modal/src/ModalFix';
+import { h } from 'vue';
+import { notification, Button } from 'ant-design-vue';
+
+/**
+ * 通知类型
+ * @type {Object}
+ * @property {string} show - 显示
+ * @property {string} notice - 通知
+ * @property {string} noticeBig - 通知(大)
+ * @property {string} info - 信息
+ * @property {string} infoBig - 信息(大)
+ * @property {string} warning - 警告
+ * @property {string} error - 错误
+ * @property {string} success - 成功
+ * author: 刘彦鹏
+ * info: 封装antd的notification组件
+ */
 
 export default {
   /**
-     * 显示模态框
-     */
-  show : function(options){
-    var dialog = BootstrapDialog.show(options);
+   * 显示通知
+   * @param {options} 通知选项
+   * @param {title} 标题
+   * @param {message} 内容
+   * @param {buttons} 按钮选项
+   */
+  show: function (options) {
+    const key = `notify_${Date.now()}`;
+    const dialogItself = {
+      key,
+      close: () => notification.close(key),
+    };
+    const btns = options.buttons.map(btn => {
+      const type = btn.cssClass?.includes('btn-primary') ? 'primary' : 'default';
+      const action = () => btn.action(dialogItself);
+      return h(
+        Button,
+        {
+          type,
+          onClick: action,
+          style: {
+            marginLeft: '8px',
+          },
+        },
+        {
+          default: () => btn.label,
+        },
+      );
+    });
 
-    dialog.getModal().on('hidden.bs.modal', {dialog: this}, function (event) {
-      ModalFix.fix();
+    notification.open({
+      message: options.title,
+      description: options.message,
+      duration: 0,
+      key,
+      btn: btns,
+      onClose: dialogItself.close,
     });
   },
 
   /**
-	 * 显示通知
-	 * @param {title} 标题
-	 * @param {content} 内容
-	 * @param {autoClose} 自动延时关闭时间(毫秒)
-	 * author: 杨志杰
-	 * version: 1.0
-	 */
-  notice : function(title, content, autoClose){
-    var dialog = BootstrapDialog.show({
-      title: title,
-      message: content,
-      type: BootstrapDialog.TYPE_WARNING,
-    });
-
-    dialog.getModal().on('hidden.bs.modal', {dialog: this}, function (event) {
-      ModalFix.fix();
+ * 显示通知
+ * @param {title} 标题
+ * @param {content} 内容
+ * @param {autoClose} 自动延时关闭时间(毫秒)
+ * author: 杨志杰
+ * version: 1.0
+ */
+  notice: function (title, content, autoClose) {
+    notification.warning({
+      message: title,
+      description: content,
+      duration: autoClose ? autoClose / 1000 : 2,
     });
-
-    if(autoClose && autoClose > 0){
-      setTimeout(function(){
-        dialog.close();
-      }, autoClose);
-    }
   },
 
   /**
-	 * 显示通知
-	 * @param {title} 标题
-	 * @param {content} 内容
-	 * author: 杨志杰
-	 * version: 1.0
-	 */
-  noticeBig : function(title, content){
-    var dialog = BootstrapDialog.show({
-      title: title,
-      message: content,
-      type: BootstrapDialog.TYPE_WARNING,
-      size: BootstrapDialog.SIZE_WIDE,
-    });
-
-    dialog.getModal().on('hidden.bs.modal', {dialog: this}, function (event) {
-      ModalFix.fix();
+   * 显示通知
+   * @param {title} 标题
+   * @param {content} 内容
+   * author: 杨志杰
+   * version: 1.0
+   */
+  noticeBig: function (title, content) {
+    notification.warning({
+      message: title,
+      description: content,
+      duration: 0, // 不自动关闭
+      className: 'wide-notification',
+      style: { width: '800px' },
     });
   },
 
-
   /**
-	 * 显示消息
-	 * @param {title} 标题
-	 * @param {content} 内容
-	 * @param {autoClose} 自动延时关闭时间(毫秒)
-	 * author: 杨志杰
-	 * version: 1.0
-	 */
-  info : function(title, content, autoClose){
-    var dialog = BootstrapDialog.show({
-      title: title,
-      message: content,
-      type: BootstrapDialog.TYPE_INFO,
+ * 显示消息
+ * @param {title} 标题
+ * @param {content} 内容
+ * @param {autoClose} 自动延时关闭时间(毫秒)
+ * author: 杨志杰
+ * version: 1.0
+ */
+  info: function (title, content, autoClose) {
+    notification.info({
+      message: title,
+      description: content,
+      duration: autoClose ? autoClose / 1000 : 2,
     });
-
-    dialog.getModal().on('hidden.bs.modal', {dialog: this}, function (event) {
-      ModalFix.fix();
-    });
-
-        
-    if(autoClose && autoClose > 0){
-      setTimeout(function(){
-        dialog.close();
-      }, autoClose);
-    }
   },
 
-
   /**
-	 * 显示消息
-	 * @param {title} 标题
-	 * @param {content} 内容
-	 * @param {autoClose} 自动延时关闭时间(毫秒)
-	 * author: 杨志杰
-	 * version: 1.0
-	 */
-  infoBig : function(title, content, autoClose){
-    var dialog = BootstrapDialog.show({
-      title: title,
-      message: content,
-      type: BootstrapDialog.TYPE_INFO,
-      size: BootstrapDialog.SIZE_WIDE,
-    });
-
-    dialog.getModal().on('hidden.bs.modal', {dialog: this}, function (event) {
-      ModalFix.fix();
+ * 显示消息
+ * @param {title} 标题
+ * @param {content} 内容
+ * @param {autoClose} 自动延时关闭时间(毫秒)
+ * author: 杨志杰
+ * version: 1.0
+ */
+  infoBig: function (title, content, autoClose) {
+    notification.info({
+      message: title,
+      description: content,
+      duration: autoClose ? autoClose / 1000 : 2,
+      className: 'wide-notification',
+      style: { width: '800px' },
     });
-
-        
-    if(autoClose && autoClose > 0){
-      setTimeout(function(){
-        dialog.close();
-      }, autoClose);
-    }
   },
 
   /**
-	 * 显示成功信息
-	 * @param {title} 标题
-	 * @param {content} 内容
-	 * @param {autoClose} 自动延时关闭时间(毫秒)
-	 * author: 杨志杰
-	 * version: 1.0
-	 */
-  success : function(title, content, autoClose){
-    var dialog = BootstrapDialog.show({
-      title: title,
-      message: content,
-      type: BootstrapDialog.TYPE_SUCCESS,
+ * 显示成功信息
+ * @param {title} 标题
+ * @param {content} 内容
+ * @param {autoClose} 自动延时关闭时间(毫秒)
+ * author: 杨志杰
+ * version: 1.0
+ */
+  success: function (title, content, autoClose) {
+    notification.success({
+      message: title,
+      description: content,
+      duration: autoClose === true ? 2 : typeof autoClose === 'number' && !isNaN(autoClose) ? autoClose / 1000 : 2,
     });
-
-    dialog.getModal().on('hidden.bs.modal', {dialog: this}, function (event) {
-      ModalFix.fix();
-    });
-
-        
-    if(autoClose && autoClose > 0){
-      setTimeout(function(){
-        dialog.close();
-      }, autoClose);
-    }
   },
 
   /**
-     * 显示错误信息
-     * @param {title} 标题
-     * @param {content} 内容
-     * @param {autoClose} 自动延时关闭时间(毫秒)
-     * author: 杨志杰
-     * version: 1.0
-     */
-  error : function(title, content, autoClose){
-    var dialog = BootstrapDialog.show({
-      title: title,
-      message: content,
-      type: BootstrapDialog.TYPE_DANGER,
-    });
-
-    dialog.getModal().on('hidden.bs.modal', {dialog: this}, function (event) {
-      ModalFix.fix();
+   * 显示错误信息
+   * @param {title} 标题
+   * @param {content} 内容
+   * @param {autoClose} 自动延时关闭时间(毫秒)
+   * author: 杨志杰
+   * version: 1.0
+   */
+  error: function (title, content, autoClose) {
+    const duration = autoClose === true ? 2 : autoClose === -1 ? 0 : autoClose  ? autoClose / 1000 : 0;
+    notification.error({
+      message: title,
+      description: content,
+      duration,
     });
   },
-    
 };

+ 2 - 1
packages/components.js

@@ -49,7 +49,7 @@ import JsUtil from './common/JsUtil.js';
 import ModalFix from './modal/src/ModalFix.js';
 import PrintUtil from './print/src/PrintUtil.js';
 import WriteEpcUtil from './print/src/WriteEpcUtil.js';
-
+import AntdPagination from './antd-pagination/index.js';
 export {
   Loading,
   Modal,
@@ -95,4 +95,5 @@ export {
   CssUtil,
   JsUtil,
   WriteEpcUtil,
+  AntdPagination,
 };

+ 43 - 172
packages/date/src/Date.vue

@@ -1,188 +1,59 @@
 <template>
-  <div
-    class="datetime-container input-group"
-    :class="{'has-error' : isValid === false}"
-  >
-    <input
-      id="datetime"
-      autocomplete="off"
-      type="date"
-      :readonly="readonly"
-      :value="dateTime"
-      class="datetime-item-1 form-control"
-      @change="dateValueChanged($event)"
-    />
-
-    <input
-      autocomplete="off"
-      type="text"
-      :readonly="readonly"
-      :value="dateTime"
-      class="datetime-item-2 form-control"
-      @change="textValueChanged($event)"
-    />
-
-    <span
-      v-if="isValid === false"
-      class="glyphicon glyphicon-remove datetime-item-3 form-control-feedback"
-      aria-hidden="true"
+  <div>
+    <a-date-picker
+      v-model:value="selectedDate"
+      style="width: 100%"
+      allow-clear
+      :disabled="readonly"
+      :placeholder="placeholder"
+      @change="handleChange"
     />
   </div>
 </template>
 
-<script>
-
+<script setup>
 import dayjs from 'dayjs';
+import { ref, watch, defineProps, defineEmits, defineOptions } from 'vue';
 
-export default {
-
-  // eslint-disable-next-line vue/multi-word-component-names
+defineOptions({
   name: 'Date',
+});
 
-  components: {
-
+const props = defineProps({
+  modelValue: {
+    type: [String, Date, null],
+    default: null,
   },
-
-  props: {
-    'modelValue': {
-      type: String,
-      default: null,
-    },
-    'readonly': {
-      type: Boolean,
-      default: false,
-    },
-  },
-
-  emits: ['update:modelValue'],
-
-  data: function () {
-    return {
-      'isValid': true,
-    };
-  },
-
-
-  computed: {
-
-    /**
-     * 把(YYYY-MM-DD)格式的日期字符串转换成datetime-local(YYYY-MM-DD)
-     */
-    dateTime: function () {
-      if (this.modelValue == null || this.modelValue.length == 0) {
-        return null;
-      } else {
-        if(this.modelValue.length > 10){
-          return dayjs(this.modelValue, 'YYYY-MM-DD HH:mm:ss').format('YYYY-MM-DD');
-        }else{
-          return dayjs(this.modelValue, 'YYYY-MM-DD').format('YYYY-MM-DD');
-        }
-      }
-    },
-
+  placeholder: {
+    type: String,
+    default: '请选择日期',
   },
-
-  mounted: function () {
-
+  readonly: {
+    type: Boolean,
+    default: false,
   },
+});
+const emit = defineEmits(['update:modelValue', 'selected']);
 
-  methods: {
-    /**
-     * 是否是有效的日期时间格式,YYYY-MM-DD
-     */
-    isValidDateTime: function (text) {
-      if (text == null || text.length == 0) {
-        return true;
-      }
-      return dayjs(text, 'YYYY-MM-DD', true).isValid();
-    },
-
-    textValueChanged: function (event) {
-      let newValue = event.target.value;
+const selectedDate = ref(null);
 
-      // 日期时间校验
-      if (this.isValidDateTime(newValue)) {
-        if (this.readonly == true && (newValue == null || newValue.length == 0)) {
-          this.isValid = false;
-        } else {
-          this.isValid = true;
-        }
-        console.log('Date input value changed: orginal value: %s, current value: %s', this.modelValue, newValue);
-        this.$emit('update:modelValue', newValue);
-      } else {
-        this.isValid = false;
-      }
-    },
-
-
-    /**
-     * 值改变事件
-     */
-    dateValueChanged: function (event) {
-      let newValue = event.target.value;
-      let parsedDateTime = '';
-      if (newValue != null && newValue.length > 0) {
-        parsedDateTime = dayjs(newValue).format('YYYY-MM-DD');
-      }
-
-      // 日期时间校验
-      if (this.isValidDateTime(parsedDateTime)) {
-        if (this.readonly == true && (parsedDateTime == null || parsedDateTime.length == 0)) {
-          this.isValid = false;
-        } else {
-          this.isValid = true;
-        }
-        console.log('Date value changed: orginal value: %s, current value: %s', newValue, parsedDateTime);
-        this.$emit('update:modelValue', parsedDateTime);
-      } else {
-        this.isValid = false;
-      }
-    },
+// 初始化时处理日期
+watch(
+  () => props.modelValue,
+  newVal => {
+    selectedDate.value = newVal ? dayjs(newVal) : null;
   },
+  { immediate: true },
+);
+
+// 完善日期处理逻辑
+const handleChange = (date, dateString) => {
+  if (!date) {
+    emit('update:modelValue', null);
+    emit('selected', null);
+    return;
+  }
+  emit('update:modelValue', dateString);
+  emit('selected', dateString);
 };
-</script>
-
-<style>
-/* .form-inline .datetime-container {
-    display: inline-flex !important;
-    vertical-align: middle;
-} */
-</style>
-
-
-<style scoped>
-.datetime-container {
-    position: relative;
-    height: 34px;
-    width: auto;
-    vertical-align: middle;
-    min-width: 200px;
-    /* display : inline-flex; */
-    display: inline-flex;
-}
-
-.datetime-item-1 {
-    position: absolute;
-    display: inline;
-    width: 100%;
-    cursor: pointer;
-    border-radius: 4px !important;
-}
-
-.datetime-item-2 {
-    position: absolute !important;
-    border-radius: 4px 0px 0px 4px !important;
-    display: inline;
-    width: calc(100% - 39px) !important;
-}
-
-.datetime-item-3 {
-    right: 39px;
-}
-
-/*控制下拉小箭头的*/
-input[type="datetime-local"]::-webkit-calendar-picker-indicator {
-    padding-right: 0px;
-}
-</style>
-
+</script>

+ 39 - 166
packages/datetime/src/DateTime.vue

@@ -1,183 +1,56 @@
 <template>
-  <div
-    class="datetime-container input-group"
-    :class="{'has-error' : isValid === false}"
-  >
-    <input
-      id="datetime"
-      autocomplete="off"
-      type="datetime-local"
-      :readonly="readonly"
-      :value="dateTime"
-      class="datetime-item-1 form-control"
-      @change="datetimeLocalValueChanged($event)"
-    />
-
-    <input
-      autocomplete="off"
-      type="text"
-      :readonly="readonly"
-      :value="modelValue"
-      class="datetime-item-2 form-control"
-      @change="textValueChanged($event)"
-    />
-
-    <span
-      v-if="isValid === false"
-      class="glyphicon glyphicon-remove datetime-item-3 form-control-feedback"
-      aria-hidden="true"
+  <div>
+    <a-date-picker
+      v-model:value="selectedDateTime" style="width: 100%" show-time allow-clear :disabled="readonly"
+      :placeholder="placeholder" @change="handleChange"
     />
   </div>
 </template>
 
-<script>
-
+<script setup>
 import dayjs from 'dayjs';
+import { ref, watch, defineProps, defineEmits, defineOptions } from 'vue';
 
-export default {
-
+defineOptions({
   name: 'DateTime',
+});
 
-  components: {
-
+const props = defineProps({
+  modelValue: {
+    type: [String, Date, null],
+    default: null,
   },
-
-  props: {
-    'modelValue': {
-      type: String,
-      default: null,
-    },
-    'readonly': {
-      type: Boolean,
-      default: false,
-    },
+  readonly: {
+    type: Boolean,
+    default: false,
   },
-
-  emits: ['update:modelValue'],
-
-  data: function () {
-    return {
-      'isValid': true,
-    };
+  placeholder: {
+    type: String,
+    default: '请选择日期时间',
   },
+});
 
+const emit = defineEmits(['update:modelValue', 'selected']);
 
-  computed: {
-
-    /**
-             * 把(YYYY-MM-DD HH:mm:ss)格式的日期字符串转换成datetime-local(YYYY-MM-DDTHH:mm:ss)
-             */
-    dateTime: function () {
-      if (this.modelValue == null || this.modelValue.length == 0) {
-        return null;
-      } else {
-        return dayjs(this.modelValue, 'YYYY-MM-DD HH:mm:ss').format('YYYY-MM-DDTHH:mm:ss');
-      }
-    },
+const selectedDateTime = ref(null);
 
+// 初始化时处理日期时间 
+watch(
+  () => props.modelValue,
+  newVal => {
+    selectedDateTime.value = newVal ? dayjs(newVal) : null;
   },
-
-  mounted: function () {
-
-  },
-
-  methods: {
-    /**
-         * 是否是有效的日期时间格式,YYYY-MM-DD HH:mm:ss
-         */
-    isValidDateTime: function (text) {
-      if (text == null || text.length == 0) {
-        return true;
-      }
-      return dayjs(text, 'YYYY-MM-DD HH:mm:ss', true).isValid();
-    },
-
-    textValueChanged: function (event) {
-      let newValue = event.target.value;
-
-      // 日期时间校验
-      if (this.isValidDateTime(newValue)) {
-        if (this.readonly == true && (newValue == null || newValue.length == 0)) {
-          this.isValid = false;
-        } else {
-          this.isValid = true;
-        }
-        console.log('DateTimeV2 input value changed: orginal value: %s, current value: %s', this.modelValue, newValue);
-        this.$emit('update:modelValue', newValue);
-      } else {
-        this.isValid = false;
-      }
-    },
-
-
-    /**
-             * 值改变事件
-             */
-    datetimeLocalValueChanged: function (event) {
-      let newValue = event.target.value;
-      let parsedDateTime = '';
-      if (newValue != null && newValue.length > 0) {
-        parsedDateTime = dayjs(newValue).format('YYYY-MM-DD HH:mm:ss');
-      }
-
-      // 日期时间校验
-      if (this.isValidDateTime(parsedDateTime)) {
-        if (this.readonly == true && (parsedDateTime == null || parsedDateTime.length == 0)) {
-          this.isValid = false;
-        } else {
-          this.isValid = true;
-        }
-        console.log('DateTimeV2 value changed: orginal value: %s, current value: %s', newValue, parsedDateTime);
-        this.$emit('update:modelValue', parsedDateTime);
-      } else {
-        this.isValid = false;
-      }
-    },
-  },
+  { immediate: true },
+);
+
+// 完善日期处理逻辑
+const handleChange = (date, dateString) => {
+  if (!date) {
+    emit('update:modelValue', null);
+    emit('selected', null);
+    return;
+  }
+  emit('update:modelValue', dateString);
+  emit('selected', dateString);
 };
-</script>
-
-<style>
-/* .form-inline .datetime-container {
-    display: inline-flex !important;
-    vertical-align: middle;
-} */
-</style>
-
-
-<style scoped>
-.datetime-container {
-    position: relative;
-    height: 34px;
-    width: auto;
-    vertical-align: middle;
-    min-width: 200px;
-    /* display : inline-flex; */
-    display: inline-flex;
-}
-
-.datetime-item-1 {
-    position: absolute;
-    display: inline;
-    width: 100%;
-    cursor: pointer;
-    border-radius: 4px !important;
-}
-
-.datetime-item-2 {
-    position: absolute !important;
-    border-radius: 4px 0px 0px 4px !important;
-    display: inline;
-    width: calc(100% - 39px) !important;
-}
-
-.datetime-item-3 {
-    right: 39px;
-}
-
-/*控制下拉小箭头的*/
-input[type="datetime-local"]::-webkit-calendar-picker-indicator {
-    padding-right: 0px;
-}
-</style>
-
+</script>

+ 36 - 35
packages/info/src/DocGenerator.vue

@@ -1,24 +1,10 @@
 <template>
-  <ul class="nav nav-tabs m-row" role="tablist">
-    <li role="presentation" :class="{ active: tabIndex === 1 }">
-      <a
-        @click="
-          tabIndex = 1;
-          isGenerator = false;
-        "
-      >{{ $t("lang.QueryCondition.simpleQuery") }}</a>
-    </li>
-    <li role="presentation" :class="{ active: tabIndex === 2 }">
-      <a
-        @click="advancedQuery
-
-        "
-      >{{ $t("lang.QueryCondition.advancedQuery") }}</a>
-    </li>
-    <li role="presentation" :class="{ active: tabIndex === 3 }">
-      <a @click="openSelect">{{ $t("lang.DocGenerator.selectedDatas") }}</a>
-    </li>
-  </ul>
+  <a-tabs v-model:activeKey="tabIndex" style="margin-bottom: 16px !important;" @change="handleTabChange">
+    <a-tab-pane :key="1" :tab="$t('lang.QueryCondition.simpleQuery')" />
+    <a-tab-pane :key="2" :tab="$t('lang.QueryCondition.advancedQuery')" />
+    <a-tab-pane :key="3" :tab="$t('lang.DocGenerator.selectedDatas')" />
+  </a-tabs>
+
   <div class="grid-container-2">
     <div class="grid-header-2">
       <QueryCondition
@@ -28,15 +14,16 @@
         @complex-search="complexSearch" @refresh-search="queryInfoWindowData" @change-search="tabIndex = 1"
       />
     </div>
+
     <div class="grid-content-2">
       <DocGeneratorGrid
-        v-show="tabIndex !== 3" ref="docGeneratorGrid" :info-window-no="infoWindowNo"
+        v-show="tabIndex !== 3" ref="docGeneratorGrid" :info-window-no="infoWindowNo" :is-tab-active="tabIndex !== 3 ? true : false"
         :info-grid-fields="infoGridFields" :info-window-data="infoWindowData" :is-selected-by-id="isSelectedById"
         @refresh-search="queryInfoWindowData" @select-changed="selectChanged"
       />
 
       <DocGeneratorSelected
-        v-show="tabIndex === 3" ref="docGeneratorSelected" :info-window-no="infoWindowNo"
+        v-show="tabIndex === 3" ref="docGeneratorSelected" :info-window-no="infoWindowNo" :is-tab-active="tabIndex === 3 ? true : false"
         :info-grid-fields="infoGridFields" @select-changed="deleteChange" @update-datas="updateDatas"
       />
     </div>
@@ -83,6 +70,8 @@ export default {
     },
   },
 
+  emits: ['showTitle'],
+
   data: function () {
     return {
       infoWindowDto: {},
@@ -133,7 +122,7 @@ export default {
           Common.addTokenToRequest(request);
         },
         success: function (response) {
-          if(response.errorCode == 0){
+          if (response.errorCode == 0) {
             const data = response.data;
             _self.loading = true;
             _self.infoWindowDto = data;
@@ -141,7 +130,7 @@ export default {
             _self.$nextTick(function () {
               _self.initQueryPage();
             });
-          }else{
+          } else {
             Notify.error('查询窗口定义错误', response.errorMessage, false);
           }
         },
@@ -151,8 +140,19 @@ export default {
         },
       });
     },
+
+    handleTabChange: function (key) {
+      this.tabIndex = key;
+      if (key === 1) {
+        this.isGenerator = false;
+      } else if (key === 2) {
+        this.advancedQuery();
+      } else if (key === 3) {
+        this.openSelect();
+      }
+    },
+
     openSelect: function () {
-      this.$refs.queryCondition.changeSearch(true);
       this.tabIndex = 3;
       this.isGenerator = true;
     },
@@ -277,7 +277,7 @@ export default {
         data: JSON.stringify(infoQueryParam),
         success: function (response) {
           _self.loading = false;
-          if(response.errorCode != 0){
+          if (response.errorCode != 0) {
             Notify.error('Error', response.errorMessage, false);
             return;
           }
@@ -334,11 +334,11 @@ export default {
         data: JSON.stringify(infoQueryParam),
         success: function (response) {
           _self.loading = false;
-          if(response.errorCode != 0){
+          if (response.errorCode != 0) {
             Notify.error('Error', response.errorMessage, false);
             return;
           }
-          
+
           const data = response.data;
           if (data != undefined && data.range != undefined) {
             if (isDelete === true) {
@@ -413,15 +413,16 @@ export default {
   grid-column: 1 / 2;
   overflow: auto;
 }
-</style>
 
-<style scoped>
-/** 修复分页的样式 By YangZhiJie 2021-07-06 11:23 */
-nav>>>ul.pagination {
-  margin: 0 !important;
+:deep(.ant-tabs) {
+  margin-bottom: 16px !important;
+}
+
+:deep(.ant-tabs-nav) {
+  margin: 0;
 }
 
-.nav {
-  margin-bottom: 4px;
+:deep(.ant-tabs-content) {
+  height: 100%;
 }
 </style>

+ 61 - 87
packages/info/src/DocGeneratorGrid.vue

@@ -1,36 +1,21 @@
 <template>
   <div class="flex-container-1">
     <div class="flex-content-1 table-fix-head">
-      <table
-        class="fixed-table table-striped table-bordered"
-        :width="tableWidth"
-        height="40px"
-      >
+      <table class="fixed-table1 table-striped table-bordered" :width="tableWidth" height="40px">
         <thead>
           <tr height="40px">
             <th width="50px" class="fixed-cell">
-              <input
-                autocomplete="off"
-                :checked="allSelected"
-                type="checkbox"
-                @click="selectAll($event)"
-              />
+              <input autocomplete="off" :checked="allSelected" type="checkbox" @click="selectAll($event)" />
             </th>
 
             <th
-              v-for="infoGridField in infoGridFields"
-              v-show="infoGridField.isShow"
-              :key="infoGridField.fieldName"
-              :width="infoGridField.width + 'px'"
-              @dragover="ondragover($event, infoGridField)"
+              v-for="infoGridField in infoGridFields" v-show="infoGridField.isShow" :key="infoGridField.fieldName"
+              :width="infoGridField.width + 'px'" @dragover="ondragover($event, infoGridField)"
               @click="onSort(infoGridField)"
             >
               <div
-                :id="'infoGridFieldId_' + infoGridField.fieldName"
-                class="rz-handle"
-                draggable="true"
-                @dragstart="ondragstart($event, infoGridField)"
-                @drag="ondrag($event, infoGridField)"
+                :id="'infoGridFieldId_' + infoGridField.fieldName" class="rz-handle" draggable="true"
+                @dragstart="ondragstart($event, infoGridField)" @drag="ondrag($event, infoGridField)"
                 @dragend="ondragend($event, infoGridField)"
               />
 
@@ -43,32 +28,18 @@
         <tbody>
           <tr v-for="rowData in dataList" :key="rowData.id" height="40px">
             <td class="fixed-cell">
-              <input
-                v-model="rowData.checked"
-                autocomplete="off"
-                type="checkbox"
-                :value="rowData.id"
-              />
+              <input v-model="rowData.checked" autocomplete="off" type="checkbox" :value="rowData.id" />
             </td>
-            <td
-              v-for="infoGridField in infoGridFields"
-              :key="infoGridField.fieldName + '_' + rowData.id"
-            >
-              <input
-                v-if="infoGridField.simpleDisplayType == 'TextEditor'"
-                autocomplete="off"
-                type="text"
-                class="form-control"
+            <td v-for="infoGridField in infoGridFields" :key="infoGridField.fieldName + '_' + rowData.id">
+              <a-input
+                v-if="infoGridField.simpleDisplayType == 'TextEditor'" style="width: 100%;"
                 :value="getDisplayValue(rowData, infoGridField)"
-                @keyup="valueChange($event, rowData, infoGridField)"
+                @change="(value) => valueChange(value, rowData, infoGridField)"
               />
-              <input
-                v-if="infoGridField.simpleDisplayType == 'NumberEditor'"
-                autocomplete="off"
-                type="number"
-                class="form-control"
+              <a-input-number
+                v-if="infoGridField.simpleDisplayType == 'NumberEditor'" style="width: 100%;" :min="0"
                 :value="getDisplayValue(rowData, infoGridField)"
-                @keyup="valueChange($event, rowData, infoGridField)"
+                @change="(value) => valueChange(value, rowData, infoGridField)"
               />
               <span
                 v-if="
@@ -90,23 +61,7 @@
     </div>
 
     <div class="flex-footer-1" style="margin-top: 10px">
-      <div class="pull-left">
-        <span>
-          第
-          {{ (pagination.current_page - 1) * pagination.per_page + 1 }}
-          -
-          {{ pagination.current_page * pagination.per_page }}
-          条,共计
-          {{ pagination.total }}
-          条,每页
-        </span>
-        <PageSizeSelect @page-size-changed="gridSizeSelect" />
-
-        <span>条</span>
-      </div>
-      <div class="pull-right">
-        <Pagination :pagination="pagination" :callback="refreshSearch" />
-      </div>
+      <AntdPagination :pagination="pagination" @get-page-params="getPageParams" />
     </div>
   </div>
 </template>
@@ -114,13 +69,11 @@
 <script>
 import Common from '../../common/Common.js';
 import InfoUtil from './InfoUtil.js';
-import Pagination from '../../vue-bootstrap-pagination/src/vue-bootstrap-pagination.vue';
-import PageSizeSelect from '../../page-size-select/src/PageSizeSelect.vue';
+import AntdPagination from '../../antd-pagination/src/antd-pagination.vue';
 
 export default {
   components: {
-    Pagination,
-    PageSizeSelect,
+    AntdPagination,
   },
 
   props: {
@@ -144,6 +97,10 @@ export default {
       type: Function,
       default: null,
     },
+    isTabActive: {
+      type: Boolean,
+      default: true,
+    },
   },
 
   emits: ['selectChanged', 'refreshSearch'],
@@ -155,7 +112,6 @@ export default {
         total: 0,
         per_page: Common.pageSize, // required
         current_page: 1, // required
-        last_page: 10, // required
       },
       sortStyle: '',
       sortClause: '',
@@ -216,6 +172,12 @@ export default {
       this.setDataList(newValue);
     },
 
+    isTabActive(newValue) {
+      if (newValue === true) {
+        this.fixedTableHeader();
+      }
+    },
+
     dataList: {
       handler: function (newValue, oldValue) {
         // 清除延迟执行
@@ -247,6 +209,15 @@ export default {
       this.pagination.total = 0;
     },
 
+    /**
+     * 获取分页参数
+     */
+    getPageParams(page, pageSize) {
+      this.pagination.current_page = page;
+      this.pagination.per_page = pageSize;
+      this.refreshSearch();
+    },
+
     /**
      * 设置分页
      * @author YangZhiJie 20210909
@@ -359,11 +330,15 @@ export default {
     fixedTableHeader: function () {
       let _self = this;
       _self.$nextTick(function () {
-        var $th = $('.table-fix-head').find('thead');
-        var $fixedCell = $('.table-fix-head').find('.fixed-cell');
-        $('.table-fix-head').on('scroll', function () {
-          $th.css('transform', 'translateY(' + this.scrollTop + 'px)');
-          $fixedCell.css('transform', 'translateX(' + this.scrollLeft + 'px)');
+        // var $th = $('.table-fix-head').find('thead');
+        // var $fixedCell = $('.table-fix-head').find('.fixed-cell');
+        // $('.table-fix-head').on('scroll', function () {
+        //   $th.css('transform', 'translateY(' + this.scrollTop + 'px)');
+        //   $fixedCell.css('transform', 'translateX(' + this.scrollLeft + 'px)');
+        // });
+        $('.fixed-table1').tableFixer({
+          left: 1,
+          head: true,
         });
       });
     },
@@ -372,9 +347,9 @@ export default {
      * 表格中填写的值发生了改变
      * @author YangZhiJie 20210909
      */
-    valueChange: function (event, rowData, infoGridField) {
+    valueChange: function (value, rowData, infoGridField) {
       var _self = this;
-      var value = event.target.value;
+      // var value = event.target.value;
       const fieldName = infoGridField.fieldName;
       if (rowData.data[fieldName] == undefined) {
         var tempFieldValue = {
@@ -489,23 +464,24 @@ export default {
 
 
 <style scoped>
-.fixed-table {
+.fixed-table1 {
   table-layout: fixed;
 }
 
-table.fixed-table th {
+table.fixed-table1 th {
   position: relative;
   min-width: 10px;
 }
 
-table.fixed-table tr td:first-child,
-table.fixed-table tr th:first-child {
+table.fixed-table1 tr td:first-child,
+table.fixed-table1 tr th:first-child {
   text-align: center;
 }
 
-table.fixed-table th,
-table.fixed-table td {
+table.fixed-table1 th,
+table.fixed-table1 td {
   text-align: left;
+  text-align: center;
   overflow: hidden;
   white-space: nowrap;
   text-overflow: ellipsis;
@@ -514,23 +490,21 @@ table.fixed-table td {
   background-color: white;
 }
 
-table.fixed-table th .rz-handle {
+table.fixed-table1 th .rz-handle {
   width: 10px;
   height: 100%;
   position: absolute;
   top: 0;
   right: 0;
-  background: repeating-linear-gradient(
-    45deg,
-    transparent,
-    transparent 2px,
-    rgba(0, 0, 0, 0.05) 2px,
-    rgba(0, 0, 0, 0.05) 4px
-  );
+  background: repeating-linear-gradient(45deg,
+      transparent,
+      transparent 2px,
+      rgba(0, 0, 0, 0.05) 2px,
+      rgba(0, 0, 0, 0.05) 4px);
   cursor: ew-resize !important;
 }
 
-table.fixed-table th .rz-handle.rz-handle-active {
+table.fixed-table1 th .rz-handle.rz-handle-active {
   border-right: 2px solid #000;
   transform: scaleX(100);
   background: rgba(0, 0, 0, 0.05) 2px;

+ 49 - 59
packages/info/src/DocGeneratorSelected.vue

@@ -1,30 +1,20 @@
 <template>
   <div class="flex-container-2">
     <div class="flex-content-2 table-fix-head-2">
-      <table
-        class="fixed-table table-striped table-bordered"
-        :width="tableWidth"
-        height="40px"
-      >
+      <table class="fixed-table table-striped table-bordered" :width="tableWidth" height="40px">
         <thead>
           <tr height="40px">
             <th width="50px" class="fixed-cell">序号</th>
 
-            <th width="50px" class="fixed-cell">操作</th>
+            <th width="67px" class="fixed-cell">操作</th>
 
             <th
-              v-for="infoGridField in infoGridFields"
-              v-show="infoGridField.isShow"
-              :key="infoGridField.fieldName"
-              :width="infoGridField.width + 'px'"
-              @click="onSort(infoGridField)"
+              v-for="infoGridField in infoGridFields" v-show="infoGridField.isShow" :key="infoGridField.fieldName"
+              :width="infoGridField.width + 'px'" @click="onSort(infoGridField)"
             >
               <div
-                :id="'infoGridFieldId_' + infoGridField.fieldName"
-                class="rz-handle"
-                draggable="true"
-                @dragstart="ondragstart($event, infoGridField)"
-                @drag="ondrag($event, infoGridField)"
+                :id="'infoGridFieldId_' + infoGridField.fieldName" class="rz-handle" draggable="true"
+                @dragstart="ondragstart($event, infoGridField)" @drag="ondrag($event, infoGridField)"
                 @dragend="ondragend($event, infoGridField)"
               />
 
@@ -35,40 +25,25 @@
           </tr>
         </thead>
         <tbody>
-          <tr
-            v-for="(rowData, index) in dataList"
-            :key="rowData.id"
-            height="40px"
-          >
+          <tr v-for="(rowData, index) in dataList" :key="rowData.id" height="40px">
             <td class="fixed-cell">
               {{ index + 1 }}
             </td>
-            <td class="fixed-cell">
-              <span
-                class="label label-danger"
-                style="cursor: pointer"
-                @click="removeRow(rowData)"
-              >删除</span>
+            <td class="fixed-cell" style="width: 67px;">
+              <a-button type="link" danger @click="removeRow(rowData)">
+                删除
+              </a-button>
             </td>
-            <td
-              v-for="infoGridField in infoGridFields"
-              :key="infoGridField.fieldName + '_' + rowData.id"
-            >
-              <input
-                v-if="infoGridField.simpleDisplayType == 'TextEditor'"
-                autocomplete="off"
-                type="text"
-                class="form-control"
+            <td v-for="infoGridField in infoGridFields" :key="infoGridField.fieldName + '_' + rowData.id">
+              <a-input
+                v-if="infoGridField.simpleDisplayType == 'TextEditor'" style="width: 100%;"
                 :value="getDisplayValue(rowData, infoGridField)"
-                @keyup="valueChange($event, rowData, infoGridField)"
+                @change="(value) => valueChange(value, rowData, infoGridField)"
               />
-              <input
-                v-if="infoGridField.simpleDisplayType == 'NumberEditor'"
-                autocomplete="off"
-                type="number"
-                class="form-control"
+              <a-input-number
+                v-if="infoGridField.simpleDisplayType == 'NumberEditor'" style="width: 100%;" :min="0"
                 :value="getDisplayValue(rowData, infoGridField)"
-                @keyup="valueChange($event, rowData, infoGridField)"
+                @change="(value) => valueChange(value, rowData, infoGridField)"
               />
               <span v-if="infoGridField.simpleDisplayType == undefined">
                 {{
@@ -109,6 +84,10 @@ export default {
       type: Object,
       default: null,
     },
+    isTabActive: {
+      type: Boolean,
+      default: true,
+    },
   },
 
   emits: ['selectChanged', 'updateDatas'],
@@ -142,6 +121,14 @@ export default {
     },
   },
 
+  watch: {
+    isTabActive(newValue) {
+      if (newValue === true) {
+        this.fixedTableHeader();
+      }
+    },
+  },
+
   methods: {
     /**
      * 列开始拖动
@@ -212,13 +199,17 @@ export default {
      */
     fixedTableHeader: function () {
       let _self = this;
-      _self.$nextTick(function () {
-        var $th = $('.table-fix-head-2').find('thead');
-        var $fixedCell = $('.table-fix-head-2').find('.fixed-cell');
-        $('.table-fix-head-2').on('scroll', function () {
-          $th.css('transform', 'translateY(' + this.scrollTop + 'px)');
-          $fixedCell.css('transform', 'translateX(' + this.scrollLeft + 'px)');
-        });
+      // _self.$nextTick(function () {
+      //   var $th = $('.table-fix-head-2').find('thead');
+      //   var $fixedCell = $('.table-fix-head-2').find('.fixed-cell');
+      //   $('.table-fix-head-2').on('scroll', function () {
+      //     $th.css('transform', 'translateY(' + this.scrollTop + 'px)');
+      //     $fixedCell.css('transform', 'translateX(' + this.scrollLeft + 'px)');
+      //   });
+      // });
+      $('.fixed-table').tableFixer({
+        left: 2,
+        head: true,
       });
     },
 
@@ -226,9 +217,9 @@ export default {
      * 表格中填写的值发生了改变
      * @author YangZhiJie 20210909
      */
-    valueChange: function (event, rowData, infoGridField) {
+    valueChange: function (value, rowData, infoGridField) {
       var _self = this;
-      var value = event.target.value;
+      // var value = event.target.value;
       const fieldName = infoGridField.fieldName;
       if (rowData.data[fieldName] == undefined) {
         var tempFieldValue = {
@@ -398,6 +389,7 @@ table.fixed-table tr th:first-child {
 table.fixed-table th,
 table.fixed-table td {
   text-align: left;
+  text-align: center;
   overflow: hidden;
   white-space: nowrap;
   text-overflow: ellipsis;
@@ -412,13 +404,11 @@ table.fixed-table th .rz-handle {
   position: absolute;
   top: 0;
   right: 0;
-  background: repeating-linear-gradient(
-    45deg,
-    transparent,
-    transparent 2px,
-    rgba(0, 0, 0, 0.05) 2px,
-    rgba(0, 0, 0, 0.05) 4px
-  );
+  background: repeating-linear-gradient(45deg,
+      transparent,
+      transparent 2px,
+      rgba(0, 0, 0, 0.05) 2px,
+      rgba(0, 0, 0, 0.05) 4px);
   cursor: ew-resize !important;
 }
 

+ 47 - 9
packages/info/src/EnumSelectWidgetInfo.vue

@@ -1,6 +1,16 @@
 <template>
   <div>
     <!-- <label :for="'enum-select-widget-' + field.fieldName" class="m-form-group-label">{{ field.name }}</label> -->
+
+    <a-select
+      :id="'enum-select-widget-' + field.fieldName" v-model:value="selectedValue" style="width: 100%;"
+      @change="selectChanged"
+    >
+      <a-select-option v-for="keyValue in field.keyValues" :key="keyValue.keyStr" :value="keyValue.keyStr">
+        {{ keyValue.value }}
+      </a-select-option>
+    </a-select>
+
     <select :id="'enum-select-widget-' + field.fieldName" v-model="selectedValue" class="form-control form-control-complex form-input">
       <option value="" />
       <option v-for="keyValue in field.keyValues" :key="keyValue.keyStr" :value="keyValue.keyStr">{{ keyValue.value }}</option>
@@ -25,19 +35,47 @@ export default {
 
   data: function(){
     return {
-      selectedValue: ((this.fieldValue == undefined || this.fieldValue.displayValue == undefined) ? '' : this.fieldValue.displayValue[0]),
+      // selectedValue: ((this.fieldValue == undefined || this.fieldValue.displayValue == undefined) ? '' : this.fieldValue.displayValue[0]),
+      selectedValue: '',
     };
   },
 
   watch: {
-    selectedValue: function(curVal,oldVal){
-      if(curVal != oldVal){					
-        var newFieldValue = {
-          displayValue: [curVal],
-          fieldType: 'String',
-        };
-        this.$emit('valueChanged', newFieldValue);
-      }
+    // selectedValue: function(curVal,oldVal){
+    //   if(curVal != oldVal){					
+    //     var newFieldValue = {
+    //       displayValue: [curVal],
+    //       fieldType: 'String',
+    //     };
+    //     this.$emit('valueChanged', newFieldValue);
+    //   }
+    // },
+  },
+  mounted() {
+    if (this.fieldValue && this.fieldValue.displayValue && this.fieldValue.displayValue.length) {
+      const newFieldValue = {
+        displayValue: [this.fieldValue.displayValue[0]],
+        fieldType: 'String',
+      };
+      this.$emit('valueChanged', newFieldValue);
+      this.selectedValue = this.fieldValue.displayValue[0];
+    } else {
+      const newFieldValue = {
+        displayValue: [this.field.defaultValue],
+        fieldType: 'String',
+      };
+      this.$emit('valueChanged', newFieldValue);
+      this.selectedValue = this.field.defaultValue;
+    }
+  },
+  methods:{
+    selectChanged(e) {
+      const newFieldValue = {
+        displayValue: [e],
+        fieldType: 'String',
+      };
+      this.$emit('valueChanged', newFieldValue);
+      this.selectedValue = e;
     },
   },
 };

+ 2 - 1
packages/info/src/InfoHeader.vue

@@ -6,13 +6,14 @@
       style="padding:0;border-bottom: solid 1px #d1cfcf;margin-bottom: 8px;"
       :title="headerName"
       :sub-title="subHeaderName"
+      :back-icon="showBack ? undefined : false"
       @back="() => $router.go(-1)"
     >
       <template #backIcon>
         <ArrowLeftOutlined v-if="showBack" />
       </template>
       <template #extra>
-        <a-flex justify="flex-start" align="center" style="height: 46px;" gap="middle">
+        <a-flex justify="flex-start" align="center" style="height: 32px;" gap="middle">
           <a-dropdown>
             <a class="ant-dropdown-link" @click.prevent>
               设置

+ 5 - 0
packages/info/src/InfoWindow.vue

@@ -8,6 +8,7 @@
       :field-value="fieldValue" 
       :info-window="infoWindowDto"
       :where-clause-source="whereClauseSource" 
+      :show-back="showBack"
       :is-search-widget="isSearchWidget" 
       :parent-model-data="parentModelData"
       :model-data="modelData" 
@@ -92,6 +93,10 @@ export default defineComponent({
       type: Boolean,
       default: false,
     },
+    showBack: {
+      type: Boolean,
+      default: true,
+    },
   },
 
   emits: ['dataSelected', 'valueChanged', 'deleteSelected','getSelectModelData'],

+ 124 - 123
packages/info/src/MultiSearchWidget.vue

@@ -1,75 +1,65 @@
 <template>
-  <div class="content">
-    <div class="box">
-      <span
-        v-for="(item, index) in selectedDatas"
-        :key="item + '-' + index"
-        class="selected-tag"
+  <div :style="style">
+    <a-input-group compact>
+      <a-select
+        v-model:value="selectedValue" :style="{ width: 'calc(100% - 32px)' }" :suffix-icon="null"
+        :open="false" mode="multiple" @deselect="(value) => deleteSelected(value, 'antd')"
       >
-        {{ item.value }}
-        <button
-          type="button"
-          class="close"
-          aria-label="Remove option"
-          @click="deleteSelected(item)"
+        <a-select-option
+          v-for="keyValue in selectedDatas" :key="keyValue.value" :value="keyValue.value"
+          style="display: none"
         >
-          <span aria-hidden="true">&times;</span>
-        </button>
-      </span>
-      <span
-        class="glyphicon glyphicon-search search-icon"
-        @click="showSearchDialog"
-      />
-    </div>
-    <Modal
-      v-model:show="modal"
-      :full="true"
-      @ok="searchDialogOk"
-      @cancel="searchDialogCancel"
-    >
-      <template #header>
-        <div>{{ infoWindowDto.name }}</div>
-      </template>
-      <template #default>
-        <InfoWindow
-          ref="info"
-          :field-value="fieldValue"
-          :where-clause-source="whereClauseSource"
-          :is-search-widget="true"
-          :model-data="modelData"
-          :info-window-no="infoWindowNo"
-          :multiple="true"
-          @data-selected="dataSelected"
-          @delete-selected="deleteSelected"
-        />
-      </template>
-    </Modal>
-    <Loading v-if="loading" />
+          {{ keyValue.label }}
+        </a-select-option>
+      </a-select>
+      <a-button @click="showSearchDialog">
+        <template #icon>
+          <SearchOutlined />
+        </template>
+      </a-button>
+    </a-input-group>
   </div>
+
+  <Modal v-model:show="modal" :full="true" @ok="searchDialogOk" @cancel="searchDialogCancel">
+    <template #header>
+      <div>{{ infoWindowDto.name }}</div>
+    </template>
+    <template #default>
+      <InfoWindow
+        v-if="modal"
+        ref="info" :field-value="fieldValue" :where-clause-source="whereClauseSource"
+        :is-search-widget="true" :model-data="modelData" :info-window-no="infoWindowNo" :multiple="true"
+        @data-selected="dataSelected" @delete-selected="deleteSelected"
+      />
+    </template>
+  </Modal>
+  <Loading v-if="loading" />
 </template>
 <script>
 import { defineAsyncComponent } from 'vue';
 
 import Modal from '../../modal/src/Modal.vue';
 import Loading from '../../loading/src/Loading.vue';
+import { SearchOutlined } from '@ant-design/icons-vue';
 
 export default {
 
   components: {
-    Modal, 
+    Modal,
     InfoWindow: defineAsyncComponent(() =>
       import('./InfoWindow.vue'),
     ),
     Loading,
+    SearchOutlined,
   },
   props: {
     /**
      * 查询窗口编号
      */
-    'infoWindowNo':{
+    'infoWindowNo': {
       type: String,
       default: null,
-    }, 
+    },
     /**
      * 显示的值
      * fieldValue:{
@@ -89,18 +79,18 @@ export default {
     'whereClauseSource': {
       type: Object,
       default: null,
-    }, 
+    },
     /**
      * 文本框中显示的字段
      */
     'displayName': {
       type: String,
       default: null,
-    }, 
+    },
     /**
      * 弹出窗口的标题
      */
-    'titleName':{
+    'titleName': {
       type: String,
       default: null,
     },
@@ -108,6 +98,10 @@ export default {
       type: Object,
       default: null,
     },
+    'style': {
+      type: Object,
+      default: null,
+    },
   },
 
   emits: ['valueChanged'],
@@ -123,6 +117,7 @@ export default {
       selectedDatas: [],
       loading: false,
       modal: false,
+      selectedValue: [],
     };
   },
 
@@ -145,7 +140,7 @@ export default {
     // 显示搜索对话框
     showSearchDialog: function () {
       var _self = this;
-      _self.modal=true;
+      _self.modal = true;
     },
 
     searchDialogOk: function () {
@@ -181,7 +176,7 @@ export default {
           displayValue.push(existDisplayValue[i]);
         }
       }
-      
+
       let fieldName = _self.displayName;
       let text = '';
       if (fieldName != undefined && data.data[fieldName] != null && data.data[fieldName].displayValue != null) {
@@ -215,6 +210,7 @@ export default {
      * @return {[type]}
      */
     reComputeSearchText: function (fieldValue) {
+      console.log('reComputeSearchText', fieldValue);
       var arr = [];
       var ids = fieldValue.ids;
       var displayValue = fieldValue.displayValue;
@@ -227,45 +223,50 @@ export default {
           arr.push(obj);
         }
       }
-      return this.selectedDatas = arr;
+      this.selectedValue = ids;
+      const options = arr.map(item => {
+        return {
+          value: item.id,
+          label: item.value,
+        };
+      });
+      return this.selectedDatas = options;
     },
 
     // 删除选中数据
-    deleteSelected: function (item) {
-      var id = item.id;
-      var _self = this;
-      var newIds = [];
-      var displayValues = [];
-      if (_self.fieldValue.ids != undefined) {
-        for (let i = 0; i < _self.fieldValue.ids.length; i++) {
-          newIds.push(_self.fieldValue.ids[i]);
-        }
-      }
-
-      if (_self.fieldValue.displayValue != undefined) {
-        for (let i = 0; i < _self.fieldValue.displayValue.length; i++) {
-          displayValues.push(_self.fieldValue.displayValue[i]);
-        }
-      }
-
-      var index = newIds.indexOf(id);
+    deleteSelected: function (item, flag) {
+      console.log('deleteSelected', item, flag);
+      // 获取要删除的ID
+      const id = flag === 'antd' ? item : item.id;
+      
+      // 创建新的数组副本(保持响应式)
+      const newIds = [...this.fieldValue.ids];
+      const displayValues = [...this.fieldValue.displayValue];
+      
+      // 查找索引位置
+      const index = newIds.indexOf(id);
       if (index > -1) {
+        // 同步删除两个数组中的对应项
         newIds.splice(index, 1);
-        _self.fieldValue.ids.splice(index, 1);
-        if (displayValues.length > index) {
-          displayValues.splice(index, 1);
-          _self.fieldValue.displayValue.splice(index, 1);
-        }
+        displayValues.splice(index, 1);
+
+        // 创建新字段值对象
+        const newFieldValue = {
+          displayValue: displayValues,
+          fieldType: 'ManyToManyKey',
+          ids: newIds,
+        };
+
+        // 立即更新本地状态
+        this.selectedValue = newIds; 
+        this.selectedDatas = newIds.map((id, i) => ({
+          value: id,
+          label: displayValues[i],
+        }));
+        console.log('newFieldValue', newFieldValue);
+        // 触发父组件更新
+        this.$emit('valueChanged', newFieldValue);
       }
-
-      var newFieldValue = {
-        displayValue: displayValues,
-        fieldType: 'ManyToManyKey',
-        ids: newIds,
-      };
-
-      this.$emit('valueChanged', newFieldValue);
-      this.reComputeSearchText(newFieldValue);
     },
   },
 };
@@ -273,61 +274,61 @@ export default {
 
 <style scoped>
 .required-mark {
-    color: red;
-    margin-right: 10px;
+  color: red;
+  margin-right: 10px;
 }
 
 .box {
-    width: 200px;
-    min-height: 34px;
-    border: 1px solid rgba(60, 60, 60, 0.26);
-    border-radius: 4px;
-    white-space: normal;
-    transition: border-radius 0.25s;
-    background-color: #ffffff;
-    position: relative;
+  width: 200px;
+  min-height: 34px;
+  border: 1px solid rgba(60, 60, 60, 0.26);
+  border-radius: 4px;
+  white-space: normal;
+  transition: border-radius 0.25s;
+  background-color: #ffffff;
+  position: relative;
 }
 
 .search-icon {
-    position: absolute;
-    top: 9px;
-    right: 7px;
+  position: absolute;
+  top: 9px;
+  right: 7px;
 }
 
 .selected-tag {
-    color: #333;
-    background-color: #f0f0f0;
-    border: 1px solid #ccc;
-    border-radius: 4px;
-    height: 26px;
-    margin: 4px 1px 0px 3px;
-    padding: 3px 0.25em;
-    line-height: 34px;
+  color: #333;
+  background-color: #f0f0f0;
+  border: 1px solid #ccc;
+  border-radius: 4px;
+  height: 26px;
+  margin: 4px 1px 0px 3px;
+  padding: 3px 0.25em;
+  line-height: 34px;
 }
 
 .close {
-    float: none;
-    margin-right: 0;
-    font-size: 20px;
-    appearance: none;
-    padding: 0;
-    cursor: pointer;
-    background: 0 0;
-    border: 0;
-    font-weight: 700;
-    line-height: 1;
-    color: #000;
-    text-shadow: 0 1px 0 #fff;
-    filter: alpha(opacity=20);
-    opacity: 0.2;
+  float: none;
+  margin-right: 0;
+  font-size: 20px;
+  appearance: none;
+  padding: 0;
+  cursor: pointer;
+  background: 0 0;
+  border: 0;
+  font-weight: 700;
+  line-height: 1;
+  color: #000;
+  text-shadow: 0 1px 0 #fff;
+  filter: alpha(opacity=20);
+  opacity: 0.2;
 }
 
 .div-readonly {
-    background-color: #eee !important;
+  background-color: #eee !important;
 }
 
 .content {
-    display: inline-block !important;
-    width: 200px;
+  display: inline-block !important;
+  width: 200px;
 }
 </style>

+ 1 - 0
packages/info/src/QueryCondition.vue

@@ -20,6 +20,7 @@
             width="440px"
             style="z-index: 1050;"
             placement="right"
+            :body-style="{ padding: '8px 16px 0 8px' }"
             @udpate:open="searchConditionInstance.setComplex($event)"
             @close="closeSearch"
           >

+ 197 - 323
packages/info/src/QueryConditionComplex.vue

@@ -1,250 +1,176 @@
 <!-- 复杂查询过滤 -->
 <template>
-  <div class="buttons">
-    <a-button
-      type="primary"
-      class="item"
-      @click="complexSearch()"
-    >
-      {{ $t('lang.QueryConditionComplex.filter') }}
-    </a-button>
-  </div>
-  <div>
-    <div>
-      <div class="form-inline">
-        <div
-          v-for="(item,index) in filterFields"
-          v-show="item.isShow"
-          :key="index"
-          class="form-group m-form-group"
-        >
-          <label
-            v-tooltip.right="Language.getHelpTrl($i18n.locale, item)"
-            :for="item.id"
-            class="m-form-group-label"
-          >
-            {{ Language.getNameTrl($i18n.locale, item) }}
-          </label>
-          <div
-            v-if="item.index == 1"
-            class="form-inline-div"
-            @keyup.enter="complexSearch()"
-          >
-            <SearchInput
-              v-if="item.displayType =='TextEditor' && item.apiUrl != null && item.apiUrl.length >0"
-              v-model:value="item.value.value1"
-              :api-url="item.apiUrl"
-              :api-response-data-text-filed-name="
-                item.apiResponseDataTextFiledName
-              "
-              class="form-control form-control-complex form-input"
-            />
-            <input
-              v-if="item.displayType =='TextEditor' && !item.apiUrl"
-              :id="item.id"
-              v-model="item.value.value1"
-              autocomplete="off"
-              type="text"
-              :placeholder="$t('lang.QueryConditionComplex.pleaseInputTheContent')"
-              class="form-control form-control-complex form-input"
-            />
-            <input
-              v-if="item.displayType =='NumberEditor'"
-              :id="item.id"
-              v-model="item.value.value1"
-              autocomplete="off"
-              type="number"
-              class="form-control form-control-complex form-input"
-              :placeholder="$t('lang.QueryConditionComplex.pleaseEnterANumber')"
-              onmousewheel="return false;"
-              @mousewheel="mouseWheelEvent"
-            />
-
-            <select
-              v-if="item.displayType =='CheckBoxEditor'"
-              v-model="item.value.value1"
-              class="form-control form-control-complex form-input form-select"
-            >
-              <option value="">{{ $t('lang.QueryConditionComplex.all') }}</option>
-              <option value="true">{{ $t('lang.QueryConditionComplex.true') }}</option>
-              <option value="false">{{ $t('lang.QueryConditionComplex.false') }}</option>
-            </select>
-
-            <DateTime
-              v-if="item.displayType =='DateTimeBoxEditor'"
-              v-model="item.value.value1"
-              class="m-form-input"
-              @update:model-value="dateValueChange($event, item, 'value1')"
-            />
-
-            <!--  年份选择器-->
-            <YearPicker
-              v-if="item.displayType =='YearEditor'"
-              v-model="item.value.value1"
-              class="m-form-input"
-              @selected="textChanged(item, 'value1', $event)"
-            />
-
-            <!--  年月选择器  -->
-            <VueMonthlyPicker
-              v-if="item.displayType =='YearMonthEditor'"
-              id="month-picker"
-              v-model="item.value.value1"
-              date-format="YYYY-MM"
-              class="form-inline-div m-form-input"
-              @selected="refresh"
-            />
-
-            <!-- 日期选择器  -->
-            <DateWidget
-              v-if="item.displayType =='DateBoxEditor'"
-              v-model="item.value.value1"
-              class="m-form-input"
-              @on-value-change="dateValueChange($event, item, 'value1')"
-            />
-
-            <EnumSelectWidgetInfo
-              v-if="item.displayType =='ListBoxEnumEditor'"
-              :field="item"
-              :field-value="item.fieldValue"
-              @value-changed="tabValueChanged($event, item, 'value1')"
-            />
-
-            <SearchWidget
-              v-if="item.displayType =='SearchBoxEditor'"
-              :where-clause-source="{'infoFilterField': {'infoWindowNo': infoWindowNo, 'fieldName' : item.fieldName}}"
-              :info-window-no="item.infoWindowNo"
-              :title-name="item.name"
-              :field-value="item.fieldValue"
-              :display-name="item.listFieldNames"
-              class="m-form-input"
-              @value-changed="tabValueChanged($event, item)"
-            />
-
-            <!-- 多选搜索框 number类型-->
-            <MultiSearchWidget
-              v-if="item.displayType =='MultiSearchBoxEditor'"
-              :where-clause-source="{'infoFilterField': {'infoWindowNo': infoWindowNo, 'fieldName' : item.fieldName}}"
-              :info-window-no="item.infoWindowNo"
-              :title-name="item.name"
-              :field-value="item.fieldValue"
-              :display-name="item.listFieldNames"
-              class="m-form-input"
-              @value-changed="multiSearchValueChange($event, item)"
-            />
-          </div>
-          <div
-            v-if="item.index == 2"
-            class="form-inline-div"
-          >
-            <SearchInput
-              v-if="item.displayType =='TextEditor' && item.apiUrl != null && item.apiUrl.length >0"
-              v-model:value="item.value.value1"
-              :api-url="item.apiUrl"
-              :api-response-data-text-filed-name="
-                item.apiResponseDataTextFiledName
-              "
-              class="form-control form-control-complex form-input"
-              @keyup.enter="complexSearch()"
-            />
-            <input
-              v-if="item.displayType =='TextEditor' && !item.apiUrl"
-              :id="item.id"
-              v-model="item.value.value1"
-              autocomplete="off"
-              type="text"
-              :placeholder="$t('lang.QueryConditionComplex.pleaseInputTheContent')"
-              class="form-control form-control-complex form-input"
-            />
-            <input
-              v-if="item.displayType =='NumberEditor'"
-              :id="item.id"
-              v-model="item.value.value2"
-              autocomplete="off"
-              type="number"
-              class="form-control form-control-complex form-input"
-              :placeholder="$t('lang.QueryConditionComplex.pleaseEnterANumber')"
-              @keyup.enter="complexSearch()"
-            />
-
-            <select
-              v-if="item.displayType =='CheckBoxEditor'"
-              v-model="item.value.value2"
-              class="form-control form-control-complex form-input form-select"
-            >
-              <option value="">{{ $t('lang.QueryConditionComplex.all') }}</option>
-              <option value="true">{{ $t('lang.QueryConditionComplex.true') }}</option>
-              <option value="false">{{ $t('lang.QueryConditionComplex.false') }}</option>
-            </select>
-
-            <!-- <input autocomplete="off" v-if="item.displayType =='CheckBoxEditor'" 
-                type="checkbox" class="form-control form-control-complex form-input" 
-                :id="item.id" v-model="item.value.value2" 
-                @keyup.enter="complexSearch()"> -->
-            <!-- <input autocomplete="off" v-if="item.displayType =='DateTimeBoxEditor'" 
-                type="date" 
-                placeholder="yyyy-MM-dd" 
-                class="form-control form-control-complex form-input" 
-                :id="item.id" 
-                v-model="item.value.value2" 
-                @keyup.enter="complexSearch()"> -->
-            <DateTime
-              v-if="item.displayType =='DateTimeBoxEditor'"
-              v-model="item.value.value2"
-              class="m-form-input"
-              @update:model-value="dateValueChange($event, item, 'value2')"
-            />
-
-            <!--  年份选择器-->
-            <YearPicker
-              v-if="item.displayType =='YearEditor'"
-              v-model="item.value.value2"
-              class="m-form-input"
-              @selected="textChanged(item, 'value2', $event)"
-            />
-
-            <!--  年月选择器  -->
-            <vue-monthly-picker
-              v-if="item.displayType =='YearMonthEditor'"
-              id="month-picker"
-              v-model="item.value.value2"
-              date-format="YYYY-MM"
-              class="form-inline-div m-form-input"
-              @selected="refresh"
-            />
-
-            <!-- 日期选择器  -->
-            <DateWidget
-              v-if="item.displayType =='DateBoxEditor'"
-              v-model="item.value.value2"
-              class="m-form-input"
-              @on-value-change="dateValueChange($event, item, 'value2')"
-            />
-
-            <EnumSelectWidgetInfo
-              v-if="item.displayType =='ListBoxEnumEditor'"
-              :field="item"
-              :field-value="item.fieldValue"
-              class="m-form-input"
-              @value-changed="tabValueChanged($event, item)"
-            />
-
-            <!--单选number类型-->
-            
-            <SearchWidget
-              v-if="item.displayType =='SearchBoxEditor'"
-              :where-clause-source="{'infoFilterField': {'infoWindowNo': infoWindowNo, 'fieldName' : item.fieldName}}"
-              :info-window-no="item.infoWindowNo"
-              :title-name="item.name"
-              :field-value="item.fieldValue"
-              :display-name="item.listFieldNames"
-              class="m-form-input"
-              @value-changed="tabValueChanged($event, item)"
-            />
-          </div>
-        </div>
-      </div>
+  <div class="ant-query-container">
+    <div class="ant-query-header">
+      <a-button type="primary" @click="complexSearch">
+        {{ $t('lang.QueryConditionComplex.filter') }}
+      </a-button>
     </div>
+
+    <a-row :gutter="[8, 0]">
+      <template v-for="(item,index) in filterFields" :key="index">
+        <a-col v-show="item.isShow" :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
+          <a-form-item
+            :label="Language.getNameTrl($i18n.locale, item)" :label-col="{ flex: '120px' }"
+            class="ant-query-item"
+          >
+            <!-- 条件1的输入区域 -->
+            <template v-if="item.index === 1">
+              <!-- 文本输入 -->
+              <SearchInput
+                v-if="item.displayType === 'TextEditor' && item.apiUrl" v-model:value="item.value.value1"
+                :api-url="item.apiUrl" :api-response-data-text-filed-name="item.apiResponseDataTextFiledName"
+                @keyup.enter="complexSearch"
+              />
+
+              <!-- 普通文本输入 -->
+              <a-input
+                v-else-if="item.displayType === 'TextEditor'" v-model:value="item.value.value1"
+                :placeholder="$t('lang.QueryConditionComplex.pleaseInputTheContent')" allow-clear
+                @keyup.enter="complexSearch"
+              />
+
+              <!-- 数字输入 -->
+              <a-input-number
+                v-else-if="item.displayType === 'NumberEditor'" v-model:value="item.value.value1"
+                :placeholder="$t('lang.QueryConditionComplex.pleaseEnterANumber')" class="full-width"
+                @keyup.enter="complexSearch"
+              />
+
+              <!-- 布尔选择 -->
+              <a-select
+                v-else-if="item.displayType === 'CheckBoxEditor'" v-model:value="item.value.value1"
+                class="full-width"
+              >
+                <a-select-option value="">{{ $t('lang.QueryConditionComplex.all') }}</a-select-option>
+                <a-select-option value="true">{{ $t('lang.QueryConditionComplex.true') }}</a-select-option>
+                <a-select-option value="false">{{ $t('lang.QueryConditionComplex.false') }}</a-select-option>
+              </a-select>
+
+              <!-- 日期时间选择 -->
+              <DateTime
+                v-else-if="item.displayType === 'DateTimeBoxEditor'" v-model="item.value.value1"
+                class="full-width" @update:model-value="dateValueChange($event, item, 'value1')"
+              />
+
+              <!-- 年份选择 -->
+              <YearPicker
+                v-else-if="item.displayType === 'YearEditor'" v-model="item.value.value1" class="full-width"
+                @selected="textChanged(item, 'value1', $event)"
+              />
+
+              <!-- 年月选择 -->
+              <VueMonthlyPicker
+                v-else-if="item.displayType === 'YearMonthEditor'" v-model="item.value.value1"
+                date-format="YYYY-MM" class="full-width" @selected="refresh"
+              />
+
+              <!-- 日期选择 -->
+              <DateWidget
+                v-else-if="item.displayType === 'DateBoxEditor'" v-model="item.value.value1"
+                class="full-width" @on-value-change="dateValueChange($event, item, 'value1')"
+              />
+
+              <!-- 枚举选择 -->
+              <EnumSelectWidgetInfo
+                v-else-if="item.displayType === 'ListBoxEnumEditor'" :field="item"
+                :field-value="item.fieldValue" class="full-width"
+                @value-changed="tabValueChanged($event, item, 'value1')"
+              />
+
+              <!-- 搜索框 -->
+              <SearchWidget
+                v-else-if="item.displayType === 'SearchBoxEditor'"
+                :where-clause-source="{ infoFilterField: { infoWindowNo: infoWindowNo, fieldName: item.fieldName } }"
+                :info-window-no="item.infoWindowNo" :title-name="item.name" :field-value="item.fieldValue"
+                :display-name="item.listFieldNames" class="full-width" @value-changed="tabValueChanged($event, item)"
+              />
+
+              <!-- 多选搜索 -->
+              <MultiSearchWidget
+                v-else-if="item.displayType === 'MultiSearchBoxEditor'"
+                :where-clause-source="{ infoFilterField: { infoWindowNo: infoWindowNo, fieldName: item.fieldName } }"
+                :info-window-no="item.infoWindowNo" :title-name="item.name" :field-value="item.fieldValue"
+                :display-name="item.listFieldNames" class="full-width"
+                @value-changed="multiSearchValueChange($event, item)"
+              />
+            </template>
+
+            <!-- 条件2的输入区域 -->
+            <template v-if="item.index === 2">
+              <!-- 文本输入(带API搜索) -->
+              <SearchInput
+                v-if="item.displayType === 'TextEditor' && item.apiUrl" v-model:value="item.value.value2"
+                :api-url="item.apiUrl" :api-response-data-text-filed-name="item.apiResponseDataTextFiledName"
+                @keyup.enter="complexSearch"
+              />
+
+              <!-- 普通文本输入 -->
+              <a-input
+                v-else-if="item.displayType === 'TextEditor'" v-model:value="item.value.value2"
+                :placeholder="$t('lang.QueryConditionComplex.pleaseInputTheContent')" allow-clear
+                @keyup.enter="complexSearch"
+              />
+
+              <!-- 数字输入 -->
+              <a-input-number
+                v-else-if="item.displayType === 'NumberEditor'" v-model:value="item.value.value2"
+                :placeholder="$t('lang.QueryConditionComplex.pleaseEnterANumber')" class="full-width"
+                @keyup.enter="complexSearch"
+              />
+
+              <!-- 布尔选择 -->
+              <a-select
+                v-else-if="item.displayType === 'CheckBoxEditor'" v-model:value="item.value.value2"
+                class="full-width"
+              >
+                <a-select-option value="">{{ $t('lang.QueryConditionComplex.all') }}</a-select-option>
+                <a-select-option value="true">{{ $t('lang.QueryConditionComplex.true') }}</a-select-option>
+                <a-select-option value="false">{{ $t('lang.QueryConditionComplex.false') }}</a-select-option>
+              </a-select>
+
+              <!-- 日期时间选择 -->
+              <DateTime
+                v-else-if="item.displayType === 'DateTimeBoxEditor'" v-model="item.value.value2"
+                class="full-width" @update:model-value="dateValueChange($event, item, 'value2')"
+              />
+
+              <!-- 年份选择 -->
+              <YearPicker
+                v-else-if="item.displayType === 'YearEditor'" v-model="item.value.value2" class="full-width"
+                @selected="textChanged(item, 'value2', $event)"
+              />
+
+              <!-- 年月选择 -->
+              <VueMonthlyPicker
+                v-else-if="item.displayType === 'YearMonthEditor'" v-model="item.value.value2"
+                date-format="YYYY-MM" class="full-width" @selected="refresh"
+              />
+
+              <!-- 日期选择 -->
+              <DateWidget
+                v-else-if="item.displayType === 'DateBoxEditor'" v-model="item.value.value2"
+                class="full-width" @on-value-change="dateValueChange($event, item, 'value2')"
+              />
+
+              <!-- 枚举选择 -->
+              <EnumSelectWidgetInfo
+                v-else-if="item.displayType === 'ListBoxEnumEditor'" :field="item"
+                :field-value="item.fieldValue" class="full-width" @value-changed="tabValueChanged($event, item)"
+              />
+
+              <!-- 搜索框 -->
+              <SearchWidget
+                v-else-if="item.displayType === 'SearchBoxEditor'"
+                :where-clause-source="{ infoFilterField: { infoWindowNo: infoWindowNo, fieldName: item.fieldName } }"
+                :info-window-no="item.infoWindowNo" :title-name="item.name" :field-value="item.fieldValue"
+                :display-name="item.listFieldNames" class="full-width" @value-changed="tabValueChanged($event, item)"
+              />
+            </template>
+          </a-form-item>
+        </a-col>
+      </template>
+    </a-row>
   </div>
 </template>
 
@@ -265,10 +191,10 @@ export default {
   components: {
     EnumSelectWidgetInfo,
     DateTime,
-    SearchWidget : defineAsyncComponent(() =>
+    SearchWidget: defineAsyncComponent(() =>
       import('./SearchWidget.vue'),
     ),
-    MultiSearchWidget : defineAsyncComponent(() =>
+    MultiSearchWidget: defineAsyncComponent(() =>
       import('./MultiSearchWidget.vue'),
     ),
     DateWidget,
@@ -278,7 +204,7 @@ export default {
   },
 
   props: {
-    'infoWindowNo':{
+    'infoWindowNo': {
       type: String,
       default: null,
     },
@@ -290,7 +216,7 @@ export default {
       type: Array,
       default: null,
     },
-    'isSearchWidget':{
+    'isSearchWidget': {
       type: Boolean,
       default: null,
     },
@@ -371,7 +297,7 @@ export default {
          * @return {void} 
          */
     complexSearch: function () {
-      this.$emit('complexSearch','complex');
+      this.$emit('complexSearch', 'complex');
     },
 
     /**
@@ -412,90 +338,38 @@ export default {
 
 
 <style scoped>
-.form-input {
-    border-radius: 4px !important;
-}
-.form-inline-div {
-    display: inline-block;
-}
-.m-select {
-    display: inline-block !important;
-}
-.m-form-group {
-    margin-left: 5px !important;
-    margin-right: 5px !important;
-    margin-bottom: 5px !important;
-}
-
-.m-form-group-label{
-		white-space: nowrap;
-    text-overflow: ellipsis;
-} 
-
-@media (max-width: 768px) {
-    .m-form-group-label {
-        text-align: left;
-        padding-right: 10px;
-    }
+.ant-query-header {
+  margin-bottom: 16px;
+  margin-left: 16px;
 }
 
-@media (min-width: 768px) {
-    .m-form-group-label {
-        width: 100px;
-        text-align: center;
-        padding-right: 10px;
-    }
-
-    .input-switches {
-        width: 100%;
-    }
-}
-.btn-process {
-    margin-right: 5px;
+.ant-query-item {
+  margin-bottom: 8px;
 }
 
-.m-row {
-    margin-bottom: 5px;
-    text-align: left;
+.full-width {
+  width: 100%;
 }
 
-.form-control-complex {
-    float: none !important;
-    width: auto !important;
+:deep(.ant-form-item-label) {
+  overflow: visible;
+  white-space: nowrap;
+  text-overflow: ellipsis;
 }
 
-.input-simple {
-    width: 100% !important;
+:deep(.ant-picker),
+:deep(.ant-input-number),
+:deep(.ant-select) {
+  width: 100%;
 }
 
-.input-switches {
-    width: 200px;
-}
-.form-select {
-    width: 200px !important;
-}
-.m-form-input {
-    border-radius: 4px !important;
-    width: 200px !important;
-}
-.form-control-complex {
-    width: 200px !important;
-}
-.m-btn {
-    float: left;
-    margin-right: 5px;
-}
-.buttons {
-  display: flex;
-  justify-content: space-between;
-  flex-wrap: wrap;
-  margin-bottom: 6px;
-}
-.buttons:after {
-  content: "";
-  flex: auto;
+@media (max-width: 768px) {
+  :deep(.ant-form-item-label) {
+    text-align: left;
+  }
 }
-.item{
-  margin-right: 4px;
+:deep(.ant-form-item-label > label) {
+  font-size: 14px !important;
+  font-weight: 500 !important;
 }
 </style>

+ 11 - 24
packages/info/src/QueryPage.vue

@@ -13,7 +13,7 @@
             :info-grid-fields="infoGridFieldsInstance.infoGridFields"
             :header-name="Language.getNameTrl($i18n.locale, infoWindowDto)"
             :sub-header-name="Language.getHelpTrl($i18n.locale, infoWindowDto)" :info-filter-fields="infoFilterFields"
-            :info-window-no="infoWindowDto.no" :show-back="isSearchWidget == null || isSearchWidget == false"
+            :info-window-no="infoWindowDto.no" :show-back="showBack"
             @filter-field-property-changed="filterFieldPropertyChanged($event)"
             @grid-field-property-changed="gridFieldPropertyChanged($event)"
           />
@@ -94,26 +94,9 @@
         @delete-selected="$emit('deleteSelected', $event)"
       />
     </div>
-    <div class="flex-footer" style="margin-top: 10px">
-      <div class="pull-left">
-        <!-- <span>{{ $t("lang.QueryPage.the") }}
-          {{ (pagination.current_page - 1) * pagination.per_page + 1 }}
-          -
-          {{ pagination.current_page * pagination.per_page }}
-          {{ $t("lang.QueryPage.strip") }}
-          ,
-          {{ $t("lang.QueryPage.total") }}
-          {{ pagination.total }}
-          {{ $t("lang.QueryPage.strip") }}
-          ,
-          {{ $t("lang.QueryPage.displayOnEachPage") }}
-        </span>
-        <PageSizeSelect :size="pagination.per_page" @page-size-changed="gridSizeSelect" />
-        <span>{{ $t("lang.QueryPage.strip") }}</span> -->
-      </div>
-      <div class="pull-right">
-        <!-- <Pagination :pagination="pagination" :callback="pageSearch" /> -->
-      </div>
+    <div class="flex-footer">
+      <div class="pull-left" />
+      <div class="pull-right" />
     </div>
     <Loading v-if="loading" />
     <a-modal v-model:open="modal" :title="$t('lang.QueryPage.resultsOfEnforcement')" @ok="modal = false">
@@ -201,6 +184,10 @@ export default {
       type: Boolean,
       default: false,
     },
+    showBack: {
+      type: Boolean,
+      default: true,
+    },
     parentModelData: {
       type: Object,
       default() {
@@ -1063,7 +1050,7 @@ export default {
   flex-direction: column;
   width: 100%;
   /*视口被均分为100单位的vh 占据整个窗口*/
-  height: calc(100vh - 75px);
+  height: calc(100vh - 90px);
 }
 
 .flex-container-modal {
@@ -1082,8 +1069,8 @@ export default {
 }
 
 .flex-footer {
-  height: 40px;
-  flex: 0 0 40px;
+  height: 26px;
+  flex: 0 0 26px;
 }
 
 .flex-content {

+ 34 - 4
packages/info/src/QueryPageTable.vue

@@ -1,6 +1,6 @@
 <template>
   <div :id="tableOutDivId" class="flex-main table-fix-head">
-    <table class="fixed-table table-striped table-bordered" :width="tableWidth" height="40px">
+    <table class="fixed-table" :width="tableWidth" height="40px">
       <thead>
         <tr height="40px">
           <th width="50px">{{ $t("lang.QueryPage.serialNumber") }}</th>
@@ -351,9 +351,13 @@ export default {
     fixedTableHeader: function () {
       let _self = this;
       _self.$nextTick(function () {
-        var $th = $('#' + _self.tableOutDivId).find('thead');
-        $('#' + _self.tableOutDivId).on('scroll', function () {
-          $th.css('transform', 'translateY(' + this.scrollTop + 'px)');
+        // var $th = $('#' + _self.tableOutDivId).find('thead');
+        // $('#' + _self.tableOutDivId).on('scroll', function () {
+        //   $th.css('transform', 'translateY(' + this.scrollTop + 'px)');
+        // });
+        $('.fixed-table').tableFixer({
+          left: 2,
+          head: true,
         });
       });
     },
@@ -444,4 +448,30 @@ table.fixed-table th .rz-handle.rz-handle-active {
 .rz-handle:hover {
     background: rgba(0, 0, 0, 0.2) 4px;
 }
+.fixed-table {
+  border-collapse: collapse;
+  width: 100%;
+}
+
+/* 表头和单元格边框 */
+.fixed-table th,
+.fixed-table td {
+  border: 1px solid #e8e8e8;
+  padding: 8px;
+}
+
+/* 表头背景色 */
+.fixed-table th {
+  background-color: #fafafa;
+}
+
+/* 斑马纹效果 */
+.fixed-table tr:nth-child(even) {
+  background-color: #f9f9f9;
+}
+
+/* 固定列边框加强 */
+.sticky-col {
+  border-right: 2px solid #d9d9d9 !important;
+}
 </style>

+ 71 - 53
packages/info/src/SearchAutoCompleteWidget.vue

@@ -1,9 +1,5 @@
 <template>
-  <div
-    v-if="show"
-    class="div-autoComplete"
-    :style="{ left: realLeftComputed }"
-  >
+  <div v-if="show" class="div-autoComplete" :style="{ left: realLeftComputed }">
     <div class="table-responsive">
       <table class="table table-bordered table-hover">
         <thead>
@@ -24,7 +20,7 @@
             v-for="(item1, index) in infoWindowData.dataList"
             :key="'tr-' + item1.id"
             height="40px"
-            :class="{'select-tr': index == selectIndex}"
+            :class="{ 'select-tr': index == selectIndex }"
             @click="selectNode(item1)"
           >
             <td
@@ -32,7 +28,11 @@
               :key="'tr-' + item1.id + '-td-' + item2.fieldName"
               align="center"
             >
-              {{ (item1.data[item2.fieldName] == undefined) ? "" : item1.data[item2.fieldName].displayValue[0] }}
+              {{
+                item1.data[item2.fieldName] == undefined
+                  ? ""
+                  : item1.data[item2.fieldName].displayValue[0]
+              }}
             </td>
           </tr>
         </tbody>
@@ -51,27 +51,27 @@ export default {
     /**
      * 是否显示自动提示列表
      */
-    'show':{
+    show: {
       type: Boolean,
       default: false,
     },
-    'infoWindowNo':{
+    infoWindowNo: {
       type: String,
       default: null,
     },
-    'leftPosition':{
+    leftPosition: {
       type: Number,
       default: null,
     },
-    'whereClauseSource':{
+    whereClauseSource: {
       type: Object,
       default: null,
     },
-    'parentModelData': {
+    parentModelData: {
       type: Object,
       default: null,
     },
-    'modelData': {
+    modelData: {
       type: Object,
       default: null,
     },
@@ -91,7 +91,7 @@ export default {
 
   computed: {
     realLeftComputed: function () {
-      return (((this.realLeft > 0) ? this.realLeft : 0) + 'px');
+      return (this.realLeft > 0 ? this.realLeft : 0) + 'px';
     },
   },
 
@@ -119,29 +119,37 @@ export default {
     },
   },
 
-  mounted: function () {
-
-  },
+  mounted: function () {},
 
   methods: {
     /**
      * 向下
-     * @return {void} 
+     * @return {void}
      */
     selectDown: function () {
       var _self = this;
+      if (
+        !_self.infoWindowData.dataList ||
+        !_self.infoWindowData.dataList.length
+      )
+        return;
       var length = _self.infoWindowData.dataList.length;
-      if (_self.selectIndex < (length - 1)) {
+      if (_self.selectIndex < length - 1) {
         _self.selectIndex++;
       }
     },
 
     /**
      * 向上
-     * @return {void} 
+     * @return {void}
      */
     selectUp: function () {
       var _self = this;
+      if (
+        !_self.infoWindowData.dataList ||
+        !_self.infoWindowData.dataList.length
+      )
+        return;
       var length = _self.infoWindowData.dataList.length;
       if (_self.selectIndex > 0) {
         _self.selectIndex--;
@@ -168,7 +176,11 @@ export default {
      */
     getFirstData: function () {
       var _self = this;
-      if (_self.infoWindowData != null && _self.infoWindowData.dataList != null && _self.infoWindowData.dataList.length > 0) {
+      if (
+        _self.infoWindowData != null &&
+        _self.infoWindowData.dataList != null &&
+        _self.infoWindowData.dataList.length > 0
+      ) {
         return _self.infoWindowData.dataList[0];
       }
       return null;
@@ -176,7 +188,7 @@ export default {
 
     /**
      * 查询InfoWindowDto
-     * @return {void} 
+     * @return {void}
      */
     getInfoWindowDto: function (resolve, reject) {
       var _self = this;
@@ -184,15 +196,15 @@ export default {
         url: Common.getApiURL('InfoWindowResource/uniqueByNo'),
         type: 'GET',
         dataType: 'json',
-        data: { 'infoWindowNo': _self.infoWindowNo },
+        data: { infoWindowNo: _self.infoWindowNo },
         beforeSend: function (request) {
           Common.addTokenToRequest(request);
         },
         success: function (response) {
-          if(response.errorCode == 0){
+          if (response.errorCode == 0) {
             _self.infoWindowDto = response.data;
             resolve();
-          }else{
+          } else {
             reject(response.errorMessage);
           }
         },
@@ -206,18 +218,24 @@ export default {
     /**
      * 根据条件初始化查询
      * @param  {String} text 查询条件
-     * @return {void}      
+     * @return {void}
      */
     initSearch: function (text) {
       var _self = this;
       if (text != undefined) {
-        if (_self.infoWindowDto == undefined || _self.infoWindowDto.infoGridFields == undefined) {
-          new Promise(_self.getInfoWindowDto).then(function (value) {
-            // success
-            _self.getInfoWindowData(text);
-          }, function (error) {
-            // error
-          });
+        if (
+          _self.infoWindowDto == undefined ||
+          _self.infoWindowDto.infoGridFields == undefined
+        ) {
+          new Promise(_self.getInfoWindowDto).then(
+            function (value) {
+              // success
+              _self.getInfoWindowData(text);
+            },
+            function (error) {
+              // error
+            },
+          );
         } else {
           _self.getInfoWindowData(text);
         }
@@ -228,16 +246,16 @@ export default {
 
     /**
      * 选择节点
-     * @return {void} 
+     * @return {void}
      */
     selectNode: function (data) {
+      console.log(data, '22222222222');
       this.$emit('selectData', data);
     },
 
-
     /**
      * 查询infoWindowData
-     * @return {void} 
+     * @return {void}
      */
     getInfoWindowData: function (text) {
       var _self = this;
@@ -264,7 +282,7 @@ export default {
         contentType: 'application/json',
         data: JSON.stringify(infoQueryParam),
         success: function (response) {
-          if(response.errorCode != 0){
+          if (response.errorCode != 0) {
             Notify.error('Error', response.errorMessage, false);
             return;
           }
@@ -282,26 +300,26 @@ export default {
 
 <style scoped>
 .div-autoComplete {
-    position: absolute;
-    z-index: 999;
-    background-color: #fff;
-    border: 1px #e5e5e5 solid;
-    padding: 15px 15px 0px 15px;
-    box-shadow: 0 0 5px rgba(81, 203, 238, 1);
-    /*width: 300px;*/
-    /*height: 300px;*/
-    /*max-height: 400px;*/
-    max-width: 800px;
-    min-width: 400px;
-    /*overflow: auto;*/
-    top: 32px;
+  position: absolute;
+  z-index: 999;
+  background-color: #fff;
+  border: 1px #e5e5e5 solid;
+  padding: 15px 15px 0px 15px;
+  box-shadow: 0 0 5px rgba(81, 203, 238, 1);
+  /*width: 300px;*/
+  /*height: 300px;*/
+  /*max-height: 400px;*/
+  max-width: 800px;
+  min-width: 400px;
+  /*overflow: auto;*/
+  top: 32px;
 }
 
 .no-padding-left {
-    padding-left: 0px !important;
+  padding-left: 0px !important;
 }
 
 .select-tr {
-    background-color: #eee;
+  background-color: #eee;
 }
-</style>
+</style>

+ 49 - 75
packages/info/src/SearchWidget.vue

@@ -1,47 +1,24 @@
 <template>
-  <div class="input-group">
-    <input
-      autocomplete="off"
-      aria-describedby="addon"
-      type="text"
-      class="form-control"
-      style="border-top-right-radius: 0; border-bottom-right-radius: 0;"
-      :class="validInput"
-      :value="searchText"
-      :readonly="readonly"
-      @input="textChange($event)"
-      @keyup.up="selectUp"
-      @keyup.down="selectDown"
-      @keyup.enter="selectEnter"
-      @keyup.esc="autoCompleteVisible = false"
-    />
-    <div :class="[classSize != undefined ? 'input-group-btn classSize' : 'input-group-btn']">
-      <button
-        type="button"
-        :class="[classSize != undefined ? 'btn btn-default classSize' : 'btn btn-default']"
-        @click="showSearchDialog"
-      >
-        <span class="glyphicon glyphicon-search" />
-      </button>
-      <slot name="button1" />
-      <slot name="button2" />
-      <slot name="button3" />
-    </div>
-
-    <Modal
-      v-model:show="modal"
-      :full="true"
-      @ok="searchDialogOk"
-      @cancel="searchDialogCancel"
-    >
+  <div style="width: 100%;">
+    <a-input-group compact>
+      <a-input
+        v-model:value="searchText" :class="validInput" :style="{ width: 'calc(100% - 32px)' }" :disabled="readonly"
+        @input="textChange($event)" @keyup.up="selectUp" @keyup.down="selectDown" @keyup.enter="selectEnter"
+        @keyup.esc="autoCompleteVisible = false"
+      />
+      <a-button :disabled="readonly" @click="showSearchDialog">
+        <template #icon>
+          <SearchOutlined />
+        </template>
+      </a-button>
+    </a-input-group>
+
+    <Modal v-model:show="modal" :full="true" @ok="searchDialogOk" @cancel="searchDialogCancel">
       <template #default>
         <InfoWindow
-          ref="infoWindow"
-          :field-value="fieldValue"
-          :info-window-no="infoWindowNo"
-          :where-clause-source="whereClauseSource"
-          :is-search-widget="true"
-          :model-data="modelData"
+          v-if="modal"
+          ref="infoWindow" :field-value="fieldValue" :info-window-no="infoWindowNo"
+          :where-clause-source="whereClauseSource" :is-search-widget="true" :model-data="modelData"
           @data-selected="dataSelected"
         />
       </template>
@@ -51,12 +28,8 @@
     </Modal>
 
     <SearchAutoCompleteWidget
-      ref="autoComplete"
-      v-model:show="autoCompleteVisible"
-      :info-window-no="infoWindowNo"
-      :where-clause-source="whereClauseSource"
-      class="auto-complete"
-      @select-data="dataSelected"
+      ref="autoComplete" v-model:show="autoCompleteVisible" :info-window-no="infoWindowNo"
+      :where-clause-source="whereClauseSource" class="auto-complete" @select-data="dataSelected"
     />
 
     <Loading v-if="loading" />
@@ -66,32 +39,33 @@
 <script>
 import { defineAsyncComponent } from 'vue';
 import Modal from '../../modal/src/Modal.vue';
-import InfoWindow from './InfoWindow.vue';
 import SearchAutoCompleteWidget from './SearchAutoCompleteWidget.vue';
 import Loading from '../../loading/src/Loading.vue';
+import { SearchOutlined } from '@ant-design/icons-vue';
 
 export default {
 
   name: 'SearchWidget',
 
   components: {
-    Modal, 
+    Modal,
     // InfoWindow, 
     InfoWindow: defineAsyncComponent(() =>
       import('./InfoWindow.vue'),
     ),
-    SearchAutoCompleteWidget, 
+    SearchAutoCompleteWidget,
     Loading,
+    SearchOutlined,
   },
   props: {
     /**
      * 查询窗口编号
      */
-    'infoWindowNo':{
+    'infoWindowNo': {
       type: String,
       default: null,
     },
-    
+
     /**
      * 显示的值
      * fieldValue:{
@@ -107,21 +81,21 @@ export default {
     /**
      * 弹出窗口的标题
      */
-    'titleName':{
+    'titleName': {
       type: String,
       default: null,
     },
     /**
      * 文本框中显示的字段
      */
-    'displayName':{
+    'displayName': {
       type: String,
       default: null,
     },
     /**
      * 约束条件来源
      */
-    'whereClauseSource':{
+    'whereClauseSource': {
       type: Object,
       default: null,
     },
@@ -133,7 +107,7 @@ export default {
       type: Object,
       default: null,
     },
-    'classSize':{
+    'classSize': {
       type: String,
       default: null,
     },
@@ -237,7 +211,7 @@ export default {
         return;
       }
 
-      this.modal=true;
+      this.modal = true;
 
       _self.autoCompleteVisible = false;
     },
@@ -246,12 +220,12 @@ export default {
      * 搜索框【确定】按钮点击事件
      */
     searchDialogOk: function () {
-      var _self = this;
-      var selectedModelDatas = _self.$refs.infoWindow.getSelectedModelDatas();
-      if (selectedModelDatas != undefined || selectedModelDatas.length > 0) {
-        // 选中了数据,更新数据
-        _self.dataSelected(selectedModelDatas[0]);
-      }
+      // var _self = this;
+      // var selectedModelDatas = _self.$refs.infoWindow.getSelectedModelDatas();
+      // if (selectedModelDatas != undefined || selectedModelDatas.length > 0) {
+      //   // 选中了数据,更新数据
+      //   _self.dataSelected(selectedModelDatas[0]);
+      // }
     },
 
     searchDialogCancel: function () {
@@ -276,15 +250,14 @@ export default {
     // 数据已经选择
     dataSelected: function (modelData) {
       var _self = this;
-      this.modal=false;
-
+      this.modal = false;
       _self.autoCompleteVisible = false;
 
       if (modelData == undefined) {
         return;
       }
 
-      console.log('已经选择了数据:' + modelData.id);
+      console.log('已经选择了数据:' , modelData);
       var displayValue = '';
       if (modelData.data && modelData.data[_self.displayName]) {
         displayValue = modelData.data[_self.displayName].displayValue[0];
@@ -318,22 +291,23 @@ export default {
 
 <style scoped>
 .auto-complete {
-    left: 0px;
-    top: 34px;
+  left: 0px;
+  top: 34px;
 }
 
 .m-input-group-addon {
-    border-top-right-radius: 5px !important;
-    border-bottom-right-radius: 5px !important;
+  border-top-right-radius: 5px !important;
+  border-bottom-right-radius: 5px !important;
 }
 
 .invalid-input {
-    color: #fff;
-    background-color: #d9534f;
-    border-color: #d43f3a;
+  color: #fff;
+  background-color: #d9534f;
+  border-color: #d43f3a;
 }
+
 .classSize {
-    font-size: 40px;
-    height: 60px;
+  font-size: 40px;
+  height: 60px;
 }
 </style>

+ 50 - 172
packages/modal/src/Modal.vue

@@ -1,76 +1,42 @@
 <template>
-  <teleport to="body">
-    <div
-      v-if="show"
-      :transition="transition"
-    >
-      <div
-        class="modal"
-        @click.self="clickMask"
-      >
-        <div
-          class="modal-dialog"
-          :class="modalClass"
-          name="dialog"
-        >
-          <div class="modal-content">
-            <!--Header-->
-            <div class="modal-header">
-              <a
-                v-if="showTopRightCloseButton"
-                type="button"
-                class="close"
-                @click="cancel"
-              >x</a>
-              <h4 class="modal-title">
-                <slot name="header">
-                  {{ title }}
-                </slot>
-              </h4>
-            </div>
-            <!--Container-->
-            <div class="modal-body">
-              <slot />
-            </div>
-            <!--Footer-->
-            <div class="modal-footer">
-              <button
-                v-if="showCanelButton"
-                type="button"
-                class="btn btn-info"
-                @click="cancel"
-              >
-                {{ $t('lang.modal.cancel') }}
-              </button>
-              <button
-                v-if="showOkButton"
-                type="button"
-                class="btn btn-primary"
-                @click="ok"
-              >
-                {{ $t('lang.modal.confirm') }}
-              </button>
-              <slot name="footer" />
-            </div>
-          </div>
-        </div>
-      </div>
-      <div class="modal-backdrop in" />
+  <a-modal
+    v-model:open="internalVisible" :width="modalWidth" :mask-closable="!force"
+    :closable="showTopRightCloseButton" @ok="handleOk" @cancel="handleCancel"
+  >
+    <!-- 自定义标题插槽 -->
+    <template #title>
+      <slot name="header">
+        {{ title }}
+      </slot>
+    </template>
+
+    <!-- 主体内容 -->
+    <div class="ant-modal-body">
+      <slot />
     </div>
-  </teleport>
+
+    <!-- 自定义底部 -->
+    <template #footer>
+      <div class="ant-modal-footer">
+        <a-space>
+          <a-button v-if="showCanelButton" class="ant-btn ant-btn-default" @click="handleCancel">
+            {{ $t('lang.modal.cancel') }}
+          </a-button>
+          <a-button v-if="showOkButton" type="primary" class="ant-btn ant-btn-primary" @click="handleOk">
+            {{ $t('lang.modal.confirm') }}
+          </a-button>
+          <slot name="footer" />
+        </a-space>
+      </div>
+    </template>
+  </a-modal>
 </template>
 
 <script>
-
-import ModalFix from './ModalFix.js';
-
 export default {
   // eslint-disable-next-line
-    name: 'Modal',
+  name: 'Modal',
   props: {
-    /**
-     * 是否显示模态框
-     */
     show: {
       type: Boolean,
       default: false,
@@ -94,148 +60,60 @@ export default {
     // 为true时无法通过点击遮罩层关闭modal
     force: {
       type: Boolean,
-      default: null,
-    },
-    // 自定义组件transition
-    transition: {
-      type: String,
-      default: '',
+      default: true,
     },
-    // 显示确定按钮
+    // 是否显示确定按钮
     showOkButton: {
       type: Boolean,
       default: true,
     },
-    // 显示取消按钮
+    // 是否显示取消按钮
     showCanelButton: {
       type: Boolean,
       default: true,
     },
-    // 显示标题栏的关闭按钮
+    // 是否显示右上角关闭按钮
     showTopRightCloseButton: {
       type: Boolean,
       default: true,
     },
   },
-
   emits: ['ok', 'cancel', 'close', 'update:show'],
 
   data: function () {
     return {
-      okClass: '',
-      cancelClass: '',
-      closeClass: '',
+      internalVisible: this.show,
     };
   },
-
   computed: {
-    modalClass: function () {
-      return {
-        'modal-lg': this.large || this.large == 'true',
-        'modal-sm': this.small || this.small == 'true',
-        'modal-full': this.full || this.full == 'true',
-      };
+    modalWidth: function () {
+      if (this.full) return '95%';
+      if (this.large) return '80%';
+      if (this.small) return '50%';
+      return undefined; // 默认宽度520px
     },
   },
   watch: {
-    show: function (value) {
-      console.log('modal watch show = ' + value);
-      // 在显示时去掉body滚动条,防止出现双滚动条
-      if (value) {
-        if (document.body.className.indexOf('modal-open') < 0) {
-          document.body.className += ' modal-open';
-        }
-      } else {
-        this.$nextTick(function () {
-          ModalFix.fix();
-        });
-      }
+    show: function (newVal) {
+      this.internalVisible = newVal;
     },
   },
-
-  created: function () {
-    if (this.show) {
-      if (document.body.className.indexOf('modal-open') < 0) {
-        document.body.className += ' modal-open';
-      }
-    }
-  },
-
-
   methods: {
-    ok: function () {
+    handleOk: function () {
       this.$emit('ok');
       this.$emit('update:show', false);
-      this.$nextTick(function () {
-        ModalFix.fix();
-      });
+      this.internalVisible = false;
     },
-
-    cancel: function () {
+    handleCancel: function () {
       this.$emit('cancel');
       this.$emit('update:show', false);
-      this.$nextTick(function () {
-        ModalFix.fix();
-      });
+      this.internalVisible = false;
     },
-
-    close: function () {
+    closeModal: function () {
       this.$emit('close');
       this.$emit('update:show', false);
-      this.$nextTick(function () {
-        ModalFix.fix();
-      });
-    },
-
-    // 点击遮罩层
-    clickMask: function () {
-      if (!this.force) {
-        this.cancel();
-        this.$nextTick(function () {
-          ModalFix.fix();
-        });
-      }
+      this.internalVisible = false;
     },
   },
 };
-</script>
-
-
-<style scoped>
-.modal {
-    display: block;
-}
-.modal-transition {
-    transition: all 0.6s ease;
-}
-.modal-leave {
-    /* 样式没什么用,但可以让根标签的transitionEnd生效,以去掉modal-leave */
-    border-radius: 1px !important;
-}
-.modal-transition .modal-dialog,
-.modal-transition .modal-backdrop {
-    transition: all 0.5s ease;
-}
-.modal-enter .modal-dialog,
-.modal-leave .modal-dialog {
-    opacity: 0;
-    transform: translateY(-30%);
-}
-
-.modal-enter .modal-backdrop,
-.modal-leave .modal-backdrop {
-    opacity: 0;
-}
-
-.modal-full {
-    width: 95%;
-}
-
-.modal-lg {
-    width: 75%;
-}
-
-.modal-sm {
-    width: 50%;
-}
-</style>
+</script>

+ 20 - 49
packages/navbar/src/Navbar.vue

@@ -1,72 +1,43 @@
 <template>
-  <div class="m-page-header">
-    <h3>
-      <span
-        v-if="isGoBack == true || isGoBack == 'true'"
-        class="glyphicon glyphicon-circle-arrow-left m-page-header-image"
-        @click="goBack"
-      />
-            
-      {{ title }}
-            
-      <div class="pull-right">
-        <slot />
-      </div>
-    </h3>
-  </div>
+  <a-page-header
+    :title="title" :back-icon="isGoBack ? undefined : false"
+    style="padding:0;border-bottom: solid 1px #d1cfcf;margin-bottom: 8px;" @back="goBack"
+  >
+    <template #backIcon>
+      <ArrowLeftOutlined />
+    </template>
+    <template #extra>
+      <slot />
+    </template>
+  </a-page-header>
 </template>
 
 <script>
+import { ArrowLeftOutlined } from '@ant-design/icons-vue';
 
 export default {
   // eslint-disable-next-line
   name: 'Navbar',
-
   components: {
-
+    ArrowLeftOutlined,
   },
   props: {
-    // 是否需要返回按钮,true:需要返回按钮,false:不需要返回按钮
-    'isGoBack':{
+    isGoBack: {
       type: Boolean,
       default: false,
     },
-    // 标题
-    'title':
-    {
+    title: {
       type: String,
       default: '',
     },
   },
-
-  data: function () {
-    return {
-      data: '',
-    };
-  },
-
+  emits: ['back'],
   methods: {
-    goBack: function () {
+    goBack() {
+      if (!this.isGoBack) return;
       history.back();
+      this.$emit('back');
     },
   },
 };
-</script>
-
-<style scoped>
-.m-page-header {
-    margin: 0px 5px 5px 0px;
-    padding: 0px;
-    border-bottom: 1px solid #eee;
-}
-
-.m-page-header h3 {
-    margin: 0px;
-    padding: 5px 0px 9px 0px;
-}
-
-.m-page-header-image {
-    top: 4px;
-    cursor: pointer;
-}
-</style>
+</script>

+ 62 - 69
packages/print/src/PrintEpc.vue

@@ -3,73 +3,36 @@
  */
 
 <template>
-  <div>
-    <!-- 打印结果模态框 -->
-    <Modal
-      v-model:show="modal"
-      title="发卡机发卡"
-    >
-      <div class="form-horizontal">
-        <div class="form-group">
-          <label class="col-sm-2 control-label">EPC</label>
-          <div class="col-sm-10">
-            <input v-model="lastWriteEpc" type="text" class="form-control" placeholder="EPC" />
-          </div>
-        </div>
+  <Modal
+    v-model:show="modal"
+    title="发卡机发卡"
+    :footer="null"
+    @cancel="modal = false"
+  >
+    <a-form layout="horizontal">
+      <a-form-item label="EPC" :label-col="{ span: 4 }" :wrapper-col="{ span: 20 }">
+        <a-input v-model:value="lastWriteEpc" placeholder="请输入EPC" />
+      </a-form-item>
+
+      <!-- 操作结果提示 -->
+      <a-alert
+        v-if="printResult"
+        :message="resultMessage"
+        :type="alertType"
+        show-icon
+        class="mb-4"
+      />
+
+      <!-- 操作按钮组 -->
+      <div class="action-buttons">
+        <a-button type="primary" @click="printSingleEpc(lastWriteEpc)">打印</a-button>
+        <a-button @click="restoreEpc">重置</a-button>
+        <a-button @click="readEpc">读取</a-button>
       </div>
-      
-
-      <div
-        v-if="printResult != null && printResult.command == 'restore'"
-        class="alert alert-danger"
-        role="alert"
-      >
-        {{ printResult.success ? '操作成功' : '操作失败' }},{{ printResult.message }}
-      </div>
-
-      <button
-        type="button"
-        class="btn btn-default m-button"
-        @click="printSingleEpc(lastWriteEpc)"
-      >
-        打印
-      </button>
-
-      <button
-        type="button"
-        class="btn btn-default m-button"
-        @click="restoreEpc"
-      >
-        重置
-      </button>
-
-      <button
-        type="button"
-        class="btn btn-default m-button"
-        @click="readEpc"
-      >
-        读取
-      </button>
-
-
-      <div
-        v-if="printResult != null && printResult.command == 'write'"
-        class="alert alert-danger"
-        role="alert"
-      >
-        {{ printResult.success ? '操作成功' : '操作失败' }},{{ printResult.message }}待写入EPC:{{ lastWriteEpc }}
-      </div>
-      
-      <div
-        v-if="printResult != null && printResult.command == 'read'"
-        class="alert alert-info"
-        role="alert"
-      >
-        {{ printResult.success ? '操作成功' : '操作失败' }},读取到{{ printResult.tagCount }}个标签,{{ printResult.epcs }}
-      </div>
-    </Modal>
+    </a-form>
+    
     <Loading v-if="loading" />
-  </div>
+  </Modal>
 </template>
 
 <script>
@@ -123,6 +86,26 @@ export default {
         this.$emit('update:visible', value);
       },
     },
+    resultMessage() {
+      if (!this.printResult) return '';
+      const { command, success, message, tagCount, epcs } = this.printResult;
+      const base = success ? '操作成功' : '操作失败';
+      
+      switch(command) {
+      case 'restore':
+        return `${base}, ${message ? message : ''}`;
+      case 'write':
+        return `${base}, ${message ? message : ''} 待写入EPC:${this.lastWriteEpc}`;
+      case 'read':
+        return `${base}, 读取到${tagCount}个标签, ${epcs}`;
+      default:
+        return message;
+      }
+    },
+    alertType() {
+      if (!this.printResult) return 'info';
+      return this.printResult.success ? 'success' : 'error';
+    },
   },
 
 
@@ -248,8 +231,18 @@ export default {
 </script>
 
 <style scoped>
-  .m-button{
-    margin-right: 1rem;
-    margin-bottom: 1rem;
-  }
+.action-buttons {
+  display: flex;
+  gap: 12px;
+  margin-top: 12px;
+}
+
+.mb-4 {
+  margin: 12px 0;
+}
+
+:deep(.ant-form-item-label > label) {
+  font-size: 14px !important;
+  font-weight: 500 !important;
+}
 </style>

+ 44 - 25
packages/print/src/PrintWidget.vue

@@ -1,30 +1,32 @@
 <template>
-  <div class="form-group">
-    <label for="select-printer">{{ $t('lang.PrintWidget.selectPrinter') }}</label>
-    <select
-      id="select-printer"
-      v-model="selectedPrinterComputed"
-      class="form-control"
-      style="width: 15em"
-      @change="getPrintName"
-    >
-      <option value="" />
-      <option
-        v-for="printer in printers"
-        :key="printer.name"
-        :value="printer.name"
+  <a-form-item :label="$t('lang.PrintWidget.selectPrinter')">
+    <div class="ant-print-widget-container">
+      <a-select
+        id="select-printer"
+        v-model:value="selectedPrinterComputed"
+        class="ant-print-select"
+        :placeholder="$t('lang.PrintWidget.selectPrinter')"
+        @change="getPrintName"
       >
-        {{ printer.name }}
-      </option>
-    </select>
-    <button
-      v-if="showPrintButton"
-      class="btn btn-default"
-      @click="print()"
-    >
-      {{ $t('lang.PrintWidget.printing') }}
-    </button>
-  </div>
+        <a-select-option value="" />
+        <a-select-option
+          v-for="printer in printers"
+          :key="printer.name"
+          :value="printer.name"
+        >
+          {{ printer.name }}
+        </a-select-option>
+      </a-select>
+      <a-button
+        v-if="showPrintButton"
+        type="primary"
+        class="ant-print-btn"
+        @click="print"
+      >
+        {{ $t('lang.PrintWidget.printing') }}
+      </a-button>
+    </div>
+  </a-form-item>
 </template>
 
 <script>
@@ -167,4 +169,21 @@ export default {
 .m-row {
     margin-bottom: 15px;
 }
+.ant-print-widget-container {
+  display: flex;
+  gap: 12px;
+  align-items: center;
+}
+
+.ant-print-select {
+  width: 240px;
+}
+
+.ant-print-btn {
+  flex-shrink: 0;
+}
+:deep(.ant-form-item-label > label) {
+  font-size: 14px !important;
+  font-weight: 600 !important;
+}
 </style>

+ 114 - 33
packages/print/src/WriteEpc.vue

@@ -1,46 +1,71 @@
 /**
- * EPC 打印界面
- */
+* EPC 打印界面
+*/
 
 <template>
   <div>
     <!-- 打印结果模态框 -->
     <Modal v-model:show="modal" title="发卡机发卡">
-      <div class="form-horizontal">
-        <div class="form-group epc-container">
-          <label class="col-sm-2 epc-label">EPC</label>
-          <div style="width: 84%">
-            <input
-              v-model="lastWriteEpc"
-              type="text"
-              class="form-control"
-              placeholder="EPC"
-            />
-          </div>
+      <a-form layout="vertical">
+        <a-form-item label="EPC" :label-col="{ span: 2 }" :wrapper-col="{ span: 20 }">
+          <a-input v-model:value="lastWriteEpc" placeholder="请输入EPC" />
+        </a-form-item>
+
+        <div class="action-buttons">
+          <a-button type="primary" @click="printSingleEpc(lastWriteEpc)">打印</a-button>
+          <a-button @click="restoreEpc">重置</a-button>
+          <a-button @click="readEpc">读取</a-button>
         </div>
-      </div>
+      </a-form>
 
-      <button
-        type="button"
-        class="btn btn-default m-button"
-        @click="writeSingleEpc(lastWriteEpc)"
-      >
-        写入
-      </button>
+      <div class="message-container">
+        <!-- Write Command -->
+        <div
+          v-if="printResult != null && printResult.command == 'write'"
+          :class="['message', printResult.errorCode === 0 ? 'success' : 'error']" role="alert"
+        >
+          <p v-if="printResult.errorCode === 0">
+            <span class="icon">✓</span> 操作成功 EPC:{{ lastWriteEpc }} 写入成功
+          </p>
+          <p v-else-if="printResult.errorCode === 1">
+            <span class="icon">✗</span> 操作失败 {{ printResult.errorMessage ? printResult.errorMessage : '' }} 请先重置EPC。
+          </p>
+          <p v-else>
+            <span class="icon">✗</span> 操作失败 {{ printResult.errorMessage ? printResult.errorMessage : '' }} 待写入EPC:{{
+              lastWriteEpc
+            }}
+          </p>
+        </div>
 
-      <button
-        type="button"
-        class="btn btn-default m-button"
-        @click="restoreEpc"
-      >
-        重置
-      </button>
+        <!-- Restore Command -->
+        <div
+          v-if="printResult != null && printResult.command == 'restore'"
+          :class="['message', printResult.errorCode === 0 ? 'success' : 'error']" role="alert"
+        >
+          <p>
+            <span class="icon">{{ printResult.errorCode === 0 ? '✓' : '✗' }}</span>
+            {{ printResult.errorCode === 0 ? "操作成功" : "操作失败" }}
+            {{ printResult.errorMessage ? printResult.errorMessage : '' }}
+          </p>
+        </div>
 
-      <button type="button" class="btn btn-default m-button" @click="readEpc">
-        读取
-      </button>
+        <!-- Read Command -->
+        <div
+          v-if="printResult != null && printResult.command == 'read'"
+          :class="['message', printResult.errorCode === 0 ? 'success' : 'error']" role="alert"
+        >
+          <p class="break-word">
+            <span class="icon">{{ printResult.errorCode === 0 ? '✓' : '✗' }}</span>
+            {{ printResult.errorCode === 0 ? "操作成功" : "操作失败" }},{{
+              printResult.epcs && printResult.epcs.length > 0
+                ? `读取到 ${printResult.tagCount} 个标签:${printResult.epcs}`
+                : printResult.errorMessage ? printResult.errorMessage : ''
+            }}
+          </p>
+        </div>
+      </div>
 
-      <div
+      <!-- <div
         v-if="printResult != null && printResult.command == 'write'"
         :class="
           printResult.errorCode === 0
@@ -93,7 +118,7 @@
               : printResult.errorMessage
           }}
         </p>
-      </div>
+      </div> -->
     </Modal>
     <Loading v-if="loading" />
   </div>
@@ -247,13 +272,69 @@ export default {
   margin-right: 1rem;
   margin-bottom: 1rem;
 }
+
 .epc-container {
   display: flex;
   align-items: center;
 }
+
 .epc-label {
   margin-bottom: 0;
   width: 80px;
   text-align: center;
 }
+
+.action-buttons {
+  display: flex;
+  gap: 12px;
+  margin-top: 12px;
+}
+
+.message-container {
+  margin: 1rem 0;
+}
+
+.message {
+  padding: 15px;
+  margin-bottom: 1rem;
+  border: 1px solid transparent;
+  border-radius: 4px;
+  font-size: 14px;
+}
+
+.message.success {
+  background-color: #dff0d8;
+  border-color: #d6e9c6;
+  color: #3c763d;
+}
+
+.message.error {
+  background-color: #f2dede;
+  border-color: #ebccd1;
+  color: #a94442;
+}
+
+.icon {
+  margin-right: 8px;
+  font-weight: bold;
+}
+
+.break-word {
+  word-wrap: break-word;
+  white-space: pre-wrap;
+}
+
+:deep(.ant-form-item-label) {
+  text-align: left;
+  font-weight: 500;
+}
+
+:deep(.ant-form-item-label > label) {
+  font-size: 14px !important;
+  font-weight: 500 !important;
+}
+
+:deep(.ant-input) {
+  width: 100%;
+}
 </style>

+ 31 - 11
packages/process/src/EnumSelectWidget.vue

@@ -1,5 +1,16 @@
 <template>
-  <div class="form-group">
+  <div :style="style">
+    <a-select
+      v-model:value="selectedValue"
+      @change="selectChanged"
+    >
+      <a-select-option v-for="keyValue in keyValues" :key="keyValue.keyStr" :value="keyValue.keyStr">
+        {{ keyValue.value }}
+      </a-select-option>
+    </a-select>
+  </div>
+
+  <!-- <div class="form-group">
     <div>
       <select
         v-model="selectedValue"
@@ -14,7 +25,7 @@
         </option>
       </select>
     </div>
-  </div>
+  </div> -->
 </template>
 
 <script>
@@ -30,6 +41,10 @@ export default {
       type: String,
       default: '',
     },
+    'style': {
+      type: Object,
+      default: null,
+    },
   },
 
   emits: ['valueChanged'],
@@ -39,16 +54,21 @@ export default {
     };
   },
 
-  watch: {
-    selectedValue: function (curVal, oldVal) {
-      console.log('Enum Selected Value changed:' + curVal);
-      if (curVal != oldVal) {
-        this.$emit('valueChanged', curVal);
-      }
-    },
+  // watch: {
+  //   selectedValue: function (curVal, oldVal) {
+  //     console.log('Enum Selected Value changed:' + curVal);
+  //     if (curVal != oldVal) {
+  //       this.$emit('valueChanged', curVal);
+  //     }
+  //   },
 
-    enumValue: function (val) {
-      this.selectedValue = val;
+  //   enumValue: function (val) {
+  //     this.selectedValue = val;
+  //   },
+  // },
+  methods: {
+    selectChanged(value) {
+      this.$emit('valueChanged', value);
     },
   },
 };

+ 121 - 139
packages/process/src/ProcessReportDynamic.vue

@@ -1,147 +1,92 @@
 <template>
   <div>
-    <Navbar
-      :title="processReportDto.name"
-      :is-go-back="processReportDto.goback"
-    />
+    <Navbar :title="processReportDto.name" :is-go-back="processReportDto.goback" />
     <div>
       <h5>{{ processReportDto.description }}</h5>
     </div>
-    <div>
-      <div class="form-inline">
-        <div
-          v-for="(item, index) in parameters"
-          :key="'parameter-' + index"
-          class="form-group m-form-group"
+    <a-form :colon="false">
+      <a-row :gutter="[8, 14]" justify="space-start">
+        <a-col
+          v-for="(item, index) in parameters" :key="'parameter-' + index"
+          style="display: flex; align-items: center;"
         >
-          <div class="form-inline-div">
-            <label
-              v-if="item.displayType != 'ListBoxEnumEditor'"
-              :for="'editor_' + item.id"
-              class="m-label"
-            >{{ item.displayName }}</label>
-
-            <input
-              v-if="item.displayType =='TextEditor'"
-              :id="'editor_' + item.id"
-              v-model="item.fieldValue.displayValue[0]"
-              autocomplete="off"
-              type="text"
-              class="form-control m-input-group"
-              placeholder="请输入内容"
-              @change="valueChanged(item)"
+          <a-form-item
+            :label="item.displayType !== 'ListBoxEnumEditor' ? item.displayName : ''"
+            :label-col="{ style: 'width: 108px' }" wrap-col="{ style: 'width: 230px' }" class="horizontal-form-item"
+          >
+            <a-input
+              v-if="item.displayType === 'TextEditor'" v-model:value="item.fieldValue.displayValue[0]"
+              class="w-full" placeholder="请输入内容" @change="valueChanged(item)"
             />
 
-            <textarea
-              v-if="item.displayType =='TextAreaEditor'"
-              :id="'editor_' + item.id"
-              v-model="item.fieldValue.displayValue[0]"
-              rows="5"
-              type="text"
-              class="form-control m-input-group"
-              placeholder="请输入内容"
-              @change="valueChanged(item)"
+            <a-textarea
+              v-if="item.displayType === 'TextAreaEditor'" v-model:value="item.fieldValue.displayValue[0]"
+              placeholder="请输入内容" :rows="1" class="w-full" @change="valueChanged(item)"
             />
 
-            <input
-              v-if="item.displayType =='NumberEditor'"
-              :id="'editor_' + item.id"
-              v-model="item.fieldValue.displayValue[0]"
-              autocomplete="off"
-              type="number"
-              class="form-control m-input-group"
-              placeholder="请输入数字"
-              @change="valueChanged(item)"
+            <a-input-number
+              v-if="item.displayType === 'NumberEditor'" v-model:value="item.fieldValue.displayValue[0]"
+              placeholder="请输入数字" class="w-full" @change="valueChanged(item)"
             />
 
-
+            <!-- 开关组件 -->
             <Switches
-              v-if="item.displayType =='CheckBoxEditor'"
-              v-model="item.fieldValue.displayValue[0]"
-              color="green"
-              type-bold="true"
+              v-if="item.displayType === 'CheckBoxEditor'" v-model:checked="item.fieldValue.displayValue[0]"
               @change="valueChanged(item)"
             />
+
+            <!-- 日期时间组件 -->
             <DateTime
-              v-if="item.displayType =='DateTimeBoxEditor'"
-              :id="'editor_' + item.id"
-              v-model="item.fieldValue.displayValue[0]"
-              class="m-input-group"
-              name="datetime"
+              v-if="item.displayType == 'DateTimeBoxEditor'" :id="'editor_' + item.id"
+              v-model="item.fieldValue.displayValue[0]" class="w-full" name="datetime"
               @update:model-value="changeValue(item, $event)"
             />
 
             <!-- 日期选择器  -->
             <Date
-              v-if="item.displayType =='DateBoxEditor'"
-              :id="'DateBoxEditor_' + item.id"
-              v-model="item.fieldValue.displayValue[0]"
-              class="m-input-group"
-              @update:model-value="changeValue(item, $event)"
+              v-if="item.displayType == 'DateBoxEditor'" :id="'DateBoxEditor_' + item.id"
+              v-model="item.fieldValue.displayValue[0]" @update:model-value="changeValue(item, $event)"
             />
 
             <EnumSelectWidget
-              v-if="item.displayType =='ListBoxEnumEditor'"
-              :field="item"
-              :field-value="item.fieldValue"
-              class="m-input-group"
-              @value-changed="valueChanged($event, item)"
+              v-if="item.displayType == 'ListBoxEnumEditor'" style="width: 230px;" :field="item"
+              :field-value="item.fieldValue" @value-changed="valueChanged($event, item)"
             />
 
             <MultiSearchWidget
-              v-if="item.displayType =='MultiSearchBoxEditor'"
-              :info-window-no="item.infoWindowNo"              
-              :where-clause-source="{'processReportParameter': {'processReportNo': processReportDto.no, 'fieldName': item.fieldName}}"
-              :field="item"
-              :field-value="item.fieldValue"
-              class="m-input-group"
-              :display-name="item.listDisplayFieldNames"
+              v-if="item.displayType == 'MultiSearchBoxEditor'" :info-window-no="item.infoWindowNo"
+              style="width: 230px;"
+              :where-clause-source="{ 'processReportParameter': { 'processReportNo': processReportDto.no, 'fieldName': item.fieldName } }"
+              :field="item" :field-value="item.fieldValue" :display-name="item.listDisplayFieldNames"
               @value-changed="tabValueChanged($event, item)"
             />
 
             <SearchWidget
-              v-if="item.displayType =='SearchBoxEditor'"
-              :where-clause-source="{'processReportParameter': {'processReportNo': processReportDto.no, 'fieldName': item.fieldName}}"
-              :info-window-no="item.infoWindowNo"
-              :field="item"
-              :field-value="item.fieldValue"
-              :display-name="item.listDisplayFieldNames"
-              class="m-input-group"
-              :parent-model-data="parentModelData"
+              v-if="item.displayType == 'SearchBoxEditor'" style="width: 230px;"
+              :where-clause-source="{ 'processReportParameter': { 'processReportNo': processReportDto.no, 'fieldName': item.fieldName } }"
+              :info-window-no="item.infoWindowNo" :field="item" :field-value="item.fieldValue"
+              :display-name="item.listDisplayFieldNames" :parent-model-data="parentModelData"
               @value-changed="tabValueChanged($event, item)"
             />
-          </div>
-          <!--<div v-if = "item.constraintEnum == 'Between'" class="form-inline-div">
-						<label v-if="item.displayType != 'ListBoxEnumEditor'" :for="'editor_' + item.id">——</label>
-						<input autocomplete="off" v-if="item.displayType =='NumberEditor'" type="number" v-model="item.value2" 
-              class="form-control m-input-group" :id="'editor_' + item.id" placeholder="请输入数字" @change="valueChanged(item)"/>
-		
-						<DateTime v-if="item.displayType =='DateTimeBoxEditor'" :dateValue="item.value2" 
-            class="form-control m-input-group" name="datetime" 
-            :id="'editor_' + item.id" @on-value-change="changeValue(item, $event)" />
-					</div>	-->
-        </div>
-      </div>
+          </a-form-item>
+        </a-col>
+      </a-row>
+    </a-form>
+
+    <div>
       <div class="form-group">
-        <button
+        <a-button
           v-if="processReportDto.htmlHelpUrl != null && processReportDto.htmlHelpUrl != ''"
-          class="btn btn-default"
           @click="openHtmlHelp(processReportDto.htmlHelpUrl)"
         >
           <span class="glyphicon glyphicon-question-sign" />
-        </button>
-        <input
-          autocomplete="off"
-          type="button"
-          class="btn btn-primary"
-          style="margin-top: 15px;"
-          value="确定"
-          @click="runProcessDynamic()"
-        />
+        </a-button>
+        <a-button type="primary" style="margin-top: 15px;" @click="runProcessDynamic()">
+          确定
+        </a-button>
       </div>
       <ProcessReportResultPreview
-        :process-report-result="processReportResult"
-        :pdf-only="processReportDto.pdfOnly"
+        :process-report-result="processReportResult" :pdf-only="processReportDto.pdfOnly"
         :excel-only="processReportDto.excelOnly"
       />
     </div>
@@ -162,7 +107,7 @@ import Loading from '../../loading/src/Loading.vue';
 import ProcessReportResultPreview from './ProcessReportResultPreview.vue';
 import SearchWidget from '../../info/src/SearchWidget.vue';
 import Switches from '../../switches/src/Switches.vue';
-
+import EnumSelectWidget from './EnumSelectWidget.vue';
 
 
 export default {
@@ -170,23 +115,24 @@ export default {
   components: {
     DateTime,
     Date,
-    MultiSearchWidget : defineAsyncComponent(() =>
+    MultiSearchWidget: defineAsyncComponent(() =>
       import('../../info/src/MultiSearchWidget.vue'),
     ),
     Loading,
     ProcessReportResultPreview,
     SearchWidget,
-    Switches,
+    EnumSelectWidget,
+    // Switches,
     Navbar,
   },
   props: {
-    'processReportDto':{
+    'processReportDto': {
       type: Object,
       default: null,
     },
   },
 
-  emits:['valueChanged'],
+  emits: ['valueChanged'],
   data: function () {
     return {
       'processReportId': '',
@@ -305,13 +251,12 @@ export default {
           data: {},
         },
       };
-      _self.parameters.forEach(function (item) {
-        var fieldName = item.fieldName;
-        _self.processResultData.modelData.data[fieldName] = item.fieldValue;
+      const modelData = _self.processResultData.modelData.data;
+      _self.parameters.forEach(item => {
+        modelData[item.fieldName] = item.fieldValue;
       });
       _self.processReportResult = {};
-
-      _self.loading=true;
+      _self.loading = true;
       $.ajax({
         url: Common.getApiURL('ProcessReportResource/runProcessDynamic'),
         type: 'post',
@@ -322,20 +267,20 @@ export default {
         contentType: 'application/json',
         data: JSON.stringify(_self.processResultData),
         success: function (data) {
-          _self.loading=false;
+          _self.loading = false;
           _self.processReportResult = data;
 
           if (_self.processReportResult.reportResults != undefined && _self.processReportResult.reportResults.length > 0) {
             _self.processReportResult.reportResults.forEach(function (item, index) {
-              if(item.reportDefinitionType!=='ExcelReport'){
-                item.previewIndex=1;
-              }else{
-                item.previewIndex=2;
+              if (item.reportDefinitionType !== 'ExcelReport') {
+                item.previewIndex = 1;
+              } else {
+                item.previewIndex = 2;
               }
               if (index == 0) {
-                item.showPreview=true;
+                item.showPreview = true;
               } else {
-                item.showPreview=false;
+                item.showPreview = false;
               }
             });
           }
@@ -345,7 +290,7 @@ export default {
 
         },
         error: function (XMLHttpRequest, textStatus, errorThrown) {
-          _self.loading=false;
+          _self.loading = false;
           Common.processException(XMLHttpRequest, textStatus, errorThrown);
         },
       });
@@ -358,7 +303,7 @@ export default {
          * @return {void}          
          */
     changeValue: function (item, newValue) {
-      item.fieldValue.displayValue[0]=newValue;
+      item.fieldValue.displayValue[0] = newValue;
       this.valueChanged(item);
     },
 
@@ -369,6 +314,7 @@ export default {
          * @return {void}               
          */
     tabValueChanged: function (newFieldValue, item) {
+      console.log('tabValueChanged', newFieldValue, item);
       item.fieldValue = newFieldValue;
       this.valueChanged(item);
     },
@@ -432,38 +378,74 @@ export default {
 </script>
 <style scoped>
 .m-form-group label {
-    font-size: 15px;
-    width: 80px;
-    text-align: center;
+  font-size: 15px;
+  width: 80px;
+  text-align: center;
 }
 
 .processResult-textarea {
-    width: 100%;
-    height: 200px;
+  width: 100%;
+  height: 200px;
 }
 
 .form-input {
-    border-radius: 4px !important;
+  border-radius: 4px !important;
 }
 
 .form-inline-div {
-    display: inline;
+  display: inline;
 }
 
 .m-form-group {
-    margin-left: 5px !important;
-    margin-right: 5px !important;
-    margin-bottom: 5px !important;
+  margin-left: 5px !important;
+  margin-right: 5px !important;
+  margin-bottom: 5px !important;
 }
 
 .m-input-group {
-    border-radius: 4px !important;
-    width: 200px !important;
+  border-radius: 4px !important;
+  width: 200px !important;
 }
+
 .m-label {
-    width: 5em;
-    margin-left: 1em;
-    margin-right: 1em;
-    display: inline;
+  width: 5em;
+  margin-left: 1em;
+  margin-right: 1em;
+  display: inline;
+}
+
+/* 添加横向布局样式 */
+.horizontal-form-item {
+  display: flex;
+  align-items: center;
+  gap: 8px;
+}
+
+:deep(.ant-form-item) {
+  margin-bottom: -5px !important;
+}
+
+/* 调整标签样式 */
+:deep(.ant-form-item-label) {
+  flex: 0 0 auto;
+  white-space: nowrap;
+  overflow: visible;
+  text-overflow: unset;
+}
+
+/* 确保控件容器填充剩余空间 */
+:deep(.ant-form-item-control) {
+  flex: 1;
+  min-width: 0;
+}
+
+/* 设置组件宽度 */
+.w-full {
+  width: 230px;
+}
+
+:deep(.ant-form-item-label > label) {
+  font-size: 14px !important;
+  font-weight: 600 !important;
 }
 </style>

+ 153 - 114
packages/process/src/ProcessReportResultPreview.vue

@@ -33,133 +33,103 @@
       :process-report-result="processReportResult"
     />
 
-    <template
-      v-for="(reportResult, index) in processReportResult.reportResults"
-      :key="'reportResult-' + index"
+    <a-collapse
+      v-model:activeKey="activeKeys"
+      class="custom-collapse"
     >
-      <div
-        v-if="processReportResult.reportResults != undefined"
-        id="pr.id"
-        class="form-group"
+      <a-collapse-panel
+        v-for="(reportResult, index) in processReportResult.reportResults"
+        v-show="processReportResult.reportResults != undefined"
+        :key="'reportResult-' + index"
+        :class="'report-panel-' + index"
+        :show-arrow="false"
       >
-        <div class="panel panel-default">
-          <div
-            class="panel-heading"
-            style="height: 50px;"
-            @click.self="reportResult.showPreview = !reportResult.showPreview"
-          >
-            <div class="pull-left">
-              {{ index + 1 + (processReportResult.processResult == undefined ? 0 : 1) }}.{{ reportResult.reportName }}
-            </div>
-            <div
-              v-if="reportResult.reportDefinitionType !== 'ExcelReport'"
-              class="pull-left"
-              style="padding-left: 30px; cursor: pointer;"
-              @click="iframeBack(reportResult, index)"
-            >
-              后退
-            </div>
-            <div
-              v-if="reportResult.reportDefinitionType !== 'ExcelReport'"
-              class="pull-left"
-              style="padding-left: 30px; cursor: pointer;"
-              @click="iframeForward(reportResult, index)"
-            >
-              前进
-            </div>
-            <div
-              v-if="reportResult.reportDefinitionType == 'UReport2'"
-              class="pull-left"
-              style="padding-left: 30px; cursor: pointer;"
-              @click="editReport(reportResult, index)"
-            >
-              编辑
+        <!-- 自定义面板头部 -->
+        <template #header>
+          <div class="panel-header-content">
+            <!-- 左侧区域 -->
+            <div class="header-left">
+              <span class="panel-title">
+                {{ index + 1 + (processReportResult.processResult == undefined ? 0 : 1) }}.{{ reportResult.reportName }}
+              </span>
+            
+              <!-- 操作按钮组 -->
+              <a-space v-if="reportResult.reportDefinitionType !== 'ExcelReport'" class="action-buttons">
+                <a-button type="text" @click.stop="iframeBack(reportResult, index)">后退</a-button>
+                <a-button type="text" @click.stop="iframeForward(reportResult, index)">前进</a-button>
+                <a-button 
+                  v-if="reportResult.reportDefinitionType == 'UReport2'"
+                  type="text" 
+                  @click.stop="editReport(reportResult, index)"
+                >
+                  编辑
+                </a-button>
+              </a-space>
             </div>
-            <div
-              class="pull-right"
-              style="width: 200px;"
-            >
-              <div class="input-group m-input-group">
-                <select
+
+            <!-- 右侧下载控制 -->
+            <div class="header-right">
+              <a-space @click.stop>
+                <a-select
                   v-if="reportResult.reportDefinitionType !== 'ExcelReport'"
-                  v-model="reportResult.previewIndex"
-                  class="form-control"
+                  v-model:value="reportResult.previewIndex"
+                  style="width: 100px"
                 >
-                  <option
-                    v-if="excelOnly != true"
-                    value="1"
-                  >
-                    PDF
-                  </option>
-                  <option
-                    v-if="pdfOnly != true"
-                    value="2"
-                  >
-                    Excel
-                  </option>
-                </select>
-                <select
+                  <a-select-option v-if="!excelOnly" :value="1">PDF</a-select-option>
+                  <a-select-option v-if="!pdfOnly" :value="2">Excel</a-select-option>
+                </a-select>
+              
+                <a-select
                   v-else-if="reportResult.reportDefinitionType == 'ExcelReport'"
-                  v-model="reportResult.previewIndex"
-                  class="form-control"
+                  v-model:value="reportResult.previewIndex"
+                  style="width: 100px"
                 >
-                  <option
-                    v-if="pdfOnly != true"
-                    value="2"
-                  >
-                    Excel
-                  </option>
-                </select>
-                <span
-                  class="input-group-addon btn-download"
-                  @click="download(reportResult)"
-                >下载</span>
-              </div>
+                  <a-select-option v-if="!pdfOnly" :value="2">Excel</a-select-option>
+                </a-select>
+
+                <a-button
+                  type="primary"
+                  @click.stop="download(reportResult)"
+                >
+                  下载
+                </a-button>
+              </a-space>
             </div>
           </div>
-          <div
-            v-if="reportResult.showPreview"
-            class="panel-body"
-          >
-            <div v-if="reportResult.isSuccess">
-              <div v-if="reportResult.reportDefinitionType !== 'ExcelReport'">
-                <div
-                  v-if="reportResult.previewIndex == 1"
-                  class="embed-responsive embed-responsive-4by3"
-                >
-                  <embed
-                    :id="uuid + 'pdfIframe' + index"
-                    class="embed-responsive-item"
-                    type="application/pdf"
-                    :src="getReport(reportResult.pdfDownLoadUrl, '#' + uuid + 'pdfIframe' + index)"
-                  />
-                </div>
-                <div
-                  v-else
-                  class="embed-responsive embed-responsive-4by3"
-                >
-                  <iframe
-                    :id="uuid + 'htmlIframe' + index"
-                    class="embed-responsive-item"
-                    :src="getReport(reportResult.htmlPreviewUrl, '#' + uuid + 'htmlIframe' + index)"
-                  />
-                </div>
-              </div>
-              <div v-else style="width: 100%;height: 500px;">
-                <iframe
-                  :id="uuid + 'htmlIframe' + index"
-                  style="width: 100%;height: 100%;"
-                  :src="reportResult.htmlPreviewUrl"
-                />
-              </div>
+        </template>
+
+        <!-- 面板内容 -->
+        <div v-if="reportResult.isSuccess">
+          <div v-if="reportResult.reportDefinitionType !== 'ExcelReport'">
+            <div v-if="reportResult.previewIndex == 1" class="preview-container">
+              <embed
+                :id="uuid + 'pdfIframe' + index"
+                class="preview-content"
+                type="application/pdf"
+                :src="getReport(reportResult.pdfDownLoadUrl, '#' + uuid + 'pdfIframe' + index)"
+              />
             </div>
-            <div v-else>
-              生成失败
+            <div v-else class="preview-container">
+              <iframe
+                :id="uuid + 'htmlIframe' + index"
+                class="preview-content"
+                :src="getReport(reportResult.htmlPreviewUrl, '#' + uuid + 'htmlIframe' + index)"
+              />
             </div>
           </div>
+          <div v-else class="excel-preview">
+            <iframe
+              :id="uuid + 'htmlIframe' + index"
+              class="full-size-iframe"
+              :src="reportResult.htmlPreviewUrl"
+            />
+          </div>
         </div>
-      </div>
-    </template>
+        <div v-else class="error-message">
+          生成失败
+        </div>
+      </a-collapse-panel>
+    </a-collapse>
   </div>
 </template>
 
@@ -195,8 +165,10 @@ export default {
     return {
       'uuid': Uuid.createUUID(),
       loginClientName: '',
+      activeKeys: [],
     };
   },
+  
   computed: {
     // 是否文本区域显示流程结果
     isTextAreaShowProcessResult: function () {
@@ -219,6 +191,18 @@ export default {
     },
 
   },
+  watch: {
+    processReportResult: {
+      handler(newVal) {
+        if (newVal.reportResults && newVal.reportResults.length > 0) {
+          this.activeKeys = newVal.reportResults.map((_, index) => `reportResult-${index}`);
+        } else {
+          this.activeKeys = [];
+        }
+      },
+      immediate: true,
+    },
+  },
   mounted: function () {
     const loginInfoJson = localStorage.getItem('#LoginInfo');
     const loginInfo = JSON.parse(loginInfoJson);
@@ -296,4 +280,59 @@ export default {
 .btn-download {
     cursor: pointer;
 }
+.panel-header-content {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  width: 100%;
+  height: 50px;
+}
+
+.header-left {
+  display: flex;
+  align-items: center;
+  gap: 20px;
+}
+
+.panel-title {
+  font-weight: 500;
+}
+
+.action-buttons :deep(.ant-btn) {
+  padding: 0 8px;
+}
+
+.preview-container {
+  position: relative;
+  /* padding-bottom: 75%; */
+  height: 500px;
+}
+
+.preview-content {
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 500px;
+}
+
+.excel-preview {
+  width: 100%;
+  height: 500px;
+}
+
+.full-size-iframe {
+  width: 100%;
+  height: 500px;
+  border: none;
+}
+
+.error-message {
+  padding: 20px;
+  color: #ff4d4f;
+  text-align: center;
+}
+:deep(.ant-collapse>.ant-collapse-item >.ant-collapse-header) {
+  padding: 0 16px !important;
+}
 </style>

+ 104 - 127
packages/process/src/ProcessReportStatic.vue

@@ -1,153 +1,103 @@
 <template>
   <div>
-    <Navbar
-      :title="processReportDto.name"
-      :is-go-back="processReportDto.goback"
-    />
+    <Navbar :title="processReportDto.name" :is-go-back="processReportDto.goback" />
     <div>
       <h5>{{ processReportDto.description }}</h5>
     </div>
-    <div class="form-inline">
-      <template v-for="item in processReportDtos.processReportParameters" :key="'processReportParameter-' + item.fieldName">
-        <div
-        
-          v-if="processReportDtos != undefined && processReportDtos.processReportParameters != undefined"
-        
-          class="form-group"
+    <a-form v-if="processReportDtos != undefined && processReportDtos.processReportParameters != undefined" :colon="false">
+      <a-row :gutter="[8, 14]" justify="space-start">
+        <a-col
+          v-for="(item) in processReportDtos.processReportParameters"
+          :key="'processReportParameter-' + item.fieldName" style="display: flex; align-items: center;"
         >
-          <label
-            v-if="item.displayType != 'ListBoxEnumEditor'"
-            class="m-label"
-            :for="'editor_' + item.id"
-          >{{ item.displayName }}</label>
-          <span
-            v-show="!item.mandatory"
-            style="color: red;"
-          >该项为必填项字段</span>
-
-          <div class="input-group">
-            <input
-              v-if="item.displayType =='TextEditor'"
-              :id="'editor_' + item.id"
-              v-model="item.fieldValue.displayValue[0]"
-              autocomplete="off"
-              type="text"
-              class="form-control"
-              placeholder="请输入内容"
-              @change="valueChanged(item)"
+          <a-form-item
+            :label="item.displayType !== 'ListBoxEnumEditor' ? item.displayName : ''"
+            :label-col="{ style: 'width: 108px' }" class="horizontal-form-item"
+          >
+            <a-input
+              v-if="item.displayType === 'TextEditor'" v-model:value="item.fieldValue.displayValue[0]" class="w-full"
+              placeholder="请输入内容" @change="valueChanged(item)"
             />
 
-            <textarea
-              v-if="item.displayType =='TextAreaEditor'"
-              :id="'editor_' + item.id"
-              v-model="item.fieldValue.displayValue[0]"
-              rows="5"
-              type="text"
-              class="form-control"
-              placeholder="请输入内容"
-              @change="valueChanged(item)"
+            <a-textarea
+              v-if="item.displayType === 'TextAreaEditor'" v-model:value="item.fieldValue.displayValue[0]"
+              placeholder="请输入内容" :rows="1" class="w-full" @change="valueChanged(item)"
             />
 
-            <input
-              v-if="item.displayType =='NumberEditor'"
-              :id="'editor_' + item.id"
-              v-model="item.fieldValue.displayValue[0]"
-              autocomplete="off"
-              type="number"
-              class="form-control"
-              placeholder="请输入数字"
-              @change="valueChanged(item)"
+            <a-input-number
+              v-if="item.displayType === 'NumberEditor'" v-model:value="item.fieldValue.displayValue[0]"
+              placeholder="请输入数字" class="w-full" @change="valueChanged(item)"
             />
-            <!-- {{ item.displayType }} -->
+
+            <!-- 开关组件 -->
             <Switches
-              v-if="item.displayType =='CheckBoxEditor'"
-              v-model="item.fieldValue.displayValue[0]"
-              color="green"
-              type-bold="true"
+              v-if="item.displayType === 'CheckBoxEditor'" v-model:checked="item.fieldValue.displayValue[0]"
               @change="valueChanged(item)"
             />
 
+            <!-- 日期时间组件 -->
             <DateTime
-              v-if="item.displayType =='DateTimeBoxEditor'"
-              :id="'editor_' + item.id"
-              v-model="item.fieldValue.displayValue[0]"
-              name="datetime"
+              v-if="item.displayType == 'DateTimeBoxEditor'" :id="'editor_' + item.id"
+              v-model="item.fieldValue.displayValue[0]" name="datetime"
               @update:model-value="changeValue(item, $event)"
             />
 
+            <!-- 日期选择器  -->
+            <Date
+              v-if="item.displayType == 'DateBoxEditor'" :id="'DateBoxEditor_' + item.id"
+              v-model="item.fieldValue.displayValue[0]" @update:model-value="changeValue(item, $event)"
+            />
+
             <EnumSelectWidget
-              v-if="item.displayType =='ListBoxEnumEditor'"
-              :key-values="item.keyValues"
-              :enum-value="item.fieldValue.displayValue[0]"
-              @value-changed="changeValue(item, $event)"
+              v-if="item.displayType == 'ListBoxEnumEditor'" style="width: 230px;" :field="item"
+              :field-value="item.fieldValue" @value-changed="valueChanged($event, item)"
             />
 
             <MultiSearchWidget
-              v-if="item.displayType =='MultiSearchBoxEditor'"
-              :info-window-no="item.infoWindowNo"              
-              :where-clause-source="{'processReportParameter': {'processReportNo': processReportDto.no, 'fieldName': item.fieldName}}"
-              :field="item"
-              :field-value="item.fieldValue"
-              :display-name="item.listDisplayFieldNames"
+              v-if="item.displayType == 'MultiSearchBoxEditor'"
+              style="width: 230px;" :info-window-no="item.infoWindowNo"
+              :where-clause-source="{ 'processReportParameter': { 'processReportNo': processReportDto.no, 'fieldName': item.fieldName } }"
+              :field="item" :field-value="item.fieldValue" :display-name="item.listDisplayFieldNames"
               @value-changed="tabValueChanged($event, item)"
             />
 
             <SearchWidget
-              v-if="item.displayType =='SearchBoxEditor'"              
-              :where-clause-source="{'processReportParameter': {'processReportNo': processReportDto.no, 'fieldName': item.fieldName}}"
-              :info-window-no="item.infoWindowNo"
-              :field="item"
-              :field-value="item.fieldValue"
-              :display-name="item.listDisplayFieldNames"
-              :model-data="modelData"
+              v-if="item.displayType == 'SearchBoxEditor'"
+              style="width: 230px;"
+              :where-clause-source="{ 'processReportParameter': { 'processReportNo': processReportDto.no, 'fieldName': item.fieldName } }"
+              :info-window-no="item.infoWindowNo" :field="item" :field-value="item.fieldValue"
+              :display-name="item.listDisplayFieldNames" :parent-model-data="parentModelData"
               @value-changed="tabValueChanged($event, item)"
             />
 
-            <!-- 日期选择器  -->
-            <Date
-              v-if="item.displayType =='DateBoxEditor'"
-              v-model="item.fieldValue.displayValue[0]"
-              @selected="changeValue(item, $event)"
-            />
-
             <VueMonthlyPicker
-              v-if="item.displayType =='YearMonthEditor'"
-              :value="item.fieldValue.displayValue[0]"
-              :allow-change-value="false"
-              date-format="YYYY-MM"
-              class="vue-monthly-picker m-date-fieldEditView"
+              v-if="item.displayType == 'YearMonthEditor'" :value="item.fieldValue.displayValue[0]"
+              :allow-change-value="false" date-format="YYYY-MM" class="vue-monthly-picker m-date-fieldEditView"
               @selected="changeValue(item, $event)"
             />
             <YearPicker
-              v-if="item.displayType =='YearEditor'"
-              :date-value="item.fieldValue.displayValue[0]"
+              v-if="item.displayType == 'YearEditor'" :date-value="item.fieldValue.displayValue[0]"
               @selected="changeValue(item, $event)"
             />
-          </div>
-        </div>
-      </template>
-    </div>
+          </a-form-item>
+        </a-col>
+      </a-row>
+    </a-form>
+
     <div>
       <div class="form-group">
-        <button
-          v-if="processReportDtos.htmlHelpUrl != null && processReportDtos.htmlHelpUrl != ''"
-          class="btn btn-default"
-          @click="openHtmlHelp(processReportDtos.htmlHelpUrl)"
+        <a-button
+          v-if="processReportDto.htmlHelpUrl != null && processReportDto.htmlHelpUrl != ''"
+          @click="openHtmlHelp(processReportDto.htmlHelpUrl)"
         >
           <span class="glyphicon glyphicon-question-sign" />
-        </button>
-        <input
-          autocomplete="off"
-          type="button"
-          class="btn btn-primary"
-          style="margin-top: 15px;"
-          value="确定"
-          @click="subDatas()"
-        />
+        </a-button>
+        <a-button type="primary" style="margin-top: 15px;" @click="subDatas()">
+          确定
+        </a-button>
       </div>
       <ProcessReportResultPreview
-        :process-report-result="processReportResult"
-        :pdf-only="processReportDto.pdfOnly"
+        :process-report-result="processReportResult" :pdf-only="processReportDto.pdfOnly"
         :excel-only="processReportDto.excelOnly"
       />
     </div>
@@ -170,6 +120,7 @@ import Switches from '../../switches/src/Switches.vue';
 import Navbar from '../../navbar/src/Navbar.vue';
 import VueMonthlyPicker from '../../vue-monthly-picker/src/VueMonthlyPicker.vue';
 import EnumSelectWidget from './EnumSelectWidget.vue';
+import { message } from 'ant-design-vue';
 
 
 
@@ -177,7 +128,7 @@ export default {
 
   components: {
     DateTime,
-    MultiSearchWidget : defineAsyncComponent(() =>
+    MultiSearchWidget: defineAsyncComponent(() =>
       import('../../info/src/MultiSearchWidget.vue'),
     ),
     Loading,
@@ -185,18 +136,19 @@ export default {
     SearchWidget,
     Switches,
     Navbar,
+    Date,
     VueMonthlyPicker,
     YearPicker,
     EnumSelectWidget,
   },
   props: {
-    'processReportDto':{
+    'processReportDto': {
       type: Object,
       default: null,
     },
   },
 
-  emits:['valueChanged'],
+  emits: ['valueChanged'],
   data: function () {
     return {
       processReportId: '',
@@ -286,7 +238,7 @@ export default {
       _self.complete = true;
       if (
         _self.processReportDtos &&
-                _self.processReportDtos.processReportParameters
+        _self.processReportDtos.processReportParameters
       ) {
         _self.processReportDtos.processReportParameters.forEach(
           function (item) {
@@ -304,7 +256,7 @@ export default {
          * 执行流程
          * @return {void}
          */
-    subDatas: function () {
+    subDatas: async function () {
       var _self = this;
       _self.judgeDataFull();
 
@@ -330,6 +282,7 @@ export default {
 
       _self.processReportResult = {};
       if (!_self.complete) {
+        message.error('所有字段为必填选项,请填写完整');
         return;
       }
       _self.loading=true;
@@ -383,7 +336,7 @@ export default {
          * @return {void}
          */
     changeValue: function (item, newValue) {
-      item.fieldValue.displayValue[0]=newValue;
+      item.fieldValue.displayValue[0] = newValue;
       this.valueChanged(item);
 
     },
@@ -395,7 +348,7 @@ export default {
          */
     tabValueChanged: function (newFieldValue, item) {
       item.fieldValue = newFieldValue;
-      
+
       this.valueChanged(item);
     },
     // 值改变事件
@@ -409,25 +362,49 @@ export default {
 };
 </script>
 <style scoped>
-.control-label {
-    font-size: 15px;
+
+/* 添加横向布局样式 */
+.horizontal-form-item {
+  display: flex;
+  align-items: center;
+  gap: 8px;
+}
+
+:deep(.ant-form-item) {
+  margin-bottom: -5px !important;
+}
+
+/* 调整标签样式 */
+:deep(.ant-form-item-label) {
+  flex: 0 0 auto;
+  white-space: nowrap;
+  overflow: visible;
+  text-overflow: unset;
+}
+
+/* 确保控件容器填充剩余空间 */
+:deep(.ant-form-item-control) {
+  flex: 1;
+  min-width: 0;
+}
+
+/* 设置组件宽度 */
+.w-full {
+  width: 230px;
 }
 
-.processResult-textarea {
-    width: 100%;
-    height: 200px;
+.form-group{
+  margin-bottom: 10px;
 }
 
-.m-label {
-    width: 5em;
-    margin-left: 1em;
-    margin-right: 1em;
-    display: inline;
+:deep(.ant-form-item-label > label) {
+  font-size: 14px !important;
+  font-weight: 600 !important;
 }
 </style>
 
 <style>
-.m-date-fieldEditView > div:first-child {
-    width: 100%;
+.m-date-fieldEditView>div:first-child {
+  width: 100%;
 }
 </style>

+ 90 - 53
packages/switches/src/Switches.vue

@@ -1,5 +1,10 @@
 <template>
-  <label :class="classObject">
+  <a-switch
+    v-model:checked="value" :size="size" :checked-children="isShowText ? textTrue : ''"
+    :un-checked-children="isShowText ? textFalse : ''" :disabled="disabled"
+  />
+
+  <!-- <label :class="classObject">
     <input
       v-model="value"
       autocomplete="off"
@@ -23,7 +28,7 @@
         v-text="textFalse"
       />
     </span>
-  </label>
+  </label> -->
 </template>
 
 <script>
@@ -36,45 +41,50 @@ export default {
   props: {
     // 选择状态, false
     'modelValue':
-    {
-      type: Boolean,
-      default: false,
-    }, 
+        {
+          type: Boolean,
+          default: false,
+        },
     // 禁用, false
     'disabled':
-    {
-      type: Boolean,
-      default: false,
-    }, 
+        {
+          type: Boolean,
+          default: false,
+        },
     // 是否显示文字提示
     'showText':
-    {
-      type: Boolean,
-      default: false,
-    }, 
+        {
+          type: Boolean,
+          default: false,
+        },
     // True状态下的文字
     'textTrueIn':
-    {
-      type: String,
-      default: '',
-    },  
+        {
+          type: String,
+          default: '',
+        },
     // False状态下的文字
     'textFalseIn':
-    {
-      type: String,
-      default: '',
-    }, 
+        {
+          type: String,
+          default: '',
+        },
     // 显示的颜色default,primary,success,info,warning,danger
     'color':
-    {
-      type: String,
-      default: '',
-    }, 
+        {
+          type: String,
+          default: '',
+        },
     // 大图标
-    'typeBold':{
+    'typeBold': {
       type: Boolean,
       default: false,
     },
+    // 小图标
+    'size': {
+      type: String,
+      default: 'default',
+    },
   },
 
   emits: ['update:modelValue'],
@@ -114,13 +124,16 @@ export default {
         [`vue-switcher-color--${_self.colorCss}`]: _self.colorCss,
       };
     },
+    isShowText: function () {
+      return this.showText === undefined || this.showText === null || this.showText === true;
+    },
   },
   watch: {
-    value: function (val, oldVal) {   // eslint-disable-line
+        value: function (val, oldVal) {   // eslint-disable-line
       this.$emit('update:modelValue', val);
     },
 
-    modelValue: function (val, oldVal) {    // eslint-disable-line
+        modelValue: function (val, oldVal) {    // eslint-disable-line
       if (val != undefined) {
         this.value = (val == 'true' || val == true);
         if (val == 'true' || val == true) {
@@ -155,6 +168,7 @@ export default {
     margin-bottom: 0px;
     top: 7px;
 }
+
 .vue-switcher__label {
     position: absolute;
     left: 50px;
@@ -165,6 +179,7 @@ export default {
     font-size: 10px;
     margin-bottom: 0px;
 }
+
 .vue-switcher input {
     position: absolute;
     left: 0px;
@@ -177,6 +192,7 @@ export default {
     cursor: pointer;
     margin: 0px !important;
 }
+
 .vue-switcher div {
     position: absolute;
     left: 0px;
@@ -191,6 +207,7 @@ export default {
     justify-content: flex-start;
     cursor: pointer;
 }
+
 .vue-switcher div:after {
     position: absolute;
     top: -4;
@@ -204,116 +221,136 @@ export default {
     margin-left: -17px;
     cursor: pointer;
 }
+
 .vue-switcher--unchecked div {
     justify-content: flex-end;
 }
+
 .vue-switcher--unchecked div:after {
     left: 15px;
 }
+
 .vue-switcher--disabled div {
     opacity: 0.3;
 }
+
 .vue-switcher--disabled input {
     cursor: not-allowed;
 }
+
 .vue-switcher--bold div {
     top: 0px;
     height: 26px;
     width: 50px;
 }
+
 .vue-switcher--bold div:after {
     margin-left: -22px;
     top: 4px;
 }
+
 .vue-switcher--bold--unchecked div:after {
     left: 26px;
 }
+
 .vue-switcher--bold .vue-switcher__label span {
     padding-bottom: 7px;
     display: inline-block;
 }
+
 .vue-switcher-theme--default.vue-switcher-color--default div {
     background-color: #b7b7b7;
 }
+
 .vue-switcher-theme--default.vue-switcher-color--default div:after {
     background-color: #9d9d9d;
 }
-.vue-switcher-theme--default.vue-switcher-color--default.vue-switcher--unchecked
-    div {
+
+.vue-switcher-theme--default.vue-switcher-color--default.vue-switcher--unchecked div {
     background-color: #aaa;
 }
-.vue-switcher-theme--default.vue-switcher-color--default.vue-switcher--unchecked
-    div:after {
+
+.vue-switcher-theme--default.vue-switcher-color--default.vue-switcher--unchecked div:after {
     background-color: #c4c4c4;
 }
+
 .vue-switcher-theme--default.vue-switcher-color--blue div {
     background-color: #77b0c8;
 }
+
 .vue-switcher-theme--default.vue-switcher-color--blue div:after {
     background-color: #539bb9;
 }
-.vue-switcher-theme--default.vue-switcher-color--blue.vue-switcher--unchecked
-    div {
+
+.vue-switcher-theme--default.vue-switcher-color--blue.vue-switcher--unchecked div {
     background-color: #c0dae5;
 }
-.vue-switcher-theme--default.vue-switcher-color--blue.vue-switcher--unchecked
-    div:after {
+
+.vue-switcher-theme--default.vue-switcher-color--blue.vue-switcher--unchecked div:after {
     background-color: #77b0c8;
 }
+
 .vue-switcher-theme--default.vue-switcher-color--red div {
     background-color: #c87777;
 }
+
 .vue-switcher-theme--default.vue-switcher-color--red div:after {
     background-color: #b95353;
 }
-.vue-switcher-theme--default.vue-switcher-color--red.vue-switcher--unchecked
-    div {
+
+.vue-switcher-theme--default.vue-switcher-color--red.vue-switcher--unchecked div {
     background-color: #e5c0c0;
 }
-.vue-switcher-theme--default.vue-switcher-color--red.vue-switcher--unchecked
-    div:after {
+
+.vue-switcher-theme--default.vue-switcher-color--red.vue-switcher--unchecked div:after {
     background-color: #c87777;
 }
+
 .vue-switcher-theme--default.vue-switcher-color--yellow div {
     background-color: #c9c377;
 }
+
 .vue-switcher-theme--default.vue-switcher-color--yellow div:after {
     background-color: #bab353;
 }
-.vue-switcher-theme--default.vue-switcher-color--yellow.vue-switcher--unchecked
-    div {
+
+.vue-switcher-theme--default.vue-switcher-color--yellow.vue-switcher--unchecked div {
     background-color: #e6e3c0;
 }
-.vue-switcher-theme--default.vue-switcher-color--yellow.vue-switcher--unchecked
-    div:after {
+
+.vue-switcher-theme--default.vue-switcher-color--yellow.vue-switcher--unchecked div:after {
     background-color: #c9c377;
 }
+
 .vue-switcher-theme--default.vue-switcher-color--orange div {
     background-color: #c89577;
 }
+
 .vue-switcher-theme--default.vue-switcher-color--orange div:after {
     background-color: #b97953;
 }
-.vue-switcher-theme--default.vue-switcher-color--orange.vue-switcher--unchecked
-    div {
+
+.vue-switcher-theme--default.vue-switcher-color--orange.vue-switcher--unchecked div {
     background-color: #e5cec0;
 }
-.vue-switcher-theme--default.vue-switcher-color--orange.vue-switcher--unchecked
-    div:after {
+
+.vue-switcher-theme--default.vue-switcher-color--orange.vue-switcher--unchecked div:after {
     background-color: #c89577;
 }
+
 .vue-switcher-theme--default.vue-switcher-color--green div {
     background-color: #77c88d;
 }
+
 .vue-switcher-theme--default.vue-switcher-color--green div:after {
     background-color: #53b96e;
 }
-.vue-switcher-theme--default.vue-switcher-color--green.vue-switcher--unchecked
-    div {
+
+.vue-switcher-theme--default.vue-switcher-color--green.vue-switcher--unchecked div {
     background-color: #c0e5ca;
 }
-.vue-switcher-theme--default.vue-switcher-color--green.vue-switcher--unchecked
-    div:after {
+
+.vue-switcher-theme--default.vue-switcher-color--green.vue-switcher--unchecked div:after {
     background-color: #77c88d;
 }
 </style>

+ 31 - 35
packages/time/src/Time.vue

@@ -1,67 +1,63 @@
 <template>
-  <input v-model="innerValue" autocomplete="off" type="time" :readonly="readonly" />
+  <a-time-picker
+    v-model:value="innerValue"
+    style="width: 100%"
+    value-format="HH:mm:ss"
+    :placeholder="placeholder"
+    :disabled="readonly"
+    @change="handleChange"
+  />
 </template>
 
 <script>
-
 export default {
   // eslint-disable-next-line
-  name: 'Time',
+  name: "Time",
 
-  props:{
-    'modelValue':
-    {
+  props: {
+    modelValue: {
       type: String,
       default: '',
-    }, 
-    'readonly':{
+    },
+    readonly: {
       type: Boolean,
       default: false,
     },
+    placeholder: {
+      type: String,
+      default: '请选择时间',
+    },
   },
 
   emits: ['update:modelValue', 'on-value-change'],
 
-  data: function(){
-    return{
-      innerValue : '',
+  data: function () {
+    return {
+      innerValue: '',
     };
   },
 
-  watch:{
+  watch: {
     modelValue: {
-      handler(newValue, oldValue){    // eslint-disable-line
-        if(newValue != null && newValue != ''){
-          this.innerValue = this.getTimeValue(newValue);
-        }else{
+      handler(newValue, oldValue) {
+        // eslint-disable-line
+        if (newValue != null && newValue != '') {
           this.innerValue = newValue;
         }
       },
       immediate: true,
     },
-
-
-    innerValue: function(newValue, oldValue){  // eslint-disable-line
-      // 向外部发送事件通知
-      let newValue1 = '';
-      if(newValue == null || newValue == ''){
-        newValue1 = newValue;
-      }else{
-        newValue1 = newValue + ':00';
-      }
-      console.log('time has been changed:', newValue1);
-      this.$emit('update:modelValue', newValue1);
-      this.$emit('on-value-change', newValue1);
-    },
   },
 
   methods: {
-    getTimeValue: function(value){
-      if(value != null && value.length == 8){
-        return value.substring(0, 5);
-      }else{
-        return value;
+    handleChange(_, value) {
+      if (!value) {
+        this.$emit('update:modelValue', null);
+        this.$emit('on-value-change', null);
+        return;
       }
+      this.$emit('update:modelValue', value);
+      this.$emit('on-value-change', value);
     },
   },
 };

+ 69 - 111
packages/tree/src/TreeViewNode.vue

@@ -1,141 +1,99 @@
 <template>
-  <ul
-    :id="node.id"
-    :class="{'root-node' : isRoot}"
-  >
-    <li :class="{'root-node' : isRoot}">
-      <span
-        class="node-text icon expand-icon glyphicon"
-        :class="{'glyphicon-plus-sign' : (isNodeOpen == false), 'glyphicon-minus-sign' : (isNodeOpen == true), 'glyphicon-leaf' : (isNodeOpen == undefined)}"
-        @click="nodeExpand(node)"
-      />
-
-      <span
-        v-if="isShowCheck==undefined || isShowCheck"
-        class="glyphicon select-node"
-        :class="{'selected-node' : node.selected, 'glyphicon-check' : node.selected, 'glyphicon-unchecked' : !node.selected}"
-        @click="nodeSelect(node)"
-      />
-
-      <font>{{ node.text }}</font>
-
-      <template
-        v-for="childrenNode in node.childrenDatas"
-        :key="childrenNode.id"
-      >
-        <TreeViewNode
-          v-if="node.open && node.childrenDatas != undefined && node.childrenDatas.length > 0"
-          :node="childrenNode"
-          :is-show-check="childrenNode.isShowCheck"
-          @node-expand="nodeExpand"
-          @node-select="nodeSelect"
-        />
-      </template>
-    </li>
-  </ul>
+  <a-tree
+    :tree-data="treeData" :checkable="isShowCheck" :expanded-keys="expandedKeys"
+    :checked-keys="checkedKeys" :selected-keys="selectedKeys"
+    :field-names="{ children: 'childrenDatas', key: 'id', title: 'text' }" @expand="handleExpand"
+    @check="handleCheck"
+  />
+  <!-- @select="handleSelect" -->
 </template>
 
 <script>
-
 export default {
   name: 'TreeViewNode',
-  components: {
-
-  },
-
   props: {
-    'node': {
+    node: {
       type: Object,
-      default: null,
+      default: () => ({}),
     },
-    'isShowCheck': {
+    isShowCheck: {
       type: Boolean,
       default: false,
     },
-    'isRoot': {
+    isRoot: {
       type: Boolean,
       default: false,
     },
   },
-
-  emits: ['nodeExpand','nodeSelect'],
-
-  data: function () {
+  emits: ['nodeExpand', 'nodeSelect'],
+  data() {
     return {
+      expandedKeys: [],
+      checkedKeys: [],
+      selectedKeys: [],
     };
   },
-
   computed: {
-    // 节点是否打开
-    isNodeOpen: function () {
-      if (this.node.childrenDatas == undefined || this.node.childrenDatas.length == 0) {
-        console.log(this.node.text + '无子节点');
-        return undefined;
-      } else {
-        console.log(this.node.text + '有子节点' + this.node.open);
-        return this.node.open == true;
-      }
-
+    treeData() {
+      return this.isRoot ? [this.node] : this.node.childrenDatas || [];
     },
   },
-
-  mounted: function () {
-
+  watch: {
+    node: {
+      handler(newVal) {
+        if (newVal.selected) {
+          this.checkedKeys = [newVal.id];
+        } else {
+          this.checkedKeys = this.collectSelectedIds(newVal.childrenDatas || []);
+        }
+      },
+      deep: true,
+      immediate: true,
+    },
   },
   methods: {
-    nodeExpand: function (node) {
-      if (node === this.node) {
-        // eslint-disable-next-line
-                this.node.open = !this.node.open;
-      }
-      // 触发父组件的事件
-      // if(node.open){
+    handleExpand(expandedKeys) {
+      this.expandedKeys = expandedKeys;
+      const node = this.findNode(expandedKeys[expandedKeys.length - 1]);
       this.$emit('nodeExpand', node);
-      // }
     },
-
-    nodeSelect: function (node) {
-      this.$emit('nodeSelect', node);
+    handleCheck(checkedKeys, { node }) {
+    //   this.checkedKeys = checkedKeys;
+      this.$emit('nodeSelect', node.dataRef);
+    },
+    handleSelect(selectedKeys, { node }) {
+    //   this.selectedKeys = selectedKeys;
+      this.$emit('nodeSelect', node.dataRef);
+    },
+    findNode(key) {
+      const find = nodes => {
+        for (const node of nodes) {
+          if (node.id === key) return node;
+          if (node.childrenDatas) {
+            const found = find(node.childrenDatas);
+            if (found) return found;
+          }
+        }
+      };
+      return find(this.treeData);
     },
 
+    // 获取所有子节点中selected为true的ID
+    collectSelectedIds(nodes, result = []) {
+      const _self = this;
+      if (!nodes || nodes.length === 0) return result;
+
+      nodes.forEach(node => {
+        if (node.selected) {
+          result.push(node.id);
+        } else {
+          if (node.childrenDatas && node.childrenDatas.length > 0) {
+            _self.collectSelectedIds(node.childrenDatas, result);
+          }
+        }
+      });
+      return result;
+    },
   },
 };
-</script>
-
-<style scoped>
-.root-node {
-    margin-left: 0px;
-    padding-left: 0px;
-    text-align: left;
-}
-
-.node-text {
-    height: 30px;
-    line-height: 40px !important;
-}
-
-.node-text:hover {
-    cursor: pointer;
-}
-
-ul {
-    padding-left: 10px;
-}
-
-li {
-    padding-left: 10px;
-    list-style: none;
-}
-
-.select-node {
-    cursor: pointer;
-    color: #0066ff;
-    font-size: large;
-}
-
-.selected-node {
-    cursor: pointer;
-    color: #0066ff;
-    font-size: large;
-}
-</style>
+</script>

+ 23 - 51
packages/upload-widget/src/UploadWidget.vue

@@ -1,79 +1,51 @@
 <template>
   <div>
     <input
-      ref="fileInput"
-      autocomplete="off"
-      type="file"
-      class="form-control file-input"
-      :accept="fileType"
+      ref="fileInput" autocomplete="off" type="file" class="file-input" :accept="fileType"
       @change="onFileChange"
     />
-    <label for="attachment">
-      <a
-        role="button"
-        class="btn btn-primary btn-sm"
-        @click="clickButton"
-      >
-        <i class="fa fa-upload" />
-                &nbsp;
-        {{ $t('lang.uploadWidget.uploadFile') }}
-      </a>
-    </label>
+    <a-button type="primary" @click="clickButton">
+      <upload-outlined />
+      {{ $t('lang.uploadWidget.uploadFile') }}
+    </a-button>
   </div>
 </template>
 
 <script>
-
+import { Button } from 'ant-design-vue';
+import { UploadOutlined } from '@ant-design/icons-vue';
 export default {
   name: 'UploadWidget',
-  /**
-	 * fileType: 上传文件类型,eg:".xls,.doc,.txt,.pdf"
-	 */
+  components: {
+    AButton: Button, UploadOutlined,
+  },
   props: {
-    'fileType': {
+    fileType: {
       type: String,
       default: '',
     },
   },
-
-  emits: [ 'upload' ],
-
-  data: function () {
-    return {
-
-    };
-  },
+  emits: ['upload'],
   methods: {
-    /**
-     * 点击上传按钮事件
-     * @return {[type]} [description]
-     */
-    clickButton: function () {
-      $(this.$refs.fileInput).click();
+    clickButton() {
+      this.$refs.fileInput.click();
     },
-
-    /**
-     * 选择了文件事件
-     * @return {[type]} [description]
-     */
-    onFileChange: function (e) {
-      var files = e.target.files || e.dataTransfer.files;
-      if (!files.length)
-        return;
+    onFileChange(e) {
+      const files = e.target.files || e.dataTransfer.files;
+      if (!files.length) return;
       this.$emit('upload', files);
     },
   },
 };
 </script>
 
-
 <style scoped>
 .file-input {
-    width: 0.1px;
-    height: 0.1px;
-    opacity: 0;
-    overflow: hidden;
-    position: absolute;
-    z-index: -1;
+  width: 0.1px;
+  height: 0.1px;
+  opacity: 0;
+  overflow: hidden;
+  position: absolute;
+  z-index: -1;
 }
 </style>

+ 53 - 445
packages/vue-monthly-picker/src/VueMonthlyPicker.vue

@@ -1,460 +1,68 @@
 <template>
-  <div class="vue-monthly-picker">
-    <div
-      class="month-picker-wrapper"
-      :class="{ 'active visible':showMenu }"
-    >
-      <div class="month-year-label picker" type="text" tabindex="0" @click="openMenu">
-        <div
-          class="month-year-display"
-          :disabled="disabled"
-          :class="[inputClass, {'placeholder': !modelValue}]"
-          @click="openMenu"
-        >
-          <div class="display-text" :class="'display-text-'+alignment" :style="[{'text-align': alignment}]">{{ displayText }}</div>
-          <span v-if="clearOption && modelValue" class="vmp-input-append" @click.stop.prevent="clearSelect">
-            <i class="vmp-clear-icon" />
-          </span>
-        </div>
-      </div>
-      <div class="text" />
-      <div class="date-popover" :class="menuClass" :style="menuStyle" tabindex="-1">
-        <div class="picker" style="text-align: center">
-          <div class="flexbox">
-            <span class="prev" :class="{deactive: !canBack}" @click="prevYear" />
-            <div>{{ year }}</div>
-            <span class="next" :class="{deactive: !canNext}" @click="nextYear" />
-          </div>
-          <div class="flexbox monthItem">
-            <template v-for="(monthLabel, idx) in monthLabels">
-              <div
-                v-if="isActive(idx)"
-                :key="'active-' + idx"
-                class="item active"
-                :class="{'selected': isCurrentSelected(year, idx)}"
-                :style="[{'background-color': getBackgroundColor(year, idx)}]"
-                @click="selectMonth(idx)"
-              >
-                {{ monthLabel }}
-              </div>
-              <div
-                v-else
-                :key="'deactive-' + idx"
-                :class="{'selected': isCurrentSelected(year, idx)}"
-                class="item deactive"
-              >
-                {{ monthLabel }}
-              </div>
-            </template>
-          </div>
-        </div>
-      </div>
-    </div>
-  </div>
+  <a-date-picker
+    v-model:value="selectedMonth"
+    picker="month"
+    :placeholder="placeholder"
+    :format="format"
+    :value-format="valueFormat"
+    :disabled="disabled"
+    style="width: 100%"
+    @change="handleChange"
+  />
 </template>
 
-<script>
+<script setup>
 import dayjs from 'dayjs';
+import { ref, watch, defineProps, defineEmits, defineOptions } from 'vue';
 
-export default {
+defineOptions({
   name: 'VueMonthlyPicker',
-  props: {
-    'modelValue': {
-      type: [String, Object] ,
-      default: () => {
-        return null;
-      },
-    },
-    'disabled': {
-      type: Boolean,
-      default: false,
-    },
-    'inputClass': {
-      type: [String, Object],
-      default: 'input',
-    },
-    'placeHolder': {
-      type: String,
-      default: '',
-    },
-    'alignment': {
-      type: String,
-      default: 'left',
-      validator: function (value) {
-        // The value must match one of these strings
-        return ['left', 'right', 'center'].indexOf(value) !== -1;
-      },
-    },
-    'selectedBackgroundColor': {
-      type: String,
-      default: '#007bff',
-    },
-    monthLabels: {
-      type: Array,
-      default: function () {
-        return ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12'];
-      },
-    },
-    min: {
-      type: Date,
-      default: null,
-    },
-    max: {
-      type: Date,
-      default: null,
-    },
-    dateFormat: {
-      type: String,
-      default: 'YYYY/MM',
-    },
-    clearOption: {
-      type: Boolean,
-      default: true,
-    },
+});
+
+const props = defineProps({
+  modelValue: {
+    type: [String, Date, null],
+    default: null,
   },
-  emits: ['update:modelValue', 'selected'],
-  data () {
-    return {
-      showMenu: false,
-      year: dayjs().format('YYYY'),
-      month: dayjs().format('MM'),
-    };
+  placeholder: {
+    type: String,
+    default: '请选择月份',
   },
-  computed: {
-    menuClass () {
-      return {
-        visible: this.showMenu,
-        hidden: !this.showMenu,
-      };
-    },
-    menuStyle () {
-      return {
-        display: this.showMenu ? 'block' : 'none',
-        'left': this.alignment === 'right' ? '100%' : this.alignment === 'center' ? '50%' : '',
-        'transform': this.alignment === 'right' ? 'translate(-100%,0)' : this.alignment === 'center' ? 'translate(-50%,0)' : '',
-      };
-    },
-    displayText () {
-      if (this.modelValue) {
-        let valueMoment = null;
-        if (typeof this.modelValue === 'string') {
-          valueMoment = dayjs(this.modelValue);
-        } else {
-          valueMoment = this.modelValue;
-        }
-        if (valueMoment && valueMoment.isValid()) {
-          return valueMoment.format(this.dateFormat);
-        }
-        return null;
-      } else {
-        return this.placeHolder;
-      }
-    },
-    canBack () {
-      if (!this.min) return true;
-      const currentVal = this.internalMomentValue.clone().startOf('year');
-      return this.min.isBefore(currentVal);
-    },
-    canNext () {
-      if (!this.max) return true;
-      const currentVal = this.internalMomentValue.clone().endOf('year');
-      return currentVal.isBefore(this.max);
-    },
-    internalMomentValue () {
-      const yrMonth = this.year + '-' + this.month + '-01';
-      return dayjs(yrMonth);
-    },
+  format: {
+    type: String,
+    default: 'YYYY-MM',
   },
-  watch: {
-    modelValue: function (value) {
-      this.setValue(value);
-    },
+  valueFormat: {
+    type: String,
+    default: 'YYYY-MM',
   },
-  mounted () {
-    this.init();
+  disabled: {
+    type: Boolean,
+    default: false,
   },
-  methods: {
-    init () {
-      document.addEventListener('click', e => {
-        if (this.$el && !this.$el.contains(e.target)) {
-          this.closeMenu();
-        }
-      }, false);
-      this.setValue(this.modelValue);
-    },
-    openMenu () {
-      if (!this.disabled) {
-        this.showMenu = true;
-      }
-    },
-    closeMenu () {
-      this.showMenu = false;
-    },
-    prevYear () {
-      if (!this.canBack) return;
-      let newYear = parseInt(this.year) - 1;
-      this.year = newYear.toString();
-    },
-    nextYear () {
-      if (!this.canNext) return;
-      let newYear = parseInt(this.year) + 1;
-      this.year = newYear.toString();
-    },
-    selectMonth (idx) {
-      this.month = (parseInt(idx) + 1).toString();
-      this.selectPicker();
-      this.closeMenu();
-    },
-    selectPicker () {
-      const currentValue = this.internalMomentValue.clone();
-      if (typeof this.modelValue === 'string') {
-        this.$emit('update:modelValue', currentValue.format('YYYY-MM'));
-        this.$emit('selected', currentValue.format('YYYY-MM'));
-      }else{
-        this.$emit('update:modelValue', currentValue);
-        this.$emit('selected', currentValue);
-      }
+});
+
+const emit = defineEmits(['update:modelValue', 'selected']);
 
-      
-    },
-    setValue (value) {
-      if (typeof value === 'string') {
-        value = dayjs(value);
-      }
+const selectedMonth = ref(null);
 
-      if (value && value.isValid()) {
-        this.month = value.format('MM');
-        this.year = value.format('YYYY');
-      }
-    },
-    isActive (idx) {
-      let realMonth = idx + 1;
-      const yrMonth = this.year + '/' + (realMonth < 10 ? '0' + realMonth : realMonth);
-      if (this.min && dayjs(yrMonth, 'YYYY/MM').isBefore(this.min)) {
-        return false;
-      }
-      if (this.max && dayjs(yrMonth, 'YYYY/MM').isAfter(this.max)) {
-        return false;
-      }
-      return true;
-    },
-    isCurrentSelected (year, monthIdx) {
-      if (!this.modelValue) {
-        return false;
-      }
-      let checkValue = this.modelValue;
-      if (typeof this.modelValue === 'string') {
-        checkValue = dayjs(this.modelValue);
-      }
-      if (checkValue && checkValue.isValid()) {
-        const currentMonth = checkValue.format('MM');
-        const currentYear = checkValue.format('YYYY');
-        return Number(currentMonth) === Number(monthIdx + 1) && Number(currentYear) === Number(year);
-      }
-      return false;
-    },
-    getBackgroundColor (year, monthIdx) {
-      if (this.isCurrentSelected(year, monthIdx)) {
-        return this.selectedBackgroundColor;
-      }
-    },
-    clearSelect () {
-      this.$emit('update:modelValue', null);
-      this.$emit('selected', null);
-    },
+// 监听外部值变化
+watch(
+  () => props.modelValue,
+  newVal => {
+    selectedMonth.value = newVal;
   },
+  { immediate: true },
+);
+
+// 处理日期变化
+const handleChange = value => {
+  if (!value) {
+    emit('update:modelValue', null);
+    emit('selected', null);
+    return;
+  }
+  emit('update:modelValue', value);
+  emit('selected', value);
 };
-</script>
-
-<style>
-.vue-monthly-picker .picker .next:hover,
-.vue-monthly-picker .picker .prev:hover {
-  cursor: pointer;
-}
-
-.vue-monthly-picker .picker .monthItem .item {
-  border-top: 1px solid #d4d4d4;
-}
-
-.vue-monthly-picker .picker .monthItem .item.active:hover {
-  cursor: pointer;
-  background-color: #d4d4d4;
-}
-
-.vue-monthly-picker .picker .flexbox {
-  padding: 0px;
-  display: flex;
-  flex-wrap: wrap;
-}
-
-.vue-monthly-picker .picker .flexbox div {
-  flex-grow: 1;
-  padding: 15px 0;
-}
-
-.vue-monthly-picker .picker .flexbox .item {
-  flex: 1;
-  flex-basis: 25%;
-}
-
-.vue-monthly-picker .placeholder {
-  color: #8b8b8b;
-}
-
-.vue-monthly-picker .date-popover {
-  overflow-x: hidden;
-  overflow-y: hidden;
-  outline: none;
-  max-width: 350px;
-  width: 100%;
-  border-radius: 0 0 .28571429rem .28571429rem;
-  box-shadow: 0 2px 3px 0 rgba(34, 36, 38, 0.15);
-  background: #fff;
-  transition: opacity .1s ease;
-  position: absolute;
-  margin: auto;
-  z-index: 10;
-  border: 1px solid #d4d4d4;
-  font-size: 1rem;
-  font-weight: 200;
-}
-
-.vue-monthly-picker .month-picker-wrapper {
-  position: relative;
-  display: block;
-  min-width: 200px;
-}
-
-.vue-monthly-picker .month-year-label {
-  outline: none;
-}
-
-.vue-monthly-picker .month-year-label .vmp-input-append {
-  display: none;
-}
-
-.vue-monthly-picker .month-year-label:hover .vmp-input-append {
-  display: block;
-}
-
-.vue-monthly-picker .text {
-  position: relative;
-  z-index: 2;
-}
-
-.vue-monthly-picker .month-year-display:hover {
-  cursor: pointer;
-}
-
-.vue-monthly-picker .next,
-.vue-monthly-picker .prev {
-  width: 16%;
-  float: left;
-  text-indent: -10000px;
-  position: relative;
-}
-
-.vue-monthly-picker .next:after,
-.vue-monthly-picker .prev:after {
-  content: "";
-  position: absolute;
-  left: 50%;
-  top: 50%;
-  -webkit-transform: translateX(-50%) translateY(-50%);
-  transform: translateX(-50%) translateY(-50%);
-  border: 6px solid transparent;
-}
-
-.vue-monthly-picker .next:after {
-  border-left: 10px solid #000;
-  margin-left: 5px;
-}
-
-.vue-monthly-picker .next.deactive:hover {
-  cursor: default;
-}
-
-.vue-monthly-picker .next.deactive:after {
-  border-left: 10px solid #999999;
-}
-
-.vue-monthly-picker .prev:after {
-  border-right: 10px solid #000;
-  margin-left: -5px;
-}
-
-.vue-monthly-picker .prev.deactive:hover {
-  cursor: default;
-}
-
-.vue-monthly-picker .prev.deactive:after {
-  border-right: 10px solid #999999;
-}
-
-.vue-monthly-picker .input {
-  -moz-appearance: none;
-  -webkit-appearance: none;
-  align-items: center;
-  border: 1px solid transparent;
-  border-radius: 3px;
-  box-shadow: none;
-  display: inline-flex;
-  font-size: 1rem;
-  height: 2.25em;
-  justify-content: flex-start;
-  line-height: 1.5;
-  padding: 2px calc(.625em - 1px);
-  position: relative;
-  vertical-align: top;
-  background-color: #fff;
-  border-color: #dbdbdb;
-  color: #363636;
-  box-shadow: inset 0 1px 2px rgba(10, 10, 10, 0.1);
-  max-width: 100%;
-  width: 100%;
-}
-
-.vue-monthly-picker .deactive {
-  color: #999999;
-}
-
-.vue-monthly-picker .selected {
-  color: #fff;
-  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
-  font-weight: bold;
-}
-
-.vue-monthly-picker .display-text {
-  width: 100%;
-}
-
-.vue-monthly-picker .display-text-right {
-  margin-right: 20px;
-}
-
-.vue-monthly-picker .vmp-input-append {
-  position: absolute;
-  top: 0;
-  right: 0;
-  width: 30px;
-  height: 100%;
-  padding: 6px;
-}
-
-.vue-monthly-picker .vmp-clear-icon {
-  display: inline-block;
-  width: 100%;
-  height: 100%;
-  font-style: normal;
-  color: #555;
-  text-align: center;
-  cursor: pointer;
-}
-
-.vue-monthly-picker .vmp-clear-icon:before {
-  display: inline-block;
-  content: '\2716';
-  vertical-align: middle;
-}
-
-</style>
+</script>

+ 72 - 79
packages/year-picker/src/YearPicker.vue

@@ -1,91 +1,84 @@
 <template>
-  <select
-    v-model="year"
-    class="m-select form-control"
-    :readonly="readonly"
-    style="width:100%"
-  >
-    <option
-      v-for="item in years"
-      :key="item"
-      :value="item"
-    >
-      {{ item }}
-    </option>
-  </select>
+  <a-date-picker
+    v-model:value="selectedYear"
+    picker="year"
+    :placeholder="placeholder"
+    :format="format"
+    :value-format="valueFormat"
+    :disabled="readonly"
+    style="width: 100%"
+    @change="handleChange"
+  />
 </template>
 
-<script>
+<script setup>
+import dayjs from 'dayjs';
+import { ref, watch, defineProps, defineEmits, defineOptions } from 'vue';
 
-export default {
+defineOptions({
   name: 'YearPicker',
-  props: {
-    'modelValue':
-    {
-      type: String,
-      default: '',
-    }, 
-    'readonly':{
-      type: Boolean,
-      default: false,
-    },
+});
+
+const props = defineProps({
+  modelValue: {
+    type: [String, Date, null],
+    default: null,
   },
-  emits: ['update:modelValue'],
-  data: function () {
-    return {
-      start: 1990,
-      end: 2050,
-      years: [],
-      year: '',
-    };
+  dateValue: {
+    type: [String, Date, null],
+    default: null,
   },
-  watch: {
-    'year': function () {
-      this.$emit('update:modelValue', this.year);
-    },
-
-    'modelValue': {
-      handler: function (newValue, oldValue) { // eslint-disable-line
-        this.year = newValue;
-      },
-      immediate: true,
-    },
+  placeholder: {
+    type: String,
+    default: '请选择年份',
   },
-  mounted: function () {
-    this.initYear();
+  format: {
+    type: String,
+    default: 'YYYY',
   },
-  methods: {
-    /**
-             * 初始化时间年份列表
-             */
-    initYear: function () {
-      var _self = this;
-      if (!_self.end) {
-        _self.end = new Date().getFullYear();
-      }
-      for (var i = _self.start; i <= _self.end; i++) {
-        _self.years.push(i);
-      }
-      _self.years.sort(function (a, b) {
-        return b - a;
-      });
-    },
-
-    /**
-             * 判断年份是否存在,如果年不存在就添加
-             */
-    checkYear: function (value) {
-      if (value != null && value.length == 4 && this.years.indexOf(value) < 0) {
-        this.years.push(value);
-      }
-    },
+  valueFormat: {
+    type: String,
+    default: 'YYYY',
   },
-};
+  readonly: {
+    type: Boolean,
+    default: false,
+  },
+});
 
-</script>
+const emit = defineEmits(['update:modelValue', 'selected']);
 
-<style scoped>
-.m-select {
-    border-radius: 4px !important;
-}
-</style>
+const selectedYear = ref(null);
+// 监听外部值变化
+watch(
+  () => props.modelValue,
+  newVal => {
+    if (newVal) {
+      selectedYear.value = newVal;
+    }
+  },
+  {
+    immediate: true,
+  },
+);
+watch(
+  () => props.dateValue,
+  newVal => {
+    if (newVal) {
+      selectedYear.value = newVal;
+    }
+  },
+  { immediate: true },
+);
+
+// 处理日期变化
+const handleChange = value => {
+  if (!value) {
+    emit('update:modelValue', null);
+    emit('selected', null);
+    return;
+  }
+  emit('update:modelValue', value);
+  emit('selected', value);
+};
+</script>