regular-template-form.vue 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653
  1. <template>
  2. <view class="page-no-tab">
  3. <uni-nav-bar
  4. fixed="true"
  5. statusBar="true"
  6. left-icon="back"
  7. title="转正申请模板"
  8. background-color="#157A2C"
  9. color="#fff"
  10. @clickLeft="back"
  11. ></uni-nav-bar>
  12. <view class="form-intro">
  13. <ModuleIcon :icon="meta.icon" :color="meta.color" soft />
  14. <view>
  15. <text class="intro-title">{{ form.id ? '编辑模板' : '新增模板' }}</text>
  16. <text class="intro-sub">{{ introSub }}</text>
  17. </view>
  18. </view>
  19. <view v-if="form.id && !isDraft" class="notice">
  20. <text>
  21. 已{{ form.templateStatusLabel || '启用' }}模板:正文与变量改完后需点底部「发布新版本」保存;
  22. 发布后模板会自动回到停用态,需重新启用。分类暂不支持修改。
  23. </text>
  24. </view>
  25. <view class="section-title"><text>基础信息</text></view>
  26. <view class="form-card card section">
  27. <view class="field">
  28. <text class="label required">模板名称</text>
  29. <input v-model="form.templateName" class="text-input" maxlength="128" placeholder="请输入模板名称" />
  30. </view>
  31. <view class="divider"></view>
  32. <view class="field">
  33. <text class="label required">模板编码</text>
  34. <input v-model="form.templateCode" class="text-input" maxlength="64" placeholder="同租户唯一" />
  35. </view>
  36. <view class="divider"></view>
  37. <hr-picker-row
  38. v-bind="pickerRowMetrics"
  39. label="模板分类"
  40. required
  41. :value="form.categoryId"
  42. :display="categoryLabel"
  43. :options="categoryOptions"
  44. :disabled="formDisabled"
  45. @change="onCategoryChange"
  46. />
  47. <view class="divider"></view>
  48. <hr-picker-row
  49. v-bind="pickerRowMetrics"
  50. label="所属机构"
  51. required
  52. :value="form.legalId"
  53. :display="form.legalName"
  54. :options="companies.map((item) => ({ label: item.name, value: item.id }))"
  55. :disabled="formDisabled || !companies.length"
  56. hint="机构列表为空"
  57. @change="onLegalChange"
  58. />
  59. <view class="divider"></view>
  60. <hr-picker-row
  61. v-bind="pickerRowMetrics"
  62. mode="tree"
  63. label="所属组织"
  64. required
  65. :value="form.deptId"
  66. :display="form.deptPath"
  67. :tree="deptTree"
  68. :disabled="formDisabled || !form.legalId"
  69. hint="请先选择所属机构"
  70. @change="onDeptPick"
  71. />
  72. <view class="divider"></view>
  73. <view class="field textarea-field">
  74. <text class="label">模板说明</text>
  75. <textarea v-model="form.remark" maxlength="2000" placeholder="选填,说明模板适用场景" />
  76. <text class="counter">{{ form.remark.length }}/2000</text>
  77. </view>
  78. </view>
  79. <view class="section-title"><text>模板正文</text></view>
  80. <view class="form-card card section">
  81. <view class="field textarea-field">
  82. <text class="label required">A4 画布正文</text>
  83. <textarea
  84. v-model="form.documentContent"
  85. placeholder="JSON 或 HTML 文本"
  86. />
  87. <text class="hint">{{ contentHint }}</text>
  88. </view>
  89. <view class="divider"></view>
  90. <view class="field textarea-field">
  91. <text class="label">变量定义</text>
  92. <textarea
  93. v-model="form.variablesJson"
  94. placeholder="变量定义 JSON 数组,选填"
  95. />
  96. </view>
  97. </view>
  98. <view class="section-title"><text>画布预览</text></view>
  99. <view class="form-card card section">
  100. <A4Preview :content="form.documentContent" />
  101. </view>
  102. <block v-if="form.id">
  103. <view class="section-title"><text>版本</text></view>
  104. <view class="form-card card section">
  105. <view class="field">
  106. <text class="label">当前版本</text>
  107. <text class="value">V{{ form.currentVersionNo || 1 }} · {{ form.versionStatus || '—' }}</text>
  108. </view>
  109. <view class="divider"></view>
  110. <view class="field textarea-field">
  111. <text class="label">新版本变更说明</text>
  112. <textarea v-model="versionChangeRemark" maxlength="200" placeholder="发布新版本时记录,选填" />
  113. </view>
  114. <view class="divider"></view>
  115. <view class="field press" @click="onPublishVersion">
  116. <text class="label">发布新版本</text>
  117. <text class="value link">用当前正文发布 ›</text>
  118. </view>
  119. </view>
  120. </block>
  121. <view class="footer-tip muted"><text>{{ footerTip }}</text></view>
  122. <view class="bottom-action">
  123. <view class="draft-btn press" @click="onCancel">取消</view>
  124. <view class="submit-btn press" @click="onSubmit">{{ submitLabel }}</view>
  125. </view>
  126. </view>
  127. </template>
  128. <script>
  129. import A4Preview from "@/pages/hr/components/A4Preview.vue";
  130. import ModuleIcon from "@/pages/hr/components/ModuleIcon.vue";
  131. import { applicationTypes } from "@/pages/hr/data/apply-config";
  132. import { listOrganizations } from "@/api/hr/organization";
  133. import { buildDeptTreeUnderLegal } from "@/utils/hr/organization-tree";
  134. import { getOrgOptionsWithFallback } from "@/utils/hr/current-org";
  135. import HrPickerRow from "@/components/hr/HrPickerRow.vue";
  136. import {
  137. TEMPLATE_STATUS_LABELS,
  138. loadOnlineTemplateCategories,
  139. loadOnlineTemplateDetail,
  140. publishOnlineTemplateVersion,
  141. saveOnlineTemplate,
  142. } from "@/api/hr/onlineDocument";
  143. function emptyForm() {
  144. return {
  145. id: "",
  146. templateName: "",
  147. templateCode: "",
  148. categoryId: "",
  149. legalId: "",
  150. legalName: "",
  151. deptId: "",
  152. deptPath: "",
  153. remark: "",
  154. documentContent: "",
  155. variablesJson: "",
  156. templateStatus: "",
  157. templateStatusLabel: "",
  158. versionStatus: "",
  159. currentVersionNo: 1,
  160. };
  161. }
  162. export default {
  163. components: { A4Preview, ModuleIcon, HrPickerRow },
  164. data() {
  165. return {
  166. form: emptyForm(),
  167. orgList: [],
  168. companies: [],
  169. deptTree: [],
  170. categories: [],
  171. versionChangeRemark: "",
  172. submitting: false,
  173. };
  174. },
  175. computed: {
  176. /** 统一选择行(HrPickerRow)的行度量:与本页 .field/.label 口径一致,避免左侧对不齐 */
  177. pickerRowMetrics() {
  178. return {
  179. rowMinHeight: "108rpx",
  180. rowPadding: "28rpx",
  181. labelWidth: "200rpx",
  182. };
  183. },
  184. meta() {
  185. return applicationTypes.regular || { title: "转正申请", subtitle: "", icon: "正", color: "#269a99" };
  186. },
  187. /** 只有草稿模板允许直接改正文 / 变量 / 分类,其余要走「发布新版本」 */
  188. isDraft() {
  189. return !this.form.id || this.form.templateStatus === "DRAFT";
  190. },
  191. introSub() {
  192. return this.form.id
  193. ? `${this.form.templateStatusLabel || TEMPLATE_STATUS_LABELS[this.form.templateStatus] || ""} · 当前版本 V${this.form.currentVersionNo || 1}`
  194. : "线上 Word 模板,供转正申请选用";
  195. },
  196. submitLabel() {
  197. if (!this.form.id) return "创建模板";
  198. return this.isDraft ? "保存修改" : "发布新版本";
  199. },
  200. contentHint() {
  201. return this.isDraft
  202. ? "变量用双花括号占位,例如 {{EMPLOYEE_NAME}}"
  203. : "已启用 / 停用模板:改完正文点底部「发布新版本」生效";
  204. },
  205. footerTip() {
  206. return "保存走 /hr/online-documents/templates,新建后默认为停用,需手动启用";
  207. },
  208. /** 模板分类候选(统一选择器用) */
  209. categoryOptions() {
  210. return (this.categories || []).map((item) => ({ label: item.categoryName, value: String(item.id) }));
  211. },
  212. categoryLabel() {
  213. if (!this.form.categoryId) return "";
  214. const hit = this.categories.find((item) => String(item.id) === String(this.form.categoryId));
  215. return hit ? hit.categoryName : `分类 ${this.form.categoryId}`;
  216. },
  217. },
  218. onLoad(options) {
  219. this.init(options || {});
  220. },
  221. methods: {
  222. validate() {
  223. if (!this.form.templateName.trim()) return "请填写模板名称";
  224. if (!this.form.templateCode.trim()) return "请填写模板编码";
  225. if (!this.form.categoryId) return "请选择模板分类";
  226. if (!this.form.deptId) return "请选择所属组织";
  227. if (!this.form.documentContent.trim()) return "请填写模板正文";
  228. const variables = this.form.variablesJson.trim();
  229. if (variables) {
  230. try {
  231. const parsed = JSON.parse(variables);
  232. if (!Array.isArray(parsed)) return "变量定义需为 JSON 数组";
  233. } catch (error) {
  234. return "变量定义不是合法 JSON";
  235. }
  236. }
  237. return "";
  238. },
  239. async refreshOrganizations() {
  240. try {
  241. // 组织树取全量:部门级联要按当前机构从中过滤出部门
  242. this.orgList = await listOrganizations();
  243. } catch (error) {
  244. this.orgList = [];
  245. uni.showToast({ title: "组织列表加载失败", icon: "none" });
  246. }
  247. // 机构候选与 PC 一致:只给当前账号所属公司(登录缓存 loginChangeGroupVOList),
  248. // 不再列全量机构树;缺名称时回落组织树,编辑老数据时补当前项
  249. this.companies = getOrgOptionsWithFallback(this.orgList, this.form.legalId, this.form.legalName);
  250. },
  251. refreshDeptTree(legalId) {
  252. // 所属机构已经在上面选过,不再作为部门级联的第一列重复展示:
  253. // 直接从部门层开始,选出来的部门路径也不带机构名。
  254. const nodes = legalId ? buildDeptTreeUnderLegal(this.orgList, legalId) : [];
  255. const legal = nodes.find((node) => String(node.id) === String(legalId)) || nodes[0];
  256. this.deptTree = legal && Array.isArray(legal.children) ? legal.children : [];
  257. },
  258. /** 在组织树里定位 deptId 所在的三级索引,用于回填 picker */
  259. findDeptIndex(tree, deptId) {
  260. const list = tree || [];
  261. const key = String(deptId || "");
  262. for (let i = 0; i < list.length; i += 1) {
  263. if (String(list[i].id) === key) return [i, 0, 0];
  264. const level2 = list[i].children || [];
  265. for (let j = 0; j < level2.length; j += 1) {
  266. if (String(level2[j].id) === key) return [i, j, 0];
  267. const level3 = level2[j].children || [];
  268. for (let k = 0; k < level3.length; k += 1) {
  269. if (String(level3[k].id) === key) return [i, j, k];
  270. }
  271. }
  272. }
  273. return [0, 0, 0];
  274. },
  275. /** 由模板的 deptId 反查所属机构与组织路径(编辑态回填,避免保存时丢组织) */
  276. restoreOrganization(deptId) {
  277. this.form.legalId = "";
  278. this.form.legalName = "";
  279. this.form.deptPath = "";
  280. this.form.deptId = deptId ? String(deptId) : "";
  281. if (!this.form.deptId) return;
  282. const byId = new Map(this.orgList.map((item) => [String(item.id), item]));
  283. const node = byId.get(this.form.deptId);
  284. // 组织列表里查不到(跨机构 / 已停用组织)时保留原主键,只做提示
  285. if (!node) {
  286. this.form.deptPath = `组织 ${this.form.deptId}`;
  287. return;
  288. }
  289. const isCompany = (item) => this.companies.some((company) => String(company.id) === String(item.id));
  290. // 自下而上收集祖先链(含自身)
  291. const chain = [];
  292. const visited = new Set();
  293. let cursor = node;
  294. while (cursor && !visited.has(String(cursor.id))) {
  295. visited.add(String(cursor.id));
  296. chain.unshift(cursor);
  297. const parentId = cursor.parentId == null ? "0" : String(cursor.parentId);
  298. cursor = parentId === "0" ? null : byId.get(parentId) || null;
  299. }
  300. const legal = chain.filter(isCompany)[0];
  301. const deptNodes = chain.filter((item) => !isCompany(item));
  302. const tail = deptNodes.length ? deptNodes : chain;
  303. this.form.deptId = tail[tail.length - 1].id;
  304. this.form.deptPath = tail.map((item) => item.name).filter(Boolean).join(" / ");
  305. if (!legal) return;
  306. this.form.legalId = legal.id;
  307. this.form.legalName = legal.name;
  308. this.refreshDeptTree(legal.id);
  309. this.deptIndex = this.findDeptIndex(this.deptTree, this.form.deptId);
  310. },
  311. chooseCategory() {
  312. if (!this.isDraft) {
  313. uni.showToast({ title: "已启用 / 停用模板不可改分类,请发布新版本", icon: "none" });
  314. return;
  315. }
  316. const options = this.categories;
  317. if (!options.length) {
  318. uni.showModal({
  319. title: "模板分类",
  320. content: "后端暂未提供分类列表接口,请直接填写分类主键(数字)",
  321. showCancel: false,
  322. success: () => this.promptCategoryId(),
  323. });
  324. return;
  325. }
  326. this.form.categoryId = options[0] ? String(options[0].id) : "";
  327. },
  328. /** 模板分类(统一选择器):选中后写入主键;需要手填主键时走 promptCategoryId */
  329. onCategoryChange(categoryId) {
  330. if (this.formDisabled) return;
  331. const hit = this.categories.find((item) => String(item.id) === String(categoryId));
  332. this.form.categoryId = hit ? String(hit.id) : String(categoryId);
  333. },
  334. promptCategoryId() {
  335. uni.showModal({
  336. title: "输入分类主键",
  337. editable: true,
  338. placeholderText: "请输入模板分类主键(数字)",
  339. success: (r) => {
  340. if (!r.confirm) return;
  341. const text = String(r.content || "").trim();
  342. if (!text) return;
  343. this.form.categoryId = text;
  344. },
  345. });
  346. },
  347. onLegalChange(legalId) {
  348. if (this.formDisabled) return;
  349. const picked = this.companies.find((item) => String(item.id) === String(legalId));
  350. if (!picked) return;
  351. this.form.legalId = picked.id;
  352. this.form.legalName = picked.name;
  353. this.form.deptId = "";
  354. this.form.deptPath = "";
  355. this.refreshDeptTree(picked.id);
  356. },
  357. /** 所属组织:树选择器回传节点 id,这里按树补出路径名 */
  358. onDeptPick(deptId) {
  359. const chain = this.deptChainById(this.deptTree, deptId);
  360. this.form.deptId = deptId;
  361. this.form.deptPath = chain.map((node) => node.name).filter(Boolean).join(" / ");
  362. },
  363. /** 在组织树里按 id 取「根 → 自身」的节点链 */
  364. deptChainById(tree, id, parents = []) {
  365. for (const node of tree || []) {
  366. const path = parents.concat(node);
  367. if (String(node.id) === String(id)) return path;
  368. const hit = this.deptChainById(node.children || [], id, path);
  369. if (hit.length) return hit;
  370. }
  371. return [];
  372. },
  373. async onSave() {
  374. if (this.submitting) return;
  375. const error = this.validate();
  376. if (error) {
  377. uni.showToast({ title: error, icon: "none" });
  378. return;
  379. }
  380. this.submitting = true;
  381. uni.showLoading({ title: "保存中..." });
  382. try {
  383. await saveOnlineTemplate({
  384. form: Object.assign({}, this.form),
  385. existingId: this.form.id || null,
  386. });
  387. uni.hideLoading();
  388. uni.showToast({ title: this.form.id ? "已保存" : "模板已创建", icon: "success" });
  389. setTimeout(() => this.onCancel(), 800);
  390. } catch (errorSave) {
  391. uni.hideLoading();
  392. uni.showToast({ title: (errorSave && errorSave.message) || "保存失败", icon: "none" });
  393. } finally {
  394. this.submitting = false;
  395. }
  396. },
  397. /** 底部主按钮:草稿直接保存,已启用 / 停用走发布新版本 */
  398. onSubmit() {
  399. if (this.submitting) return;
  400. if (this.isDraft) return this.onSave();
  401. return this.onPublishVersion();
  402. },
  403. async onPublishVersion() {
  404. if (!this.form.id) return;
  405. if (!this.form.documentContent.trim()) {
  406. uni.showToast({ title: "请先填写模板正文", icon: "none" });
  407. return;
  408. }
  409. uni.showModal({
  410. title: "发布新版本",
  411. content: "将用当前正文创建新版本,确认发布?",
  412. success: async (r) => {
  413. if (!r.confirm) return;
  414. uni.showLoading({ title: "发布中..." });
  415. try {
  416. await publishOnlineTemplateVersion(this.form.id, {
  417. documentContent: this.form.documentContent,
  418. variablesJson: this.form.variablesJson,
  419. changeRemark: this.versionChangeRemark,
  420. });
  421. uni.hideLoading();
  422. this.versionChangeRemark = "";
  423. // 发布新版本会自动停用模板并生成草稿版本,重新拉一次详情同步状态
  424. await this.loadTemplate(this.form.id);
  425. uni.showToast({ title: "新版本已发布", icon: "success" });
  426. } catch (error) {
  427. uni.hideLoading();
  428. uni.showToast({ title: (error && error.message) || "发布失败", icon: "none" });
  429. }
  430. },
  431. });
  432. },
  433. onCancel() {
  434. uni.redirectTo({ url: "/pages/hr/manage/regular-template-list" });
  435. },
  436. /** 拉取模板详情并回填表单(编辑进入与发布新版本后复用) */
  437. async loadTemplate(id) {
  438. const row = await loadOnlineTemplateDetail(id);
  439. if (!row) throw new Error("未找到该模板");
  440. Object.assign(this.form, {
  441. id: row.id,
  442. templateName: row.templateName || "",
  443. templateCode: row.templateCode || "",
  444. categoryId: row.categoryId || "",
  445. remark: row.remark || "",
  446. documentContent: row.documentContent || "",
  447. variablesJson: row.variablesJson || "",
  448. templateStatus: row.templateStatus || "",
  449. templateStatusLabel: row.templateStatusLabel || "",
  450. versionStatus: row.versionStatus || "",
  451. currentVersionNo: row.currentVersionNo || 1,
  452. });
  453. // 详情里没有机构 / 组织路径,需要用 deptId 反查回填,避免保存时丢组织
  454. this.restoreOrganization(row.deptId);
  455. return row;
  456. },
  457. async init(options) {
  458. uni.setNavigationBarTitle({ title: "转正申请模板" });
  459. await this.refreshOrganizations();
  460. try {
  461. this.categories = await loadOnlineTemplateCategories();
  462. } catch (error) {
  463. this.categories = [];
  464. }
  465. const id = options.id || "";
  466. if (!id) return;
  467. uni.showLoading({ title: "加载中..." });
  468. try {
  469. await this.loadTemplate(id);
  470. } catch (e) {
  471. uni.hideLoading();
  472. uni.showToast({ title: (e && e.message) || "加载失败", icon: "none" });
  473. setTimeout(() => this.onCancel(), 900);
  474. return;
  475. }
  476. uni.hideLoading();
  477. },
  478. },
  479. };
  480. </script>
  481. <style scoped lang="scss">
  482. @import "@/pages/hr/common-style.scss";
  483. .page-no-tab {
  484. padding-bottom: 170rpx;
  485. }
  486. .form-intro {
  487. padding: 30rpx 30rpx 22rpx;
  488. display: flex;
  489. align-items: center;
  490. background: #fff;
  491. }
  492. .form-intro > view:last-child {
  493. margin-left: 22rpx;
  494. }
  495. .intro-title {
  496. display: block;
  497. font-size: 32rpx;
  498. font-weight: 600;
  499. }
  500. .intro-sub {
  501. display: block;
  502. margin-top: 9rpx;
  503. color: #8b939f;
  504. font-size: 23rpx;
  505. }
  506. .form-card {
  507. overflow: hidden;
  508. }
  509. .notice {
  510. margin: 20rpx 24rpx 0;
  511. padding: 20rpx 24rpx;
  512. border-radius: 12rpx;
  513. background: #fff8e6;
  514. color: #a86b00;
  515. font-size: 23rpx;
  516. line-height: 1.6;
  517. }
  518. .field {
  519. position: relative;
  520. min-height: 108rpx;
  521. padding: 28rpx;
  522. display: flex;
  523. align-items: center;
  524. }
  525. .label {
  526. width: 200rpx;
  527. flex-shrink: 0;
  528. font-size: 28rpx;
  529. }
  530. .required::before {
  531. content: "*";
  532. color: #ee4d4d;
  533. margin-right: 6rpx;
  534. }
  535. .value {
  536. flex: 1;
  537. text-align: right;
  538. color: #1f2329;
  539. font-size: 27rpx;
  540. }
  541. .value.link {
  542. color: #157a2c;
  543. }
  544. .placeholder {
  545. flex: 1;
  546. text-align: right;
  547. color: #b2b7be;
  548. font-size: 27rpx;
  549. }
  550. .arrow {
  551. margin-left: 13rpx;
  552. color: #c4c8ce;
  553. font-size: 38rpx;
  554. }
  555. .text-input {
  556. flex: 1;
  557. height: 68rpx;
  558. text-align: right;
  559. font-size: 27rpx;
  560. color: #1f2329;
  561. }
  562. .textarea-field {
  563. display: block;
  564. min-height: 240rpx;
  565. }
  566. .textarea-field .label {
  567. display: block;
  568. width: auto;
  569. margin-bottom: 20rpx;
  570. }
  571. .textarea-field textarea {
  572. width: 100%;
  573. height: 180rpx;
  574. padding: 18rpx;
  575. border-radius: 12rpx;
  576. background: #f6f7f8;
  577. font-size: 25rpx;
  578. box-sizing: border-box;
  579. }
  580. .counter {
  581. display: block;
  582. margin-top: 10rpx;
  583. text-align: right;
  584. color: #b2b7be;
  585. font-size: 22rpx;
  586. }
  587. .hint {
  588. display: block;
  589. margin-top: 12rpx;
  590. color: #8b939f;
  591. font-size: 22rpx;
  592. }
  593. .footer-tip {
  594. padding: 8rpx 30rpx 0;
  595. font-size: 22rpx;
  596. }
  597. .bottom-action {
  598. position: fixed;
  599. z-index: 10;
  600. left: 0;
  601. right: 0;
  602. bottom: 0;
  603. height: 120rpx;
  604. padding: 16rpx 24rpx;
  605. background: #fff;
  606. border-top: 1rpx solid #e8e9eb;
  607. display: flex;
  608. gap: 20rpx;
  609. box-sizing: border-box;
  610. }
  611. .draft-btn {
  612. flex: 1;
  613. height: 84rpx;
  614. line-height: 84rpx;
  615. text-align: center;
  616. border-radius: 12rpx;
  617. background: #f5f6f7;
  618. color: #4a5058;
  619. font-size: 30rpx;
  620. }
  621. .submit-btn {
  622. flex: 2;
  623. height: 84rpx;
  624. line-height: 84rpx;
  625. text-align: center;
  626. border-radius: 12rpx;
  627. background: #157a2c;
  628. color: #fff;
  629. font-size: 30rpx;
  630. }
  631. @media (min-width: 800px) {
  632. .bottom-action {
  633. max-width: 520px;
  634. left: 50%;
  635. transform: translateX(-50%);
  636. }
  637. }
  638. </style>