index.vue 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464
  1. <template>
  2. <PageWrapper title="表单基础示例" contentFullHeight>
  3. <CollapseContainer title="基础示例">
  4. <BasicForm
  5. autoFocusFirstItem
  6. :labelWidth="200"
  7. :schemas="schemas"
  8. :actionColOptions="{ span: 24 }"
  9. @submit="handleSubmit"
  10. @reset="handleReset"
  11. >
  12. <template #localSearch="{ model, field }">
  13. <ApiSelect
  14. :api="optionsListApi"
  15. showSearch
  16. v-model:value="model[field]"
  17. optionFilterProp="label"
  18. resultField="list"
  19. labelField="name"
  20. valueField="id"
  21. />
  22. </template>
  23. <template #remoteSearch="{ model, field }">
  24. <ApiSelect
  25. :api="optionsListApi"
  26. showSearch
  27. v-model:value="model[field]"
  28. :filterOption="false"
  29. resultField="list"
  30. labelField="name"
  31. valueField="id"
  32. :params="searchParams"
  33. @search="onSearch"
  34. />
  35. </template>
  36. </BasicForm>
  37. </CollapseContainer>
  38. </PageWrapper>
  39. </template>
  40. <script lang="ts">
  41. import { computed, defineComponent, unref, ref } from 'vue';
  42. import { BasicForm, FormSchema, ApiSelect } from '/@/components/Form/index';
  43. import { CollapseContainer } from '/@/components/Container';
  44. import { useMessage } from '/@/hooks/web/useMessage';
  45. import { PageWrapper } from '/@/components/Page';
  46. import { optionsListApi } from '/@/api/demo/select';
  47. import { useDebounceFn } from '@vueuse/core';
  48. const provincesOptions = [
  49. {
  50. id: 'guangdong',
  51. label: '广东省',
  52. value: '1',
  53. key: '1',
  54. },
  55. {
  56. id: 'jiangsu',
  57. label: '江苏省',
  58. value: '2',
  59. key: '2',
  60. },
  61. ];
  62. const citiesOptionsData = {
  63. guangdong: [
  64. {
  65. label: '珠海市',
  66. value: '1',
  67. key: '1',
  68. },
  69. {
  70. label: '深圳市',
  71. value: '2',
  72. key: '2',
  73. },
  74. {
  75. label: '广州市',
  76. value: '3',
  77. key: '3',
  78. },
  79. ],
  80. jiangsu: [
  81. {
  82. label: '南京市',
  83. value: '1',
  84. key: '1',
  85. },
  86. {
  87. label: '无锡市',
  88. value: '2',
  89. key: '2',
  90. },
  91. {
  92. label: '苏州市',
  93. value: '3',
  94. key: '3',
  95. },
  96. ],
  97. };
  98. const schemas: FormSchema[] = [
  99. {
  100. field: 'field1',
  101. component: 'Input',
  102. label: '字段1',
  103. colProps: {
  104. span: 8,
  105. },
  106. // componentProps:{},
  107. // can func
  108. componentProps: ({ schema, formModel }) => {
  109. console.log('form:', schema);
  110. console.log('formModel:', formModel);
  111. return {
  112. placeholder: '自定义placeholder',
  113. onChange: (e: any) => {
  114. console.log(e);
  115. },
  116. };
  117. },
  118. renderComponentContent: () => {
  119. return {
  120. prefix: () => 'pSlot',
  121. suffix: () => 'sSlot',
  122. };
  123. },
  124. },
  125. {
  126. field: 'field2',
  127. component: 'Input',
  128. label: '带后缀',
  129. defaultValue: '111',
  130. colProps: {
  131. span: 8,
  132. },
  133. componentProps: {
  134. onChange: (e: any) => {
  135. console.log(e);
  136. },
  137. },
  138. suffix: '天',
  139. },
  140. {
  141. field: 'field3',
  142. component: 'DatePicker',
  143. label: '字段3',
  144. colProps: {
  145. span: 8,
  146. },
  147. },
  148. {
  149. field: 'field4',
  150. component: 'Select',
  151. label: '字段4',
  152. colProps: {
  153. span: 8,
  154. },
  155. componentProps: {
  156. options: [
  157. {
  158. label: '选项1',
  159. value: '1',
  160. key: '1',
  161. },
  162. {
  163. label: '选项2',
  164. value: '2',
  165. key: '2',
  166. },
  167. ],
  168. },
  169. },
  170. {
  171. field: 'field5',
  172. component: 'CheckboxGroup',
  173. label: '字段5',
  174. colProps: {
  175. span: 8,
  176. },
  177. componentProps: {
  178. options: [
  179. {
  180. label: '选项1',
  181. value: '1',
  182. },
  183. {
  184. label: '选项2',
  185. value: '2',
  186. },
  187. ],
  188. },
  189. },
  190. {
  191. field: 'field7',
  192. component: 'RadioGroup',
  193. label: '字段7',
  194. colProps: {
  195. span: 8,
  196. },
  197. componentProps: {
  198. options: [
  199. {
  200. label: '选项1',
  201. value: '1',
  202. },
  203. {
  204. label: '选项2',
  205. value: '2',
  206. },
  207. ],
  208. },
  209. },
  210. {
  211. field: 'field8',
  212. component: 'Checkbox',
  213. label: '字段8',
  214. colProps: {
  215. span: 8,
  216. },
  217. renderComponentContent: 'Check',
  218. },
  219. {
  220. field: 'field9',
  221. component: 'Switch',
  222. label: '字段9',
  223. colProps: {
  224. span: 8,
  225. },
  226. },
  227. {
  228. field: 'field10',
  229. component: 'RadioButtonGroup',
  230. label: '字段10',
  231. colProps: {
  232. span: 8,
  233. },
  234. componentProps: {
  235. options: [
  236. {
  237. label: '选项1',
  238. value: '1',
  239. },
  240. {
  241. label: '选项2',
  242. value: '2',
  243. },
  244. ],
  245. },
  246. },
  247. {
  248. field: 'field11',
  249. component: 'Cascader',
  250. label: '字段11',
  251. colProps: {
  252. span: 8,
  253. },
  254. componentProps: {
  255. options: [
  256. {
  257. value: 'zhejiang',
  258. label: 'Zhejiang',
  259. children: [
  260. {
  261. value: 'hangzhou',
  262. label: 'Hangzhou',
  263. children: [
  264. {
  265. value: 'xihu',
  266. label: 'West Lake',
  267. },
  268. ],
  269. },
  270. ],
  271. },
  272. {
  273. value: 'jiangsu',
  274. label: 'Jiangsu',
  275. children: [
  276. {
  277. value: 'nanjing',
  278. label: 'Nanjing',
  279. children: [
  280. {
  281. value: 'zhonghuamen',
  282. label: 'Zhong Hua Men',
  283. },
  284. ],
  285. },
  286. ],
  287. },
  288. ],
  289. },
  290. },
  291. {
  292. field: 'field30',
  293. component: 'ApiSelect',
  294. label: '懒加载远程下拉',
  295. required: true,
  296. componentProps: {
  297. // more details see /src/components/Form/src/components/ApiSelect.vue
  298. api: optionsListApi,
  299. params: {
  300. id: 1,
  301. },
  302. resultField: 'list',
  303. // use name as label
  304. labelField: 'name',
  305. // use id as value
  306. valueField: 'id',
  307. // not request untill to select
  308. immediate: false,
  309. onChange: (e) => {
  310. console.log('selected:', e);
  311. },
  312. // atfer request callback
  313. onOptionsChange: (options) => {
  314. console.log('get options', options.length, options);
  315. },
  316. },
  317. colProps: {
  318. span: 8,
  319. },
  320. defaultValue: '0',
  321. },
  322. {
  323. field: 'field31',
  324. component: 'Input',
  325. label: '下拉本地搜索',
  326. helpMessage: ['ApiSelect组件', '远程数据源本地搜索', '只发起一次请求获取所有选项'],
  327. required: true,
  328. slot: 'localSearch',
  329. colProps: {
  330. span: 8,
  331. },
  332. defaultValue: '0',
  333. },
  334. {
  335. field: 'field32',
  336. component: 'Input',
  337. label: '下拉远程搜索',
  338. helpMessage: ['ApiSelect组件', '将关键词发送到接口进行远程搜索'],
  339. required: true,
  340. slot: 'remoteSearch',
  341. colProps: {
  342. span: 8,
  343. },
  344. defaultValue: '0',
  345. },
  346. {
  347. field: 'field20',
  348. component: 'InputNumber',
  349. label: '字段20',
  350. required: true,
  351. colProps: {
  352. span: 8,
  353. },
  354. },
  355. {
  356. field: 'province',
  357. component: 'Select',
  358. label: '省份',
  359. colProps: {
  360. span: 8,
  361. },
  362. componentProps: ({ formModel, formActionType }) => {
  363. return {
  364. options: provincesOptions,
  365. placeholder: '省份与城市联动',
  366. onChange: (e: any) => {
  367. // console.log(e)
  368. let citiesOptions =
  369. e == 1
  370. ? citiesOptionsData[provincesOptions[0].id]
  371. : citiesOptionsData[provincesOptions[1].id];
  372. // console.log(citiesOptions)
  373. if (e === undefined) {
  374. citiesOptions = [];
  375. }
  376. formModel.city = undefined; // reset city value
  377. const { updateSchema } = formActionType;
  378. updateSchema({
  379. field: 'city',
  380. componentProps: {
  381. options: citiesOptions,
  382. },
  383. });
  384. },
  385. };
  386. },
  387. },
  388. {
  389. field: 'city',
  390. component: 'Select',
  391. label: '城市',
  392. colProps: {
  393. span: 8,
  394. },
  395. componentProps: {
  396. options: [], // defalut []
  397. placeholder: '省份与城市联动',
  398. },
  399. },
  400. {
  401. field: 'field21',
  402. component: 'Slider',
  403. label: '字段21',
  404. componentProps: {
  405. min: 0,
  406. max: 100,
  407. range: true,
  408. marks: {
  409. 20: '20°C',
  410. 60: '60°C',
  411. },
  412. },
  413. colProps: {
  414. span: 8,
  415. },
  416. },
  417. {
  418. field: 'field22',
  419. component: 'Rate',
  420. label: '字段22',
  421. defaultValue: 3,
  422. colProps: {
  423. span: 8,
  424. },
  425. componentProps: {
  426. disabled: false,
  427. allowHalf: true,
  428. },
  429. },
  430. ];
  431. export default defineComponent({
  432. components: { BasicForm, CollapseContainer, PageWrapper, ApiSelect },
  433. setup() {
  434. const check = ref(null);
  435. const { createMessage } = useMessage();
  436. const keyword = ref<string>('');
  437. const searchParams = computed<Recordable>(() => {
  438. return { keyword: unref(keyword) };
  439. });
  440. function onSearch(value: string) {
  441. keyword.value = value;
  442. }
  443. return {
  444. schemas,
  445. optionsListApi,
  446. onSearch: useDebounceFn(onSearch, 300),
  447. searchParams,
  448. handleReset: () => {
  449. keyword.value = '';
  450. },
  451. handleSubmit: (values: any) => {
  452. createMessage.success('click search,values:' + JSON.stringify(values));
  453. },
  454. check,
  455. };
  456. },
  457. });
  458. </script>