order-item.vue 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. <template>
  2. <div class="order-item">
  3. <!-- Order Header -->
  4. <div class="order-header">
  5. <el-checkbox v-model="order.checked" style="margin-right: 12px;" />
  6. <span class="mr-4">订单编号: {{ order.orderId }} <el-button link type="primary" size="small"
  7. @click="handleCopy(order.orderId)">复制</el-button></span>
  8. <span class="mr-4">创建时间: {{ order.createTime }}</span>
  9. <span class="mr-4">支付渠道: {{ getPayType(order.payType) }}</span>
  10. <span class="mr-4">订单来源: 商城小程序</span>
  11. <span class="flag-icon" v-if="order.flag"><el-icon>
  12. <Flag />
  13. </el-icon></span>
  14. <span class="urge-tag" v-if="order.isUrge">催发货</span>
  15. </div>
  16. <!-- Order Body -->
  17. <div class="order-body">
  18. <!-- Products Column -->
  19. <div class="col-products-wrapper">
  20. <div v-for="(product, idx) in order.detailList" :key="idx" class="product-row">
  21. <div class="col-product product-info mr-2">
  22. <el-image :src="product.cover" class="product-img" fit="cover" />
  23. <div class="product-detail">
  24. <div class="product-title">{{ product.bookName }}</div>
  25. <div class="product-isbn">ISBN: <span class="link">{{ product.isbn }}</span>
  26. <el-icon class="cursor-pointer" @click="handleCopy(product.isbn)">
  27. <CopyDocument />
  28. </el-icon> (品相: {{ getConditionText(product.conditionType) }})
  29. </div>
  30. <div class="product-tags">
  31. <span class="tag">回收折扣: {{ product.discount || 1 }}折</span>
  32. <span class="tag success">(回收状态: {{ getRecycleStatusText(product.recycleStatus) }})</span>
  33. </div>
  34. </div>
  35. </div>
  36. <div class="col-price">¥ {{ product.price }}</div>
  37. <div class="col-qty">x1</div>
  38. <div class="col-aftersales">
  39. <span
  40. :class="{ 'text-blue': product.status === '3', 'text-red': product.status === '2' }">
  41. {{ getDetailStatusText(product.status) }}
  42. </span>
  43. </div>
  44. </div>
  45. </div>
  46. <!-- Merged Columns -->
  47. <div class="col-merged col-buyer">
  48. <div class="buyer-info">
  49. <el-avatar :size="30" :src="order.avatar" />
  50. <div class="buyer-name">{{ order.userNick }}</div>
  51. <div class="buyer-phone">{{ order.receiverMobile }}</div>
  52. </div>
  53. </div>
  54. <div class="col-merged col-payment">
  55. <div class="payment-amount">¥ {{ order.totalMoney }}</div>
  56. <div class="shipping-fee">(含邮费: ¥ {{ order.expressMoney }})</div>
  57. </div>
  58. <div class="col-merged col-logistics">
  59. <div>{{ order.expressName }}</div>
  60. <div>{{ order.waybillCode }}</div>
  61. </div>
  62. <div class="col-merged col-status">
  63. <div :class="getStatusColor(order.status)">{{ getStatusText(order.status) }}</div>
  64. <el-button link type="primary" @click="$emit('view-detail', order)">[查看详情]</el-button>
  65. </div>
  66. <div class="col-merged col-action">
  67. <el-button link type="primary" @click="$emit('push-sms', order)">[推送短信]</el-button>
  68. <el-button link type="warning" @click="$emit('refund', order)">[缺货退款]</el-button>
  69. </div>
  70. </div>
  71. <!-- Buyer Note -->
  72. <div class="buyer-note" v-if="order.remark">
  73. <span class="note-label">买家备注:</span>
  74. <span class="note-content">{{ order.remark }}</span>
  75. </div>
  76. </div>
  77. </template>
  78. <script setup>
  79. import { Flag, CopyDocument } from '@element-plus/icons-vue';
  80. import { EleMessage } from 'ele-admin-plus/es';
  81. import { useClipboard } from '@vueuse/core';
  82. const props = defineProps({
  83. order: {
  84. type: Object,
  85. required: true
  86. }
  87. });
  88. defineEmits(['view-detail', 'push-sms', 'refund']);
  89. const { copy } = useClipboard();
  90. const handleCopy = async (text) => {
  91. try {
  92. await copy(text);
  93. EleMessage.success('复制成功');
  94. } catch (e) {
  95. EleMessage.error('复制失败');
  96. }
  97. };
  98. const getStatusText = (status) => {
  99. const statusMap = {
  100. '1': '等待买家付款',
  101. '2': '等待卖家发货',
  102. '3': '等待买家确认收货',
  103. '4': '已完成',
  104. '5': '退款成功',
  105. '6': '退款中',
  106. '7': '已取消'
  107. };
  108. return statusMap[status] || status;
  109. };
  110. const getStatusColor = (status) => {
  111. // Implement color logic if needed, e.g. return 'text-red'
  112. return '';
  113. };
  114. const getDetailStatusText = (status) => {
  115. const map = {
  116. '1': '正常',
  117. '2': '退款中',
  118. '3': '已退款'
  119. };
  120. return map[status] || '';
  121. };
  122. const getConditionText = (type) => {
  123. const map = {
  124. '1': '良好',
  125. '2': '中等',
  126. '3': '次品',
  127. '4': '全新'
  128. };
  129. return map[type] || '-';
  130. };
  131. const getRecycleStatusText = (status) => {
  132. const map = {
  133. '1': '正在回收',
  134. '2': '暂停回收',
  135. '3': '未加入回收书单',
  136. '4': '黑名单',
  137. '5': '手动暂停'
  138. };
  139. return map[status] || '-';
  140. };
  141. const getPayType = (type) => {
  142. if (!type) {
  143. return '-';
  144. }
  145. const map = {
  146. '1': '余额',
  147. '2': '微信',
  148. '3': '支付宝'
  149. };
  150. return map[type] || type;
  151. };
  152. </script>
  153. <style scoped>
  154. .order-item {
  155. border: 1px solid #e4e7ed;
  156. margin-bottom: 20px;
  157. font-size: 13px;
  158. }
  159. .order-header {
  160. background-color: #f5f7fa;
  161. padding: 10px 20px;
  162. display: flex;
  163. align-items: center;
  164. border-bottom: 1px solid #e4e7ed;
  165. }
  166. .order-body {
  167. display: flex;
  168. align-items: stretch;
  169. }
  170. .col-products-wrapper {
  171. flex: 1;
  172. min-width: 0;
  173. display: flex;
  174. flex-direction: column;
  175. border-right: 1px solid #e4e7ed;
  176. }
  177. .product-row {
  178. display: flex;
  179. align-items: center;
  180. padding: 15px 0;
  181. border-bottom: 1px solid #ebeef5;
  182. }
  183. .product-row:last-child {
  184. border-bottom: none;
  185. }
  186. .col-product {
  187. flex: 1;
  188. min-width: 200px;
  189. padding-left: 20px;
  190. display: flex;
  191. }
  192. .product-img {
  193. width: 60px;
  194. height: 60px;
  195. border-radius: 4px;
  196. margin-right: 10px;
  197. }
  198. .product-detail {
  199. display: flex;
  200. flex-direction: column;
  201. justify-content: space-between;
  202. }
  203. .product-title {
  204. font-weight: 500;
  205. margin-bottom: 4px;
  206. overflow: hidden;
  207. text-overflow: ellipsis;
  208. display: -webkit-box;
  209. -webkit-line-clamp: 2;
  210. -webkit-box-orient: vertical;
  211. }
  212. .col-price {
  213. width: 100px;
  214. flex: none;
  215. text-align: center;
  216. display: flex;
  217. align-items: center;
  218. justify-content: center;
  219. }
  220. .col-qty {
  221. width: 80px;
  222. flex: none;
  223. text-align: center;
  224. display: flex;
  225. align-items: center;
  226. justify-content: center;
  227. }
  228. .col-aftersales {
  229. width: 100px;
  230. flex: none;
  231. text-align: center;
  232. display: flex;
  233. align-items: center;
  234. justify-content: center;
  235. }
  236. .col-merged {
  237. display: flex;
  238. flex-direction: column;
  239. justify-content: center;
  240. align-items: center;
  241. border-right: 1px solid #e4e7ed;
  242. padding: 10px;
  243. text-align: center;
  244. }
  245. .col-merged:last-child {
  246. border-right: none;
  247. }
  248. .col-buyer {
  249. width: 150px;
  250. flex: none;
  251. }
  252. .col-payment {
  253. width: 120px;
  254. flex: none;
  255. }
  256. .col-logistics {
  257. width: 150px;
  258. flex: none;
  259. }
  260. .col-status {
  261. width: 120px;
  262. flex: none;
  263. }
  264. .col-action {
  265. width: 120px;
  266. flex: none;
  267. }
  268. .buyer-note {
  269. background-color: #fff8e6;
  270. padding: 8px 20px;
  271. color: #e6a23c;
  272. border-top: 1px solid #faecd8;
  273. }
  274. .text-blue {
  275. color: #409eff;
  276. }
  277. .text-red {
  278. color: #f56c6c;
  279. }
  280. .flag-icon {
  281. color: #f56c6c;
  282. margin-left: 10px;
  283. }
  284. .urge-tag {
  285. background-color: #f56c6c;
  286. color: #fff;
  287. padding: 2px 6px;
  288. border-radius: 4px;
  289. font-size: 12px;
  290. margin-left: 10px;
  291. }
  292. .tag {
  293. background-color: #f0f2f5;
  294. padding: 2px 6px;
  295. border-radius: 4px;
  296. margin-right: 5px;
  297. font-size: 12px;
  298. }
  299. .tag.success {
  300. background-color: #f0f9eb;
  301. color: #67c23a;
  302. }
  303. </style>