当前位置:   article > 正文

vue3一个相对完整的form组件_a-input v-model

a-input v-model

form.vue

  1. <template>
  2. <div>
  3. <a-form
  4. :model="form"
  5. ref="formRef"
  6. :label-col="labelCol"
  7. :wrapper-col="wrapperCol"
  8. :rules="rules"
  9. >
  10. <a-form-item
  11. v-for="(item, index) in formData"
  12. :key="index"
  13. v-show="item.show"
  14. :label="item.label"
  15. :name="item.key"
  16. >
  17. <a-input
  18. v-model:value.trim="form[item.key]"
  19. v-if="item.type == 'input'"
  20. :disabled="item.disabled"
  21. ></a-input>
  22. <!-- 编码查重开始 -->
  23. <a-input
  24. v-if="item.type == 'inputRepeat'"
  25. @blur="blurRepeatEvent(item)"
  26. @change="changeInputRepeat(item)"
  27. v-model:value.trim="form[item.key]"
  28. :disabled="formTitle.indexOf('修改') > -1"
  29. ></a-input>
  30. <div
  31. class="errortip"
  32. v-if="item.type == 'inputRepeat' && item.repeatObj.totalCount > 0"
  33. >
  34. {{ item.repeatObj.errorMessage }}
  35. </div>
  36. <div
  37. class="helptip"
  38. v-if="item.type == 'inputRepeat' && item.repeatObj?.checked"
  39. >
  40. 查重已通过
  41. </div>
  42. <!-- 编码查重结束 -->
  43. <a-textarea
  44. v-model:value.trim="form[item.key]"
  45. autoSize
  46. v-if="item.type == 'textarea'"
  47. :disabled="item.disabled"
  48. @blur="
  49. item.delSpaces
  50. ? blurEvent(`${item.key}`)
  51. : () => {
  52. return true;
  53. }
  54. "
  55. ></a-textarea>
  56. <!-- 籍贯 -->
  57. <v-distpicker
  58. v-if="item.type == 'space'"
  59. v-model="form[item.key]"
  60. @selected="selected"
  61. hide-area
  62. :province="nativePlace.province"
  63. :city="nativePlace.city"
  64. ></v-distpicker>
  65. <a-switch
  66. v-model:checked="form[item.key]"
  67. v-if="item.type == 'switch'"
  68. :disabled="item.disabled"
  69. ></a-switch>
  70. <a-date-picker
  71. v-if="item.type == 'datepicker'"
  72. :disabled="item.disabled"
  73. v-model:value="form[item.key]"
  74. />
  75. <a-input-search
  76. v-if="item.type == 'secretInput'"
  77. v-model:value="form[item.key]"
  78. @search="changeRandom(item.key)"
  79. :disabled="item.disabled"
  80. >
  81. <template #enterButton>
  82. <a-button :disabled="item.disabled">随机生成</a-button>
  83. </template></a-input-search
  84. >
  85. <a-select
  86. v-model:value="form[item.key]"
  87. v-if="item.type == 'select'"
  88. :disabled="item.disabled"
  89. :allowClear="item.allowClear"
  90. :getPopupContainer="(triggerNode) => triggerNode.parentNode"
  91. >
  92. <a-select-option
  93. v-for="selectOption in item.selectList"
  94. :key="selectOption.id"
  95. :value="selectOption.id"
  96. >{{
  97. selectOption.displayName || selectOption.name
  98. }}</a-select-option
  99. >
  100. </a-select>
  101. <Select
  102. ref="selectRef"
  103. v-if="item.type == 'requestSelect'"
  104. :objectName="item.key"
  105. :popupScroll="item.requestApi"
  106. :watchParams="item.watchParams"
  107. :params="item.requestParams"
  108. :isAffect="item.isAffect"
  109. :allowClear="item.requestAllowClear"
  110. @selectedValue="
  111. (value) => selectedValue(value, item.isAffect, item.key)
  112. "
  113. ></Select>
  114. <!-- 用户声明 -->
  115. <div v-if="item.type=='claims'">
  116. <div @click="selectDeclare">
  117. <a-input v-model:value="selectedDeclare"></a-input>
  118. </div>
  119. <div class="modal">
  120. <a-modal
  121. v-model:visible="visibleDeclare"
  122. :centered="true"
  123. :width="700"
  124. :closable="false"
  125. >
  126. <div class="modalBox">
  127. <div class="left">
  128. <div class="leftTitle">选择</div>
  129. <div class="leftList" v-if="leftList.length">
  130. <div
  131. v-for="(item, index) in leftList"
  132. :key="index"
  133. @click="selectEvent(item)"
  134. >
  135. {{ item.name }}
  136. </div>
  137. </div>
  138. <div class="leftList" v-else>
  139. <!-- <a-empty :image="Empty.PRESENTED_IMAGE_SIMPLE" /> -->
  140. </div>
  141. </div>
  142. <div class="right">
  143. <div class="leftTitle">已选</div>
  144. <div class="leftList" v-if="selectedList.length">
  145. <div v-for="(item, index) in selectedList" :key="index">
  146. {{ item.name }}
  147. <close-outlined
  148. @click="delSelectEvent(item)"
  149. style="font-size: 12px; float: right; line-height: 24px"
  150. />
  151. </div>
  152. </div>
  153. <div class="leftList" v-else>
  154. <!-- <a-empty :image="Empty.PRESENTED_IMAGE_SIMPLE" /> -->
  155. </div>
  156. </div>
  157. </div>
  158. <template #footer>
  159. <div style="text-align: center">
  160. <a-button @click="() => (visibleDeclare = false)">取消</a-button>
  161. <a-button type="primary" @click="ok">确定</a-button>
  162. </div>
  163. </template>
  164. </a-modal>
  165. </div>
  166. <!-- <selectModal
  167. :handleDelSelect="handleDelSelect"
  168. :selected="Selected"
  169. :visible="visibleDeclare"
  170. :cancel="cancelDeclare"
  171. :ok="ok"
  172. >
  173. <a-list bordered :data-source="selectList" >
  174. <a-list-item
  175. @click="getDeclareData(item)"
  176. slot="renderItem"
  177. slot-scope="item"
  178. style="padding-left: 20px;"
  179. >{{ item.name }}
  180. </a-list-item>
  181. </a-list>
  182. </selectModal> -->
  183. </div>
  184. </a-form-item>
  185. <div class="btn_box" v-if="showBtnGroup.submitBtn||showBtnGroup.cancelBtn">
  186. <div class="btnGroup">
  187. <a-button
  188. type="primary"
  189. v-show="showBtnGroup.submitBtn"
  190. :loading="loading"
  191. @click="submit"
  192. >提交</a-button
  193. >
  194. <a-button v-show="showBtnGroup.cancelBtn" @click="cancel"
  195. >取消</a-button
  196. >
  197. </div>
  198. </div>
  199. </a-form>
  200. </div>
  201. </template>
  202. <script setup>
  203. import moment from "moment";
  204. import selectModal from '@/components/selectModal/index.vue'
  205. import { getResource, getCurResource } from "@/api/resourceApi";
  206. import { getUserfield } from "@/api/userfieldApi";
  207. import VDistpicker from "v-distpicker";
  208. import { reactive, ref, watch, onMounted, nextTick, computed } from "vue";
  209. import { message } from "ant-design-vue";
  210. import Select from "@/components/Select/index.vue";
  211. import { useRoute } from "vue-router";
  212. import {getRandom}from '@/utils/globalFunc'
  213. const route = useRoute();
  214. // 表单
  215. let form = reactive({});
  216. // 表单的ref
  217. const formRef = ref();
  218. // 表单样式
  219. const labelCol = { span: 6 };
  220. const wrapperCol = { span: 14 };
  221. // 父组件传递的参数
  222. const props = defineProps({
  223. curRoleID: {
  224. type: String,
  225. default: "",
  226. },
  227. roleId: {
  228. type: String,
  229. default: "",
  230. },
  231. // 传递表单数据
  232. formData: {
  233. type: Array,
  234. default: () => {
  235. return [
  236. {
  237. key: "name", // 字段名(必填)
  238. value: "", //字段默认值(必填)
  239. label: "日志集名称", // 字段label名(必填)
  240. repeatObj: {
  241. validatorPass: false,
  242. checked: false,
  243. totalCount: 0,
  244. errorMessage: "",
  245. }, //查重必传属性
  246. rulesObj: {
  247. rule: [{ required: true, message: "名称为必填项" }],
  248. validate: null, //() => {}
  249. validataTrigger: "", //change/blur
  250. },
  251. type: "input", // 输入类型(必填)('input','select','inputRepeat(需要查重时使用)','textarea','switch','requestSelect(下拉列表需要滚动请求)',)
  252. delSpaces: false, // 'input', 'textarea'时,如果值中包含空格,失去焦点时自动去除
  253. show: true, // 该输入框是否展示(必填)
  254. disabled: false, // 输入框是否禁用(必填)
  255. selectList: [], // 类型为'select'必填
  256. allowClear: false, // 类型为'select'时,是否允许清除
  257. requestApi: () => {}, // 'requestSelect'时,请求接口
  258. requestAllowClear: false, // 'requestSelect'时,是否允许清除
  259. watchParams: true, // 'requestSelect'时,是否请求的监听参数
  260. requestParams: {}, // 'requestSelect'时,请求接口参数
  261. isAffect: true, // 'requestSelect'时,选值时是否影响其他requestSelect的选择
  262. },
  263. ];
  264. },
  265. },
  266. showBtnGroup: {
  267. type: Object,
  268. default: {
  269. submitBtn: true, // 提交按钮是否展示
  270. cancelBtn: true, // 取消按钮是否展示
  271. },
  272. },
  273. // 添加调用的接口
  274. addApi: {
  275. type: Function,
  276. default: () => {},
  277. },
  278. // 添加权限组调用的接口
  279. addGroupApi: {
  280. type: Function,
  281. default: () => {},
  282. },
  283. // 修改调用的接口closeForm
  284. editApi: {
  285. type: Function,
  286. default: () => {},
  287. },
  288. // 提交成功后刷新页面方法
  289. refreshFunc: {
  290. type: Function,
  291. default: () => {},
  292. },
  293. // 表单标题
  294. formTitle: {
  295. type: String,
  296. default: "",
  297. },
  298. // 关闭表单方法
  299. closeForm: {
  300. type: Function,
  301. default: () => {},
  302. },
  303. // 添加权限组成功后的回调
  304. childrenTable: {
  305. type: Function,
  306. default: () => {},
  307. },
  308. // 监听参数(是否打开表单)
  309. visible: {
  310. type: Boolean,
  311. default: false,
  312. },
  313. // 被控制/被影响的其他请求下拉框
  314. controlledSelect: {
  315. type: Function,
  316. default: () => {},
  317. },
  318. //用户管理列表修改、添加时,自定义字段的接口
  319. addCustomizeApi: {
  320. type: Function,
  321. default: () => {},
  322. },
  323. editCustomizeApi: {
  324. type: Function,
  325. default: () => {},
  326. },
  327. selectResourceCount: {
  328. type: Number,
  329. default: 0,
  330. },
  331. selectScopeCount: {
  332. type: Number,
  333. default: 0,
  334. },
  335. });
  336. onMounted(() => {
  337. // console.log('1',props.selectResourceCount)
  338. });
  339. // 请求下拉框的ref
  340. const selectRef = ref(null);
  341. // 防抖
  342. let loading = ref(false);
  343. let rules = ref({});
  344. const getRules = () => {
  345. props.formData.forEach((item) => {
  346. rules.value[item.key] = item.rulesObj
  347. ? [
  348. ...item.rulesObj.rule,
  349. {
  350. validator: async (rule, value) => {
  351. if (value) {
  352. if (item.rulesObj.validate) {
  353. const { success, message } = await item.rulesObj.validate(
  354. value,
  355. item
  356. );
  357. if (success) {
  358. return Promise.resolve();
  359. } else {
  360. return Promise.reject(message);
  361. }
  362. } else {
  363. return Promise.resolve();
  364. }
  365. }
  366. },
  367. trigger: item.rulesObj.validataTrigger
  368. ? item.rulesObj.validataTrigger
  369. : ["change", "blur"],
  370. },
  371. ]
  372. : [];
  373. });
  374. };
  375. // 查重
  376. const blurRepeatEvent = (item) => {
  377. if (item.repeatObj.validatorPass) {
  378. item
  379. .requestApi({ ...item.requestParams, code: form[item.key] })
  380. .then((res) => {
  381. if (res.totalCount > 0) {
  382. if (
  383. props.formTitle.indexOf("修改") > -1 &&
  384. item.value == form[item.key]
  385. ) {
  386. item.repeatObj.checked = true;
  387. } else {
  388. item.repeatObj.checked = false;
  389. item.repeatObj.totalCount = res.totalCount;
  390. }
  391. } else {
  392. item.repeatObj.checked = true;
  393. console.log('value',form[item.key])
  394. }
  395. })
  396. .catch((err) => {
  397. console.log("err", err);
  398. });
  399. }
  400. };
  401. function changeInputRepeat(item) {
  402. item.repeatObj.totalCount = 0;
  403. item.repeatObj.checked = false;
  404. }
  405. // 查重校验是否可提交
  406. let isSubmit = ref(true);
  407. // 校验
  408. // 查重校验
  409. async function checkCode(_rule, value) {
  410. const reg = /[^\x21-\x7E]+/g;
  411. isTrue.value = false;
  412. // showhelp.value = false;
  413. if (codeDuplicate.value == 0) {
  414. if (value && reg.test(value)) {
  415. return Promise.reject(
  416. "只允许大写字母、小写字母、数字和特殊符号(除空格)"
  417. );
  418. } else if (value && value.length > 18) {
  419. return Promise.reject(`输入字符不能超过18`);
  420. } else {
  421. isSubmit.value = true;
  422. isTrue.value = true;
  423. return Promise.resolve();
  424. }
  425. } else {
  426. isSubmit.value = false;
  427. codeDuplicate.value = 0;
  428. return Promise.reject(`该编码已被占用,请重新输入`);
  429. }
  430. }
  431. // input框失去焦点时,去除空格
  432. function blurEvent(params) {
  433. // var reg = /\s+/g;
  434. form[params] = form[params].trim();
  435. formRef.value.validate(`${params}`);
  436. }
  437. // checkName校验
  438. async function checkName(_rule, value) {
  439. var reg = /\s+/g;
  440. const maxLength = _rule.field == "code" ? 18 : 20;
  441. if (value && value.length > maxLength) {
  442. return Promise.reject(`输入字符不能超过${maxLength}`);
  443. } else if (reg.test(value)) {
  444. return Promise.reject("不允许输入空格");
  445. } else {
  446. return Promise.resolve();
  447. }
  448. }
  449. // 不做校验
  450. async function checkNo() {
  451. return Promise.resolve();
  452. }
  453. // 随机生成按钮
  454. function changeRandom(value) {
  455. form[value] = getRandom();
  456. formRef.value.validate(`${value}`);
  457. }
  458. // 校验密码
  459. async function checkSecret(_rule, value) {
  460. const rules = /^[0-9a-zA-Z]*$/g;
  461. if (rules.test(value)) {
  462. return Promise.resolve();
  463. }
  464. return Promise.reject("只允许输入数字和字母");
  465. }
  466. let nativePlace = reactive({
  467. provice: "",
  468. city: "",
  469. });
  470. // 提交
  471. function submit() {
  472. // 是否做查重:isRepeatInput为true需要做查重,否则不做
  473. let isRepeatInput = true;
  474. props.formData.forEach((item) => {
  475. if (item.repeatObj && item.repeatObj.totalCount > 0) {
  476. repeat = false;
  477. }
  478. });
  479. if (isRepeatInput) {
  480. formRef.value
  481. .validate()
  482. .then((res) => {
  483. loading.value = true;
  484. if (props.formTitle.indexOf("添加权限组用户") > -1) {
  485. props
  486. .addApi({
  487. roleGroupId: props.curRoleID,
  488. userId: form.userId,
  489. type: form.type,
  490. })
  491. .then((res) => {
  492. message.success("添加权限组用户成功");
  493. props.refreshFunc();
  494. cancel();
  495. props.closeForm();
  496. })
  497. .catch((err) => {
  498. loading.value = false;
  499. });
  500. }
  501. else if (props.formTitle.indexOf("添加权限用户") > -1) {
  502. props
  503. .addApi({
  504. roleId: props.roleId,
  505. ordinal: 0,
  506. // ...form,
  507. type:form.type,
  508. userId:form.userId
  509. })
  510. .then((res) => {
  511. message.success("添加权限用户成功");
  512. props.refreshFunc();
  513. cancel();
  514. props.closeForm();
  515. })
  516. .catch((err) => {
  517. loading.value = false;
  518. });
  519. }
  520. else if (props.formTitle.indexOf("添加权限组") > -1) {
  521. props
  522. .addGroupApi({
  523. roleGroupId: form.roleGroupId,
  524. roleId: form.roleID,
  525. ordinal: 0,
  526. ...form,
  527. })
  528. .then((res) => {
  529. message.success("添加权限组成功");
  530. props.refreshFunc();
  531. cancel();
  532. props.closeForm();
  533. })
  534. .catch((err) => {
  535. loading.value = false;
  536. });
  537. }
  538. else if (props.formTitle.indexOf("添加权限") > -1) {
  539. if (route.fullPath == "/appConfig/powerManage/powerAssign"){
  540. props
  541. .addApi({
  542. roleGroupId: props.curRoleID,
  543. roleId: form.name,
  544. ordinal: 0,
  545. })
  546. .then((res) => {
  547. message.success("添加权限成功");
  548. props.refreshFunc();
  549. cancel();
  550. props.closeForm();
  551. })
  552. .catch((err) => {
  553. loading.value = false;
  554. });
  555. }
  556. else if(route.fullPath == "/appConfig/powerManage/powerList"){
  557. props
  558. .addApi({ ...form })
  559. .then((res) => {
  560. message.success("添加成功");
  561. props.refreshFunc();
  562. cancel();
  563. props.closeForm();
  564. })
  565. .catch((err) => {
  566. loading.value = false;
  567. });
  568. }
  569. }
  570. else if (props.formTitle.indexOf("添加") > -1) {
  571. const apiScopeClaims = selectedList.value.map(item => {
  572. delete item.name
  573. return item
  574. })
  575. props
  576. .addApi({ ...form,apiScopeClaims: JSON.parse(JSON.stringify(apiScopeClaims).replace(/value/g, 'type')) })
  577. .then((res) => {
  578. message.success("添加成功");
  579. props.refreshFunc();
  580. cancel();
  581. props.closeForm();
  582. })
  583. .catch((err) => {
  584. loading.value = false;
  585. });
  586. } else if (props.formTitle.indexOf("修改") > -1) {
  587. props
  588. .editApi({ ...form }, form.id)
  589. .then((res) => {
  590. props.refreshFunc();
  591. cancel();
  592. props.closeForm();
  593. })
  594. .catch((err) => {
  595. loading.value = false;
  596. });
  597. }
  598. })
  599. .catch((err) => {
  600. message.warning("请输入/选择必填项");
  601. });
  602. }
  603. }
  604. // 取消
  605. function cancel() {
  606. loading.value = false;
  607. formRef.value.resetFields();
  608. props.closeForm();
  609. nativePlace = {
  610. provice: "",
  611. city: "",
  612. };
  613. }
  614. // select组件调用的方法(params子组件中传递的值,isAffect是否影响其他请求下拉框)
  615. function selectedValue(params, isAffect, key) {
  616. // form[params.key] = params.value;
  617. // nextTick(() => {
  618. // formRef.value.validate(`${params.key}`);
  619. // });
  620. // if (isAffect) {
  621. // // 影响作用请求下拉框选中数据改变,被影响请求下拉框值清空
  622. // props.controlledSelect(form);
  623. // if (selectRef.value[1]) {
  624. // selectRef.value[1].delSelectedData();
  625. // }
  626. // }
  627. form[params.key] = params.value;
  628. nextTick(() => {
  629. formRef.value.validate(`${params.key}`);
  630. });
  631. if (props.formTitle == "添加权限" && isAffect) {
  632. if (key == "scopeId") {
  633. getResource({
  634. Enabled: true,
  635. MaxResultCount: 15,
  636. PageNumber: 1,
  637. ApiScopeId: form.scopeId,
  638. }).then((res) => {
  639. if (res.items) {
  640. selectRef.value[1].selectList = res.items;
  641. selectRef.value[1].selectedData = "";
  642. }
  643. });
  644. props.formData[2].selectList.splice(0);
  645. form.name = "";
  646. form.apiResourceId = "";
  647. } else if (key == "apiResourceId") {
  648. getCurResource({ id: form.apiResourceId }).then((res) => {
  649. if (res.roles) {
  650. props.formData[2].selectList = res.roles;
  651. form.name = "";
  652. }
  653. });
  654. }
  655. }
  656. }
  657. //用户声明相关的方法和变量
  658. const Selected=ref([])
  659. const selectedData1=ref([])
  660. const selectList=ref([])
  661. const oldName=ref('')
  662. // 用户声明的input框
  663. const selectedDeclare1=ref('')
  664. // 用户声明的弹窗框的显示
  665. const visibleDeclare=ref(false)
  666. // 用户声明的弹出框的可选择的列表数据
  667. const selectDeclareList=ref([
  668. { name: '用户资料', value: 'profile' },
  669. { name: '唯一标识', value: 'sub' },
  670. { name: '姓名', value: 'name' },
  671. { name: '昵称', value: 'nickname' },
  672. { name: '性别', value: 'gender' },
  673. { name: '头像', value: 'picture' },
  674. { name: '生日', value: 'birthdate' },
  675. { name: '时区', value: 'zoneinfo' },
  676. { name: '区域', value: 'locale' },
  677. { name: '地址', value: 'address' },
  678. { name: '权限', value: 'role' },
  679. { name: '邮箱', value: 'email' },
  680. { name: '邮箱验证', value: 'email_verified' },
  681. { name: '电话号', value: 'phone_number' },
  682. { name: '电话号验证', value: 'phone_number_verified' },
  683. { name: '企业ID', value: 'EnterpriseId' },
  684. { name: '企业名称', value: 'EnterpriseName' },
  685. { name: '地区', value: 'NativePlace' }
  686. ])
  687. // 弹出框显示出来
  688. function selectDeclare1() {
  689. // Selected.value = selectedData.value
  690. // const selected = Selected.value.map(item => item.value)
  691. // selectList.value = selectDeclareList.value.filter(item => !selected.includes(item.value))
  692. visibleDeclare.value = true
  693. }
  694. // 删除弹窗框中选中的值
  695. function handleDelSelect(index){
  696. Selected.value.splice(index, 1)
  697. const selected = selected.value.map(item => item.value)
  698. selectList.value = selectDeclareList.value.filter(item => !selected.includes(item.value))
  699. }
  700. // 关闭弹出框
  701. function cancelDeclare(){
  702. // this.selected = []
  703. visibleDeclare.value = false
  704. }
  705. // 选中数据值关闭弹出框
  706. function ok1(){
  707. visibleDeclare.value = false
  708. selectedData.value = Selected.value
  709. if (selectedData.value.length > 0) {
  710. for (var i = 0; i < selectedData.value.length; i++) {
  711. if (i == 0) {
  712. selectedDeclare.value = selectedData.value[i].name
  713. } else {
  714. selectedDeclare.value = selectedDeclare.value + ',' + selectedData.value[i].name
  715. }
  716. }
  717. } else {
  718. selectedDeclare.value = ''
  719. }
  720. }
  721. function getData(){
  722. detailApiScope(this.id).then(res => {
  723. // 用户声明
  724. for (var i = 0; i < res.apiScopeClaims.length; i++) {
  725. if (i == 0) {
  726. selectedDeclare.value = selectList.value.find(item => {
  727. return item.value == res.apiScopeClaims[0].type
  728. }).name
  729. } else {
  730. selectedDeclare.value =
  731. selectedDeclare.value +
  732. ',' +
  733. selectList.value.find(item => {
  734. return item.value == res.apiScopeClaims[i].type
  735. }).name
  736. }
  737. selectedData.value[i] = {
  738. value: res.apiScopeClaims[i].type,
  739. name: selectList.value.find(item => {
  740. return item.value == res.apiScopeClaims[i].type
  741. }).name
  742. }
  743. }
  744. Selected.value = [...selectedData.value]
  745. oldName.value = res.name
  746. const apiScopeClaims = res.apiScopeClaims.map(item => item.type)
  747. selectList.value = selectList.value.filter(item => !apiScopeClaims.includes(item.value))
  748. apiScopeForm.value = {
  749. id: this.id,
  750. name: res.name,
  751. displayName: res.displayName,
  752. enabled: res.enabled,
  753. showInDiscoveryDocument: res.showInDiscoveryDocument,
  754. required: res.required,
  755. emphasize: res.emphasize,
  756. description: res.description
  757. }
  758. })
  759. }
  760. // 后来换的
  761. const selectedData=ref([])
  762. const selectedList = ref([]);
  763. // 用户声明的input框
  764. const selectedDeclare=ref('')
  765. function selectDeclare() {
  766. // Selected.value = selectedData.value
  767. // const selected = Selected.value.map(item => item.value)
  768. // selectList.value = selectDeclareList.value.filter(item => !selected.includes(item.value))
  769. visibleDeclare.value = true
  770. }
  771. const leftList = ref([
  772. { name: '用户资料', value: 'profile' },
  773. { name: '唯一标识', value: 'sub' },
  774. { name: '姓名', value: 'name' },
  775. { name: '昵称', value: 'nickname' },
  776. { name: '性别', value: 'gender' },
  777. { name: '头像', value: 'picture' },
  778. { name: '生日', value: 'birthdate' },
  779. { name: '时区', value: 'zoneinfo' },
  780. { name: '区域', value: 'locale' },
  781. { name: '地址', value: 'address' },
  782. { name: '权限', value: 'role' },
  783. { name: '邮箱', value: 'email' },
  784. { name: '邮箱验证', value: 'email_verified' },
  785. { name: '电话号', value: 'phone_number' },
  786. { name: '电话号验证', value: 'phone_number_verified' },
  787. { name: '企业ID', value: 'EnterpriseId' },
  788. { name: '企业名称', value: 'EnterpriseName' },
  789. { name: '地区', value: 'NativePlace' }
  790. ]);
  791. const selectEvent = (value) => {
  792. const index = leftList.value.findIndex((item) => item.name == value.name);
  793. leftList.value.splice(index, 1);
  794. selectedList.value.push({ name: value.name,type:value.value });
  795. };
  796. const delSelectEvent = (value) => {
  797. const index = selectedList.value.findIndex(
  798. (item) => item.name == value.name
  799. );
  800. selectedList.value.splice(index, 1);
  801. leftList.value.push({ name: value.name,type:value.value });
  802. };
  803. // 选中数据值关闭弹出框
  804. function ok(){
  805. visibleDeclare.value = false
  806. selectedData.value = selectedList.value
  807. if (selectedData.value.length > 0) {
  808. for (var i = 0; i < selectedData.value.length; i++) {
  809. if (i == 0) {
  810. selectedDeclare.value = selectedData.value[i].name
  811. } else {
  812. selectedDeclare.value = selectedDeclare.value + ',' + selectedData.value[i].name
  813. }
  814. }
  815. } else {
  816. selectedDeclare.value = ''
  817. }
  818. }
  819. // 暴露给父组件的数据
  820. defineExpose({
  821. form,
  822. cancel,
  823. });
  824. // 监听visible
  825. // watch(
  826. // () => visibleDeclare.value,
  827. // (newVal, oldVal) => {
  828. // if(newVal){
  829. // // selectList.value = selectDeclareList.value
  830. // // // console.log('list',selectList.value)
  831. // // if (props.curRoleID) {
  832. // // getData()
  833. // // }
  834. // }
  835. // },
  836. // { deep: true, immediate: true }
  837. // )
  838. watch(
  839. () => props.visible,
  840. (newVal, oldVal) => {
  841. // showhelp.value = false;
  842. // 展示表单时
  843. if (newVal) {
  844. getRules();
  845. } else {
  846. // formRef.value.resetFields();
  847. // 关闭表单时
  848. if (formRef.value) {
  849. formRef.value.resetFields();
  850. props.closeForm();
  851. nativePlace = {
  852. provice: "",
  853. city: "",
  854. };
  855. if (selectRef.value) {
  856. selectRef.value.forEach((item) => {
  857. item.delSelectedData();
  858. });
  859. }
  860. }
  861. }
  862. },
  863. { deep: true, immediate: true }
  864. );
  865. watch(
  866. () => props.formData,
  867. (newVal, oldVal) => {
  868. // 展示表单时
  869. if (newVal) {
  870. newVal.map((item) => {
  871. if(item.key=='nativePlace'&&item.value){
  872. nativePlace.province = item.value.split(",")[0];
  873. nativePlace.city = item.value.split(",")[1];
  874. form[item.key] = item.value
  875. }
  876. else{
  877. form[item.key] = item.value;
  878. }
  879. });
  880. }
  881. },
  882. { deep: true, immediate: true }
  883. );
  884. // 籍贯
  885. function selected(info) {
  886. form.nativePlace = info.province.value + "," + info.city.value;
  887. nativePlace = {
  888. province: info.province.value,
  889. city: info.city.value,
  890. };
  891. }
  892. watch(
  893. () => props.roleId,
  894. (newVal, oldVal) => {
  895. props.roleId=newVal
  896. },
  897. )
  898. </script>
  899. <style lang="less" scoped>
  900. .btn_box {
  901. width: 650px;
  902. padding-top: 20px;
  903. padding-bottom: 10px;
  904. border-top: solid 1px #e8e8e8;
  905. position: absolute;
  906. bottom: 0;
  907. right: 0;
  908. text-align: center;
  909. z-index: 2;
  910. background: #fff;
  911. }
  912. .btnGroup {
  913. width: 146px;
  914. display: flex;
  915. justify-content: space-between;
  916. margin: 0 auto;
  917. }
  918. // 查重样式
  919. .checkDuplicate {
  920. position: absolute;
  921. width: 30px;
  922. font-size: 12px;
  923. margin-left: 5px;
  924. line-height: 32px;
  925. }
  926. .helptip {
  927. color: #52c41a;
  928. font-size: 13px;
  929. }
  930. </style>
  931. <style lang="less" scoped>
  932. :deep(.ant-list-items){
  933. height: 376px;
  934. overflow-y: scroll;
  935. cursor: pointer;
  936. }
  937. .add-form-warp {
  938. background-color: #fff;
  939. .addSource {
  940. border: solid 1px #ccc;
  941. border-radius: 5px;
  942. width: 1000px;
  943. margin-left: auto;
  944. margin-right: auto;
  945. }
  946. .showSource {
  947. margin-top: 20px;
  948. width: 1000px;
  949. margin-left: auto;
  950. margin-right: auto;
  951. border: solid 1px #ccc;
  952. border-radius: 5px;
  953. :deep(.ant-table-pagination.ant-pagination) {
  954. margin-right: 20px;
  955. }
  956. }
  957. .title {
  958. line-height: 50px;
  959. border-bottom: solid 1px #ccc;
  960. background-color: rgba(0, 0, 0, 0.03);
  961. margin-bottom: 20px;
  962. div {
  963. margin-left: 20px;
  964. }
  965. }
  966. .picker {
  967. margin-top: 20px;
  968. }
  969. }
  970. </style>
  971. <style lang="less" scoped>
  972. .clientPage {
  973. background-color: #fff;
  974. padding: 24px;
  975. min-height: calc(100vh - 100px);
  976. .basicBox {
  977. margin: 20px auto;
  978. }
  979. .appAuthorBox {
  980. margin: 20px auto;
  981. display: flex;
  982. justify-content: space-between;
  983. .sourceBox {
  984. width: 48%;
  985. :deep(.ant-btn) {
  986. width: 100%;
  987. }
  988. }
  989. .empowerBox {
  990. width: 48%;
  991. :deep(.ant-btn) {
  992. width: 100%;
  993. }
  994. }
  995. }
  996. .secretBox {
  997. width: 80%;
  998. margin: 20px auto;
  999. button {
  1000. width: 100%;
  1001. }
  1002. }
  1003. .tokenBox {
  1004. width: 80%;
  1005. margin: 20px auto;
  1006. // text-align: center;
  1007. .declareBox {
  1008. margin: 20px auto;
  1009. .declareBtn {
  1010. width: 100%;
  1011. }
  1012. }
  1013. }
  1014. }
  1015. .modalBox {
  1016. display: flex;
  1017. justify-content: space-between;
  1018. // height: 480px;
  1019. .leftTitle {
  1020. font-size: 16px;
  1021. color: #363636;
  1022. padding-bottom: 14px;
  1023. }
  1024. .leftList {
  1025. width: 300px;
  1026. height: 380px;
  1027. background-color: #f4f6f8;
  1028. border: 1px solid #dedede;
  1029. border-radius: 5px;
  1030. overflow-y: auto;
  1031. list-style: none;
  1032. div {
  1033. width: 100%;
  1034. padding: 10px 20px;
  1035. border-bottom: 1px solid #e8e8e8;
  1036. cursor: pointer;
  1037. &:last-child {
  1038. border-bottom: none;
  1039. }
  1040. }
  1041. }
  1042. }
  1043. :deep(.ant-modal-footer) {
  1044. text-align: center !important;
  1045. }
  1046. </style>

