ProductList.vue 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  1. 模板
  2. <template>
  3. <div class="manage-dialog">
  4. <div class="manage-shopping-title">
  5. <div class="manage-shopping-title-left" style="white-space: nowrap"></div>
  6. <div class="manage-shopping-title-right" style="white-space: nowrap">
  7. <el-form inline>
  8. <el-form-item>
  9. <el-input
  10. style="width: 100%"
  11. v-model="searchForm.name"
  12. placeholder="商品名称"
  13. />
  14. </el-form-item>
  15. <el-form-item >
  16. <el-button type="primary" @click="searchFun">查询</el-button>
  17. </el-form-item>
  18. </el-form>
  19. </div>
  20. </div>
  21. <div v-if="chunkedManagelist.length > 0" v-for="(row, rowIndex) in chunkedManagelist" :key="rowIndex" style="margin-bottom: 20px;">
  22. <el-row :gutter="20">
  23. <el-col v-for="(item, colIndex) in row" :key="colIndex" :span="4">
  24. <div class="product-item">
  25. <el-row>
  26. <el-col :span="24">
  27. <el-image class="product-image" :src="item.cover"/>
  28. </el-col>
  29. </el-row>
  30. <el-row>
  31. <el-col :span="24" class="product-info">
  32. <span class="product-name">{{ item.goods_name }}</span>
  33. <span class="product-price">{{ item.price_selling }}元</span>
  34. <el-button class="add-to-cart-btn" type="primary" @click="openToCart(item)">添加购物车</el-button>
  35. </el-col>
  36. </el-row>
  37. </div>
  38. </el-col>
  39. </el-row>
  40. </div>
  41. </div>
  42. <div class="pagination-container">
  43. <div class="pagination-wrapper">
  44. <el-pagination
  45. v-model:currentPage="currentPage"
  46. v-model:page-size="pageSize"
  47. layout="total, prev, pager, next, jumper"
  48. :total="total"
  49. @size-change="handleSizeChange"
  50. @current-change="handleCurrentChange"
  51. />
  52. </div>
  53. </div>
  54. <el-dialog
  55. v-model="dialogVisible"
  56. title="选择规格"
  57. width="500"
  58. >
  59. <div class="display-flex-center mr20 mb30 ">
  60. <el-image :src="detailData.cover" style="width: 100px; height: 100px" fit="fit" />
  61. <div class="ml15">
  62. <text class="fs12 color-556 fw400">¥</text>
  63. <text class="fs20 color-556 fw700 mr20">{{ irem_price_selling}}</text>
  64. <div class="color-777 mt5">
  65. <text>已选择 {{ selectSuitDisplay }}</text>
  66. </div>
  67. </div>
  68. </div>
  69. <div v-for="(item, pIndex) in goodsSpecData" :key="pIndex">
  70. <div class="fw700 mb10">{{ item.name }}</div>
  71. <div class="suit-btn-box">
  72. <view @click="suitChange(suit, item)" :key="index"
  73. :class="['suit-btn',suit.isChecked ? 'suit-btn-active' : '']" v-for="(suit, index) in item.list">
  74. {{ suit.name }}
  75. </view>
  76. </div>
  77. </div>
  78. <template #footer>
  79. <div class="dialog-footer">
  80. <el-button @click="dialogVisible = false">取消</el-button>
  81. <el-button type="primary" @click="addToCart">
  82. 加入购物车
  83. </el-button>
  84. </div>
  85. </template>
  86. </el-dialog>
  87. </template>
  88. <script setup>
  89. import { ref } from 'vue';
  90. import { listApi as managelistApi } from '@/plugins/api/shopping/manage';
  91. let dialogVisible = ref(false);
  92. let chunkedManagelist = ref([[]]);
  93. let goodsSpecData = ref([]);
  94. let irem_price_selling = ref('');
  95. const currentPage = ref(1);
  96. const pageSize = ref(12);
  97. const total = ref(0);
  98. let mark = ref(["店内服务","店内商品"]);
  99. let searchForm = ref({});
  100. function initFun(type, row) {
  101. searchForm.value ={};
  102. if ("second"==type){
  103. mark.value = "店内商品";
  104. }else if("third"==type){
  105. mark.value = "店内服务";
  106. }else{
  107. mark.value = ["店内服务","店内商品"];
  108. }
  109. getData();
  110. }
  111. const emit = defineEmits(['refreshList', 'addToCart']); // 确保只声明一次 emit
  112. const handleSizeChange = (val) => {
  113. pageSize.value = val;
  114. getData();
  115. };
  116. const handleCurrentChange = (val) => {
  117. currentPage.value = val;
  118. getData();
  119. };
  120. let selectData = ref([]);
  121. function searchFun() {
  122. currentPage.value = 1;
  123. selectData.value = [];
  124. getData();
  125. }
  126. function getData() {
  127. let obj = Object.assign(
  128. {
  129. mark:mark.value,
  130. page: currentPage.value,
  131. pageSize: pageSize.value,
  132. },
  133. searchForm.value
  134. );
  135. managelistApi(obj).then((data) => {
  136. if (data != null && data.list != null) {
  137. const chunkSize = 6;
  138. const result = [];
  139. for (let i = 0; i < data.list.length; i += chunkSize) {
  140. result.push(data.list.slice(i, i + chunkSize));
  141. }
  142. chunkedManagelist.value = result.slice(0, 2);
  143. }
  144. console.log(data.page.total);
  145. total.value = data.page.total;
  146. });
  147. }
  148. function suitChange(item, pItem) {
  149. if (item.disabled) return
  150. pItem.list.forEach(spec => {
  151. spec.isChecked = false
  152. })
  153. console.log('item',item)
  154. item.isChecked = true
  155. irem_price_selling.value=item['price_selling']
  156. }
  157. let detailData = ref({});
  158. let addToCartData = ref({});
  159. function openToCart(item) {
  160. detailData.value=item
  161. if (item.specs){
  162. let price_selling_data =[] ;
  163. item.items.forEach(item => {
  164. let specsArr=item.goods_spec.split(';;')
  165. price_selling_data[specsArr[specsArr.length-1]]=item.price_selling
  166. })
  167. item.specs.forEach(pItem => {
  168. pItem.list = pItem.list.map((item, index) => {
  169. item['price_selling']= price_selling_data[item.group+'::'+item.name]
  170. if (index === 0) {
  171. item.isChecked= true
  172. irem_price_selling.value=item['price_selling']
  173. } else {
  174. item.isChecked= false
  175. }
  176. return item
  177. })
  178. })
  179. }
  180. goodsSpecData.value= item.specs
  181. dialogVisible.value = true
  182. addToCartData.value = {
  183. id: item.id,
  184. goods_name: item.goods_name,
  185. selectSuitDisplay: selectSuitDisplay.value,
  186. price_selling: irem_price_selling.value,
  187. num: 1, // 默认数量为1,可以根据需要调整
  188. priceCount: irem_price_selling.value // 小计可以是单价乘以数量,这里简化为单价
  189. }
  190. }
  191. function addToCart(item) {
  192. addToCartData.value.selectSuitDisplay =selectSuitDisplay.value
  193. addToCartData.value.price_selling =irem_price_selling.value
  194. addToCartData.value.priceCount =irem_price_selling.value
  195. emit('addToCart', addToCartData.value);
  196. dialogVisible = false
  197. }
  198. // 定义 computed 属性
  199. const selectSuitDisplay = computed(() => {
  200. let priceSuit = []
  201. if (detailData) {
  202. detailData.value.specs.forEach(pItem => {
  203. let tempList = pItem.list.filter(item => item.isChecked)
  204. tempList = tempList.map(item => {
  205. return {
  206. group_name: item.group,
  207. spec_name: item.name
  208. }
  209. })
  210. priceSuit = priceSuit.concat(tempList)
  211. })
  212. }
  213. let tempData='';
  214. tempData = priceSuit.map(item => {
  215. return `${item.group_name}:${item.spec_name}`;
  216. });
  217. return tempData.join(',');
  218. });
  219. defineExpose({
  220. initFun,
  221. });
  222. </script>
  223. <style scoped lang="scss">
  224. .product-item {
  225. display: flex;
  226. flex-direction: column;
  227. align-items: center;
  228. padding: 20px;
  229. border: 1px solid #ebeef5;
  230. border-radius: 4px;
  231. background-color: #fff;
  232. box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
  233. }
  234. .product-image {
  235. width: 100px;
  236. height: 100px;
  237. margin-bottom: 10px; /* 添加间距 */
  238. }
  239. .product-info {
  240. display: flex;
  241. flex-direction: column;
  242. align-items: center;
  243. width: 100%; /* 确保宽度占满 */
  244. }
  245. .product-name {
  246. font-size: 16px;
  247. font-weight: bold;
  248. line-height: 1.2; /* 行高 */
  249. max-height: 2.4em; /* 最多两行 */
  250. overflow: hidden;
  251. text-overflow: ellipsis;
  252. display: -webkit-box;
  253. -webkit-line-clamp: 2; /* 最多两行 */
  254. -webkit-box-orient: vertical;
  255. width: 100%; /* 确保宽度占满 */
  256. height: 2.4em; /* 固定高度 */
  257. }
  258. .product-price {
  259. font-size: 14px;
  260. color: #909399;
  261. margin-bottom: 10px; /* 添加间距 */
  262. }
  263. .pagination-container {
  264. display: flex;
  265. justify-content: center; /* 水平居中 */
  266. margin-top: 10px;
  267. }
  268. .pagination-wrapper {
  269. display: flex;
  270. justify-content: center; /* 确保内部内容居中 */
  271. }
  272. .manage-shopping-title {
  273. width: 100%;
  274. display: flex;
  275. justify-content: space-between;
  276. border-bottom: 1px solid #eeeeee;
  277. padding-bottom: 10px;
  278. .manage-shopping-title-left {
  279. font-size: 18px;
  280. font-weight: 700;
  281. color: #172b4d;
  282. :deep(.el-form-item) {
  283. width: calc(100% / 7 - 20px);
  284. margin-bottom: 0 !important;
  285. }
  286. }
  287. }
  288. .suit-btn-active {
  289. color: #C29556;
  290. background-color: #F9F2E6;
  291. }
  292. .suit-btn-disabled{
  293. background-color: #fffafa;
  294. border-color: #d0d0d0;
  295. color: #ababab;
  296. }
  297. .display-flex-center {
  298. display: flex;
  299. align-items: center;
  300. }
  301. .add-to-cart-btn {
  302. width: 100%;
  303. max-width: 150px; /* 可选:设置最大宽度 */
  304. }
  305. .mr20 {
  306. margin-right: 20px;
  307. }
  308. .mb30 {
  309. margin-bottom: 30px;
  310. }
  311. .ml15{
  312. margin-left: 15px;
  313. }
  314. .color-556 {
  315. color: #C29556;
  316. }
  317. .fw700 {
  318. font-weight: 700 !important;
  319. }
  320. .fw600 {
  321. font-weight: 600!important;
  322. }
  323. .fw500 {
  324. font-weight: 500!important;
  325. }
  326. .fw400 {
  327. font-weight: 400!important;
  328. }
  329. .mr20 {
  330. margin-right: 20px;
  331. }
  332. .mb10 {
  333. margin-bottom: 10px;
  334. }
  335. .mt5 {
  336. margin-top: 5px;
  337. }
  338. .color-777 {
  339. color: #777777;
  340. }
  341. .suit-btn-box {
  342. display: flex;
  343. // justify-content: space-between;
  344. .suit-btn {
  345. background-color: #F6F6F6;
  346. border-radius: 4px;
  347. border: 1px solid transparent;
  348. height: 38px;
  349. line-height: 38px;
  350. text-align: center;
  351. width: calc(33% - 10px);
  352. color: #232323;
  353. margin-right: 10px;
  354. box-sizing: border-box;
  355. margin-bottom: 20px;
  356. &-active {
  357. color: #C29556;
  358. background-color: #F9F2E6 ;
  359. }
  360. &-disabled {
  361. background-color: #fffafa;
  362. border-color: #d0d0d0;
  363. color: #ababab;
  364. }
  365. &-column {
  366. width: 100%;
  367. text-align: left;
  368. padding: 0 10rpx;
  369. flex-shrink: 0;
  370. }
  371. }
  372. }
  373. </style>