shMethod.vue 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881
  1. <template>
  2. <view class="sh-method-page app-content">
  3. <!-- 顶部 Tab 切换 -->
  4. <view class="tab-bar">
  5. <view
  6. v-for="(tab, index) in tabs"
  7. :key="index"
  8. class="tab-item"
  9. :class="{ active: tabIndex === index }"
  10. @click="changeTab(index)"
  11. >
  12. {{ tab.name }}
  13. </view>
  14. </view>
  15. <!-- 配置表单区域 -->
  16. <scroll-view scroll-y class="form-scroll">
  17. <view class="form-container">
  18. <tui-list-cell class="line-cell" :hover="false">
  19. <view class="tui-title">名称</view>
  20. <input type="text" v-model="form.name" maxlength="4" @focus="form.name = ''" class="tui-input" placeholder="请填写名称,最多4个字" />
  21. </tui-list-cell>
  22. <!-- 算运费方式 (仅当选择跑腿 form.style === 2 时展示) -->
  23. <tui-list-cell class="line-cell" :hover="false" v-if="form.style === 2">
  24. <view class="tui-title">算运费方式</view>
  25. <view class="btn-group">
  26. <button
  27. class="admin-button-com middle"
  28. :class="[form.calcType == 0 ? 'blue' : 'default']"
  29. @click="form.calcType = 0"
  30. >
  31. 用跑腿
  32. </button>
  33. <button
  34. class="admin-button-com middle"
  35. :class="[form.calcType == 1 ? 'blue' : 'default']"
  36. @click="form.calcType = 1"
  37. style="margin-left: 20upx;"
  38. >
  39. 用自定义
  40. </button>
  41. </view>
  42. </tui-list-cell>
  43. <!-- 跑腿提供方 (仅当选择跑腿 form.style === 2 时展示) -->
  44. <tui-list-cell class="line-cell" :hover="false" v-if="form.style === 2">
  45. <view class="tui-title">跑腿提供方</view>
  46. <view class="btn-group">
  47. <button
  48. class="admin-button-com middle default"
  49. @click="pageTo({ url: '/admin/delivery/deliveryManage' })"
  50. >
  51. 管理
  52. </button>
  53. </view>
  54. </tui-list-cell>
  55. <!-- 状态 -->
  56. <tui-list-cell class="line-cell" :hover="false">
  57. <view class="tui-title">状态</view>
  58. <view class="btn-group">
  59. <button
  60. class="admin-button-com middle"
  61. :class="[form.status == 1 ? 'blue' : 'default']"
  62. @click="form.status = 1"
  63. >
  64. 启用
  65. </button>
  66. <button
  67. class="admin-button-com middle"
  68. :class="[form.status == 0 ? 'blue' : 'default']"
  69. @click="form.status = 0"
  70. style="margin-left: 20upx;"
  71. >
  72. 禁用
  73. </button>
  74. </view>
  75. </tui-list-cell>
  76. <!-- 位置 -->
  77. <tui-list-cell class="line-cell" :hover="false">
  78. <view class="tui-title">位置</view>
  79. <input type="number" v-model="form.sort" @focus="form.sort = ''" class="tui-input" placeholder="请填写顺序" />
  80. </tui-list-cell>
  81. <!-- 送货 / 快递 特有字段 -->
  82. <block v-if="form.style === 0 || form.style === 4">
  83. <tui-list-cell class="line-cell" :hover="false">
  84. <view class="tui-title">最低消费金额</view>
  85. <input type="digit" v-model="form.minAmount" @focus="form.minAmount = ''" class="tui-input" placeholder="不限制填0" />
  86. </tui-list-cell>
  87. <tui-list-cell class="line-cell" :hover="false">
  88. <view class="tui-title">最低消费数量</view>
  89. <input type="number" v-model="form.minNum" @focus="form.minNum = ''" class="tui-input" placeholder="不限制填0" />
  90. </tui-list-cell>
  91. <tui-list-cell class="line-cell" :hover="false">
  92. <view class="tui-title">不满条件</view>
  93. <view class="btn-group">
  94. <button
  95. class="admin-button-com middle"
  96. :class="[form.unMeet == 0 ? 'blue' : 'default']"
  97. @click="form.unMeet = 0"
  98. >
  99. 收运费
  100. </button>
  101. <button
  102. class="admin-button-com middle"
  103. :class="[form.unMeet == 1 ? 'blue' : 'default']"
  104. @click="form.unMeet = 1"
  105. style="margin-left: 10upx;"
  106. >
  107. 收包装费
  108. </button>
  109. <button
  110. class="admin-button-com middle"
  111. :class="[form.unMeet == 2 ? 'blue' : 'default']"
  112. @click="form.unMeet = 2"
  113. style="margin-left: 10upx;"
  114. >
  115. 不能买
  116. </button>
  117. </view>
  118. </tui-list-cell>
  119. <tui-list-cell class="line-cell" :hover="false" v-if="form.unMeet != 2">
  120. <view class="tui-title">{{ form.unMeet == 1 ? '包装费' : '运费' }}</view>
  121. <input type="digit" v-model="form.unMeetFee" @focus="form.unMeetFee = ''" class="tui-input" placeholder="请填写金额" />
  122. </tui-list-cell>
  123. </block>
  124. <!-- 跑腿 特有字段 -->
  125. <block v-if="form.style === 2">
  126. <!-- 满减规则圈起来 -->
  127. <view class="rule-section-wrapper">
  128. <view class="section-header no-margin">
  129. <text class="section-title">满减规则</text>
  130. <button class="admin-button-com mini blue" @click="addReduceRule">添加</button>
  131. </view>
  132. <view class="rule-list" v-if="form.reduceRules && form.reduceRules.length > 0">
  133. <view class="rule-card" v-for="(rule, index) in form.reduceRules" :key="index">
  134. <view class="rule-row">
  135. <text class="rule-label">满</text>
  136. <input type="number" v-model="rule.meetNum" @focus="clearReduceRuleInputOnFocus(rule, 'meetNum')" @blur="normalizeReduceRuleInput(rule, 'meetNum')" class="rule-input" placeholder="0" />
  137. <text class="rule-label">扎和</text>
  138. <input type="digit" v-model="rule.meetAmount" @focus="clearReduceRuleInputOnFocus(rule, 'meetAmount')" @blur="normalizeReduceRuleInput(rule, 'meetAmount')" class="rule-input-large" placeholder="0.00" />
  139. <text class="rule-label">元</text>
  140. <input type="digit" v-model="rule.freeKm" @focus="clearReduceRuleInputOnFocus(rule, 'freeKm')" @blur="normalizeReduceRuleInput(rule, 'freeKm')" class="rule-input-large" placeholder="0" />
  141. <text class="rule-label">公里内免跑腿费</text>
  142. </view>
  143. <button class="admin-button-com mini rule-del-btn" @click="removeReduceRule(index)">
  144. 删除
  145. </button>
  146. </view>
  147. </view>
  148. <view class="no-data-tip" v-else>暂无满减规则</view>
  149. </view>
  150. <view class="notice-text">
  151. 不符合满减规则时,将通过跑腿或用自定义方式计费
  152. </view>
  153. <!-- 自定义计费 -->
  154. <view class="section-header">
  155. <text class="section-title">自定义计费</text>
  156. </view>
  157. <tui-list-cell class="line-cell" :hover="false">
  158. <view class="tui-title">起步价</view>
  159. <view class="input-row">
  160. <input type="digit" v-model="form.startKm" @focus="form.startKm = ''" class="tui-input-sm" placeholder="0" />
  161. <text class="unit-text">公里内</text>
  162. <input type="digit" v-model="form.startPrice" @focus="form.startPrice = ''" class="tui-input-sm" placeholder="0.00" />
  163. <text class="unit-text">元</text>
  164. </view>
  165. </tui-list-cell>
  166. <tui-list-cell class="line-cell" :hover="false">
  167. <view class="tui-title">超出起步</view>
  168. <view class="input-row">
  169. <text class="unit-text">每公里加</text>
  170. <input type="digit" v-model="form.perKmPrice" @focus="form.perKmPrice = ''" class="tui-input-sm" placeholder="0.00" />
  171. <text class="unit-text">元</text>
  172. </view>
  173. </tui-list-cell>
  174. <tui-list-cell class="line-cell" :hover="false">
  175. <view class="tui-title">临时涨价</view>
  176. <view class="input-row">
  177. <input type="digit" v-model="form.changeRate" @focus="form.changeRate = ''" class="tui-input-sm" placeholder="0" />
  178. <text class="unit-text">%</text>
  179. <text class="unit-text">填负值时为降价</text>
  180. </view>
  181. </tui-list-cell>
  182. </block>
  183. <!-- 物流 特有字段 -->
  184. <block v-if="form.style === 3">
  185. <tui-list-cell class="line-cell" :hover="false">
  186. <view class="tui-title">配送物流</view>
  187. <view style="margin-left: auto;">
  188. <button class="admin-button-com middle blue" @click="manageWl">管理物流</button>
  189. </view>
  190. </tui-list-cell>
  191. </block>
  192. <!-- 说明项区域圈起来 -->
  193. <view class="explain-section-wrapper">
  194. <view class="section-header no-margin">
  195. <text class="section-title">说明(最多5个)</text>
  196. <button class="admin-button-com mini blue" @click="addExplain">添加</button>
  197. </view>
  198. <view class="explain-list" v-if="form.explains && form.explains.length > 0">
  199. <view class="explain-card" v-for="(exp, index) in form.explains" :key="index">
  200. <textarea
  201. v-model="exp.explain"
  202. class="explain-textarea"
  203. placeholder="最多50个字"
  204. maxlength="50"
  205. :class="[
  206. exp.color == 2 ? 'text-red' : '',
  207. exp.color == 3 ? 'text-blue' : '',
  208. exp.fontWeight == 2 ? 'text-bold' : ''
  209. ]"
  210. />
  211. <view class="explain-actions">
  212. <view class="action-group">
  213. <button
  214. class="admin-button-com mini"
  215. :class="[exp.color == 1 ? 'blue' : 'default']"
  216. @click="setExplainColor(index, 1)"
  217. >
  218. 黑色
  219. </button>
  220. <button
  221. class="admin-button-com mini"
  222. :class="[exp.color == 2 ? 'blue' : 'default']"
  223. @click="setExplainColor(index, 2)"
  224. style="margin-left: 10upx;"
  225. >
  226. 红色
  227. </button>
  228. <button
  229. class="admin-button-com mini"
  230. :class="[exp.color == 3 ? 'blue' : 'default']"
  231. @click="setExplainColor(index, 3)"
  232. style="margin-left: 10upx;"
  233. >
  234. 蓝色
  235. </button>
  236. </view>
  237. <view class="action-group" style="margin-left: 20upx;">
  238. <button
  239. class="admin-button-com mini"
  240. :class="[exp.fontWeight == 1 ? 'blue' : 'default']"
  241. @click="setExplainWeight(index, 1)"
  242. >
  243. 常规
  244. </button>
  245. <button
  246. class="admin-button-com mini"
  247. :class="[exp.fontWeight == 2 ? 'blue' : 'default']"
  248. @click="setExplainWeight(index, 2)"
  249. style="margin-left: 10upx;"
  250. >
  251. 加粗
  252. </button>
  253. </view>
  254. <button class="admin-button-com mini explain-del-btn" @click="removeExplain(index)">
  255. 删除
  256. </button>
  257. </view>
  258. </view>
  259. </view>
  260. <view class="no-data-tip" v-else>暂无说明项</view>
  261. </view>
  262. </view>
  263. </scroll-view>
  264. <!-- 底部保存按钮 -->
  265. <view class="footer-btn-wrap">
  266. <view class="sort-indicator">
  267. <text class="sort-label">显示顺序:</text>
  268. <text class="sort-value">{{ sortedMethodsText }}</text>
  269. </view>
  270. <button class="admin-button-com big blue" @click="submitSave">保存</button>
  271. </view>
  272. </view>
  273. </template>
  274. <script>
  275. import TuiListCell from "@/components/plugin/list-cell";
  276. import { getShMethodConfig, saveShMethodConfig, getShMethodSorts } from "@/api/sh-method";
  277. export default {
  278. name: "shMethod",
  279. components: {
  280. TuiListCell
  281. },
  282. data() {
  283. return {
  284. tabs: [
  285. { name: "送货", value: 0 },
  286. { name: "自取", value: 1 },
  287. { name: "跑腿", value: 2 },
  288. { name: "快递", value: 4 },
  289. { name: "物流", value: 3 }
  290. ],
  291. tabIndex: 0,
  292. sortsList: [], // 存储所有配送方式的排序和别名信息
  293. form: {
  294. id: 0,
  295. style: 0,
  296. name: "",
  297. calcType: 0,
  298. status: 1,
  299. sort: 0,
  300. minAmount: 0.00,
  301. minNum: 0,
  302. unMeet: 0,
  303. unMeetFee: 0.00,
  304. startKm: 0.00,
  305. startPrice: 0.00,
  306. perKmPrice: 0.00,
  307. changeRate: 0.00,
  308. explains: [],
  309. reduceRules: []
  310. }
  311. };
  312. },
  313. computed: {
  314. // 动态计算并按顺序值由小到大列出所有配送方式别名
  315. sortedMethodsText() {
  316. // 过滤掉已禁用的配送方式(status === 0)
  317. const enabledList = this.sortsList.filter(item => item.status !== 0);
  318. if (enabledList.length === 0) {
  319. return "暂无启用的配送方式";
  320. }
  321. // 复制一份数组以避免直接修改 state
  322. const sorted = [...enabledList];
  323. // 按 sort 升序,若 sort 相同则按 style 升序
  324. sorted.sort((a, b) => {
  325. if (a.sort !== b.sort) {
  326. return a.sort - b.sort;
  327. }
  328. return a.style - b.style;
  329. });
  330. // 拼接成 "送货 > 自取 > 跑腿..." 的格式
  331. return sorted.map(item => item.name).join(" - ");
  332. }
  333. },
  334. onLoad() {
  335. this.loadConfig(0);
  336. this.loadSorts();
  337. },
  338. methods: {
  339. init(){},
  340. /**
  341. * 加载所有配送方式的排序和别名信息
  342. */
  343. loadSorts() {
  344. getShMethodSorts()
  345. .then(res => {
  346. if (res.code == 1 && res.data) {
  347. this.sortsList = res.data;
  348. }
  349. })
  350. .catch(err => {
  351. console.error("加载排序信息失败", err);
  352. });
  353. },
  354. /**
  355. * 切换 Tab
  356. * @param {number} index - 选中的 Tab 索引
  357. */
  358. changeTab(index) {
  359. if (this.tabIndex === index) return;
  360. this.tabIndex = index;
  361. this.loadConfig(this.tabs[index].value);
  362. },
  363. /**
  364. * 加载当前配送方式配置
  365. * @param {number} style - 配送类型 (0-4)
  366. */
  367. loadConfig(style) {
  368. getShMethodConfig({ style }).then(res => {
  369. if (res.code == 1 && res.data) {
  370. const data = res.data;
  371. this.form = {
  372. id: data.id || 0,
  373. style: style,
  374. name: data.name || "",
  375. calcType: data.calcType != null ? Number(data.calcType) : 0,
  376. status: data.status != null ? Number(data.status) : 1,
  377. sort: data.sort != null ? Number(data.sort) : 0,
  378. minAmount: data.minAmount != null ? parseFloat(data.minAmount) : 0.00,
  379. minNum: data.minNum != null ? Number(data.minNum) : 0,
  380. unMeet: data.unMeet != null ? Number(data.unMeet) : 0,
  381. unMeetFee: data.unMeetFee != null ? parseFloat(data.unMeetFee) : 0.00,
  382. startKm: data.startKm != null ? parseFloat(data.startKm) : 0.00,
  383. startPrice: data.startPrice != null ? parseFloat(data.startPrice) : 0.00,
  384. perKmPrice: data.perKmPrice != null ? parseFloat(data.perKmPrice) : 0.00,
  385. changeRate: data.changeRate != null ? parseFloat(data.changeRate) : 0.00,
  386. explains: (data.explains || []).map(exp => ({
  387. ...exp,
  388. color: exp.color != null ? Number(exp.color) : 1,
  389. fontWeight: exp.fontWeight != null ? Number(exp.fontWeight) : 1
  390. })),
  391. reduceRules: (data.reduceRules || []).map(rule => ({
  392. ...rule,
  393. meetNum: rule.meetNum != null ? Number(rule.meetNum) : 0,
  394. // 接口可能返回 10.00,展示时去掉小数点后多余的 0
  395. meetAmount: rule.meetAmount != null && rule.meetAmount !== '' ? parseFloat(Number(rule.meetAmount)) : 0,
  396. freeKm: rule.freeKm != null && rule.freeKm !== '' ? parseFloat(Number(rule.freeKm)) : 0,
  397. sort: rule.sort != null ? Number(rule.sort) : 0
  398. }))
  399. }
  400. } else {
  401. this.$msg(res.msg || "加载失败")
  402. }
  403. }).catch(err => {
  404. this.$msg("加载失败,请重试");
  405. })
  406. },
  407. /**
  408. * 添加满减规则
  409. */
  410. addReduceRule() {
  411. this.form.reduceRules.push({
  412. meetNum: 0,
  413. meetAmount: 0,
  414. freeKm: 0,
  415. sort: this.form.reduceRules.length
  416. });
  417. },
  418. /**
  419. * 满减规则输入框获焦时清空,便于重新输入
  420. * @param {Object} rule - 满减规则项
  421. * @param {string} field - 字段名 meetNum | meetAmount | freeKm
  422. */
  423. clearReduceRuleInputOnFocus(rule, field) {
  424. this.$set(rule, field, "");
  425. },
  426. /**
  427. * 满减规则输入框失焦时规范化数值,去掉小数点后多余的 0
  428. * @param {Object} rule - 满减规则项
  429. * @param {string} field - 字段名 meetNum | meetAmount | freeKm
  430. */
  431. normalizeReduceRuleInput(rule, field) {
  432. const value = rule[field];
  433. if (value === "" || value == null) {
  434. this.$set(rule, field, 0);
  435. return;
  436. }
  437. const num = Number(value);
  438. if (Number.isNaN(num)) {
  439. this.$set(rule, field, 0);
  440. return;
  441. }
  442. const normalized = field === "meetNum" ? parseInt(num, 10) : parseFloat(String(num));
  443. this.$set(rule, field, normalized);
  444. },
  445. /**
  446. * 删除满减规则
  447. * @param {number} index - 规则索引
  448. */
  449. removeReduceRule(index) {
  450. this.$util.confirmModal({ content: "确认删除该满减规则吗?" }, () => {
  451. this.form.reduceRules.splice(index, 1);
  452. });
  453. },
  454. /**
  455. * 添加说明项
  456. */
  457. addExplain() {
  458. if (this.form.explains.length >= 5) {
  459. this.$msg("最多只能添加5条说明");
  460. return;
  461. }
  462. this.form.explains.push({
  463. explain: "",
  464. color: 1, // 1: 黑色, 2: 红色, 3: 蓝色
  465. fontWeight: 1, // 1: 常规, 2: 加粗
  466. sort: this.form.explains.length
  467. });
  468. },
  469. /**
  470. * 删除说明项
  471. * @param {number} index - 说明索引
  472. */
  473. removeExplain(index) {
  474. this.$util.confirmModal({ content: "确认删除该说明吗?" }, () => {
  475. this.form.explains.splice(index, 1);
  476. });
  477. },
  478. /**
  479. * 设置说明项颜色
  480. * @param {number} index - 说明项索引
  481. * @param {number} color - 颜色值 (1: 黑色, 2: 红色, 3: 蓝色)
  482. */
  483. setExplainColor(index, color) {
  484. const exp = this.form.explains[index];
  485. if (exp) {
  486. exp.color = color;
  487. // 强制触发 Vue 2 数组/对象响应式更新
  488. this.$set(this.form.explains, index, { ...exp });
  489. }
  490. },
  491. /**
  492. * 设置说明项字重
  493. * @param {number} index - 说明项索引
  494. * @param {number} fontWeight - 字重值 (1: 常规, 2: 加粗)
  495. */
  496. setExplainWeight(index, fontWeight) {
  497. const exp = this.form.explains[index];
  498. if (exp) {
  499. exp.fontWeight = fontWeight;
  500. // 强制触发 Vue 2 数组/对象响应式更新
  501. this.$set(this.form.explains, index, { ...exp });
  502. }
  503. },
  504. /**
  505. * 跳转至物流管理
  506. */
  507. manageWl() {
  508. this.$util.pageTo({ url: "/admin/shop/wl" });
  509. },
  510. /**
  511. * 保存当前配置
  512. */
  513. submitSave() {
  514. if (this.$util.isEmpty(this.form.name)) {
  515. this.$msg("请填写别名");
  516. return;
  517. }
  518. if (this.form.name.length > 4) {
  519. this.$msg("名称最多4个字");
  520. return;
  521. }
  522. // 验证说明项内容
  523. for (let i = 0; i < this.form.explains.length; i++) {
  524. if (this.$util.isEmpty(this.form.explains[i].explain)) {
  525. this.$msg(`请填写第 ${i + 1} 条说明内容`);
  526. return;
  527. }
  528. }
  529. saveShMethodConfig(this.form).then(res => {
  530. if (res.code == 1) {
  531. this.$msg("保存成功");
  532. // 重新加载配置刷新数据
  533. this.loadConfig(this.form.style);
  534. // 重新加载排序和别名信息
  535. this.loadSorts();
  536. } else {
  537. this.$msg(res.msg || "保存失败");
  538. }
  539. })
  540. }
  541. }
  542. };
  543. </script>
  544. <style lang="scss" scoped>
  545. .sh-method-page {
  546. display: flex;
  547. flex-direction: column;
  548. height: 100vh;
  549. background-color: #f5f5f5;
  550. }
  551. /* 顶部 Tab 栏 */
  552. .tab-bar {
  553. display: flex;
  554. background-color: #ffffff;
  555. border-bottom: 1upx solid #eeeeee;
  556. position: sticky;
  557. top: 0;
  558. z-index: 10;
  559. height: 90upx;
  560. align-items: center;
  561. }
  562. .tab-item {
  563. flex: 1;
  564. text-align: center;
  565. font-size: 34upx;
  566. color: #666666;
  567. height: 90upx;
  568. line-height: 90upx;
  569. position: relative;
  570. transition: all 0.2s ease;
  571. font-weight: bold;
  572. &.active {
  573. color: #3385ff;
  574. font-weight: bold;
  575. &::after {
  576. content: "";
  577. position: absolute;
  578. bottom: 0;
  579. left: 50%;
  580. transform: translateX(-50%);
  581. width: 40upx;
  582. height: 4upx;
  583. background-color: #3385ff;
  584. border-radius: 2upx;
  585. }
  586. }
  587. }
  588. /* 表单区域 */
  589. .form-scroll {
  590. flex: 1;
  591. overflow: hidden;
  592. }
  593. .form-container {
  594. padding: 20upx 20upx 160upx 20upx;
  595. }
  596. .line-cell {
  597. background-color: #ffffff;
  598. border-radius: 12upx;
  599. margin-bottom: 20upx;
  600. }
  601. .tui-title {
  602. font-size: 30upx;
  603. color: #333333;
  604. width: 200upx;
  605. }
  606. .tui-input {
  607. flex: 1;
  608. font-size: 30upx;
  609. color: #333333;
  610. text-align: right;
  611. }
  612. .btn-group {
  613. display: flex;
  614. align-items: center;
  615. margin-left: auto;
  616. }
  617. /* 跑腿自定义计费输入行 */
  618. .input-row {
  619. display: flex;
  620. align-items: center;
  621. justify-content: flex-end;
  622. flex: 1;
  623. }
  624. .tui-input-sm {
  625. width: 120upx;
  626. height: 60upx;
  627. border: 1upx solid #dddddd;
  628. border-radius: 8upx;
  629. font-size: 28upx;
  630. text-align: center;
  631. color: #333333;
  632. background-color: #fafafa;
  633. }
  634. .unit-text {
  635. font-size: 26upx;
  636. color: #666666;
  637. margin: 0 10upx;
  638. }
  639. /* 模块标题 */
  640. .section-header {
  641. display: flex;
  642. align-items: center;
  643. justify-content: space-between;
  644. margin: 30upx 10upx 15upx 10upx;
  645. }
  646. .section-title {
  647. font-size: 30upx;
  648. font-weight: bold;
  649. color: #333333;
  650. }
  651. /* 满减规则卡片 */
  652. .rule-list {
  653. margin-bottom: 20upx;
  654. }
  655. .rule-card {
  656. background-color: #ffffff;
  657. border-radius: 12upx;
  658. padding: 20upx 10upx;
  659. margin-bottom: 20upx;
  660. border: 1upx solid #eef2f9;
  661. display: flex;
  662. flex-direction: column;
  663. }
  664. .rule-row {
  665. display: flex;
  666. align-items: center;
  667. flex-wrap: wrap;
  668. font-size: 26upx;
  669. color: #333333;
  670. }
  671. .rule-label {
  672. margin: 0 8upx;
  673. }
  674. .rule-input {
  675. width: 80upx;
  676. height: 50upx;
  677. border: 1upx solid #cccccc;
  678. border-radius: 6upx;
  679. text-align: center;
  680. font-size: 26upx;
  681. background-color: #fafafa;
  682. }
  683. .rule-input-large {
  684. width: 90upx;
  685. height: 50upx;
  686. border: 1upx solid #cccccc;
  687. border-radius: 6upx;
  688. text-align: center;
  689. font-size: 26upx;
  690. background-color: #fafafa;
  691. }
  692. .rule-del-btn {
  693. margin-top: 15upx;
  694. align-self: flex-end; /* 靠右边 */
  695. background-color: #fff5f5 !important;
  696. color: #ff3841 !important;
  697. border: 1upx solid #ffcccc !important;
  698. }
  699. /* 提示文字 */
  700. .notice-text {
  701. font-size: 34upx;
  702. color: #ff6900;
  703. line-height: 36upx;
  704. padding: 15upx 20upx;
  705. background-color: #fffaf5;
  706. border-radius: 8upx;
  707. border: 1upx solid #ffe8d6;
  708. margin: 10upx 0upx;
  709. }
  710. /* 说明项区域圈起来 */
  711. .explain-section-wrapper,
  712. .rule-section-wrapper {
  713. background-color: #ffffff;
  714. border-radius: 12upx;
  715. padding: 24upx;
  716. margin-top: 30upx;
  717. border: 1upx solid #eef2f9;
  718. box-shadow: 0 2upx 8upx rgba(0, 0, 0, 0.02);
  719. }
  720. .no-margin {
  721. margin-top: 0 !important;
  722. margin-left: 0 !important;
  723. margin-right: 0 !important;
  724. margin-bottom: 20upx !important;
  725. }
  726. /* 说明卡片 */
  727. .explain-list {
  728. margin-bottom: 20upx;
  729. }
  730. .explain-card {
  731. background-color: #ffffff;
  732. border-radius: 12upx;
  733. padding: 20upx;
  734. margin-bottom: 20upx;
  735. border: 1upx solid #eef2f9;
  736. }
  737. .explain-textarea {
  738. width: 100%;
  739. height: 135upx;
  740. font-size: 30upx;
  741. color: #333333;
  742. background-color: #fafafa;
  743. border: 1upx solid #eeeeee;
  744. border-radius: 8upx;
  745. padding: 15upx;
  746. box-sizing: border-box;
  747. margin-bottom: 15upx;
  748. }
  749. .explain-actions {
  750. display: flex;
  751. align-items: center;
  752. justify-content: space-between;
  753. }
  754. .action-group {
  755. display: flex;
  756. align-items: center;
  757. }
  758. .explain-del-btn {
  759. margin-left: auto;
  760. background-color: #fff5f5 !important;
  761. color: #ff3841 !important;
  762. border: 1upx solid #ffcccc !important;
  763. }
  764. /* 文本样式控制 */
  765. .text-red {
  766. color: #ff3841 !important;
  767. }
  768. .text-blue {
  769. color: #3385ff !important;
  770. }
  771. .text-bold {
  772. font-weight: bold !important;
  773. }
  774. .no-data-tip {
  775. font-size: 26upx;
  776. color: #999999;
  777. text-align: center;
  778. padding: 40upx 0;
  779. }
  780. /* 底部保存按钮 */
  781. .footer-btn-wrap {
  782. position: fixed;
  783. bottom: 0;
  784. left: 0;
  785. right: 0;
  786. background-color: #ffffff;
  787. padding: 20upx 30upx;
  788. border-top: 1upx solid #eeeeee;
  789. z-index: 10;
  790. display: flex;
  791. justify-content: space-between; /* 居左边展示顺序,居右边保存按钮 */
  792. align-items: center;
  793. }
  794. .sort-indicator {
  795. display: flex;
  796. flex-direction: column;
  797. justify-content: center;
  798. flex: 1;
  799. margin-right: 20upx;
  800. }
  801. .sort-label {
  802. font-size: 28upx;
  803. color: #999999;
  804. }
  805. .sort-value {
  806. font-size: 28upx;
  807. color: #333333;
  808. margin-top: 4upx;
  809. }
  810. .footer-btn-wrap .admin-button-com.big {
  811. width: 180upx !important; /* 按钮长一些 */
  812. margin: 0 !important; /* 清除默认居中 margin */
  813. }
  814. </style>