JVxeDemo1.vue 11 KB

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