index.vue 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669
  1. <template>
  2. <div class="serivce-home scroll-y">
  3. <div class="wrap">
  4. <MinHeader :is-auth="true" :is-search="true" :is-service="true" :is-statuser="true" power-data="service_addition_button" @addForm="addServiceDialogShow" @searchForms="searchForms" @clearForm="clearForm" @serviceForms="serviceForms">
  5. <template #header>
  6. <div class="status flex-wrap">
  7. <div class="manageTitle">服务管理</div>
  8. <div class="status0"><span class="icon"></span>启动</div>
  9. <div class="status2"><span class="icon"></span>异常</div>
  10. <div class="status1"><span class="icon"></span>停止</div>
  11. </div>
  12. </template>
  13. </MinHeader>
  14. <div class="app-containers">
  15. <DataTable :is-Status="true" :table-header="tableColumns" :table-data="tableData" :table-btn-group="tableBtnGroup" btn-group-width="310px" :table-property="{ rowKey: 'ID' }" @btn-click="tableButtonClickHandler" />
  16. </div>
  17. <Dialog :width="serviceDialogWidth" :flag="serviceDialogVisible" :type="serviceDialogType" :del-name="delName" :msg-title="msgTitle" @del-remove="delSubmitHandler" @del-rest="delDialogHide" @submit-form="serviceSubmitHandler" @reset-form="addServiceDialogHide">
  18. <el-form ref="serviceFormRef" class="service-form" :model="serviceForm" :rules="serviceFormRules" label-position="right" label-width="90px" size="mini">
  19. <el-row :gutter="36" type="flex">
  20. <el-col :span="12">
  21. <el-form-item label="服务名称" prop="serviceName">
  22. <el-input v-model="serviceForm.serviceName" placeholder="请输入服务名称" clearable />
  23. </el-form-item>
  24. </el-col>
  25. <el-col :span="12">
  26. <el-form-item label="前序输出编号" label-width="120px" prop="serviceOutputID">
  27. <el-input v-model="serviceForm.serviceOutputID" placeholder="请输入前序输出编号" clearable />
  28. </el-form-item>
  29. </el-col>
  30. <el-col :span="12">
  31. <el-form-item label="类型" prop="serviceType">
  32. <el-select v-model="serviceForm.serviceType" clearable>
  33. <el-option :value="1" label="管理前端" />
  34. <el-option :value="2" label="管理后端" />
  35. <el-option :value="3" label="业务前端" />
  36. <el-option :value="4" label="业务后端" />
  37. </el-select>
  38. </el-form-item>
  39. </el-col>
  40. <el-col :span="12">
  41. <el-form-item label-width="14px">
  42. <el-radio-group v-model="serviceForm.isAsynchronous">
  43. <el-radio :label="1">同步</el-radio>
  44. <el-radio :label="0">异步</el-radio>
  45. </el-radio-group>
  46. </el-form-item>
  47. </el-col>
  48. <el-col :span="12">
  49. <div class="flex">
  50. <el-form-item label="数据来源" prop="dataSourceID">
  51. <el-select v-model="serviceForm.dataSourceID" clearable>
  52. <el-option v-for="dataSource in selectOptionMap[
  53. queryTemplateIDMap.dataSourceName
  54. ]" :key="dataSource.dataSourceID" :value="dataSource.dataSourceID" :label="dataSource.dataSourceName" />
  55. </el-select>
  56. </el-form-item>
  57. <el-button type="primary" size="small" style="height: 28px; line-height: 0px" @click="addDataSourceDialogShow">新增</el-button>
  58. </div>
  59. </el-col>
  60. <el-col :span="12">
  61. <el-form-item label="数据来源对象" label-width="120px" prop="sourceObjectName">
  62. <el-input v-model="serviceForm.sourceObjectName" placeholder="请输入数据来源对象名称" clearable />
  63. </el-form-item>
  64. </el-col>
  65. <el-col :span="12">
  66. <el-form-item label="服务描述" prop="serviceDescribe">
  67. <el-input v-model="serviceForm.serviceDescribe" placeholder="请输入描述" clearable />
  68. </el-form-item>
  69. </el-col>
  70. <el-col :span="12">
  71. <el-form-item label="生命周期ID键名" prop="lifeCycleCol" label-width="120px">
  72. <el-input v-model="serviceForm.lifeCycleCol" placeholder="请输入生命周期ID键名" clearable />
  73. </el-form-item>
  74. </el-col>
  75. <el-col :span="24">
  76. <el-form-item label="取值规则" prop="computingMethod">
  77. <el-input v-model="serviceForm.computingMethod" placeholder="请输入取值规则" type="textarea" :autosize="{ minRows: 4, maxRows: 4 }" resize="none" clearable />
  78. </el-form-item>
  79. </el-col>
  80. <el-col :span="24">
  81. <el-form-item label="检测规则" prop="validationExpression">
  82. <el-input v-model="serviceForm.validationExpression" placeholder="请输入检测规则" type="textarea" :autosize="{ minRows: 4, maxRows: 4 }" resize="none" clearable />
  83. </el-form-item>
  84. </el-col>
  85. <el-col :span="8">
  86. <el-form-item label="启动时间" prop="startTime">
  87. <el-date-picker v-model="serviceForm.startTime" type="datetime" format="YYYY-MM-DD HH:mm" value-format="YYYY-MM-DD HH:mm" placeholder="请选择启动时间" />
  88. </el-form-item>
  89. </el-col>
  90. <el-col :span="8">
  91. <el-form-item label="停止时间" prop="stopTime">
  92. <el-date-picker v-model="serviceForm.stopTime" type="datetime" format="YYYY-MM-DD HH:mm" value-format="YYYY-MM-DD HH:mm" placeholder="请选择停止时间" />
  93. </el-form-item>
  94. </el-col>
  95. <el-col :span="8">
  96. <el-form-item label="失败重试次数" prop="retryCount" label-width="100px">
  97. <el-input v-model="serviceForm.retryCount" type="number" placeholder="请输入重试次数" clearable />
  98. </el-form-item>
  99. </el-col>
  100. <el-col :span="8">
  101. <el-form-item label="循环次数" prop="loopCount">
  102. <el-input v-model="serviceForm.loopCount" type="number" placeholder="请输入循环次数" clearable />
  103. </el-form-item>
  104. </el-col>
  105. <el-col :span="8">
  106. <el-form-item label="循环频率" prop="frequencyCount">
  107. <el-input v-model="serviceForm.frequencyCount" type="number" placeholder="请输入循环频率" clearable />
  108. </el-form-item>
  109. </el-col>
  110. <el-col :span="8">
  111. <el-form-item label="循环频率单位" prop="frequencyUnit" label-width="100px">
  112. <el-select v-model="serviceForm.frequencyUnit" clearable>
  113. <el-option label="天" :value="24 * 60 * 60 * 1000" />
  114. <el-option label="小时" :value="60 * 60 * 1000" />
  115. <el-option label="分钟" :value="60 * 1000" />
  116. <el-option label="秒" :value="1000" />
  117. <el-option label="毫秒" :value="1" />
  118. </el-select>
  119. </el-form-item>
  120. </el-col>
  121. <el-col :span="12">
  122. <el-form-item label="日志存储位置" label-width="100px" prop="logDataSourceID">
  123. <el-select v-model="serviceForm.logDataSourceID">
  124. <el-option v-for="dataSource in selectOptionMap[
  125. queryTemplateIDMap.dataSourceName
  126. ]" :key="dataSource.dataSourceID" :value="dataSource.dataSourceID" :label="dataSource.dataSourceName" />
  127. </el-select>
  128. </el-form-item>
  129. </el-col>
  130. <el-col :span="12">
  131. <el-form-item label="日志过滤条件" label-width="100px" prop="logList">
  132. <el-input v-model="serviceForm.logList" placeholder="请输入日志过滤条件" clearable />
  133. </el-form-item>
  134. </el-col>
  135. </el-row>
  136. </el-form>
  137. </Dialog>
  138. <Dialog type="add" width="500px" :flag="dataSourceDialogVisible" msg-title="新增数据来源" @submit-form="dataSourceSubmitHandler" @reset-form="dataSourceDialogHide">
  139. <el-form ref="sourceFormRef" label-width="100px" :model="sourceForm">
  140. <el-form-item label="数据源名称">
  141. <el-input v-model="sourceForm.dataSourceName" size="small" />
  142. </el-form-item>
  143. <el-form-item label="协议名称">
  144. <el-select size="small" style="width: 100%" v-model="sourceForm.protocolID" placeholder="请选择活动区域">
  145. <el-option v-for="protocol in selectOptionMap[
  146. queryTemplateIDMap.protocolName
  147. ]" :key="protocol.protocolID" :label="protocol.protocolName" :value="protocol.protocolID" />
  148. </el-select>
  149. </el-form-item>
  150. <el-form-item label="连接参数">
  151. <el-input size="small" type="textarea" rows="3" v-model="sourceForm.connectConfig" />
  152. </el-form-item>
  153. </el-form>
  154. </Dialog>
  155. </div>
  156. </div>
  157. </template>
  158. <script setup lang="ts">
  159. import _ from "lodash";
  160. import DataTable from "@/components/tableTemp/index.vue";
  161. import MinHeader from "@/components/minheader/index.vue";
  162. import Dialog from "@/components/dialog/index.vue";
  163. import { ElMessage, FormInstance } from "element-plus";
  164. import {
  165. CommonTableColumn,
  166. CommonQueryResult,
  167. SelectOption,
  168. SelectOptionQueryResult,
  169. } from "~/common";
  170. import request from "@/utils/axiosReq";
  171. import { Query, GeneralDataReception } from "@/api/webApi";
  172. const router = useRouter();
  173. const queryTemplateIDMap = reactive<{
  174. [x: string]: number;
  175. }>({});
  176. const selectOptionMap = reactive<{
  177. [id: number]: SelectOption[];
  178. }>({});
  179. const getSelectOptionOfColumn = (columns: CommonTableColumn[]) => {
  180. columns.forEach(async ({ columnName, listqueryTemplateID }) => {
  181. if (listqueryTemplateID !== null && !queryTemplateIDMap[columnName]) {
  182. queryTemplateIDMap[columnName] = listqueryTemplateID;
  183. if (!selectOptionMap[listqueryTemplateID]) {
  184. selectOptionMap[listqueryTemplateID] = [];
  185. selectOptionMap[listqueryTemplateID] = await getSelectOptions(
  186. listqueryTemplateID
  187. );
  188. }
  189. }
  190. });
  191. };
  192. const getSelectOptions = async (id: number) => {
  193. try {
  194. const { code, returnData, message }: SelectOptionQueryResult = await Query({
  195. id,
  196. dataContent: [],
  197. });
  198. if (Number(code) !== 0) {
  199. throw new Error(message ?? "失败");
  200. }
  201. const listValues = returnData.listValues || returnData;
  202. const options = listValues.map(({ k, v, setlabel, setvalue }) => ({
  203. k,
  204. v,
  205. setlabel,
  206. setvalue,
  207. [setlabel]: k,
  208. [setvalue]: v,
  209. }));
  210. return options;
  211. } catch (error) {
  212. console.error(error);
  213. return [];
  214. }
  215. };
  216. onMounted(async () => {
  217. queryTemplateIDMap.protocolName = DATACONTENT_ID.protocolOptions;
  218. selectOptionMap[queryTemplateIDMap.protocolName] = await getSelectOptions(
  219. queryTemplateIDMap.protocolName
  220. );
  221. });
  222. // 表格
  223. const tableColumns = ref<CommonTableColumn[]>([]);
  224. const tableData = ref<any[]>([]);
  225. const tableDataCopy = ref<any[]>([]);
  226. const page = ref(0);
  227. const noMore = ref(false);
  228. const rowTitle = ref("");
  229. const serviceVal = ref("");
  230. onMounted(() => {
  231. getTableData();
  232. });
  233. const resetTable = () => {
  234. page.value = 0;
  235. noMore.value = false;
  236. tableData.value = [];
  237. getTableData();
  238. };
  239. const getTableData = async () => {
  240. try {
  241. const {
  242. code,
  243. returnData: { columnSet, listValues },
  244. message,
  245. }: CommonQueryResult = await Query({
  246. id: DATACONTENT_ID.sysServiceTable,
  247. dataContent: [],
  248. needPage: ++page.value,
  249. });
  250. if (Number(code) !== 0) {
  251. throw new Error(message || "失败");
  252. }
  253. if (listValues.length === 0) {
  254. page.value--;
  255. noMore.value = false;
  256. }
  257. const titleColumn = columnSet.find((column) => column.needShow == 1);
  258. if (titleColumn) {
  259. rowTitle.value = titleColumn.columnName;
  260. }
  261. getSelectOptionOfColumn(columnSet);
  262. tableColumns.value = columnSet;
  263. tableData.value.push(...listValues);
  264. tableDataCopy.value = _.cloneDeep(tableData.value);
  265. } catch (error) {
  266. page.value--;
  267. console.error(error);
  268. }
  269. };
  270. const tableBtnGroup = [
  271. {
  272. name: "查看",
  273. className: "editBtn",
  274. param: 1,
  275. is: "service_view_button",
  276. },
  277. {
  278. name: "编辑",
  279. className: "editBtn",
  280. param: 2,
  281. is: "service_editor_button",
  282. },
  283. {
  284. name: "停止",
  285. className: "editBtn",
  286. param: 3,
  287. is: "service_stop_button",
  288. },
  289. {
  290. name: "删除",
  291. className: "delBtn",
  292. param: 4,
  293. is: "service_deletion_button",
  294. },
  295. ];
  296. const tableButtonClickHandler = (rowIndex: number, row: any, param: number) => {
  297. switch (param) {
  298. case 1:
  299. router.push({
  300. path: "/systemSettings/serviceTopology",
  301. query: {
  302. serviceID: row["serviceID"],
  303. serviceName: row["serviceName"],
  304. },
  305. });
  306. break;
  307. case 2:
  308. router.push({
  309. path: "/systemSettings/serviceEdit",
  310. query: {
  311. serviceID: row["serviceID"],
  312. runState: row["runState"],
  313. },
  314. });
  315. break;
  316. case 3:
  317. changeServiceState(row["serviceID"], row["runState"]);
  318. break;
  319. case 4:
  320. delID = row["serviceID"];
  321. delDialogShow(row);
  322. break;
  323. default:
  324. break;
  325. }
  326. };
  327. const changeServiceState = async (serviceID: number, runState: string) => {
  328. const operate = runState === "运行" ? "stop" : "start";
  329. try {
  330. const {
  331. code,
  332. returnData: { listValues },
  333. message,
  334. } = await Query({
  335. id: DATACONTENT_ID.sysServiceNodeList,
  336. dataContent: [serviceID],
  337. btnAuth: "service_stop_button",
  338. });
  339. if (Number(code) !== 0) {
  340. throw new Error(message ?? "失败");
  341. }
  342. if (!listValues.length) {
  343. throw new Error("无部署机器");
  344. }
  345. Promise.all(
  346. listValues.map((node) => {
  347. request({
  348. url: `${node.serviceURL}${operate}`,
  349. method: "post",
  350. data: {
  351. serviceId: serviceID,
  352. },
  353. });
  354. })
  355. )
  356. .then((results: any) => {
  357. if (results.every((result) => Number(result.code) === 0)) {
  358. ElMessage.success("操作成功");
  359. } else {
  360. ElMessage.error("操作失败");
  361. }
  362. })
  363. .catch((error) => {
  364. throw new Error(error);
  365. });
  366. } catch (error) {
  367. console.error(error);
  368. }
  369. };
  370. //搜索
  371. const searchForms = (val) => {
  372. if (serviceVal.value) {
  373. const arrs = tableDataCopy.value.filter(
  374. (item) =>
  375. item.nodeState == serviceVal.value && item.serviceName.includes(val)
  376. );
  377. tableData.value = arrs;
  378. } else {
  379. const arrs = tableDataCopy.value.filter((item) =>
  380. item.serviceName.includes(val)
  381. );
  382. tableData.value = arrs;
  383. }
  384. };
  385. //清空搜索
  386. const clearForm = () => {
  387. if (serviceVal.value) {
  388. const arrs = tableDataCopy.value.filter(
  389. (item) => item.nodeState == serviceVal.value
  390. );
  391. tableData.value = arrs;
  392. } else {
  393. tableData.value = tableDataCopy.value;
  394. }
  395. };
  396. //下拉搜索
  397. const serviceForms = (val) => {
  398. serviceVal.value = val;
  399. if (val) {
  400. const arrs = tableDataCopy.value.filter((item) => item.nodeState == val);
  401. tableData.value = arrs;
  402. } else {
  403. tableData.value = tableDataCopy.value;
  404. }
  405. };
  406. // 新增/删除服务-弹窗
  407. const serviceDialogVisible = ref(false); // 弹窗开关
  408. const serviceDialogType = ref(""); // 弹窗类型是否删除
  409. const serviceDialogWidth = computed(() =>
  410. serviceDialogType.value === "del" ? "600px" : "878px"
  411. );
  412. const delName = ref(""); // 删除对象名
  413. let delID; // 删除对象ID
  414. const msgTitle = ref(""); // 服务弹窗-标题
  415. const delDialogShow = (row) => {
  416. serviceDialogType.value = "del";
  417. msgTitle.value = "删除服务";
  418. delName.value = row["serviceName"];
  419. serviceDialogVisible.value = true;
  420. };
  421. const delDialogHide = () => {
  422. serviceDialogVisible.value = false;
  423. };
  424. const delSubmitHandler = async () => {
  425. try {
  426. await deleteService();
  427. delDialogHide();
  428. resetTable();
  429. } catch (error) {
  430. console.error(error);
  431. }
  432. };
  433. const deleteService = async () => {
  434. try {
  435. const dataContent = {
  436. serviceID: delID,
  437. event: 3,
  438. };
  439. const { code, message } = await GeneralDataReception({
  440. serviceId: SERVICE_ID.sysServiceEdit,
  441. dataContent: JSON.stringify(dataContent),
  442. btnAuth: "service_deletion_button",
  443. });
  444. if (Number(code) === 0) {
  445. ElMessage.success(message ?? "成功");
  446. } else {
  447. throw new Error(message ?? "失败");
  448. }
  449. } catch (error) {
  450. return Promise.reject(error);
  451. }
  452. };
  453. const addServiceDialogShow = () => {
  454. serviceDialogType.value = "add";
  455. msgTitle.value = "新增服务管理";
  456. serviceDialogVisible.value = true;
  457. // console.log(queryTemplateIDMap, selectOptionMap);
  458. };
  459. const addServiceDialogHide = () => {
  460. serviceFormRef.value?.resetFields();
  461. serviceDialogVisible.value = false;
  462. };
  463. // 新增服务-表单
  464. const serviceFormRef = ref<FormInstance | null>(null);
  465. const serviceForm = reactive({
  466. serviceName: "",
  467. serviceOutputID: null,
  468. serviceType: null,
  469. dataSourceID: null,
  470. sourceObjectName: "",
  471. lifeCycleCol: "",
  472. isAsynchronous: 1,
  473. threads: null,
  474. datatype: null,
  475. computingMethod: "",
  476. validationExpression: "",
  477. startTime: null,
  478. stopTime: null,
  479. retryCount: null,
  480. loopCount: null,
  481. frequencyCount: null,
  482. frequencyUnit: null,
  483. serviceDescribe: "",
  484. logDataSourceID: null,
  485. logList: "",
  486. });
  487. const serviceFormRules = {
  488. serviceName: [
  489. {
  490. required: true,
  491. message: "请输入服务名称",
  492. trigger: ["change", "blur"],
  493. },
  494. ],
  495. };
  496. const serviceSubmitHandler = () => {
  497. serviceFormRef.value!.validate(async (valid) => {
  498. if (valid) {
  499. try {
  500. await createService();
  501. addServiceDialogHide();
  502. resetTable();
  503. } catch (error) {
  504. console.error(error);
  505. }
  506. }
  507. });
  508. };
  509. const createService = async () => {
  510. try {
  511. Object.keys(serviceForm).forEach((key) => {
  512. if (
  513. ![
  514. "sourceObjectName",
  515. "lifeCycleCol",
  516. "computingMethod",
  517. "validationExpression",
  518. "logList",
  519. ].includes(key) &&
  520. serviceForm[key] === ""
  521. ) {
  522. serviceForm[key] = null;
  523. }
  524. });
  525. const dataContent = { ...serviceForm, event: 1 };
  526. const { code, message } = await GeneralDataReception({
  527. serviceId: SERVICE_ID.sysServiceEdit,
  528. dataContent: JSON.stringify(dataContent),
  529. btnAuth: "service_addition_button",
  530. });
  531. if (Number(code) === 0) {
  532. ElMessage.success(message ?? "成功");
  533. } else {
  534. throw new Error(message ?? "失败");
  535. }
  536. } catch (error) {
  537. return Promise.reject(error);
  538. }
  539. };
  540. // 新增数据来源-弹窗
  541. const dataSourceDialogVisible = ref(false);
  542. const addDataSourceDialogShow = () => {
  543. dataSourceDialogVisible.value = true;
  544. };
  545. const dataSourceDialogHide = () => {
  546. sourceFormRef.value?.resetFields();
  547. dataSourceDialogVisible.value = false;
  548. };
  549. // 新增数据来源-表单
  550. const sourceFormRef = ref<FormInstance | null>(null);
  551. const sourceForm = reactive({
  552. dataSourceName: null,
  553. protocolID: null,
  554. connectConfig: null,
  555. });
  556. const dataSourceSubmitHandler = () => {
  557. dataSourceDialogHide();
  558. };
  559. </script>
  560. <style lang="scss" scoped>
  561. .app-containers {
  562. height: calc(100vh - 180px);
  563. }
  564. .icon {
  565. width: 14px;
  566. height: 14px;
  567. background: #2d67e3;
  568. border-radius: 2px;
  569. display: inline-block;
  570. vertical-align: middle;
  571. margin-right: 10px;
  572. position: relative;
  573. top: -2px;
  574. }
  575. .status0,
  576. .status2 {
  577. margin-right: 28px;
  578. position: relative;
  579. top: 5px;
  580. }
  581. .status1 {
  582. position: relative;
  583. top: 5px;
  584. .icon {
  585. background-color: #afb4bf;
  586. }
  587. }
  588. .status2 {
  589. .icon {
  590. background-color: #eb2f3b;
  591. }
  592. }
  593. .service-form:deep {
  594. display: flex;
  595. flex-wrap: wrap;
  596. padding-left: 20px;
  597. > .el-row {
  598. flex-wrap: wrap;
  599. > .el-col .el-form-item {
  600. margin-bottom: 20px;
  601. .el-form-item__label {
  602. padding-right: 16px;
  603. }
  604. .el-input,
  605. .el-select {
  606. width: 100%;
  607. }
  608. .el-input__inner,
  609. .el-textarea__inner {
  610. padding-left: 8px;
  611. }
  612. .el-date-editor {
  613. .el-input__prefix,
  614. .el-input__suffix {
  615. right: 5px;
  616. left: unset;
  617. font-size: 16px;
  618. color: #101116;
  619. .el-input__suffix-inner {
  620. font-size: 16px;
  621. }
  622. }
  623. &.value-not-null:hover .el-input__prefix {
  624. display: none;
  625. }
  626. }
  627. }
  628. }
  629. label,
  630. span,
  631. button,
  632. input,
  633. optgroup,
  634. select,
  635. textarea {
  636. font-family: DIN, Microsoft YaHei;
  637. font-size: 14px;
  638. font-weight: 400;
  639. }
  640. label {
  641. color: #303133;
  642. }
  643. input {
  644. color: #101116;
  645. &::-webkit-outer-spin-button,
  646. &::-webkit-inner-spin-button {
  647. appearance: none;
  648. -webkit-appearance: none !important;
  649. &[type="number"] {
  650. appearance: textfield;
  651. -moz-appearance: textfield !important;
  652. }
  653. }
  654. .el-radio {
  655. font-weight: 400;
  656. }
  657. }
  658. }
  659. </style>