select组件

  1. <template>
  2. <div class="selectBox">
  3. <a-select
  4. @change="changeSelect"
  5. :getPopupContainer="(triggerNode) => triggerNode.parentNode"
  6. @popupScroll="popupScrollEvent"
  7. v-model:value="selectedData"
  8. @click="focusSelect"
  9. >
  10. <a-select-option
  11. v-for="(item, index) in selectList"
  12. :key="index"
  13. :value="item.id ? item.id : item.logSetId"
  14. >{{ item.name }}</a-select-option
  15. >
  16. <template #dropdownRender="{ menuNode: menu }">
  17. <v-nodes :vnodes="menu" />
  18. <div v-if="isLoading">
  19. <span><a-spin /></span>
  20. </div>
  21. <div v-else-if="!isNewData" class="noMore">
  22. 没有更多数据了
  23. <!-- <template #description> 暂无数据 </template> -->
  24. </div>
  25. <!--显示结果-->
  26. <!--v-nodes必须要写在最后面,这个代表要渲染的下拉列表数据-->
  27. <!-- <template v-else>
  28. <v-nodes :vnodes="menu" />
  29. </template> -->
  30. </template>
  31. </a-select>
  32. </div>
  33. </template>
  34. <script setup>
  35. import { onMounted, ref, watch } from "vue";
  36. import { message } from "ant-design-vue";
  37. import { useRoute } from "vue-router";
  38. const emit = defineEmits();
  39. //必须要写
  40. const VNodes = (_, { attrs }) => {
  41. return attrs.vnodes;
  42. };
  43. const props = defineProps({
  44. // 默认选中数据
  45. value: {
  46. type: String,
  47. default: "",
  48. },
  49. // 监听参数
  50. watchParams: {
  51. type: Boolean,
  52. default: false,
  53. },
  54. // 滚动触底请求接口
  55. popupScroll: {
  56. type: Function,
  57. default: () => {},
  58. },
  59. // 对象键名
  60. objectName: {
  61. type: String,
  62. default: "",
  63. },
  64. // 请求参数
  65. params: {
  66. type: Object,
  67. default: () => {
  68. return {};
  69. },
  70. },
  71. // 表单标题 下拉框内容有时候需要特殊判断特殊处理
  72. formTitle: {
  73. type: String,
  74. default: "",
  75. },
  76. });
  77. let selectList = ref([]);
  78. let PageNumber = ref(1);
  79. const MaxResultCount = ref(10);
  80. let totalPages = ref(1);
  81. // 选中的值
  82. let selectedData = ref("");
  83. onMounted(() => {});
  84. // 是否正在请求中
  85. let isLoading = ref(true);
  86. // 接口请求的新数据
  87. let isNewData = ref(true);
  88. // 滚动事件
  89. function popupScrollEvent(e) {
  90. const { target } = e;
  91. const scrllHeight = target.scrollHeight - target.scrollTop;
  92. const clientHeight = target.clientHeight;
  93. isNewData.value = true;
  94. // 下拉框不下拉的时候
  95. if (scrllHeight === 0 && clientHeight === 0) {
  96. PageNumber.value = 1;
  97. } else if (scrllHeight - clientHeight == 0) {
  98. // 下拉到底部时
  99. if (PageNumber.value < totalPages.value) {
  100. // 如果滑到底部,则加载下一页
  101. PageNumber.value++;
  102. getListDataCode();
  103. } else {
  104. // message.warn("没有更多数据了");
  105. isNewData.value = false;
  106. }
  107. }
  108. }
  109. // 选中的select的值,调用父组件中selectedValue方法
  110. function changeSelect(val) {
  111. const params = {
  112. key: props.objectName,
  113. value: val,
  114. };
  115. selectedData.value = val;
  116. emit("selectedValue", params);
  117. }
  118. // 清空select中的数据
  119. const delSelectedData = () => {
  120. selectedData.value = undefined;
  121. selectList.value = []
  122. };
  123. // 请求方法
  124. function getListDataCode() {
  125. isLoading.value = true;
  126. props
  127. .popupScroll({
  128. PageNumber: PageNumber.value,
  129. MaxResultCount: MaxResultCount.value,
  130. ...props.params,
  131. })
  132. .then((res) => {
  133. isLoading.value = false;
  134. //需要特殊显示形势的判断 不需要就删除此判断
  135. if(route.fullPath == "/appConfig/powerManage/powerAssign"){
  136. if(props.formTitle=='添加权限用户'||props.formTitle=='添加权限组用户')
  137. res.items.forEach((item)=>{
  138. item.name=item.disPlayName + '(' + item.name + ')'
  139. })
  140. }
  141. if(route.fullPath == "/organizationManage/archite"){
  142. if(props.formTitle=='添加成员')
  143. res.items.forEach((item)=>{
  144. item.name=item.disPlayName + '(' + item.name + ')'
  145. })
  146. }
  147. selectList.value = selectList.value.concat(res.items ? res.items : res);
  148. totalPages.value = Math.ceil(res.totalCount / MaxResultCount.value);
  149. })
  150. .catch((err) => {
  151. isLoading.value = false;
  152. });
  153. }
  154. // 获取焦点时滚动条回到顶部
  155. function focusSelect() {
  156. if (!selectedData.value) {
  157. document.getElementsByClassName("rc-virtual-list-holder")[0].scrollTop = 0;
  158. }
  159. }
  160. const route = useRoute();
  161. defineExpose({
  162. delSelectedData,
  163. selectedData,
  164. selectList
  165. });
  166. watch(
  167. () => props.watchParams,
  168. (newVal, oldVal) => {
  169. PageNumber.value = 1;
  170. selectList.value = [];
  171. getListDataCode();
  172. selectedData.value = props.value;
  173. // if(props.formTitle=='添加成员'&&props.objectName=='code'){
  174. // PageNumber.value = 1;
  175. // }
  176. // else{
  177. // PageNumber.value = 1;
  178. // selectList.value = [];
  179. // getListDataCode();
  180. // selectedData.value = props.value;
  181. // }
  182. },
  183. { deep: true, immediate: true }
  184. );
  185. </script>
  186. <style lang="less">
  187. .noMore {
  188. text-align: center;
  189. }
  190. </style>

