App.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780
  1. <script setup lang="ts">
  2. import { reactive, ref, onMounted, markRaw } from 'vue'
  3. import { ElConfigProvider, ElIcon } from 'element-plus'
  4. import zhCn from 'element-plus/lib/locale/lang/zh-cn'
  5. // import en from 'element-plus/lib/locale/lang/en'
  6. import { VFrom } from '@/components/Form'
  7. import Calendar from '~icons/ep/calendar'
  8. import Check from '~icons/ep/check'
  9. import Close from '~icons/ep/close'
  10. import ChatRound from '~icons/ep/chatRound'
  11. import ChatLineRound from '~icons/ep/chatLineRound'
  12. import ChatDotRound from '~icons/ep/chatDotRound'
  13. import { useI18n } from '@/hooks/web/useI18n'
  14. const { t } = useI18n()
  15. const restaurants = ref<Recordable[]>([])
  16. const querySearch = (queryString: string, cb: Fn) => {
  17. const results = queryString
  18. ? restaurants.value.filter(createFilter(queryString))
  19. : restaurants.value
  20. // call callback function to return suggestions
  21. cb(results)
  22. }
  23. const createFilter = (queryString: string) => {
  24. return (restaurant: Recordable) => {
  25. return restaurant.value.toLowerCase().indexOf(queryString.toLowerCase()) === 0
  26. }
  27. }
  28. const loadAll = () => {
  29. return [
  30. { value: 'vue', link: 'https://github.com/vuejs/vue' },
  31. { value: 'element', link: 'https://github.com/ElemeFE/element' },
  32. { value: 'cooking', link: 'https://github.com/ElemeFE/cooking' },
  33. { value: 'mint-ui', link: 'https://github.com/ElemeFE/mint-ui' },
  34. { value: 'vuex', link: 'https://github.com/vuejs/vuex' },
  35. { value: 'vue-router', link: 'https://github.com/vuejs/vue-router' },
  36. { value: 'babel', link: 'https://github.com/babel/babel' }
  37. ]
  38. }
  39. const handleSelect = (item: Recordable) => {
  40. console.log(item)
  41. }
  42. onMounted(() => {
  43. restaurants.value = loadAll()
  44. })
  45. const initials = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']
  46. const options = ref<FormOptions[]>(
  47. Array.from({ length: 1000 }).map((_, idx) => ({
  48. value: `Option ${idx + 1}`,
  49. label: `${initials[idx % 10]}${idx}`
  50. }))
  51. )
  52. const options2 = ref<FormOptions[]>(
  53. Array.from({ length: 10 }).map((_, idx) => {
  54. const label = idx + 1
  55. return {
  56. value: `Group ${label}`,
  57. label: `Group ${label}`,
  58. options: Array.from({ length: 10 }).map((_, idx) => ({
  59. value: `Option ${idx + 1 + 10 * label}`,
  60. label: `${initials[idx % 10]}${idx + 1 + 10 * label}`
  61. }))
  62. }
  63. })
  64. )
  65. const options3: FormOptions[] = [
  66. {
  67. value: 'guide',
  68. label: 'Guide',
  69. children: [
  70. {
  71. value: 'disciplines',
  72. label: 'Disciplines',
  73. children: [
  74. {
  75. value: 'consistency',
  76. label: 'Consistency'
  77. },
  78. {
  79. value: 'feedback',
  80. label: 'Feedback'
  81. },
  82. {
  83. value: 'efficiency',
  84. label: 'Efficiency'
  85. },
  86. {
  87. value: 'controllability',
  88. label: 'Controllability'
  89. }
  90. ]
  91. },
  92. {
  93. value: 'navigation',
  94. label: 'Navigation',
  95. children: [
  96. {
  97. value: 'side nav',
  98. label: 'Side Navigation'
  99. },
  100. {
  101. value: 'top nav',
  102. label: 'Top Navigation'
  103. }
  104. ]
  105. }
  106. ]
  107. },
  108. {
  109. value: 'component',
  110. label: 'Component',
  111. children: [
  112. {
  113. value: 'basic',
  114. label: 'Basic',
  115. children: [
  116. {
  117. value: 'layout',
  118. label: 'Layout'
  119. },
  120. {
  121. value: 'color',
  122. label: 'Color'
  123. },
  124. {
  125. value: 'typography',
  126. label: 'Typography'
  127. },
  128. {
  129. value: 'icon',
  130. label: 'Icon'
  131. },
  132. {
  133. value: 'button',
  134. label: 'Button'
  135. }
  136. ]
  137. },
  138. {
  139. value: 'form',
  140. label: 'Form',
  141. children: [
  142. {
  143. value: 'radio',
  144. label: 'Radio'
  145. },
  146. {
  147. value: 'checkbox',
  148. label: 'Checkbox'
  149. },
  150. {
  151. value: 'input',
  152. label: 'Input'
  153. },
  154. {
  155. value: 'input-number',
  156. label: 'InputNumber'
  157. },
  158. {
  159. value: 'select',
  160. label: 'Select'
  161. },
  162. {
  163. value: 'cascader',
  164. label: 'Cascader'
  165. },
  166. {
  167. value: 'switch',
  168. label: 'Switch'
  169. },
  170. {
  171. value: 'slider',
  172. label: 'Slider'
  173. },
  174. {
  175. value: 'time-picker',
  176. label: 'TimePicker'
  177. },
  178. {
  179. value: 'date-picker',
  180. label: 'DatePicker'
  181. },
  182. {
  183. value: 'datetime-picker',
  184. label: 'DateTimePicker'
  185. },
  186. {
  187. value: 'upload',
  188. label: 'Upload'
  189. },
  190. {
  191. value: 'rate',
  192. label: 'Rate'
  193. },
  194. {
  195. value: 'form',
  196. label: 'Form'
  197. }
  198. ]
  199. },
  200. {
  201. value: 'data',
  202. label: 'Data',
  203. children: [
  204. {
  205. value: 'table',
  206. label: 'Table'
  207. },
  208. {
  209. value: 'tag',
  210. label: 'Tag'
  211. },
  212. {
  213. value: 'progress',
  214. label: 'Progress'
  215. },
  216. {
  217. value: 'tree',
  218. label: 'Tree'
  219. },
  220. {
  221. value: 'pagination',
  222. label: 'Pagination'
  223. },
  224. {
  225. value: 'badge',
  226. label: 'Badge'
  227. }
  228. ]
  229. },
  230. {
  231. value: 'notice',
  232. label: 'Notice',
  233. children: [
  234. {
  235. value: 'alert',
  236. label: 'Alert'
  237. },
  238. {
  239. value: 'loading',
  240. label: 'Loading'
  241. },
  242. {
  243. value: 'message',
  244. label: 'Message'
  245. },
  246. {
  247. value: 'message-box',
  248. label: 'MessageBox'
  249. },
  250. {
  251. value: 'notification',
  252. label: 'Notification'
  253. }
  254. ]
  255. },
  256. {
  257. value: 'navigation',
  258. label: 'Navigation',
  259. children: [
  260. {
  261. value: 'menu',
  262. label: 'Menu'
  263. },
  264. {
  265. value: 'tabs',
  266. label: 'Tabs'
  267. },
  268. {
  269. value: 'breadcrumb',
  270. label: 'Breadcrumb'
  271. },
  272. {
  273. value: 'dropdown',
  274. label: 'Dropdown'
  275. },
  276. {
  277. value: 'steps',
  278. label: 'Steps'
  279. }
  280. ]
  281. },
  282. {
  283. value: 'others',
  284. label: 'Others',
  285. children: [
  286. {
  287. value: 'dialog',
  288. label: 'Dialog'
  289. },
  290. {
  291. value: 'tooltip',
  292. label: 'Tooltip'
  293. },
  294. {
  295. value: 'popover',
  296. label: 'Popover'
  297. },
  298. {
  299. value: 'card',
  300. label: 'Card'
  301. },
  302. {
  303. value: 'carousel',
  304. label: 'Carousel'
  305. },
  306. {
  307. value: 'collapse',
  308. label: 'Collapse'
  309. }
  310. ]
  311. }
  312. ]
  313. }
  314. ]
  315. function generateData() {
  316. const data: {
  317. value: number
  318. desc: string
  319. disabled: boolean
  320. }[] = []
  321. for (let i = 1; i <= 15; i++) {
  322. data.push({
  323. value: i,
  324. desc: `Option ${i}`,
  325. disabled: i % 4 === 0
  326. })
  327. }
  328. return data
  329. }
  330. const schema = reactive<VFormSchema[]>([
  331. {
  332. field: 'field1',
  333. label: t('formDemo.input'),
  334. component: 'Divider'
  335. },
  336. {
  337. field: 'field2',
  338. label: t('formDemo.default'),
  339. component: 'Input'
  340. },
  341. {
  342. field: 'field3',
  343. label: `${t('formDemo.icon')}1`,
  344. component: 'Input',
  345. componentProps: {
  346. suffixIcon: markRaw(Calendar),
  347. prefixIcon: markRaw(Calendar)
  348. }
  349. },
  350. {
  351. field: 'field4',
  352. label: `${t('formDemo.icon')}2`,
  353. component: 'Input',
  354. componentProps: {
  355. slots: {
  356. suffix: true,
  357. prefix: true
  358. }
  359. }
  360. },
  361. {
  362. field: 'field5',
  363. label: t('formDemo.mixed'),
  364. component: 'Input',
  365. componentProps: {
  366. slots: {
  367. prepend: true,
  368. append: true
  369. }
  370. }
  371. },
  372. {
  373. field: 'field6',
  374. label: t('formDemo.textarea'),
  375. component: 'Input',
  376. componentProps: {
  377. type: 'textarea',
  378. rows: 1
  379. }
  380. },
  381. {
  382. field: 'field7',
  383. label: t('formDemo.autocomplete'),
  384. component: 'Divider'
  385. },
  386. {
  387. field: 'field8',
  388. label: t('formDemo.default'),
  389. component: 'Autocomplete',
  390. componentProps: {
  391. fetchSuggestions: querySearch,
  392. onSelect: handleSelect
  393. }
  394. },
  395. {
  396. field: 'field9',
  397. label: t('formDemo.slot'),
  398. component: 'Autocomplete',
  399. componentProps: {
  400. fetchSuggestions: querySearch,
  401. onSelect: handleSelect,
  402. slots: {
  403. default: true
  404. }
  405. }
  406. },
  407. {
  408. field: 'field10',
  409. component: 'Divider',
  410. label: t('formDemo.inputNumber')
  411. },
  412. {
  413. field: 'field11',
  414. label: t('formDemo.default'),
  415. component: 'InputNumber',
  416. value: 0
  417. },
  418. {
  419. field: 'field12',
  420. label: t('formDemo.position'),
  421. component: 'InputNumber',
  422. componentProps: {
  423. controlsPosition: 'right'
  424. },
  425. value: 0
  426. },
  427. {
  428. field: 'field13',
  429. label: t('formDemo.select'),
  430. component: 'Divider'
  431. },
  432. {
  433. field: 'field14',
  434. label: t('formDemo.default'),
  435. component: 'Select',
  436. options: [
  437. {
  438. label: '选项1',
  439. value: '1'
  440. },
  441. {
  442. label: '选项2',
  443. value: '2'
  444. }
  445. ]
  446. },
  447. {
  448. field: 'field15',
  449. label: t('formDemo.slot'),
  450. component: 'Select',
  451. options: [
  452. {
  453. label: '选项1',
  454. value: '1'
  455. },
  456. {
  457. label: '选项2',
  458. value: '2'
  459. }
  460. ],
  461. optionsSlot: true
  462. },
  463. {
  464. field: 'field16',
  465. label: t('formDemo.group'),
  466. component: 'Select',
  467. options: [
  468. {
  469. label: '选项1',
  470. options: [
  471. {
  472. label: '选项1-1',
  473. value: '1-1'
  474. },
  475. {
  476. label: '选项1-2',
  477. value: '1-2'
  478. }
  479. ]
  480. },
  481. {
  482. label: '选项2',
  483. options: [
  484. {
  485. label: '选项2-1',
  486. value: '2-1'
  487. },
  488. {
  489. label: '选项2-2',
  490. value: '2-2'
  491. }
  492. ]
  493. }
  494. ]
  495. },
  496. {
  497. field: 'field17',
  498. label: `${t('formDemo.group')}${t('formDemo.slot')}`,
  499. component: 'Select',
  500. options: [
  501. {
  502. label: '选项1',
  503. options: [
  504. {
  505. label: '选项1-1',
  506. value: '1-1'
  507. },
  508. {
  509. label: '选项1-2',
  510. value: '1-2'
  511. }
  512. ]
  513. },
  514. {
  515. label: '选项2',
  516. options: [
  517. {
  518. label: '选项2-1',
  519. value: '2-1'
  520. },
  521. {
  522. label: '选项2-2',
  523. value: '2-2'
  524. }
  525. ]
  526. }
  527. ],
  528. optionsSlot: true
  529. },
  530. {
  531. field: 'field18',
  532. label: `${t('formDemo.selectV2')}`,
  533. component: 'Divider'
  534. },
  535. {
  536. field: 'field19',
  537. label: t('formDemo.default'),
  538. component: 'SelectV2',
  539. options: options.value
  540. },
  541. {
  542. field: 'field20',
  543. label: t('formDemo.slot'),
  544. component: 'SelectV2',
  545. options: options.value,
  546. componentProps: {
  547. slots: {
  548. default: true
  549. }
  550. }
  551. },
  552. {
  553. field: 'field21',
  554. label: t('formDemo.group'),
  555. component: 'SelectV2',
  556. options: options2.value
  557. },
  558. {
  559. field: 'field22',
  560. label: `${t('formDemo.group')}${t('formDemo.slot')}`,
  561. component: 'SelectV2',
  562. options: options2.value,
  563. componentProps: {
  564. slots: {
  565. default: true
  566. }
  567. }
  568. },
  569. {
  570. field: 'field23',
  571. label: t('formDemo.cascader'),
  572. component: 'Divider'
  573. },
  574. {
  575. field: 'field24',
  576. label: t('formDemo.default'),
  577. component: 'Cascader',
  578. options: options3
  579. },
  580. {
  581. field: 'field25',
  582. label: t('formDemo.slot'),
  583. component: 'Cascader',
  584. options: options3,
  585. componentProps: {
  586. slots: {
  587. default: true
  588. }
  589. }
  590. },
  591. {
  592. field: 'field26',
  593. label: t('formDemo.switch'),
  594. component: 'Divider'
  595. },
  596. {
  597. field: 'field27',
  598. label: t('formDemo.default'),
  599. component: 'Switch',
  600. value: false
  601. },
  602. {
  603. field: 'field28',
  604. label: t('formDemo.icon'),
  605. component: 'Switch',
  606. value: false,
  607. componentProps: {
  608. activeIcon: markRaw(Check),
  609. inactiveIcon: markRaw(Close)
  610. }
  611. },
  612. {
  613. field: 'field29',
  614. label: t('formDemo.rate'),
  615. component: 'Divider'
  616. },
  617. {
  618. field: 'field30',
  619. label: t('formDemo.default'),
  620. component: 'Rate',
  621. value: null
  622. },
  623. {
  624. field: 'field31',
  625. label: t('formDemo.icon'),
  626. component: 'Rate',
  627. value: null,
  628. componentProps: {
  629. voidIcon: markRaw(ChatRound),
  630. icons: [markRaw(ChatRound), markRaw(ChatLineRound), markRaw(ChatDotRound)]
  631. }
  632. },
  633. {
  634. field: 'field32',
  635. label: t('formDemo.colorPicker'),
  636. component: 'Divider'
  637. },
  638. {
  639. field: 'field33',
  640. label: t('formDemo.default'),
  641. component: 'ColorPicker'
  642. },
  643. {
  644. field: 'field34',
  645. label: t('formDemo.transfer'),
  646. component: 'Divider'
  647. },
  648. {
  649. field: 'field35',
  650. label: t('formDemo.default'),
  651. component: 'Transfer',
  652. componentProps: {
  653. props: {
  654. key: 'value',
  655. label: 'desc',
  656. disabled: 'disabled'
  657. },
  658. data: generateData()
  659. },
  660. value: [],
  661. colProps: {
  662. xl: 12
  663. }
  664. },
  665. {
  666. field: 'field36',
  667. label: t('formDemo.slot'),
  668. component: 'Transfer',
  669. componentProps: {
  670. props: {
  671. key: 'value',
  672. label: 'desc',
  673. disabled: 'disabled'
  674. },
  675. leftDefaultChecked: [2, 3],
  676. rightDefaultChecked: [1],
  677. data: generateData(),
  678. slots: {
  679. default: true
  680. }
  681. },
  682. value: [1],
  683. colProps: {
  684. xl: 12
  685. }
  686. },
  687. {
  688. field: 'field37',
  689. label: `${t('formDemo.render')}`,
  690. component: 'Transfer',
  691. componentProps: {
  692. props: {
  693. key: 'value',
  694. label: 'desc',
  695. disabled: 'disabled'
  696. },
  697. leftDefaultChecked: [2, 3],
  698. rightDefaultChecked: [1],
  699. data: generateData(),
  700. renderContent: (h: Fn, option: Recordable) => {
  701. return h('span', null, `${option.value} - ${option.desc}`)
  702. }
  703. },
  704. value: [1],
  705. colProps: {
  706. xl: 12
  707. }
  708. }
  709. ])
  710. setTimeout(() => {
  711. if (schema[2].componentProps) {
  712. schema[2].componentProps.placeholder = 'test'
  713. console.log(schema[2])
  714. }
  715. }, 3000)
  716. </script>
  717. <template>
  718. <ElConfigProvider :locale="zhCn">
  719. <VFrom :schema="schema">
  720. <template #field4-prefix>
  721. <ElIcon class="el-input__icon"><Calendar /></ElIcon>
  722. </template>
  723. <template #field4-suffix>
  724. <ElIcon class="el-input__icon"><Calendar /></ElIcon>
  725. </template>
  726. <template #field5-prepend> Http:// </template>
  727. <template #field5-append> .com </template>
  728. <template #field9-default="{ item }">
  729. <div class="value">{{ item.value }}</div>
  730. <span class="link">{{ item.link }}</span>
  731. </template>
  732. <template #field15-option="{ item }">
  733. <span style="float: left">{{ item.label }}</span>
  734. <span style="float: right; font-size: 13px; color: var(--el-text-color-secondary)">
  735. {{ item.value }}
  736. </span>
  737. </template>
  738. <template #field17-option="{ item }">
  739. <span style="float: left">{{ item.label }}</span>
  740. <span style="float: right; font-size: 13px; color: var(--el-text-color-secondary)">
  741. {{ item.value }}
  742. </span>
  743. </template>
  744. <template #field20-default="{ item }">
  745. <span style="float: left">{{ item.label }}</span>
  746. <span style="float: right; font-size: 13px; color: var(--el-text-color-secondary)">
  747. {{ item.value }}
  748. </span>
  749. </template>
  750. <template #field22-default="{ item }">
  751. <span style="float: left">{{ item.label }}</span>
  752. <span style="float: right; font-size: 13px; color: var(--el-text-color-secondary)">
  753. {{ item.value }}
  754. </span>
  755. </template>
  756. <template #field25-default="{ node, data }">
  757. <span>{{ data.label }}</span>
  758. <span v-if="!node.isLeaf"> ({{ data.children.length }}) </span>
  759. </template>
  760. <template #field36-default="{ option }">
  761. <span>{{ option.value }} - {{ option.desc }}</span>
  762. </template>
  763. </VFrom>
  764. </ElConfigProvider>
  765. </template>