JVxeDemo1.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. <template>
  2. <a-space>
  3. <a-button @click="onToggleLoading">切换加载</a-button>
  4. <a-button @click="onToggleDisabled">切换禁用</a-button>
  5. </a-space>
  6. <!--这种使用场景得用height,用maxHeight底层有问题-->
  7. <JVxeTable
  8. ref="tableRef"
  9. stripe
  10. toolbar
  11. rowNumber
  12. rowSelection
  13. rowExpand
  14. resizable
  15. asyncRemove
  16. clickSelectRow
  17. :height="480"
  18. :checkboxConfig="{ range: true }"
  19. :disabledRows="{ input: ['text--16', 'text--18'] }"
  20. :loading="loading"
  21. :disabled="disabled"
  22. :columns="columns"
  23. :dataSource="dataSource"
  24. @removed="onJVxeRemove"
  25. @valueChange="handleValueChange"
  26. @blur="handleBlur"
  27. >
  28. <template #toolbarSuffix>
  29. <a-button @click="handleTableCheck">表单验证</a-button>
  30. <a-tooltip placement="top" title="获取值,忽略表单验证" :autoAdjustOverflow="true">
  31. <a-button @click="onGetData">获取数据</a-button>
  32. </a-tooltip>
  33. <a-tooltip placement="top" title="模拟加载1000条数据" :autoAdjustOverflow="true">
  34. <a-button @click="handleTableSet">设置值</a-button>
  35. </a-tooltip>
  36. <a-button @click="onGetSelData">获取选中数据</a-button>
  37. <a-button @click="onClearSel">清空选中</a-button>
  38. <a-button @click="onDelFirst">删除第一行数据</a-button>
  39. <a-button @click="onDelSel">删除选中数据</a-button>
  40. </template>
  41. <template #expandContent="props">
  42. <div style="padding: 20px">
  43. <span>Hello! My name is: {{ props.row.input }}!</span>
  44. </div>
  45. </template>
  46. <template #myAction="props">
  47. <a @click="onLookRow(props)">查看</a>
  48. <a-divider type="vertical" />
  49. <Popconfirm title="确定删除吗?" @confirm="onDeleteRow(props)">
  50. <a>删除</a>
  51. </Popconfirm>
  52. </template>
  53. </JVxeTable>
  54. </template>
  55. <script lang="ts" setup>
  56. import { ref } from 'vue';
  57. // noinspection ES6UnusedImports
  58. import { Popconfirm } from 'ant-design-vue';
  59. import { JVxeTypes, JVxeColumn, JVxeTableInstance } from '/@/components/jeecg/JVxeTable/types';
  60. import { useMessage } from '/@/hooks/web/useMessage';
  61. import { random } from 'lodash-es';
  62. import { buildUUID } from '/@/utils/uuid';
  63. import dayjs from 'dayjs';
  64. import { pushIfNotExist } from '/@/utils/common/compUtils';
  65. const { createMessage } = useMessage();
  66. const tableRef = ref<JVxeTableInstance>();
  67. const loading = ref(false);
  68. const disabled = ref(false);
  69. const columns = ref<JVxeColumn[]>([
  70. {
  71. title: 'ID',
  72. key: 'id',
  73. type: JVxeTypes.hidden,
  74. },
  75. {
  76. title: '不可编辑',
  77. key: 'noEdit',
  78. type: JVxeTypes.normal,
  79. width: 180,
  80. defaultValue: 'noEdit-new',
  81. },
  82. {
  83. title: '单行文本',
  84. key: 'input',
  85. type: JVxeTypes.input,
  86. width: 180,
  87. defaultValue: '',
  88. placeholder: '请输入${title}',
  89. validateRules: [
  90. {
  91. required: true, // 必填
  92. message: '请输入${title}', // 显示的文本
  93. },
  94. {
  95. pattern: /^[a-z|A-Z][a-z|A-Z\d_-]*$/, // 正则
  96. message: '必须以字母开头,可包含数字、下划线、横杠',
  97. },
  98. {
  99. unique: true,
  100. message: '${title}不能重复',
  101. },
  102. {
  103. handler({ cellValue, row, column }, callback, target) {
  104. // cellValue 当前校验的值
  105. // callback(flag, message) 方法必须执行且只能执行一次
  106. // flag = 是否通过了校验,不填写或者填写 null 代表不进行任何操作
  107. // message = 提示的类型,默认使用配置的 message
  108. // target 行编辑的实例对象
  109. if (cellValue === 'abc') {
  110. callback(false, '${title}不能是abc'); // false = 未通过校验
  111. } else {
  112. callback(true); // true = 通过验证
  113. }
  114. },
  115. message: '${title}默认提示',
  116. },
  117. ],
  118. },
  119. {
  120. title: '多行文本',
  121. key: 'textarea',
  122. type: JVxeTypes.textarea,
  123. width: 200,
  124. },
  125. {
  126. title: '数字',
  127. key: 'number',
  128. type: JVxeTypes.inputNumber,
  129. width: 80,
  130. defaultValue: 32,
  131. // 【统计列】sum = 求和、average = 平均值
  132. statistics: ['sum', 'average'],
  133. },
  134. {
  135. title: '下拉框',
  136. key: 'select',
  137. type: JVxeTypes.select,
  138. width: 180,
  139. // 下拉选项
  140. options: [
  141. { title: 'String', value: 'string' },
  142. { title: 'Integer', value: 'int' },
  143. { title: 'Double', value: 'double' },
  144. { title: 'Boolean', value: 'boolean' },
  145. ],
  146. // allowInput: true,
  147. allowSearch: true,
  148. placeholder: '请选择',
  149. },
  150. {
  151. title: '下拉框_字典',
  152. key: 'select_dict',
  153. type: JVxeTypes.select,
  154. width: 180,
  155. options: [],
  156. dictCode: 'sex',
  157. placeholder: '请选择',
  158. },
  159. {
  160. title: '下拉框_多选',
  161. key: 'select_multiple',
  162. type: JVxeTypes.selectMultiple,
  163. width: 205,
  164. options: [
  165. { title: 'String', value: 'string' },
  166. { title: 'Integer', value: 'int' },
  167. { title: 'Double', value: 'double' },
  168. { title: 'Boolean', value: 'boolean' },
  169. ],
  170. defaultValue: ['int', 'boolean'], // 多个默认项
  171. // defaultValue: 'string,double,int', // 也可使用这种方式
  172. placeholder: '多选',
  173. },
  174. {
  175. title: '下拉框_搜索',
  176. key: 'select_search',
  177. type: JVxeTypes.selectSearch,
  178. width: 180,
  179. options: [
  180. { title: 'String', value: 'string' },
  181. { title: 'Integer', value: 'int' },
  182. { title: 'Double', value: 'double' },
  183. { title: 'Boolean', value: 'boolean' },
  184. ],
  185. },
  186. {
  187. title: '日期时间',
  188. key: 'datetime',
  189. type: JVxeTypes.datetime,
  190. width: 200,
  191. defaultValue: '2019-04-30 14:52:22',
  192. placeholder: '请选择',
  193. },
  194. {
  195. title: '时间',
  196. key: 'time',
  197. type: JVxeTypes.time,
  198. width: 200,
  199. defaultValue: '14:52:22',
  200. placeholder: '请选择',
  201. },
  202. {
  203. title: '复选框',
  204. key: 'checkbox',
  205. type: JVxeTypes.checkbox,
  206. width: 100,
  207. customValue: ['Y', 'N'], // true ,false
  208. defaultChecked: false,
  209. },
  210. {
  211. title: '操作',
  212. key: 'action',
  213. type: JVxeTypes.slot,
  214. fixed: 'right',
  215. minWidth: 100,
  216. align: 'center',
  217. slotName: 'myAction',
  218. },
  219. ]);
  220. const dataSource = ref<any[]>([]);
  221. /* 随机生成数据 */
  222. function randomPage(current, pageSize, isLoading = false) {
  223. if (isLoading) {
  224. loading.value = true;
  225. }
  226. let randomDatetime = () => {
  227. let time = random(1000, 9999999999999);
  228. return dayjs(new Date(time)).format('YYYY-MM-DD HH:mm:ss');
  229. };
  230. let limit = (current - 1) * pageSize;
  231. let options = ['string', 'int', 'double', 'boolean'];
  232. let begin = Date.now();
  233. let values: any[] = [];
  234. for (let i = 0; i < pageSize; i++) {
  235. values.push({
  236. id: buildUUID(),
  237. noEdit: `noEdit-${limit + i + 1}`,
  238. input: `text-${limit + i + 1}`,
  239. textarea: `textarea-${limit + i + 1}`,
  240. number: random(0, 233),
  241. select: options[random(0, 3)],
  242. select_dict: random(1, 2).toString(),
  243. select_multiple: (() => {
  244. let length = random(1, 4);
  245. let arr = [];
  246. for (let j = 0; j < length; j++) {
  247. pushIfNotExist(arr, options[random(0, 3)]);
  248. }
  249. return arr.join(',');
  250. })(),
  251. select_search: options[random(0, 3)],
  252. datetime: randomDatetime(),
  253. checkbox: ['Y', 'N'][random(0, 1)],
  254. });
  255. }
  256. dataSource.value = values;
  257. let end = Date.now();
  258. let diff = end - begin;
  259. if (isLoading && diff < pageSize) {
  260. setTimeout(() => (loading.value = false), pageSize - diff);
  261. }
  262. }
  263. randomPage(0, 20, true);
  264. function onLookRow(props) {
  265. createMessage.success('请在控制台查看输出');
  266. // 参数介绍:
  267. // props.value 当前单元格的值
  268. // props.row 当前行的数据
  269. // props.rowId 当前行ID
  270. // props.rowIndex 当前行下标
  271. // props.column 当前列的配置
  272. // props.columnIndex 当前列下标
  273. // props.$table vxe实例,可以调用vxe内置方法
  274. // props.target JVXE实例,可以调用JVXE内置方法
  275. // props.caseId JVXE实例唯一ID
  276. // props.scrolling 是否正在滚动
  277. // props.triggerChange 触发change事件,用于更改slot的值
  278. console.log('查看: ', { props });
  279. }
  280. async function onDeleteRow(props) {
  281. // 调用删除方法
  282. const res = await tableRef.value?.removeRows(props.row);
  283. if (res && res.rows.length > 0) {
  284. createMessage.success('删除成功');
  285. }
  286. }
  287. function handleValueChange(event) {
  288. console.log('handleValueChange.event: ', event);
  289. }
  290. // update-begin--author:liaozhiyang---date:20230817---for:【issues/636】JVxeTable加上blur事件
  291. function handleBlur(event){
  292. console.log("blur",event);
  293. }
  294. // update-end--author:liaozhiyang---date:20230817---for:【issues/636】JVxeTable加上blur事件
  295. /** 表单验证 */
  296. function handleTableCheck() {
  297. tableRef.value!.validateTable().then((errMap) => {
  298. if (errMap) {
  299. console.log('表单验证未通过:', { errMap });
  300. createMessage.error('验证未通过,请在控制台查看详细');
  301. } else {
  302. createMessage.success('验证通过');
  303. }
  304. });
  305. }
  306. /** 获取值,忽略表单验证 */
  307. function onGetData() {
  308. const values = tableRef.value!.getTableData();
  309. console.log('获取值:', { values });
  310. createMessage.success('获取值成功,请看控制台输出');
  311. }
  312. /** 模拟加载1000条数据 */
  313. function handleTableSet() {
  314. randomPage(1, 1000, true);
  315. }
  316. function onDelFirst() {
  317. const xTable = tableRef.value!.getXTable();
  318. const record = xTable.getTableData().fullData[0];
  319. tableRef.value!.removeRows(record);
  320. }
  321. function onDelSel() {
  322. const xTable = tableRef.value!.getXTable();
  323. xTable.removeCheckboxRow();
  324. }
  325. function onGetSelData() {
  326. createMessage.info('请看控制台');
  327. console.log(tableRef.value!.getSelectionData());
  328. }
  329. function onClearSel() {
  330. tableRef.value!.clearSelection();
  331. }
  332. function onToggleLoading() {
  333. loading.value = !loading.value;
  334. }
  335. function onToggleDisabled() {
  336. disabled.value = !disabled.value;
  337. }
  338. function doDelete(deleteRows) {
  339. return new Promise((resolve) => {
  340. let rowId = deleteRows.filter((row) => row.id);
  341. console.log('删除 rowId: ', rowId);
  342. setTimeout(() => resolve(true), 1500);
  343. });
  344. }
  345. /** 异步删除示例 */
  346. async function onJVxeRemove(event) {
  347. const hideLoading = createMessage.loading('删除中…', 0);
  348. try {
  349. // 1. 向后台传递 event.deleteRows 以删除
  350. let flag = await doDelete(event.deleteRows);
  351. if (flag) {
  352. // 注:如果启用了表格的 loading 状态,则必须先停止再删除,否则会导致无法从表格上删除数据
  353. // 2. 调用 event.confirmRemove 方法确认删除成功
  354. // await tableRef.value!.removeSelection();
  355. await event.confirmRemove()
  356. createMessage.success('删除成功!');
  357. } else {
  358. // 3. 若删除失败,不调用 event.confirmRemove() 方法就不会删除数据
  359. createMessage.warn('删除失败!');
  360. }
  361. } finally {
  362. hideLoading();
  363. }
  364. }
  365. </script>