golalFuc

  1. export function getRandom(length) {
  2. var str = "",
  3. range = length?length: 16,
  4. arr = [
  5. "0",
  6. "1",
  7. "2",
  8. "3",
  9. "4",
  10. "5",
  11. "6",
  12. "7",
  13. "8",
  14. "9",
  15. "a",
  16. "b",
  17. "c",
  18. "d",
  19. "e",
  20. "f",
  21. "g",
  22. "h",
  23. "i",
  24. "j",
  25. "k",
  26. "l",
  27. "m",
  28. "n",
  29. "o",
  30. "p",
  31. "q",
  32. "r",
  33. "s",
  34. "t",
  35. "u",
  36. "v",
  37. "w",
  38. "x",
  39. "y",
  40. "z",
  41. "A",
  42. "B",
  43. "C",
  44. "D",
  45. "E",
  46. "F",
  47. "G",
  48. "H",
  49. "I",
  50. "J",
  51. "K",
  52. "L",
  53. "M",
  54. "N",
  55. "O",
  56. "P",
  57. "Q",
  58. "R",
  59. "S",
  60. "T",
  61. "U",
  62. "V",
  63. "W",
  64. "X",
  65. "Y",
  66. "Z",
  67. ];
  68. // 随机产生
  69. for (var i = 0; i < range; i++) {
  70. str += arr[Math.round(Math.random() * (arr.length - 1))];
  71. }
  72. return str
  73. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/115511
推荐阅读
相关标签
  

闽ICP备14008679号