华西海圻ELN前端工程
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

651 lines
27 KiB

2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
2 weeks ago
  1. <template>
  2. <div>
  3. <LineLabel v-if="label" :label="label" />
  4. <div v-for="(item, index) in formConfig" :key="index">
  5. <template v-if="item.type === 'cardItem'">
  6. <div class="grid-container">
  7. <div v-for="(sItem, key) in item.config" class="form-item"
  8. :class="sItem.span == 1 ? 'full-row' : ''" :key="key">
  9. <template v-if="sItem.type === 'input'">
  10. <div class="form-title">{{ sItem.label }}</div>
  11. <HandleFormItem @blur="onBlur(key, $event)" :item="sItem" v-model="formFields[key]"
  12. @copy="onCopy(sItem, key)" :error="errors[key]" @update:error="errors[key] = false"
  13. :orange-bg="orangeBgFields[key]" />
  14. </template>
  15. <template v-else-if="sItem.type === 'inputNumber'">
  16. <div class="form-title">{{ sItem.label }}</div>
  17. <HandleFormItem type="inputNumber" @blur="onBlur(key, $event)" :item="sItem"
  18. @input="onInputNumberChange(key, $event)" v-model="formFields[key]"
  19. @copy="onCopy(sItem, key)" :error="errors[key]" @update:error="errors[key] = false"
  20. :orange-bg="orangeBgFields[key]" />
  21. </template>
  22. </div>
  23. </div>
  24. </template>
  25. <template v-else-if="item.type === 'conditionItem'">
  26. <div class="form-item ">
  27. <div class="form-title fs-16" v-if="item.label">{{ item.label }}</div>
  28. <div v-for="(sItem, key) in item.config" class="c-Item grid-container">
  29. <div class="p-r-20">
  30. <div class="form-title">{{ sItem.label }}</div>
  31. <div class="flex flex1">
  32. <HandleFormItem type="select" :item="sItem" v-model="formFields[key]"
  33. @copy="onCopy(sItem, key)" @change="onSelectChange(key, $event)"
  34. :error="errors[key]" @update:error="errors[key] = false"
  35. :orange-bg="orangeBgFields[key]" />
  36. </div>
  37. </div>
  38. <div class="p-l-20">
  39. <div v-show="isShowOther(formFields[key])">
  40. <div class="form-title">其他</div>
  41. <div class="flex flex1">
  42. <HandleFormItem @blur="onBlur(key, $event)" :item="getOtherItem(sItem)"
  43. v-model="formFields[sItem.otherCode]" @copy="onCopy(sItem, key)"
  44. :error="errors[sItem.otherCode]"
  45. @update:error="errors[sItem.otherCode] = false" />
  46. </div>
  47. </div>
  48. </div>
  49. </div>
  50. </div>
  51. </template>
  52. <template v-else-if="item.type === 'cellItem'">
  53. <div class="form-item ">
  54. <div class="form-title fs-16" v-if="item.label">{{ item.label }}</div>
  55. <div class="grid-container gap2">
  56. <div v-for="(sItem, key) in item.config" class="c-Item" :class="getSpanClass(sItem)" :key="key">
  57. <div class="form-title" v-if="sItem.label">{{ sItem.label }}</div>
  58. <div v-if="sItem.type === 'dateTime'" class="flex1">
  59. <HandleFormItem type="dateTime" :item="sItem" v-model="formFields[key]"
  60. @copy="onCopy(sItem, key)" :error="errors[key]" @update:error="errors[key] = false"
  61. :orange-bg="orangeBgFields[key]" />
  62. </div>
  63. <div v-else-if="sItem.type === 'select'">
  64. <HandleFormItem type="select" :item="sItem" v-model="formFields[key]"
  65. @copy="onCopy(sItem, key)" @change="onSelectChange(key, $event)"
  66. :error="errors[key]" @update:error="errors[key] = false"
  67. :orange-bg="orangeBgFields[key]" />
  68. </div>
  69. <div v-else-if="sItem.type === 'input'">
  70. <HandleFormItem @blur="onBlur(key, $event)" :item="sItem" v-model="formFields[key]"
  71. @copy="onCopy(sItem, key)" :error="errors[key]" @update:error="errors[key] = false"
  72. :orange-bg="orangeBgFields[key]" />
  73. </div>
  74. <div v-else-if="sItem.type === 'textarea'">
  75. <HandleFormItem @blur="onBlur(key, $event)" type="textarea" :item="sItem"
  76. v-model="formFields[key]" @copy="onCopy(sItem, key)" :error="errors[key]"
  77. @update:error="errors[key] = false" :orange-bg="orangeBgFields[key]" />
  78. </div>
  79. <div v-else-if="sItem.type === 'clickable'" class="flex1">
  80. <HandleFormItem type="clickable" @clickable="handleClickable(sItem, $event)"
  81. :item="sItem" :value="formFields[key]" />
  82. </div>
  83. </div>
  84. </div>
  85. </div>
  86. </template>
  87. <template v-else-if="item.type === 'step'">
  88. <div class="grid-container gap2">
  89. <div v-for="(sItem, key) in item.config" class="c-Item flex item-center"
  90. :class="getSpanClass(sItem)" :key="key">
  91. <div class="step-form-title" v-if="sItem.label">{{ sItem.label }}</div>
  92. <div v-if="sItem.type === 'dateTime'" class="flex1">
  93. <HandleFormItem type="dateTime" :item="sItem" v-model="formFields[key]"
  94. @copy="onCopy(sItem, key)" :error="errors[key]" @update:error="errors[key] = false"
  95. :orange-bg="orangeBgFields[key]" />
  96. </div>
  97. <div v-else-if="sItem.type === 'select'" class="flex flex1">
  98. <HandleFormItem type="select" :item="sItem" style="width: auto;flex:1"
  99. v-model="formFields[key]" @copy="onCopy(sItem, key)"
  100. @change="onSelectChange(key, $event)" :error="errors[key]"
  101. @update:error="errors[key] = false" :orange-bg="orangeBgFields[key]" />
  102. <div v-show="isShowOther(formFields[key])" class="flex flex1">
  103. <div class="other-title">其他</div>
  104. <div class="flex">
  105. <HandleFormItem @blur="onBlur(key, $event)" :item="getOtherItem(sItem)"
  106. v-model="formFields[sItem.otherCode]" @copy="onCopy(sItem, key)"
  107. :error="errors[sItem.otherCode]" @update:error="errors[sItem.otherCode] = false"
  108. :orange-bg="orangeBgFields[sItem.otherCode]" />
  109. </div>
  110. </div>
  111. </div>
  112. <div v-else-if="sItem.type === 'input'" class="flex flex1">
  113. <HandleFormItem @blur="onBlur(key, $event)" class="flex1" :item="sItem"
  114. v-model="formFields[key]" @copy="onCopy(sItem, key)" :error="errors[key]"
  115. @update:error="errors[key] = false" :orange-bg="orangeBgFields[key]" />
  116. <HandleFormItem class="ml-10" v-if="sItem.subType === 'select'" type="select"
  117. :item="getSubItem(sItem)" v-model="formFields[sItem.subKey]" @copy="onCopy(sItem, key)"
  118. @change="onSelectChange(sItem.subKey, $event)" :error="errors[sItem.subKey]"
  119. @update:error="errors[sItem.subKey] = false"
  120. :orange-bg="orangeBgFields[sItem.subKey]" />
  121. <div class="ml-10" v-else-if="sItem.subType === 'span'">{{ formFields[sItem.subKey] }}</div>
  122. <HandleFormItem class="ml-10" v-else-if="sItem.subType === 'clickable'" type="clickable"
  123. @clickable="handleClickable(sItem, $event)" :item="getClickableItem(sItem)"
  124. :value="formFields[sItem.subKey]" />
  125. <div v-show="isShowOther(formFields[sItem.subKey])" class="flex flex1">
  126. <div class="other-title">其他</div>
  127. <div class="flex">
  128. <HandleFormItem @blur="onBlur(key, $event)" :item="getOtherItem(sItem)"
  129. v-model="formFields[sItem.otherCode]" @copy="onCopy(sItem, key)"
  130. :error="errors[sItem.otherCode]" @update:error="errors[sItem.otherCode] = false"
  131. :orange-bg="orangeBgFields[sItem.otherCode]" />
  132. </div>
  133. </div>
  134. <!-- <div class="clickable" :class="getFillType(sItem.subFillType)" v-else-if = "sItem.subType ==='clickable'" @click="handleClickable(sItem,$event)">
  135. <span v-if="formFields[sItem.subKey]">{{ formFields[sItem.subKey] }}</span>
  136. <span v-else class="default-placeholder-text">请选择</span>
  137. </div> -->
  138. </div>
  139. <div v-else-if="sItem.type === 'inputNumber'" class="flex flex1">
  140. <HandleFormItem type="inputNumber" @blur="onBlur(key, $event)" class="flex1" :item="sItem"
  141. @input="onInputNumberChange(key, $event)" :value="formFields[key]"
  142. @copy="onCopy(sItem, key)" :error="errors[key]" @update:error="errors[key] = false"
  143. :orange-bg="orangeBgFields[key]" />
  144. <HandleFormItem class="ml-10" v-if="sItem.subType === 'select'" type="select"
  145. :item="getSubItem(sItem)" v-model="formFields[sItem.subKey]" @copy="onCopy(sItem, key)"
  146. @change="onSelectChange(sItem.subKey, $event)" :error="errors[sItem.subKey]"
  147. @update:error="errors[sItem.subKey] = false"
  148. :orange-bg="orangeBgFields[sItem.subKey]" />
  149. <div class="ml-10" v-else-if="sItem.subType === 'span'">{{ formFields[sItem.subKey] }}</div>
  150. <HandleFormItem class="ml-10" v-else-if="sItem.subType === 'clickable'"
  151. @clickable="handleClickable(sItem, $event)" type="clickable"
  152. :item="getClickableItem(sItem)" :value="formFields[sItem.subKey]" />
  153. <!-- <div class="clickable" :class="getFillType(sItem.subFillType)" v-else-if = "sItem.subType ==='clickable'" @click="handleClickable(sItem,$event)">
  154. <span v-if="formFields[sItem.subKey]">{{ formFields[sItem.subKey] }}</span>
  155. <span v-else class="default-placeholder-text">请选择</span>
  156. </div> -->
  157. </div>
  158. <div v-else-if="sItem.type === 'clickable'" class="flex flex1">
  159. <HandleFormItem type="clickable" @clickable="handleClickable(sItem, $event)"
  160. :error="errors[key]" :item="sItem" :value="formFields[key]" />
  161. </div>
  162. </div>
  163. </div>
  164. </template>
  165. </div>
  166. </div>
  167. </template>
  168. <script>
  169. import HandleFormItem from "./HandleFormItem.vue";
  170. import LineLabel from "./LineLabel.vue";
  171. export default {
  172. components: {
  173. HandleFormItem,
  174. LineLabel
  175. },
  176. props: {
  177. label: {//当前表单的标题
  178. type: String,
  179. default: "",
  180. },
  181. formConfig: {
  182. type: Array,
  183. value: () => [],
  184. },
  185. formData: {
  186. type: Object,
  187. value: () => ({})
  188. }
  189. },
  190. data() {
  191. return {
  192. formFields: {},//表单绑定字段
  193. allFieldsConfig: {},//包含config的所有字段,主要用于校验表单是否填写
  194. errors: {},//存储表单错误信息,用于标红提示
  195. orangeBgFields: {},// 存储需要橙色背景的字段
  196. };
  197. },
  198. watch: {
  199. formData: {
  200. immediate: true,
  201. deep: true, // 深度监听,以便检测嵌套对象变化
  202. handler(v) {
  203. if (v) {
  204. this.handleFormField(true);
  205. }
  206. }
  207. },
  208. formConfig: {
  209. immediate: true,
  210. deep: true, // 深度监听,以便检测嵌套对象变化
  211. handler(v) {
  212. this.handleFormField();
  213. }
  214. }
  215. },
  216. mounted() {
  217. this.handleFormField();
  218. },
  219. unmounted() {
  220. console.log("unmounted")
  221. this.formFields = {};//清空当前填写的数据
  222. },
  223. methods: {
  224. getFillType(type) {
  225. const typeObj = {
  226. actFill: "orange-border",//实际填写的边框颜色
  227. green: "green-border",
  228. preFill: "blue-border",//预填写的边框颜色
  229. }
  230. return typeObj[type] || ""
  231. },
  232. onInputNumberChange(key, val) {
  233. this.formFields[key] = val;
  234. // 清除该表单项的错误状态
  235. if (this.errors[key]) {
  236. this.$set(this.errors, key, false);
  237. }
  238. },
  239. updateFormData(key, value) {
  240. this.formFields[key] = value;
  241. // 清除该表单项的错误状态
  242. if (this.errors[key]) {
  243. this.$set(this.errors, key, false);
  244. }
  245. },
  246. batchUpdateFormData(data) {
  247. Object.keys(data).forEach(key => {
  248. this.formFields[key] = data[key];
  249. // 清除该表单项的错误状态
  250. if (this.errors[key]) {
  251. this.$set(this.errors, key, false);
  252. }
  253. })
  254. },
  255. handleClickable(sItem, event) {
  256. console.log("clickable", sItem)
  257. if (this.$store.state.template.templateStatus !== 'actFill') {
  258. return
  259. }
  260. this.$emit("clickable", sItem)
  261. },
  262. //根据span判断一行显示几列
  263. getSpanClass(sItem) {
  264. const spanArr = ["full-row", "", "three-row"]
  265. if (sItem.span) {
  266. return spanArr[sItem.span - 1]
  267. }
  268. return ""
  269. },
  270. //获取其他下拉框的配置
  271. getOtherItem(sItem) {
  272. return {
  273. label: "其他",
  274. fillType: sItem.fillType,
  275. maxlength: sItem.otherMaxlength || 50,
  276. }
  277. },
  278. getClickableItem(sItem) {
  279. return {
  280. label: "",
  281. type: "clickable",
  282. fillType: sItem.subFillType || sItem.fillType,
  283. }
  284. },
  285. getSubItem(sItem) {
  286. return {
  287. label: "",
  288. options: sItem.subOptions || [],
  289. fillType: sItem.subFillType || sItem.fillType,
  290. }
  291. },
  292. isShowOther(v = []) {
  293. // 确保v是数组类型,以避免类型错误
  294. const arr = Array.isArray(v) ? v : [v];
  295. //和凡哥商量,只要value为负数都显示其他
  296. return arr.some(item => item < 0);
  297. },
  298. // 根据formConfig回填form表单数据
  299. handleFormField(update = false) {
  300. const result = {};
  301. let config = {};
  302. const { formConfig, formData, formFields } = this;
  303. // 遍历配置
  304. formConfig.forEach((item) => {
  305. if (item.config) {
  306. // 合并配置项
  307. config = { ...config, ...item.config }
  308. // 处理每个配置项
  309. Object.keys(item.config).forEach(key => {
  310. const currentConfig = item.config[key];
  311. let value = formData[key];
  312. // 如果formFields中已经有值,保持原值(用户输入或之前设置的值)
  313. if (formFields[key] !== null &&
  314. formFields[key] !== undefined &&
  315. formFields[key] !== ''
  316. // typeof formFields[key] !== 'object'
  317. ) {
  318. // 保留原值,不使用formData中的值
  319. result[key] = formFields[key];
  320. } else {
  321. // 使用formData中的值
  322. result[key] = value;
  323. }
  324. // 处理特殊字段 - "其他"字段
  325. if (currentConfig.otherCode) {
  326. const { otherCode } = currentConfig;
  327. //如果是更新的话,优先使用formFields中的值
  328. if (update) {
  329. result[otherCode] = formFields[otherCode] || formData[otherCode] || '';
  330. } else {
  331. result[otherCode] = formData[otherCode] || formFields[otherCode] || '';
  332. }
  333. config[otherCode] = { label: "其他", parentKey: key, type: "input", fillType: currentConfig.fillType }
  334. }
  335. if (currentConfig.subKey) {
  336. const { subKey } = currentConfig;
  337. if (update) {
  338. result[subKey] = formFields[subKey] || formData[subKey] || '';
  339. } else {
  340. result[subKey] = formData[subKey] || formFields[subKey] || '';
  341. }
  342. config[subKey] = { label: currentConfig.label, subKey, type: currentConfig.subType, fillType: currentConfig.subFillType || currentConfig.fillType }
  343. }
  344. });
  345. // 处理可能存在的直接otherCode字段
  346. if (item.config?.otherCode) {
  347. config[item.config?.otherCode] = item.config?.otherCode;
  348. }
  349. }
  350. });
  351. // 更新表单字段
  352. this.formFields = result;
  353. this.allFieldsConfig = config;
  354. },
  355. //判断是否禁用
  356. getDisabled() {
  357. const { item } = this;
  358. const { fillType } = item;
  359. if (item.hasOwnProperty("disabled")) {
  360. return item.disabled
  361. } else {
  362. const { templateStatus } = this.$store.state.template;
  363. if (fillType === "actFill") {//当模板状态是实际填写时,只有当fillType是actFill时才能填写
  364. return templateStatus !== "actFill"
  365. } else if (fillType === "preFill") {//当模板状态是预填写时,只有当fillType是preFill才能填写
  366. return templateStatus !== "preFill"
  367. } else {
  368. return true
  369. }
  370. }
  371. },
  372. // 表单数据校验
  373. validateFormData() {
  374. const { formFields, allFieldsConfig } = this;
  375. const { templateStatus } = this.$store.state.template;
  376. const errors = [];
  377. // 清空之前的错误状态
  378. this.errors = {};
  379. for (const key in allFieldsConfig) {
  380. const o = allFieldsConfig[key];
  381. if (o.otherCode) {//
  382. if (o.type === "select") {
  383. const isSelectedOther = this.isShowOther(formFields[key]);
  384. if (!isSelectedOther) {//如果其他选项没有被选择,清空其他字段
  385. formFields[o.otherCode] = "";
  386. }
  387. } else if (o.subType === "select") {
  388. const isSelectedOther = this.isShowOther(formFields[o.subKey]);
  389. if (!isSelectedOther) {//如果其他选项没有被选择,清空其他字段
  390. formFields[o.otherCode] = "";
  391. }
  392. }
  393. }
  394. if (this.isValueEmpty(formFields[key])) {
  395. // 其他字段需要判断是否显示再校验
  396. if (o.label === "其他" && !this.isShowOther(formFields[o.parentKey])) {
  397. continue
  398. }
  399. //span的字段不校验
  400. if (o.type === "span") {
  401. continue
  402. }
  403. if (o.fillType == templateStatus && !o.disabled) {
  404. let prefix = "";
  405. if (o.type === "input" || o.type === "inputNumber" || o.type === "textarea") {
  406. prefix = "填写";
  407. } else {
  408. prefix = "选择";
  409. }
  410. const errorItem = {
  411. field: key,
  412. label: o.label,
  413. error: `${prefix}${o.label}`
  414. };
  415. errors.push(errorItem);
  416. this.$set(this.errors, key, true);
  417. }
  418. }
  419. }
  420. return {
  421. valid: errors.length === 0,
  422. errors: errors
  423. };
  424. },
  425. // 判断值是否为空
  426. isValueEmpty(value) {
  427. if (value === null || value === undefined || value === '') {
  428. return true;
  429. }
  430. if (typeof value === 'string' && value.trim() === '') {
  431. return true;
  432. }
  433. if (Array.isArray(value) && value.length === 0) {
  434. return true;
  435. }
  436. return false;
  437. },
  438. getFormData() {
  439. // 数据校验
  440. const validateResult = this.validateFormData();
  441. return new Promise((resolve, reject) => {
  442. if (validateResult.valid) {
  443. resolve(this.formFields);
  444. } else {
  445. // this.$message.error("表单内容未填完,请填写后再提交");
  446. reject(validateResult.errors[0].error);
  447. }
  448. });
  449. },
  450. //直接获取表单数据,不做校验
  451. getDirectFormData() {
  452. return this.formFields;
  453. },
  454. getFormDataByKey(key) {
  455. return this.formFields[key];
  456. },
  457. onBlur(key, val) {
  458. // compareTo 功能:当fillType==="actFill"时,判断当前值是否与compareTo字段的值一样,如果不一样则将当前input框的背景色标记成橙色
  459. const currentFieldConfig = this.allFieldsConfig[key];
  460. if (currentFieldConfig && currentFieldConfig.fillType === "actFill" && currentFieldConfig.compareTo) {
  461. const compareToKey = currentFieldConfig.compareTo;
  462. const compareToValue = this.formFields[compareToKey];
  463. // 比较当前值和compareTo值,如果不相等则设置橙色背景
  464. if (val !== compareToValue) {
  465. this.$set(this.orangeBgFields, key, true);
  466. } else {
  467. // 相等则移除橙色背景
  468. this.$set(this.orangeBgFields, key, false);
  469. }
  470. }
  471. this.$emit("blur", { key, value: val, ...this.formFields });
  472. },
  473. onSelectChange(key, val) {
  474. // 获取对应的配置
  475. const currentConfig = this.allFieldsConfig[key];
  476. // // 确保多选下拉框的值是数组类型
  477. // if (currentConfig && currentConfig.multiple) {
  478. // // 多选情况,确保值为数组类型
  479. // this.formFields[key] = Array.isArray(val) ? val : (val ? [val] : []);
  480. // } else {
  481. // 单选情况
  482. this.formFields[key] = val;
  483. // }
  484. this.$emit("select", { key, value: val });
  485. // 清除该表单项的错误状态
  486. if (this.errors[key]) {
  487. this.$set(this.errors, key, false);
  488. }
  489. },
  490. //复制
  491. onCopy(config, key) {
  492. const { formFields } = this;
  493. if (config.copyFrom) {
  494. formFields[key] = formFields[config.copyFrom];
  495. this.onBlur(key, formFields[key]);
  496. }
  497. },
  498. },
  499. }
  500. </script>
  501. <style lang="scss">
  502. .grid-container {
  503. display: grid;
  504. grid-template-columns: repeat(2, 1fr);
  505. /* 默认2列 */
  506. gap: 0 20px;
  507. }
  508. .gap2 {
  509. gap: 0 64px;
  510. }
  511. .w-100 {
  512. width: 100%;
  513. }
  514. .form-item {
  515. background: #fff;
  516. padding: 20px;
  517. border-radius: 8px;
  518. box-shadow: 0 2px 12px 0 rgba(0, 0, 0, .1);
  519. margin-top: 20px;
  520. padding: 20px;
  521. border-radius: 5px 5px;
  522. }
  523. /* 或者使用 span 语法 */
  524. .full-row {
  525. grid-column: span 2;
  526. }
  527. .three-row {
  528. grid-column: span 3;
  529. }
  530. .c-Item {
  531. &:not(:last-child) {
  532. margin-bottom: 16px;
  533. }
  534. }
  535. .eo {
  536. &:nth-child(even) {
  537. padding-left: 20px;
  538. }
  539. &:nth-child(odd) {
  540. padding-right: 20px;
  541. }
  542. }
  543. .default-placeholder-text {
  544. color: #C0C4CC;
  545. }
  546. .form-title {
  547. margin-bottom: 12px;
  548. font-size: 14px;
  549. font-weight: normal;
  550. color: #606266;
  551. }
  552. .step-form-title {
  553. font-size: 14px;
  554. font-weight: normal;
  555. color: #606266;
  556. width: 150px;
  557. text-align: right;
  558. padding-right: 10px;
  559. }
  560. .p-r-20 {
  561. padding-right: 20px;
  562. }
  563. .p-l-20 {
  564. padding-left: 20px;
  565. }
  566. .fs-16 {
  567. font-size: 0.96rem;
  568. font-weight: bold;
  569. color: #464647
  570. }
  571. .flex1 {
  572. flex: 1;
  573. }
  574. .flex {
  575. display: flex;
  576. }
  577. .other-title {
  578. width: 50px;
  579. text-align: right;
  580. margin: 0 10px;
  581. font-size: 14px;
  582. font-weight: normal;
  583. color: #606266;
  584. }
  585. .mr-24 {
  586. margin-right: 24px;
  587. }
  588. .sub-select {
  589. width: 100px;
  590. margin-left: 10px;
  591. }
  592. .orange-border {
  593. border-color: #f9c588;
  594. }
  595. .green-border {
  596. border-color: green;
  597. }
  598. .blue-border {
  599. border-color: #4ea2ff;
  600. }
  601. .ml-10 {
  602. margin-left: 10px;
  603. }
  604. </style>