order-book-list.vue 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753
  1. <template>
  2. <ele-data-table
  3. row-key="userId"
  4. :columns="columns"
  5. :data="dataList"
  6. border
  7. class="order-books"
  8. :span-method="handleSpanMethod"
  9. >
  10. <template #baseInfo="{ row }">
  11. <div class="base-info flex justify-between">
  12. <div class="base-info-left flex flex-1">
  13. <el-image
  14. style="min-width: 80px; width: 80px; height: 100px"
  15. fit="cover"
  16. :src="row.cover"
  17. :preview-src-list="[row.cover]"
  18. :initial-index="0"
  19. preview-teleported
  20. />
  21. <div
  22. class="base-info-left-con flex flex-col items-start ml-3"
  23. >
  24. <div style="text-align: left;"
  25. ><el-text
  26. type="primary"
  27. style="cursor: pointer"
  28. @click="handleBooksEdit(row)"
  29. >{{ row.bookName }}</el-text
  30. ></div
  31. >
  32. <div
  33. ><el-text>ISBN:{{ row.isbn }}</el-text></div
  34. >
  35. <div class="base-info-btns flex">
  36. <el-button
  37. size="small"
  38. color="#4f4f4f"
  39. v-if="row.bookStatus != 3"
  40. @click="handleBlackList([row.isbn])"
  41. >加入黑名单</el-button
  42. >
  43. <el-button
  44. size="small"
  45. color="#4f4f4f"
  46. v-if="row.bookStatus == 3"
  47. >已在黑名单</el-button
  48. >
  49. <el-button
  50. size="small"
  51. type="success"
  52. v-if="row.bookStatus == 1"
  53. @click="handleAddBookList(row)"
  54. >加入回收书单</el-button
  55. >
  56. <el-button
  57. size="small"
  58. color="#2d430a"
  59. v-if="row.bookStatus == 2"
  60. >已在回收书单</el-button
  61. >
  62. <el-button
  63. size="small"
  64. type="warning"
  65. v-if="row.settingStatus == 0"
  66. @click="handleSpecifiedDiscount(row)"
  67. >指定回收折扣</el-button
  68. >
  69. <el-button
  70. size="small"
  71. color="#7728f5"
  72. v-if="row.settingStatus == 1"
  73. @click="handleModifyDiscount(row)"
  74. >修改回收折扣</el-button
  75. >
  76. </div>
  77. <div
  78. ><el-text type="danger"
  79. >(已回收数量:{{ row.recycleNum }}当前库存:{{
  80. row.stockNum
  81. }})</el-text
  82. ></div
  83. >
  84. </div>
  85. </div>
  86. <div class="base-info-right shrink-0" style="width: 210px">
  87. <div class="common-text flex">
  88. <el-text>定 价:</el-text>
  89. <el-text>¥ {{ row.bookPrice }}</el-text>
  90. </div>
  91. <div class="common-text flex">
  92. <el-text>回收折扣:</el-text>
  93. <el-text>{{ row.recycleDiscount }}折</el-text>
  94. <el-text
  95. v-if="row.sugDiscountStr"
  96. style="color: #f56c6c; margin-left: 10px"
  97. >{{ row.sugDiscountStr }}</el-text
  98. >
  99. </div>
  100. <div class="common-text flex" v-if="row.discountChangeLog">
  101. <el-text style="color: #3ab54b"
  102. >{{ row.discountChangeLog.userName }}:</el-text
  103. >
  104. <el-text style="color: #3ab54b">{{
  105. row.discountChangeLog.changeTime
  106. }}</el-text>
  107. </div>
  108. <div class="common-text flex">
  109. <el-text>回收单价:</el-text>
  110. <el-text>¥ {{ row.recyclePrice }}</el-text>
  111. <el-text
  112. v-if="row.isupSell"
  113. style="
  114. color: #f56c6c;
  115. font-weight: 500;
  116. margin-left: 2px;
  117. "
  118. >
  119. +{{
  120. isExpand
  121. ? row.upsellPrice
  122. : `${row.upsellPrice}×${row.upsellNum}`
  123. }}</el-text
  124. >
  125. </div>
  126. <div class="common-text flex">
  127. <el-text>销售价格:</el-text>
  128. <el-text>¥ {{ row.productPrice }}</el-text>
  129. <el-icon
  130. :size="14"
  131. color="#f56c6c"
  132. @click="handleEditProductPrice(row)"
  133. style="
  134. margin-left: 6px;
  135. position: relative;
  136. top: 5px;
  137. "
  138. >
  139. <EditPen />
  140. </el-icon>
  141. </div>
  142. <div
  143. class="common-text flex"
  144. v-if="row.productPriceChangeLog"
  145. >
  146. <el-text style="color: #3ab54b"
  147. >{{ row.productPriceChangeLog.userName }}:</el-text
  148. >
  149. <el-text style="color: #3ab54b">{{
  150. row.productPriceChangeLog.changeTime
  151. }}</el-text>
  152. </div>
  153. </div>
  154. </div>
  155. </template>
  156. <template #action="{ row }">
  157. <div class="action-btns">
  158. <el-button
  159. class="mb-10"
  160. color="#4f4f4f"
  161. @click="handleAuditPic(row)"
  162. >审核图片</el-button
  163. >
  164. <el-button
  165. class="mb-10"
  166. color="#a4adb3"
  167. @click="handleViewUrl(row, 'dd')"
  168. >查看当当</el-button
  169. >
  170. <el-button
  171. class="mb-10"
  172. color="#e99d42"
  173. @click="handleRecycleLog(row)"
  174. >回收日志</el-button
  175. >
  176. <el-button
  177. class="mb-10"
  178. color="#f27606"
  179. @click="handleViewUrl(row, 'tb')"
  180. >查看淘宝</el-button
  181. >
  182. <el-button color="#0f7dc7" @click="handleSalesLog(row)"
  183. >售价日志</el-button
  184. >
  185. <el-button color="#399420" @click="handleViewUrl(row, 'kw')"
  186. >查看孔网</el-button
  187. >
  188. </div>
  189. </template>
  190. <template #auditInfo="{ row }">
  191. <div class="audit-info flex justify-center">
  192. <el-radio-group
  193. v-model="row.sts"
  194. style="width: 120px"
  195. :disabled="!(detail.status == 8 || detail.status == 9)"
  196. @change="(value) => handleAuditInfo(value, row)"
  197. :class="row.sts == 1 ? 'class-green' : 'class-red'"
  198. >
  199. <el-radio :value="1">品相良好</el-radio>
  200. <el-radio :value="2" disabled>品相一般</el-radio>
  201. <el-radio :value="3">品相极差</el-radio>
  202. </el-radio-group>
  203. <el-select
  204. v-model="row.com"
  205. style="width: 180px"
  206. placeholder="请选择品相极差的原因"
  207. multiple
  208. :disabled="
  209. !(detail.status == 8 || detail.status == 9) ||
  210. row.sts !== 3
  211. "
  212. class="reason-select"
  213. @change="(value) => handleSelectReason(value, row)"
  214. >
  215. <el-option
  216. v-for="item in auditReason"
  217. :key="item.dictValue"
  218. :label="item.dictValue"
  219. :value="item.dictValue"
  220. />
  221. </el-select>
  222. </div>
  223. </template>
  224. </ele-data-table>
  225. <orderModifyDiscount
  226. ref="specifiedRef"
  227. @refresh="(value) => handleRefresh('specified', value)"
  228. />
  229. <setParams
  230. ref="modifyRef"
  231. @refresh="(value) => handleRefresh('modify', value)"
  232. />
  233. <orderBlacklist ref="blacklistRef" @refresh="handleRefresh('blacklist')" />
  234. <orderRecycleLog ref="recycleLogRef" />
  235. <orderSalesLog ref="salesLogRef" />
  236. <booksEdit ref="booksEditRef" />
  237. <auditScreenshotIsbn ref="auditScreenshotIsbnRef" />
  238. <ModifyProductPrice
  239. ref="productPriceDialogRef"
  240. @refresh="(value) => handleRefresh('productPrice', value)"
  241. />
  242. </template>
  243. <script setup>
  244. import { ref, reactive, watch, nextTick, onMounted, computed } from 'vue';
  245. import orderModifyDiscount from '@/views/recycle/components/modify-discount.vue';
  246. import orderBlacklist from '@/views/recycleOrder/detail/order-blacklist.vue';
  247. import orderRecycleLog from '@/views/recycleOrder/detail/order-recycle-log.vue';
  248. import orderSalesLog from '@/views/recycleOrder/detail/order-sales-log.vue';
  249. import setParams from '@/views/recycle/components/set-params.vue';
  250. import BooksEdit from '@/views/data/books/components/books-edit.vue';
  251. import auditScreenshotIsbn from '@/views/recycleOrder/components/audit-screenshot-isbn.vue';
  252. import request from '@/utils/request';
  253. import { EditPen } from '@element-plus/icons-vue';
  254. import ModifyProductPrice from '@/views/recycle/components/modify-product-price.vue';
  255. const props = defineProps({
  256. detail: {
  257. type: Object,
  258. default: () => ({
  259. detailVoList: []
  260. })
  261. },
  262. isExpand: {
  263. type: Boolean,
  264. default: false
  265. }
  266. });
  267. const dataList = ref([]);
  268. const booksEditRef = ref();
  269. function handleBooksEdit(row) {
  270. row.id = row.bookId;
  271. booksEditRef.value?.handleOpen(row);
  272. }
  273. // 处理detailVoList数据
  274. const processDetailList = (list) => {
  275. if (!list) return [];
  276. const result = [];
  277. let currentIndex = 0;
  278. list.forEach((item) => {
  279. let auditInfo = item.auditCommentList;
  280. // 根据num拆分对象
  281. for (let i = 0; i < item.num; i++) {
  282. let audit = auditInfo
  283. ? auditInfo[i]
  284. ? auditInfo[i]
  285. : { sts: 0, com: [] }
  286. : { sts: 0, com: [] };
  287. // 如果com存在且包含逗号,则分割为数组
  288. if (audit.com && typeof audit.com === 'string') {
  289. audit.com = audit.com.split(',').filter(Boolean);
  290. } else if (!Array.isArray(audit.com)) {
  291. audit.com = [];
  292. }
  293. result.push({
  294. ...item,
  295. ...audit,
  296. _index: i,
  297. _groupIndex: currentIndex,
  298. _isFirstRow: i === 0,
  299. isupSell: item.upsellNum > i
  300. });
  301. }
  302. currentIndex++;
  303. });
  304. console.log(result, 'result');
  305. return result;
  306. };
  307. // 初始化数据
  308. const initData = () => {
  309. const list = props.detail.detailVoList || [];
  310. console.log('Initializing data with list:', list);
  311. if (props.isExpand) {
  312. dataList.value = processDetailList(list);
  313. } else {
  314. const processedList = [];
  315. list.forEach((item) => {
  316. processedList.push({
  317. ...item,
  318. isupSell: item.upsellNum && item.upsellNum > 0,
  319. _index: 0,
  320. _groupIndex: processedList.length,
  321. _isFirstRow: true,
  322. sts:
  323. item.auditCommentList && item.auditCommentList[0]
  324. ? item.auditCommentList[0].sts
  325. : 0,
  326. com:
  327. item.auditCommentList &&
  328. item.auditCommentList[0] &&
  329. item.auditCommentList[0].com
  330. ? typeof item.auditCommentList[0].com === 'string'
  331. ? item.auditCommentList[0].com
  332. .split(',')
  333. .filter(Boolean)
  334. : item.auditCommentList[0].com
  335. : []
  336. });
  337. });
  338. dataList.value = processedList;
  339. }
  340. console.log('Initialized dataList:', dataList.value);
  341. };
  342. // 组件挂载时初始化数据
  343. onMounted(() => {
  344. initData();
  345. });
  346. // 添加对detail.detailVoList的监听,确保弹窗打开时数据能正确显示
  347. watch(
  348. () => props.detail.detailVoList,
  349. (newVal) => {
  350. if (!newVal) return;
  351. console.log('detail.detailVoList changed:', newVal);
  352. initData();
  353. },
  354. { immediate: true, deep: true }
  355. );
  356. watch(
  357. () => props.isExpand,
  358. (newVal) => {
  359. console.log('isExpand changed:', newVal);
  360. initData();
  361. },
  362. { deep: true, immediate: true }
  363. );
  364. // 处理单元格合并
  365. const handleSpanMethod = ({ row, column, rowIndex }) => {
  366. if (column.property === 'num') {
  367. // 确保行有必要的属性
  368. if (!row._groupIndex && row._groupIndex !== 0) {
  369. return {
  370. rowspan: 1,
  371. colspan: 1
  372. };
  373. }
  374. // 找到当前行所在组的所有行
  375. const currentGroup = dataList.value.filter(
  376. (item) => item._groupIndex === row._groupIndex
  377. );
  378. if (row._isFirstRow) {
  379. // 如果是组内第一行,设置合并行数
  380. return {
  381. rowspan: currentGroup.length,
  382. colspan: 1
  383. };
  384. } else {
  385. // 组内其他行不显示
  386. return {
  387. rowspan: 0,
  388. colspan: 0
  389. };
  390. }
  391. }
  392. return {
  393. rowspan: 1,
  394. colspan: 1
  395. };
  396. };
  397. //审核书籍
  398. function handleAudit(row) {
  399. const payload = {
  400. orderId: props.detail.orderId,
  401. isbn: row.isbn,
  402. inx: row._index,
  403. sts: row.sts,
  404. com: Array.isArray(row.com) ? row.com.join(',') : ''
  405. };
  406. request
  407. .post('/order/orderInfo/adminCheckOrder', payload)
  408. .then((res) => {
  409. if (res.data.code == 200) {
  410. ElMessage.success('操作成功');
  411. } else {
  412. ElMessage.error(res.data.msg);
  413. }
  414. });
  415. }
  416. //其余审核良好 列表中sts为0的设置为1,并提交
  417. function handleOtherAuditGood() {
  418. let stsList = [];
  419. dataList.value.forEach((item) => {
  420. if (item.sts == 0) {
  421. item.sts = 1;
  422. stsList.push({
  423. orderId: props.detail.orderId,
  424. isbn: item.isbn,
  425. sts: 1,
  426. com: '',
  427. inx: item._index
  428. });
  429. }
  430. });
  431. let data = {
  432. orderIds: [props.detail.orderId],
  433. checkType: 2
  434. };
  435. //后端接口批量审核
  436. request.post('/order/orderInfo/adminCheckBatch', data).then((res) => {
  437. if (res.data.code == 200) {
  438. ElMessage.success('操作成功');
  439. emit('close');
  440. } else {
  441. ElMessage.error(res.data.msg);
  442. }
  443. });
  444. }
  445. //单选框选择变化
  446. function handleAuditInfo(value, row) {
  447. if (value == 1) {
  448. row.com = [];
  449. nextTick(() => {
  450. handleAudit(row);
  451. });
  452. } else if (value == 3 && row.com.length > 0) {
  453. nextTick(() => {
  454. handleAudit(row);
  455. });
  456. }
  457. }
  458. //选择审核原因
  459. function handleSelectReason(value, row) {
  460. if (row.sts == 3) {
  461. row.com = value;
  462. nextTick(() => {
  463. handleAudit(row);
  464. });
  465. }
  466. }
  467. const emit = defineEmits(['update:detail', 'refresh', 'close']);
  468. const columns = ref([
  469. {
  470. type: 'index',
  471. columnKey: 'index',
  472. width: 60,
  473. align: 'center'
  474. },
  475. {
  476. label: '信息',
  477. prop: 'baseInfo',
  478. slot: 'baseInfo',
  479. minWidth: 620,
  480. align: 'center'
  481. },
  482. {
  483. label: '操作',
  484. prop: 'action',
  485. slot: 'action',
  486. width: 220,
  487. align: 'center'
  488. },
  489. {
  490. label: '数量',
  491. prop: 'num',
  492. minWidth: 90,
  493. align: 'center',
  494. formatter: (row) => {
  495. return `× ${row.num}`;
  496. }
  497. },
  498. {
  499. label: '审核信息',
  500. prop: 'auditInfo',
  501. slot: 'auditInfo',
  502. columnKey: 'auditInfo',
  503. align: 'center',
  504. minWidth: 317,
  505. renderHeader: (row) => {
  506. let data = auditStats();
  507. return `审核信息(总数:${data.total},加价数量${data.upsell},良好:${data.good},一般:${data.normal},极差:${data.bad})`;
  508. }
  509. },
  510. {
  511. label: '审核金额',
  512. prop: 'recyclePrice',
  513. align: 'center',
  514. minWidth: 100,
  515. formatter: (row) => {
  516. return row.sts == 1
  517. ? `¥ ${(row.recyclePrice + (row.isupSell ? row.upsellPrice : 0)).toFixed(2)}`
  518. : '0';
  519. }
  520. }
  521. ]);
  522. //获取审核原因的字典 book_audit_reason
  523. const auditReason = ref([]);
  524. const getAuditReason = async () => {
  525. const res = await request.get(
  526. '/system/dict/data/type/book_audit_reason'
  527. );
  528. auditReason.value = res.data.data;
  529. console.log(res, 'xxxx');
  530. };
  531. getAuditReason();
  532. //查看当当、淘宝、豆瓣链接
  533. const handleViewUrl = (row, type) => {
  534. let url = '';
  535. if (type == 'dd') {
  536. url = `https://search.dangdang.com/?key=${row.isbn}&act=input`;
  537. } else if (type == 'tb') {
  538. url = `https://s.taobao.com/search?page=1&q=${row.isbn}&sort=sale-desc&tab=all`;
  539. } else if (type == 'db') {
  540. url = `https://search.douban.com/book/subject_search?search_text=${row.isbn}`;
  541. } else if (type == 'kw') {
  542. url = `https://search.kongfz.com/product_result/?key=${row.isbn}&status=0&_stpmt=eyJzZWFyY2hfdHlwZSI6ImFjdGl2ZSJ9`;
  543. }
  544. window.open(url, '_blank');
  545. };
  546. //加入回收书单
  547. const handleAddBookList = (row) => {
  548. ElMessageBox.confirm('确认加入回收书单?', '提示', {
  549. confirmButtonText: '确定',
  550. cancelButtonText: '关闭',
  551. type: 'warning'
  552. }).then(() => {
  553. request
  554. .post('/book/bookRecycleInfo/addIn', {
  555. isbnList: [row.isbn]
  556. })
  557. .then(() => {
  558. ElMessage.success('操作成功');
  559. // 更新列表数据
  560. const index = props.detail.detailVoList.findIndex(
  561. (item) => item.isbn === row.isbn
  562. );
  563. if (index > -1) {
  564. const newList = [...props.detail.detailVoList];
  565. newList[index] = { ...newList[index], bookStatus: 2 };
  566. dataList.value = newList;
  567. }
  568. });
  569. });
  570. };
  571. const currentRow = ref(null);
  572. //修改回收折扣
  573. const modifyRef = ref();
  574. const handleModifyDiscount = (row) => {
  575. currentRow.value = row;
  576. modifyRef.value?.handleOpen(row);
  577. };
  578. //指定回收折扣
  579. const specifiedRef = ref();
  580. const handleSpecifiedDiscount = (row) => {
  581. currentRow.value = row;
  582. specifiedRef.value?.handleOpen(row);
  583. };
  584. //加入黑名单
  585. const blacklistRef = ref();
  586. const handleBlackList = (row) => {
  587. currentRow.value = row;
  588. blacklistRef.value?.handleOpen(row);
  589. };
  590. //查看回收日志
  591. const recycleLogRef = ref();
  592. const handleRecycleLog = (row) => {
  593. recycleLogRef.value?.handleOpen(row);
  594. };
  595. //查看售价日志
  596. const salesLogRef = ref();
  597. const handleSalesLog = (row) => {
  598. salesLogRef.value?.handleOpen(row);
  599. };
  600. //审核图片
  601. const auditScreenshotIsbnRef = ref();
  602. const handleAuditPic = (row) => {
  603. row.orderId = props.detail.orderId;
  604. auditScreenshotIsbnRef.value?.handleOpen(row);
  605. };
  606. const handleRefresh = (type, value) => {
  607. console.log(type, value, 'type, value');
  608. if (!currentRow.value) return;
  609. const newList = [...dataList.value];
  610. // 更新所有具有相同ISBN的项目
  611. newList.forEach((item, idx) => {
  612. if (item.isbn === currentRow.value.isbn) {
  613. if (type === 'specified' || type === 'modify') {
  614. newList[idx] = {
  615. ...newList[idx],
  616. settingStatus: 1,
  617. recycleDiscount: value
  618. };
  619. } else if (type === 'blacklist') {
  620. newList[idx] = { ...newList[idx], bookStatus: 3 };
  621. } else if (type === 'productPrice') {
  622. newList[idx] = { ...newList[idx], productPrice: value };
  623. }
  624. }
  625. });
  626. dataList.value = newList;
  627. };
  628. // 手动刷新数据
  629. const refreshData = () => {
  630. initData();
  631. };
  632. const auditStats = function () {
  633. console.log(dataList.value, 'dataList.value');
  634. const total = props.detail.totalNum;
  635. let upsell = 0,
  636. good = 0,
  637. normal = 0,
  638. bad = 0;
  639. dataList.value.forEach((item) => {
  640. if (item.isupSell) upsell++;
  641. if (item.sts == 1) good++;
  642. if (item.sts == 2) normal++;
  643. if (item.sts == 3) bad++;
  644. });
  645. return {
  646. total,
  647. upsell,
  648. good,
  649. normal,
  650. bad
  651. };
  652. };
  653. // 修改销售价格
  654. const productPriceDialogRef = ref(null);
  655. const handleEditProductPrice = (row) => {
  656. currentRow.value = row;
  657. productPriceDialogRef.value?.handleOpen(row);
  658. };
  659. defineExpose({
  660. handleOtherAuditGood,
  661. refreshData
  662. });
  663. </script>
  664. <style lang="scss" scoped>
  665. .mb-10 {
  666. margin-bottom: 7px;
  667. }
  668. .reason-select {
  669. :deep(.el-select__wrapper) {
  670. height: 120px !important;
  671. }
  672. :deep(.el-select__placeholder) {
  673. top: 0;
  674. text-wrap: wrap;
  675. white-space: normal;
  676. text-overflow: initial;
  677. }
  678. }
  679. .class-green {
  680. :deep(.el-radio.is-checked .el-radio__inner) {
  681. background: #399420;
  682. border-color: #399420;
  683. }
  684. :deep(.el-radio__input.is-checked + .el-radio__label) {
  685. color: #399420;
  686. }
  687. }
  688. .class-red {
  689. :deep(.el-radio.is-checked .el-radio__inner) {
  690. background: #f56c6c;
  691. border-color: #f56c6c;
  692. }
  693. :deep(.el-radio__input.is-checked + .el-radio__label) {
  694. color: #f56c6c;
  695. }
  696. }
  697. .order-books {
  698. .action-btns {
  699. display: flex;
  700. flex-wrap: wrap;
  701. gap: 10px;
  702. .el-button {
  703. margin: 0;
  704. color: #fff;
  705. }
  706. }
  707. // 处理合并单元格效果
  708. .el-table {
  709. td.el-table__cell {
  710. &.first-row {
  711. border-bottom: none;
  712. }
  713. }
  714. }
  715. }
  716. </style>