edit.vue 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608
  1. <template>
  2. <ion-page>
  3. <ion-header class="header-theme2">
  4. <ion-toolbar>
  5. <ion-buttons slot="start">
  6. <ion-icon :icon="arrowBackOutline" @click="onBack"></ion-icon>
  7. </ion-buttons>
  8. <ion-title>
  9. 企业信息录入
  10. </ion-title>
  11. </ion-toolbar>
  12. </ion-header>
  13. <ion-content>
  14. <div class="stepFlex">
  15. <div v-for="(record,key) in stepList" :key="key" class="stepFlex-item">
  16. <div
  17. :class="[(record.val < curStepData?.statusVal || curStepData?.statusVal == stepList.val) ? 'greenCircle' :record.val == curStepData?.statusVal ? 'now' : 'grayCircle']"></div>
  18. <div v-if="key !== stepList.length - 1"
  19. :class="[record.val < curStepData?.statusVal ? 'greenLine' : 'grayLine']"></div>
  20. <div class="stepFlex-item-label">
  21. <p class="stepFlex-item-label-title">{{ record.title }}</p>
  22. <p class="stepFlex-item-label-desc">{{ record.desc }}</p>
  23. </div>
  24. </div>
  25. </div>
  26. <form autocomplete="off">
  27. <ion-list>
  28. <ion-item>
  29. <div class="panel-title2">
  30. <div class="item-flag"></div>
  31. 基本信息
  32. </div>
  33. </ion-item>
  34. <ion-label class="title-item">统一信用代码<span class="danger">*</span></ion-label>
  35. <ion-item mode="md" :class="[v$.dataModel.companyCode.$error?'ion-invalid':'ion-valid']">
  36. <ion-input placeholder="请输入统一信用代码" label-placement="stacked" :clear-input="true"
  37. v-model="dataModel.companyCode" class="custom">
  38. </ion-input>
  39. <ion-note slot="error">统一信用代码不能为空</ion-note>
  40. </ion-item>
  41. <ion-label class="title-item">企业名称<span class="danger">*</span></ion-label>
  42. <ion-item mode="md" :class="[v$.dataModel.companyName.$error?'ion-invalid':'ion-valid']">
  43. <ion-input placeholder="请输入企业名称" label-placement="stacked" :clear-input="true"
  44. v-model="dataModel.companyName" class="custom">
  45. </ion-input>
  46. <ion-note slot="error">企业名称不能为空</ion-note>
  47. </ion-item>
  48. <ion-label class="title-item">服务驿站<span class="danger">*</span></ion-label>
  49. <ion-item mode="md" :class="[v$.dataModel.siteID.$error?'ion-invalid':'ion-valid']">
  50. <ion-select id="siteID" name="siteID" cancel-text="取消" v-model="dataModel.siteID"
  51. interface="action-sheet" placeholder="请选择服务驿站" style="width: 100%;text-align: left;">
  52. <ion-select-option v-for="(record,key) in siteList" :key="key" v-model:value="record.siteID">
  53. {{ record.siteName }}
  54. </ion-select-option>
  55. </ion-select>
  56. <ion-note slot="error">服务驿站不能为空</ion-note>
  57. </ion-item>
  58. <ion-label class="title-item">企业办公地址<span class="danger">*</span></ion-label>
  59. <ion-item mode="md" :class="[v$.dataModel.companyAddress.$error?'ion-invalid':'ion-valid']">
  60. <ion-textarea placeholder="请输入企业办公地址" label-placement="stacked" :rows="3" :clear-input="true"
  61. v-model="dataModel.companyAddress" class="custom" >
  62. </ion-textarea>
  63. <ion-note slot="error">企业办公地址不能为空</ion-note>
  64. </ion-item>
  65. <ion-label class="title-item">企业联系人<span class="danger">*</span></ion-label>
  66. <ion-item mode="md" :class="[v$.dataModel.userName.$error?'ion-invalid':'ion-valid']">
  67. <ion-input placeholder="请输入企业联系人" label-placement="stacked" :clear-input="true"
  68. v-model="dataModel.userName" class="custom">
  69. </ion-input>
  70. <ion-note slot="error">企业联系人不能为空</ion-note>
  71. </ion-item>
  72. <ion-label class="title-item">联系电话<span class="danger">*</span></ion-label>
  73. <ion-item mode="md" :class="[v$.dataModel.userMobile.$error?'ion-invalid':'ion-valid']">
  74. <ion-input placeholder="请输入联系电话" label-placement="stacked" :clear-input="true"
  75. v-model="dataModel.userMobile" class="custom">
  76. </ion-input>
  77. <ion-note slot="error">企业联系电话不能为空</ion-note>
  78. </ion-item>
  79. <ion-label class="title-item">企业状态<span class="danger">*</span></ion-label>
  80. <ion-item mode="md" :class="[v$.dataModel.recordStatus.$error?'ion-invalid':'ion-valid']">
  81. <ion-select id="recordStatus" name="recordStatus" cancel-text="取消" v-model="dataModel.recordStatus"
  82. interface="action-sheet" placeholder="请选择企业状态" style="width: 100%;text-align: left;">
  83. <ion-select-option v-for="(record,key) in companyStatusList" :key="key"
  84. v-model:value="record.value">
  85. {{ record.name }}
  86. </ion-select-option>
  87. </ion-select>
  88. <ion-note slot="error">企业状态不能为空</ion-note>
  89. </ion-item>
  90. <ion-label class="title-item">是否缺工<span class="danger">*</span></ion-label>
  91. <ion-item mode="md" :class="[v$.dataModel.isShortage.$error?'ion-invalid':'ion-valid']">
  92. <ion-select id="isShortAge" name="isShortAge" cancel-text="取消" v-model="dataModel.isShortage"
  93. interface="action-sheet" placeholder="请选择是否缺工" style="width: 100%;text-align: left;">
  94. <ion-select-option v-for="(record,key) in shortAgeTypeList" :key="key"
  95. v-model:value="record.value">
  96. {{ record.name }}
  97. </ion-select-option>
  98. </ion-select>
  99. <ion-note slot="error">企业状态不能为空</ion-note>
  100. </ion-item>
  101. <ion-item mode="md" >
  102. <div class="panel-title2" style="width: 25%;">
  103. <div class="item-flag"></div>
  104. 其他信息
  105. </div>
  106. <div style="width: 75%;text-align: right;">
  107. <ion-icon :icon="chevronDownOutline" @click="isShow=!isShow" v-show="!isShow"
  108. style="font-size: 24px;"></ion-icon>
  109. <ion-icon :icon="chevronUpOutline" @click="isShow=!isShow" v-show="isShow"
  110. style="font-size: 24px;"></ion-icon>
  111. </div>
  112. </ion-item>
  113. <ion-list v-show="isShow" >
  114. <ion-label class="title-item">法定代表人(负责人)</ion-label>
  115. <ion-item mode="md">
  116. <ion-input placeholder="请输入法定代表人" label-placement="stacked" :clear-input="true"
  117. v-model="dataModel.frName" class="custom">
  118. </ion-input>
  119. </ion-item>
  120. <ion-label class="title-item">营业执照有效期</ion-label>
  121. <ion-item mode="md">
  122. <div>
  123. <ion-radio v-model:checked="isLongDate" justify="start" labelPlacement="end"
  124. @click="changeLongDate" style="height:30px;">至长期</ion-radio>
  125. <ion-datetime-button datetime="validDate" style=""></ion-datetime-button>
  126. <ion-modal :keep-contents-mounted="true" >
  127. <ion-datetime id="validDate" name="validDate" placeholder="营业执照有效期"
  128. v-model="dataModel.validDate" :prefer-wheel="true" @ionChange="changeValidDate"
  129. dataformatas="YYYY-MM-DD" presentation="date" cancel-text="取消" done-text="确定"
  130. :show-default-buttons="true" >
  131. </ion-datetime>
  132. </ion-modal>
  133. </div>
  134. </ion-item>
  135. <ion-label class="title-item">企业邮箱</ion-label>
  136. <ion-item mode="md">
  137. <ion-input placeholder="请输入企业邮箱" label-placement="stacked" :clear-input="true"
  138. v-model="dataModel.companyEmail" class="custom">
  139. </ion-input>
  140. </ion-item>
  141. <ion-label class="title-item">企业归类</ion-label>
  142. <ion-item mode="md">
  143. <ion-select interface="action-sheet" placeholder="请选择企业归类" cancel-text="取消"
  144. id="companyType" v-model="dataModel.companyType" style="width: 100%;text-align: left;">
  145. <ion-select-option v-for="(record,key) in companyTypeList" :key="key"
  146. v-model:value="record.code">
  147. {{ record.name }}
  148. </ion-select-option>
  149. </ion-select>
  150. </ion-item>
  151. <ion-label class="title-item">企业规模</ion-label>
  152. <ion-item mode="md">
  153. <ion-select interface="action-sheet" placeholder="请选择企业规模" cancel-text="取消"
  154. id="companyModel" v-model="dataModel.companyModel" style="width: 100%;text-align: left;">
  155. <ion-select-option v-for="(record,key) in companyModelList" :key="key"
  156. v-model:value="record.value" style="width:100%;text-align: left;">
  157. {{ record.name }}
  158. </ion-select-option>
  159. </ion-select>
  160. </ion-item>
  161. <ion-label class="title-item">所属县区</ion-label>
  162. <ion-item mode="md">
  163. <ion-select interface="action-sheet" placeholder="请选择所属县区" cancel-text="取消" @ionChange="changeCity"
  164. id="regionCode" v-model="dataModel.regionCode" style="width:100%;text-align: left;">
  165. <ion-select-option v-for="(record,key) in regionList" :key="key"
  166. v-model:value="record.code">
  167. {{ record.name }}
  168. </ion-select-option>
  169. </ion-select>
  170. </ion-item>
  171. <ion-label class="title-item">所属街道</ion-label>
  172. <ion-item mode="md">
  173. <ion-select interface="action-sheet" placeholder="请选择所属街道" cancel-text="取消"
  174. id="streetCode" v-model="dataModel.streetCode" style="width: 100%;text-align: left;">
  175. <ion-select-option v-for="(record,key) in streetList" :key="key"
  176. v-model:value="record.code">
  177. {{ record.name }}
  178. </ion-select-option>
  179. </ion-select>
  180. </ion-item>
  181. <ion-label class="title-item">用工情况(人)</ion-label>
  182. <ion-item mode="md">
  183. <ion-input type="number" placeholder="请输入用工人数" label-placement="stacked" :clear-input="true"
  184. v-model="dataModel.workSituation" class="custom">
  185. </ion-input>
  186. </ion-item>
  187. <ion-label class="title-item">参保人数(人)</ion-label>
  188. <ion-item mode="md">
  189. <ion-input type="number" placeholder="请输入参保人数" label-placement="stacked" :clear-input="true"
  190. v-model="dataModel.insuredCount" class="custom">
  191. </ion-input>
  192. </ion-item>
  193. <ion-label class="title-item">经营范围</ion-label>
  194. <ion-item mode="md">
  195. <ion-textarea placeholder="请输入经营范围" :rows="3" label-placement="stacked" :clear-input="true"
  196. v-model="dataModel.businScope" class="custom">
  197. </ion-textarea>
  198. </ion-item>
  199. <ion-label class="title-item">企业简介</ion-label>
  200. <ion-item mode="md">
  201. <ion-textarea placeholder="请输入企业简介" :rows="3" label-placement="stacked" :clear-input="true"
  202. v-model="dataModel.companyDesc" class="custom">
  203. </ion-textarea>
  204. </ion-item>
  205. </ion-list>
  206. </ion-list>
  207. </form>
  208. </ion-content>
  209. <ion-footer>
  210. <ion-toolbar>
  211. <div slot="end">
  212. <ion-button shape="round" expand="block" @click="onNext">提交</ion-button>
  213. </div>
  214. </ion-toolbar>
  215. </ion-footer>
  216. </ion-page>
  217. </template>
  218. <script lang="ts">
  219. import {defineComponent, ref, reactive, computed, watch, toRefs} from "vue";
  220. import {chevronDownOutline, chevronUpOutline, arrowBackOutline} from 'ionicons/icons';
  221. import {getRegionList, getSiteList, getStreeList} from '@/api/company/index'
  222. import {useRoute,useRouter} from "vue-router";
  223. import {alertController, onIonViewDidEnter} from "@ionic/vue";
  224. import {useVuelidate} from "@vuelidate/core";
  225. import {getCompanyById,saveCompanyInfo} from "@/api/company";
  226. import {minLength,required} from "@vuelidate/validators";
  227. import {getSysDictionaryList} from "@/api/system/dictionary";
  228. import dayjs from "dayjs";
  229. interface StepParams{
  230. name: string,
  231. statusVal: number
  232. }
  233. export default defineComponent({
  234. name: 'CompanyEdit',
  235. setup() {
  236. const route = useRoute();
  237. const router = useRouter();
  238. const isAllowCommit = ref(true);
  239. const curStepData = ref<StepParams>({
  240. name:"",
  241. statusVal: 1
  242. });
  243. const isAdd = ref<any>(true);
  244. const isShow = ref<any>(false);
  245. const isLongDate = ref<any>(false);
  246. const formState = reactive({
  247. dataModel: {
  248. companyID:null,
  249. companyCode: '',
  250. companyName: null,
  251. siteID: null,
  252. companyAddress: null,
  253. userName: null,
  254. userMobile: '',
  255. recordStatus: null,
  256. isShortage: null,
  257. frName: null,
  258. validDate: dayjs().format("YYYY-MM-DD"),
  259. companyEmail: '',
  260. companyType: null,
  261. companyModel: null,
  262. regionCode: null,
  263. streetCode: null,
  264. workSituation: null,
  265. insuredCount: null,
  266. businScope: null,
  267. companyDesc: null
  268. }});
  269. const stepList = ref([
  270. {title: '基础信息', desc: '企业基础信息', val: 1},
  271. {title: '岗位信息', desc: '企业岗位信息', val: 2}
  272. ]);
  273. const companyTypeList = ref<any>([]);
  274. const companyModelList = ref<any>([]);
  275. const regionList = ref<any>([]);
  276. const streetList = ref<any>([]);
  277. const siteList = ref<any>([]);
  278. const companyStatusList = [
  279. {value: 1, name: '在营'},
  280. {value: 0, name: '关闭'},
  281. ];
  282. const shortAgeTypeList = [
  283. {value: 1, name: '是'},
  284. {value: 0, name: '否'},
  285. ];
  286. const getCompanyModelList = async function(){
  287. const companyModelResult :any = await getSysDictionaryList("CompanyModel");
  288. companyModelList.value = companyModelResult;
  289. }
  290. const rules = computed(() => {
  291. return {
  292. dataModel: {
  293. companyCode: {required},
  294. companyName: {required},
  295. siteID: {required},
  296. companyAddress: {required},
  297. userName: {required},
  298. userMobile: {required},
  299. recordStatus: {required},
  300. isShortage: {required},
  301. }
  302. }
  303. });
  304. const v$ = useVuelidate(rules, formState);
  305. const changeLongDate = ()=>{
  306. isLongDate.value = true;
  307. formState.dataModel.validDate = "2099-12-31T00:00:00.000+08:00";
  308. };
  309. const changeValidDate = () => {
  310. isLongDate.value = false;
  311. };
  312. const companyCodeValidate = ()=>{
  313. isAllowCommit.value = true;
  314. const codeReg = /^[0-9A-Z]+$/;
  315. console.log(formState.dataModel.companyCode);
  316. if(formState.dataModel.companyCode.length != 18 || !codeReg.test(formState.dataModel.companyCode)){
  317. presentAlert("输入的信用代码有误!");
  318. isAllowCommit.value = false;
  319. }else{
  320. let aCode;
  321. let aCodeValue;
  322. let total = 0;
  323. const weightedFactors = [1,3,9,27,19,26,16,17,20,29,25,13,8,24,10,30,28];
  324. const str = '0123456789ABCDEFGHJKLMNPQRTUWXY';
  325. for(let i =0;i < formState.dataModel.companyCode.length-1;i++){
  326. aCode = formState.dataModel.companyCode.substring(i,i+1);
  327. aCodeValue = str.indexOf(aCode);
  328. total += aCodeValue * weightedFactors[i];
  329. }
  330. let logicCheckCode = 31 - total % 31;
  331. if(logicCheckCode == 31){
  332. logicCheckCode = 0;
  333. }
  334. const Str = "0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F,G,H,J,K,L,M,N,P,Q,R,T,U,W,X,Y";
  335. const Array_Str = Str.split(',');
  336. const correctCodeStr = Array_Str[logicCheckCode];
  337. console.log("正确的校验码是",correctCodeStr);
  338. const currentCodeStr = formState.dataModel.companyCode.substring(17, 18);
  339. if (correctCodeStr != currentCodeStr) {
  340. presentAlert('输入的统一信用代码无效!');
  341. isAllowCommit.value = false;
  342. }
  343. }
  344. }
  345. const inputDataValidate = () =>{
  346. const mobileReg = /^1[3|4|5|6|7|8|9]\d{9}$/;
  347. if(!mobileReg.test(formState.dataModel.userMobile)){
  348. presentAlert("输入的联系电话有误!");
  349. isAllowCommit.value = false;
  350. }
  351. const emailReg = /^[a-z0-9]+([._\\-]*[a-z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$/;
  352. // 这里由于企业邮箱非必填所以先判断是否填写了企业邮箱
  353. if(formState.dataModel.companyEmail.trim()!==""){
  354. if(!emailReg.test(formState.dataModel.companyEmail)){
  355. presentAlert("输入的企业邮箱有误!");
  356. isAllowCommit.value = false;
  357. }
  358. }
  359. };
  360. const onNext = async () => {
  361. const isFormCorrect = await v$.value.$validate();
  362. if (!isFormCorrect) {
  363. await presentAlert('请输入完整信息!');
  364. return null;
  365. }
  366. /*const jsonStr = JSON.stringify(formState.dataModel);
  367. localStorage.removeItem('companyData');
  368. localStorage.setItem("companyData", jsonStr);*/
  369. companyCodeValidate();
  370. inputDataValidate();
  371. if(isAllowCommit.value){
  372. saveCompanyInfo(formState.dataModel).then(result => {
  373. if (result) {
  374. if(isAdd.value){
  375. router.push({path: './menu', query: {reload:1,id:formState.dataModel.companyID,status:2}});
  376. }
  377. else{
  378. router.push({path: './postList', query: {reload:1,id:formState.dataModel.companyID,status:3}});
  379. }
  380. }
  381. });
  382. }
  383. };
  384. const onBack=()=>{
  385. if(isAdd.value)
  386. router.push({path: './list', query: {reload:1}});
  387. else if(curStepData.value.statusVal==1)
  388. router.push({path: './menu', query: {reload:1,id:formState.dataModel.companyID,status:2}});
  389. }
  390. const getRegionListData = () => {
  391. getRegionList({}).then(data => {
  392. regionList.value = data;
  393. });
  394. }
  395. const getStreetListData = (code: any) => {
  396. getStreeList({code: code}).then(data => {
  397. streetList.value = data;
  398. });
  399. }
  400. const getSiteListData = () => {
  401. getSiteList({}).then(data => {
  402. siteList.value = data;
  403. });
  404. }
  405. const changeCity = () => {
  406. console.log(formState.dataModel.regionCode);
  407. if (formState.dataModel.regionCode)
  408. getStreetListData(formState.dataModel.regionCode);
  409. }
  410. const loadData = async (companyID: any,status:any) => {
  411. curStepData.value.statusVal = status;
  412. isAdd.value = companyID == null;
  413. const reqData = await getCompanyById(companyID);
  414. formState.dataModel = reqData;
  415. isLongDate.value = formState.dataModel.validDate == "2099-12-31T00:00:00.000+08:00";
  416. console.log('dataModel',formState.dataModel);
  417. console.log('isAdd',isAdd.value);
  418. if(formState.dataModel.regionCode!=null) getStreetListData(formState.dataModel.regionCode);
  419. };
  420. /* watch(() => route.query, () => {
  421. if (route.query.reload) {
  422. loadData(route.query.id,route.query.status);
  423. }
  424. });*/
  425. const reload = (companyID:any,status:any) => {
  426. isAdd.value = true;
  427. isShow.value = false;
  428. loadData(companyID,status);
  429. }
  430. onIonViewDidEnter(() => {
  431. if (route.query.reload) {
  432. reload(route.query.id,route.query.status);
  433. }
  434. });
  435. const presentAlert = async (message: string) => {
  436. const alert = await alertController.create({
  437. header: '错误!',
  438. message: message,
  439. buttons: [
  440. '确定'
  441. ],
  442. });
  443. await alert.present();
  444. }
  445. return {
  446. ...toRefs(formState),
  447. arrowBackOutline,
  448. chevronDownOutline,
  449. chevronUpOutline,
  450. route,
  451. router,
  452. isShow,
  453. v$,
  454. isLongDate,
  455. curStepData,
  456. stepList,
  457. companyTypeList,
  458. siteList,
  459. regionList,
  460. streetList,
  461. shortAgeTypeList,
  462. companyStatusList,
  463. companyModelList,
  464. onNext,
  465. onBack,
  466. getCompanyModelList,
  467. getRegionListData,
  468. getSiteListData,
  469. changeCity,
  470. changeLongDate,
  471. changeValidDate,
  472. loadData,
  473. }
  474. },mounted(){
  475. this.getCompanyModelList();
  476. this.getRegionListData();
  477. this.getSiteListData();
  478. }
  479. });
  480. </script>
  481. <style lang="less">
  482. .custom{
  483. --placeholder-color: gray;
  484. --placeholder-font-style:italic;
  485. --placeholder-opacity: 1;
  486. }
  487. .title-item{
  488. margin-left: 15px;
  489. color:#1c3d70 !important;
  490. font-size: 14px !important;
  491. font-weight: bold;
  492. }
  493. ion-item {
  494. --border-width: 0;
  495. --border-style: none;
  496. ion-label, ion-input, ion-select, ion-datetime-button {
  497. font-size: 14px !important;
  498. }
  499. }
  500. .stepFlex {
  501. margin: 0;
  502. display: flex;
  503. width: 100%;
  504. .stepFlex-item {
  505. position: relative;
  506. flex: 1;
  507. text-align: center;
  508. margin-top: -10px;
  509. .stepFlex-item-label {
  510. padding-top: 60px;
  511. font-size: 14px;
  512. .stepFlex-item-label-title {
  513. margin-top: 30px;
  514. }
  515. .stepFlex-item-label-desc {
  516. margin-top: 5px;
  517. color: #b9b9bd;
  518. }
  519. }
  520. }
  521. .greenCircle {
  522. top: calc(50% - 15px);
  523. left: calc(50% - 4px);
  524. position: absolute;
  525. z-index: 2;
  526. width: 10px;
  527. height: 10px;
  528. border-radius: 50%;
  529. background-color: #31A2FE;
  530. }
  531. .now {
  532. top: calc(50% - 18px);
  533. left: calc(50% - 8px);
  534. position: absolute;
  535. z-index: 3;
  536. width: 16px;
  537. height: 16px;
  538. border-radius: 50%;
  539. background-color: #31A2FE;
  540. border: 4px solid #c5e8f9;
  541. }
  542. .grayCircle {
  543. top: calc(50% - 15px);
  544. left: calc(50% - 4px);
  545. position: absolute;
  546. z-index: 2;
  547. width: 10px;
  548. height: 10px;
  549. border-radius: 50%;
  550. background-color: #ccc;
  551. }
  552. .greenLine {
  553. width: 100%;
  554. top: calc(50% - 11px);
  555. left: calc(50% - 2px);
  556. height: 2px;
  557. background-color: #31A2FE;
  558. position: absolute;
  559. }
  560. .grayLine {
  561. height: 0;
  562. border: 1px dashed #ccc;
  563. width: 100%;
  564. top: calc(50% - 11px);
  565. left: calc(50% - 2px);
  566. position: absolute;
  567. }
  568. }
  569. </style>