hwq 1 anno fa
parent
commit
0d2f02259a
100 ha cambiato i file con 38710 aggiunte e 6303 eliminazioni
  1. 45 22
      src/api/account.js
  2. 46 35
      src/api/export.js
  3. 166 166
      src/api/product.js
  4. 295 293
      src/api/setting.js
  5. 273 0
      src/api/shop.js
  6. 447 0
      src/api/shop_product.js
  7. 1156 0
      src/api/shop_setting.js
  8. 104 0
      src/api/shopuploadPictures.js
  9. 19 6
      src/api/upload.js
  10. 39 39
      src/api/uploadPictures.js
  11. 292 0
      src/components/freightTemplate2/city.vue
  12. 584 0
      src/components/freightTemplate2/index.vue
  13. 1940 0
      src/components/freightTemplate2/provinces.js
  14. 947 988
      src/components/uploadPictures/index.vue
  15. 954 0
      src/components/uploadPictures2/index.vue
  16. 76 0
      src/components/uploadPictures2/widgetImg.vue
  17. 91 103
      src/components/verifition/Verify/VerifyPoints.vue
  18. 88 105
      src/components/verifition/Verify/VerifySlide.vue
  19. 280 265
      src/layout/component/columnsAside.vue
  20. 26 23
      src/layout/footer/index.vue
  21. 98 91
      src/layout/logo/index.vue
  22. 212 205
      src/layout/navBars/breadcrumb/breadcrumb.vue
  23. 96 102
      src/layout/navBars/breadcrumb/search.vue
  24. 256 232
      src/layout/navBars/breadcrumb/userNews.vue
  25. 631 550
      src/layout/navBars/tagsView/tagsView.vue
  26. 26 0
      src/libs/settingMer.js
  27. 73 59
      src/main.js
  28. 481 459
      src/pages/account/login/index.vue
  29. 536 0
      src/pages/account/shoplogin/index.vue
  30. 134 132
      src/pages/index/components/userChart.vue
  31. 573 775
      src/pages/product/productAdd/index.vue
  32. 860 916
      src/pages/product/productList/index.vue
  33. 376 400
      src/pages/setting/systemRole/index.vue
  34. 381 0
      src/pages/shop/apply.vue
  35. 198 0
      src/pages/shop/classify.vue
  36. 724 0
      src/pages/shop/shop.vue
  37. 385 0
      src/pages/shop/type.vue
  38. 286 0
      src/pages/shop_product/list_wait.vue
  39. 3111 0
      src/pages/shop_product/productAdd/index.vue
  40. 132 0
      src/pages/shop_product/productAdd/taoBao.vue
  41. 225 0
      src/pages/shop_product/productAttr/addAttr.vue
  42. 223 0
      src/pages/shop_product/productAttr/index.vue
  43. 401 0
      src/pages/shop_product/productClassify/index.vue
  44. 115 0
      src/pages/shop_product/productList/attribute/index.vue
  45. 178 0
      src/pages/shop_product/productList/components/goodsDetail.vue
  46. 898 0
      src/pages/shop_product/productList/index.vue
  47. 40 0
      src/pages/shop_product/productList/tableExpand.vue
  48. 759 0
      src/pages/shop_product/productList/taoBao.vue
  49. 396 0
      src/pages/shop_product/productReply/index.vue
  50. 70 0
      src/pages/shop_product/tableExpand.vue
  51. 169 0
      src/pages/shop_setting/agreement/index.vue
  52. 171 0
      src/pages/shop_setting/cityDada/index.vue
  53. 241 0
      src/pages/shop_setting/clerkList/index.vue
  54. 193 0
      src/pages/shop_setting/deliveryService/index.vue
  55. 295 0
      src/pages/shop_setting/devise/components/uploadPic.vue
  56. 1467 0
      src/pages/shop_setting/devise/diyIndex.vue
  57. 115 0
      src/pages/shop_setting/devise/goodClass.vue
  58. 1279 0
      src/pages/shop_setting/devise/index.vue
  59. 134 0
      src/pages/shop_setting/devise/links.vue
  60. 663 0
      src/pages/shop_setting/devise/list.vue
  61. 115 0
      src/pages/shop_setting/devise/template.vue
  62. 816 0
      src/pages/shop_setting/devise/users.vue
  63. 132 0
      src/pages/shop_setting/devisePage/index.vue
  64. 162 0
      src/pages/shop_setting/devisePage/links.vue
  65. 253 0
      src/pages/shop_setting/devisePage/list.vue
  66. 248 0
      src/pages/shop_setting/freight/index.vue
  67. 562 0
      src/pages/shop_setting/membershipLevel/index.vue
  68. 225 0
      src/pages/shop_setting/multiLanguage/country.vue
  69. 403 0
      src/pages/shop_setting/multiLanguage/langList.vue
  70. 195 0
      src/pages/shop_setting/multiLanguage/list.vue
  71. 301 0
      src/pages/shop_setting/notification/index.vue
  72. 340 0
      src/pages/shop_setting/notification/notificationEdit.vue
  73. 36 0
      src/pages/shop_setting/setApp/index.vue
  74. 236 0
      src/pages/shop_setting/setSystem/index.vue
  75. 192 0
      src/pages/shop_setting/shippingTemplates/index.vue
  76. 934 0
      src/pages/shop_setting/storage/index.vue
  77. 270 0
      src/pages/shop_setting/storeList/index.vue
  78. 217 0
      src/pages/shop_setting/storeService/feedback.vue
  79. 665 0
      src/pages/shop_setting/storeService/index.vue
  80. 640 0
      src/pages/shop_setting/storeService/speechcraft.vue
  81. 266 0
      src/pages/shop_setting/systemAdmin/index.vue
  82. 491 0
      src/pages/shop_setting/systemMenus/components/menusFrom.vue
  83. 577 0
      src/pages/shop_setting/systemMenus/index.vue
  84. 575 0
      src/pages/shop_setting/systemOutAccount/index.vue
  85. 75 0
      src/pages/shop_setting/systemOutInterface/components/MonacoEditor.vue
  86. 456 0
      src/pages/shop_setting/systemOutInterface/debugging.vue
  87. 1077 0
      src/pages/shop_setting/systemOutInterface/index.vue
  88. 119 0
      src/pages/shop_setting/systemOutInterface/request.js
  89. 382 0
      src/pages/shop_setting/systemRole/index.vue
  90. 399 0
      src/pages/shop_setting/systemStore/index.vue
  91. 233 0
      src/pages/shop_setting/themeStyle/index.vue
  92. 120 0
      src/pages/shop_setting/user/index.vue
  93. 75 0
      src/pages/shop_setting/userFile/index.vue
  94. 315 0
      src/pages/shop_setting/verifyOrder/index.vue
  95. 164 155
      src/router/modules/frameOut.js
  96. 21 23
      src/router/modules/index.js
  97. 62 0
      src/router/modules/shop.js
  98. 78 0
      src/router/modules/shop_product.js
  99. 651 0
      src/router/modules/shop_setting.js
  100. 163 159
      src/router/routers.js

+ 45 - 22
src/api/account.js

@@ -14,52 +14,75 @@ import request from '@/libs/request';
  * 登录
  * */
 export function AccountLogin(data) {
-  return request({
-    url: '/login',
-    method: 'post',
-    data,
-  });
+	return request({
+		url: '/login',
+		method: 'post',
+		data,
+	});
 }
+/*
+ * 登录
+ * */
+export function ShopLogin(data) {
+	return request({
+		url: 'mer/login',
+		method: 'post',
+		data,
+	});
+}
+
 
 /**
  * 退出登陆
  * @constructor
  */
 export function AccountLogout() {
-  return request({
-    url: '/setting/admin/logout',
-    method: 'get',
-  });
+	return request({
+		url: '/setting/admin/logout',
+		method: 'get',
+	});
 }
 
 /**
  * 获取轮播图和logo
  */
 export function loginInfoApi() {
-  return request({
-    url: '/login/info',
-    method: 'get',
-  });
+	return request({
+		url: '/login/info',
+		method: 'get',
+	});
+}
+
+/**
+ * 获取轮播图和logo
+ */
+export function shoploginInfoApi() {
+	return request({
+		url: 'mer/login/info',
+		method: 'get',
+	});
 }
 
+
+
 /**
  * 获取菜单数据
  */
 export function menusApi() {
-  return request({
-    url: '/menus',
-    method: 'get',
-  });
+	return request({
+		url: '/menus',
+		method: 'get',
+	});
 }
 
 /**
  * 搜索菜单数据
  */
 export function menusListApi() {
-  return request({
-    url: '/menusList',
-    method: 'get',
-  });
+	return request({
+		url: '/menusList',
+		method: 'get',
+	});
 }
 
-export function AccountRegister() {}
+export function AccountRegister() {}

+ 46 - 35
src/api/export.js

@@ -14,74 +14,85 @@ import request from '@/libs/request';
  * 用户列表导出
  */
 export function exportUserList(data) {
-  return request({
-    url: '/export/user_list',
-    method: 'get',
-    params: data,
-  });
+	return request({
+		url: '/export/user_list',
+		method: 'get',
+		params: data,
+	});
 }
 
 /**
  * 订单列表导出
  */
 export function exportOrderList(data) {
-  return request({
-    url: '/export/order_list',
-    method: 'get',
-    params: data,
-  });
+	return request({
+		url: '/export/order_list',
+		method: 'get',
+		params: data,
+	});
 }
 
 /**
  * 商品列表导出
  */
 export function exportProductList(data) {
-  return request({
-    url: '/export/product_list',
-    method: 'get',
-    params: data,
-  });
+	return request({
+		url: '/export/product_list',
+		method: 'get',
+		params: data,
+	});
+}
+
+/**
+ * 商户商品列表导出
+ */
+export function shopexportProductList(data) {
+	return request({
+		url: '/mer/export/product_list',
+		method: 'get',
+		params: data,
+	});
 }
 
 /**
  * 砍价列表导出
  */
 export function exportBargainList(data) {
-  return request({
-    url: '/export/bargain_list',
-    method: 'get',
-    params: data,
-  });
+	return request({
+		url: '/export/bargain_list',
+		method: 'get',
+		params: data,
+	});
 }
 
 /**
  * 拼团列表导出
  */
 export function exportCombinationList(data) {
-  return request({
-    url: '/export/combination_list',
-    method: 'get',
-    params: data,
-  });
+	return request({
+		url: '/export/combination_list',
+		method: 'get',
+		params: data,
+	});
 }
 
 /**
  * 秒杀列表导出
  */
 export function exportSeckillList(data) {
-  return request({
-    url: '/export/seckill_list',
-    method: 'get',
-    params: data,
-  });
+	return request({
+		url: '/export/seckill_list',
+		method: 'get',
+		params: data,
+	});
 }
 
 /**
  * 会员卡导出
  */
 export function exportmberCardList(id) {
-  return request({
-    url: `/export/member_card/${id}`,
-    method: 'get',
-  });
-}
+	return request({
+		url: `/export/member_card/${id}`,
+		method: 'get',
+	});
+}

+ 166 - 166
src/api/product.js

@@ -14,62 +14,62 @@ import request from '@/libs/request';
  * 获取商品表单头数量;
  * */
 export function getGoodHeade() {
-  return request({
-    url: 'product/product/type_header',
-    method: 'get',
-  });
+	return request({
+		url: 'product/product/type_header',
+		method: 'get',
+	});
 }
 
 /*
  * 获取商品表单头数量;
  * */
 export function getGoodsCategory(data) {
-  return request({
-    url: '/goods/goods_category',
-    method: 'get',
-    params: data,
-  });
+	return request({
+		url: '/goods/goods_category',
+		method: 'get',
+		params: data,
+	});
 }
 
 /**
  * @description 商品管理-- 列表
  */
 export function getGoods(params) {
-  return request({
-    url: 'product/product',
-    method: 'get',
-    params,
-  });
+	return request({
+		url: 'product/product',
+		method: 'get',
+		params,
+	});
 }
 
 /**
  * @description 商品管理-- 临时保存
  */
 export function productCache() {
-  return request({
-    url: 'product/cache',
-    method: 'get',
-  });
+	return request({
+		url: 'product/cache',
+		method: 'get',
+	});
 }
 
 /**
  * @description 商品管理-- 取消临时保存
  */
 export function cacheDelete() {
-  return request({
-    url: 'product/cache',
-    method: 'delete',
-  });
+	return request({
+		url: 'product/cache',
+		method: 'delete',
+	});
 }
 
 /**
  * @description 商品管理-- 上下架
  */
 export function PostgoodsIsShow(id, isShow) {
-  return request({
-    url: `product/product/set_show/${id}/${isShow}`,
-    method: 'put',
-  });
+	return request({
+		url: `product/product/set_show/${id}/${isShow}`,
+		method: 'put',
+	});
 }
 
 /**
@@ -77,11 +77,11 @@ export function PostgoodsIsShow(id, isShow) {
  * @param {Object} param data {Object} 传值对象
  */
 export function productShowApi(data) {
-  return request({
-    url: `product/product/product_show`,
-    method: 'put',
-    data,
-  });
+	return request({
+		url: `product/product/product_show`,
+		method: 'put',
+		data,
+	});
 }
 
 /**
@@ -89,52 +89,52 @@ export function productShowApi(data) {
  * @param {Object} param data {Object} 传值对象
  */
 export function productUnshowApi(data) {
-  return request({
-    url: `product/product/product_unshow`,
-    method: 'put',
-    data,
-  });
+	return request({
+		url: `product/product/product_unshow`,
+		method: 'put',
+		data,
+	});
 }
 
 /**
  * @description 商品管理-- 分类
  */
 export function treeListApi(type) {
-  return request({
-    url: `product/category/tree/${type}`,
-    method: 'get',
-  });
+	return request({
+		url: `product/category/tree/${type}`,
+		method: 'get',
+	});
 }
 
 /**
  * @description 商品管理-- 分类 new
  */
 export function cascaderListApi(type) {
-  return request({
-    url: `product/category/cascader/${type}`,
-    method: 'get',
-  });
+	return request({
+		url: `product/category/cascader/${type}`,
+		method: 'get',
+	});
 }
 
 /**
  * @description 商品管理-- 详情
  */
 export function productInfoApi(id) {
-  return request({
-    url: `product/product/${id}`,
-    method: 'get',
-  });
+	return request({
+		url: `product/product/${id}`,
+		method: 'get',
+	});
 }
 
 /**
  * @description 商品管理-- 提交
  */
 export function productAddApi(data) {
-  return request({
-    url: `product/product/${data.id}`,
-    method: 'POST',
-    data,
-  });
+	return request({
+		url: `product/product/${data.id}`,
+		method: 'POST',
+		data,
+	});
 }
 
 /**
@@ -142,11 +142,11 @@ export function productAddApi(data) {
  * @param {Object} param params {Object} 传值参数
  */
 export function productListApi(params) {
-  return request({
-    url: 'product/category',
-    method: 'get',
-    params,
-  });
+	return request({
+		url: 'product/category',
+		method: 'get',
+		params,
+	});
 }
 
 /**
@@ -154,10 +154,10 @@ export function productListApi(params) {
  * @param {Object} param params {Object} 传值参数
  */
 export function productCreateApi() {
-  return request({
-    url: 'product/category/create',
-    method: 'get',
-  });
+	return request({
+		url: 'product/category/create',
+		method: 'get',
+	});
 }
 
 /**
@@ -165,10 +165,10 @@ export function productCreateApi() {
  * @param {Object} param params {Object} 传值参数
  */
 export function productEditApi(id) {
-  return request({
-    url: `product/category/${id}`,
-    method: 'get',
-  });
+	return request({
+		url: `product/category/${id}`,
+		method: 'get',
+	});
 }
 
 /**
@@ -176,21 +176,21 @@ export function productEditApi(id) {
  * @param {Object} param params {Object} 传值参数
  */
 export function setShowApi(data) {
-  return request({
-    url: `product/category/set_show/${data.id}/${data.is_show}`,
-    method: 'PUT',
-  });
+	return request({
+		url: `product/category/set_show/${data.id}/${data.is_show}`,
+		method: 'PUT',
+	});
 }
 
 /**
  * @description 选择商品 -- 列表
  */
 export function changeListApi(params) {
-  return request({
-    url: `product/product/list`,
-    method: 'GET',
-    params,
-  });
+	return request({
+		url: `product/product/list`,
+		method: 'GET',
+		params,
+	});
 }
 
 /**
@@ -198,11 +198,11 @@ export function changeListApi(params) {
  * @param {Object} param params {Object} 传值参数
  */
 export function replyListApi(params) {
-  return request({
-    url: `product/reply`,
-    method: 'get',
-    params,
-  });
+	return request({
+		url: `product/reply`,
+		method: 'get',
+		params,
+	});
 }
 
 /**
@@ -210,21 +210,21 @@ export function replyListApi(params) {
  * @param {Object} param data {Object} 传值参数
  */
 export function setReplyApi(data, id) {
-  return request({
-    url: `product/reply/set_reply/${id}`,
-    method: 'PUT',
-    data,
-  });
+	return request({
+		url: `product/reply/set_reply/${id}`,
+		method: 'PUT',
+		data,
+	});
 }
 
 /**
  * @description 获取复制商品配置
  */
 export function copyConfigApi() {
-  return request({
-    url: `product/copy_config`,
-    method: 'get',
-  });
+	return request({
+		url: `product/copy_config`,
+		method: 'get',
+	});
 }
 
 /**
@@ -232,11 +232,11 @@ export function copyConfigApi() {
  * @param {Object} param data {Object} 传值参数
  */
 export function crawlFromApi(data) {
-  return request({
-    url: `product/copy`,
-    method: 'POST',
-    data,
-  });
+	return request({
+		url: `product/copy`,
+		method: 'POST',
+		data,
+	});
 }
 
 /**
@@ -244,11 +244,11 @@ export function crawlFromApi(data) {
  * @param {Object} param data {Object} 传值参数
  */
 export function crawlSaveApi(data) {
-  return request({
-    url: `product/crawl/save`,
-    method: 'POST',
-    data,
-  });
+	return request({
+		url: `product/crawl/save`,
+		method: 'POST',
+		data,
+	});
 }
 
 /**
@@ -256,11 +256,11 @@ export function crawlSaveApi(data) {
  * @param {Object} param data {Object} 传值参数
  */
 export function generateAttrApi(data, id, type) {
-  return request({
-    url: `product/generate_attr/${id}/${type}`,
-    method: 'POST',
-    data,
-  });
+	return request({
+		url: `product/generate_attr/${id}/${type}`,
+		method: 'POST',
+		data,
+	});
 }
 
 /**
@@ -268,11 +268,11 @@ export function generateAttrApi(data, id, type) {
  * @param {Object} param params {Object} 传值参数
  */
 export function ruleListApi(params) {
-  return request({
-    url: `product/product/rule`,
-    method: 'GET',
-    params,
-  });
+	return request({
+		url: `product/product/rule`,
+		method: 'GET',
+		params,
+	});
 }
 
 /**
@@ -281,11 +281,11 @@ export function ruleListApi(params) {
  * @param {Object} param data {Object} 传值参数
  */
 export function ruleAddApi(data, id) {
-  return request({
-    url: `product/product/rule/${id}`,
-    method: 'POST',
-    data,
-  });
+	return request({
+		url: `product/product/rule/${id}`,
+		method: 'POST',
+		data,
+	});
 }
 
 /**
@@ -293,10 +293,10 @@ export function ruleAddApi(data, id) {
  * @param {Number} param id {Number} 属性id
  */
 export function ruleInfoApi(id) {
-  return request({
-    url: `product/product/rule/${id}`,
-    method: 'get',
-  });
+	return request({
+		url: `product/product/rule/${id}`,
+		method: 'get',
+	});
 }
 
 /**
@@ -304,99 +304,99 @@ export function ruleInfoApi(id) {
  * @id--产品id;
  */
 export function fictitiousReply(id) {
-  return request({
-    url: `product/reply/fictitious_reply/${id}`,
-    method: 'get',
-  });
+	return request({
+		url: `product/reply/fictitious_reply/${id}`,
+		method: 'get',
+	});
 }
 
 /**
  * @description 商品属性 -- 获取规则属性模板
  */
 export function productGetRuleApi() {
-  return request({
-    url: `product/product/get_rule`,
-    method: 'get',
-  });
+	return request({
+		url: `product/product/get_rule`,
+		method: 'get',
+	});
 }
 
 /**
  * @description 商品 -- 获取运费模板
  */
 export function productGetTemplateApi() {
-  return request({
-    url: `product/product/get_template`,
-    method: 'get',
-  });
+	return request({
+		url: `product/product/get_template`,
+		method: 'get',
+	});
 }
 
 /**
  * @description 商品 -- 获取运费模板
  */
 export function productGetTempKeysApi() {
-  return request({
-    url: `product/product/get_temp_keys`,
-    method: 'get',
-  });
+	return request({
+		url: `product/product/get_temp_keys`,
+		method: 'get',
+	});
 }
 
 /**
  * @description 商铺产品 -- 导出
  */
 export function storeProductApi(data) {
-  return request({
-    url: `export/storeProduct`,
-    method: 'get',
-    params: data,
-  });
+	return request({
+		url: `export/storeProduct`,
+		method: 'get',
+		params: data,
+	});
 }
 
 /**
  * @description 添加商品 -- 检测活动存在
  */
 export function checkActivityApi(id) {
-  return request({
-    url: `product/product/check_activity/${id}`,
-    method: 'get',
-  });
+	return request({
+		url: `product/product/check_activity/${id}`,
+		method: 'get',
+	});
 }
 
 /**
  * @description 商品添加编辑-- 用户标签
  */
 export function labelListApi() {
-  return request({
-    url: 'user/user_label',
-    method: 'get',
-  });
+	return request({
+		url: 'user/user_label',
+		method: 'get',
+	});
 }
 /**
  * @description 组件获取用户标签
  */
 export function productUserLabel() {
-  return request({
-    url: 'user/user_tree_label',
-    method: 'get',
-  });
+	return request({
+		url: 'user/user_tree_label',
+		method: 'get',
+	});
 }
 /**
  * @description 商品添加编辑-- 用户标签
  */
 export function uploadType() {
-  return request({
-    url: 'file/upload_type',
-    method: 'get',
-  });
+	return request({
+		url: 'file/upload_type',
+		method: 'get',
+	});
 }
 /**
  * @description 商品添加编辑-- 用户标签
  */
 export function importCard(data) {
-  return request({
-    url: 'product/product/import_card',
-    method: 'get',
-    params: data,
-  });
+	return request({
+		url: 'product/product/import_card',
+		method: 'get',
+		params: data,
+	});
 }
 
 /**
@@ -405,9 +405,9 @@ export function importCard(data) {
  * @param {Object} param data {Object} 传值参数
  */
 export function batchSetting(data) {
-  return request({
-    url: `product/batch/setting`,
-    method: 'POST',
-    data,
-  });
-}
+	return request({
+		url: `product/batch/setting`,
+		method: 'POST',
+		data,
+	});
+}

File diff suppressed because it is too large
+ 295 - 293
src/api/setting.js


+ 273 - 0
src/api/shop.js

@@ -0,0 +1,273 @@
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2023 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+import request from '@/libs/request';
+
+
+/**
+ * @description 获取商户分类列表
+ */
+export function lst(data) {
+	return request({
+		url: `merchant/category/lst`,
+		method: 'get',
+		data,
+	});
+}
+
+/**
+ * @description 新增商户分类
+ */
+export function addcreate(data) {
+	return request({
+		url: `merchant/category/create`,
+		method: 'POST',
+		data,
+	});
+}
+
+/**
+ * @description 新增商户分类
+ */
+export function getCreate(data) {
+	return request({
+		url: `merchant/category/getCreate`,
+		method: 'get',
+		data,
+	});
+}
+
+
+/**
+ * @description 获取商户分类详情
+ */
+export function getedit(data, id) {
+	return request({
+		url: `merchant/category/${id}/edit`,
+		method: 'get',
+		data,
+	});
+}
+
+/**
+ * @description 修改商户分类信息
+ */
+export function editcategory(data, id) {
+	return request({
+		url: `merchant/category/update/${id}`,
+		method: 'POST',
+		data,
+	});
+}
+
+/**
+ * @description 删除商户分类
+ */
+export function deletecategory(data, id) {
+	return request({
+		url: `merchant/category/delete/${id}`,
+		method: 'get',
+		data,
+	});
+}
+
+/**
+ * @description  获取权限
+ */
+export function getRole(data) {
+	return request({
+		url: `merchant/type/getRole`,
+		method: 'get',
+		data,
+	});
+}
+
+/**
+ * @description  删除类型
+ */
+export function deleteType(data, id) {
+	return request({
+		url: `merchant/type/delete/${id}`,
+		method: 'get',
+		data,
+	});
+}
+
+/**
+ * @description  更新类型类型
+ */
+export function updataType(data, id) {
+	return request({
+		url: `merchant/type/update/${id}`,
+		method: 'POST',
+		data,
+	});
+}
+
+/**
+ * @description  获取修改信息
+ */
+export function getType(data, id) {
+	return request({
+		url: `merchant/type/${id}/edit`,
+		method: 'get',
+		data,
+	});
+}
+
+/**
+ * @description  添加类型
+ */
+export function addType(data) {
+	return request({
+		url: `merchant/type/create`,
+		method: 'POST',
+		data,
+	});
+}
+
+
+/**
+ * @description  获取类型列表
+ */
+export function typeList(data) {
+	return request({
+		url: `merchant/type/lst`,
+		method: 'get',
+		data,
+	});
+}
+
+/**
+ * @description  拒绝申请
+ */
+export function refuse(data, id) {
+	return request({
+		url: `merchant/intention/refuse/${id}`,
+		method: 'get',
+		params: data,
+	});
+}
+
+/**
+ * @description  同意申请
+ */
+export function adopt(data, id) {
+	return request({
+		url: `merchant/intention/adopt/${id}`,
+		method: 'get',
+		data,
+	});
+}
+
+
+/**
+ * @description  申请列表
+ *  * @param {Object} param data {Object} 申请列表传值
+ */
+export function intentionList(data) {
+	return request({
+		url: `merchant/intention/lst`,
+		method: 'get',
+		params: data,
+	});
+}
+
+
+/**
+ * @description  修改密码
+ */
+export function changepwd(data, id) {
+	return request({
+		url: `merchant/admin/update/${id}`,
+		method: 'post',
+		data,
+	});
+}
+
+/**
+ * @description  更新商户数据
+ */
+export function updataadmin(data, id) {
+	return request({
+		url: `merchant/update/${id}`,
+		method: 'post',
+		data,
+	});
+}
+
+/**
+ * @description  添加商户
+ */
+export function addadmin(data) {
+	return request({
+		url: `merchant/create`,
+		method: 'post',
+		data,
+	});
+}
+
+
+/**
+ * @description  获取商户详情
+ */
+export function getmerchent(data, id) {
+	return request({
+		url: `merchant/${id}/edit`,
+		method: 'get',
+		data,
+	});
+}
+
+/**
+ * @description  获取商户列表
+ *  *  * @param {Object} param data {Object} 商户列表传值
+ */
+export function merchentlist(data) {
+	return request({
+		url: `merchant/lst`,
+		method: 'get',
+		params: data
+	});
+}
+
+/**
+ * @description  后台-商户-禁用/正常
+ */
+export function forbidden(data) {
+	return request({
+		url: `merchant/forbidden`,
+		method: 'POST',
+		data,
+	});
+}
+
+/**
+ * @description  后台-商户-开启关闭
+ */
+export function openMerchant(data) {
+	return request({
+		url: `merchant/openMerchant`,
+		method: 'POST',
+		data,
+	});
+}
+
+
+/**
+ * @description  后台-商户-开启关闭
+ */
+export function merchantLoginApi(data, id) {
+	return request({
+		url: `merchant/login/${id}`,
+		method: 'get',
+		data,
+	});
+}

+ 447 - 0
src/api/shop_product.js

@@ -0,0 +1,447 @@
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2023 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+import request from '@/libs/request';
+
+/*
+ * 获取商品表单头数量;
+ * */
+export function getGoodHeade() {
+	return request({
+		url: 'mer/product/type_header',
+		method: 'get',
+	});
+}
+
+/*
+ * 获取商品表单头数量;
+ * */
+export function getGoodsCategory(data) {
+	return request({
+		url: '/goods/goods_category',
+		method: 'get',
+		params: data,
+	});
+}
+
+/**
+ * @description 商品管理-- 列表
+ */
+export function getGoods(params) {
+	return request({
+		url: 'mer/product',
+		method: 'get',
+		params,
+	});
+}
+
+/**
+ * @description 商品管理-- 临时保存
+ */
+export function productCache() {
+	return request({
+		url: 'product/cache',
+		method: 'get',
+	});
+}
+
+/**
+ * @description 商品管理-- 取消临时保存
+ */
+export function cacheDelete() {
+	return request({
+		url: 'product/cache',
+		method: 'delete',
+	});
+}
+
+/**
+ * @description 商品管理-- 上下架
+ */
+export function PostgoodsIsShow(id, isShow) {
+	return request({
+		url: `mer/product/set_show/${id}/${isShow}`,
+		method: 'put',
+	});
+}
+
+/**
+ * @description 商品属性 -- 批量上下架
+ * @param {Object} param data {Object} 传值对象
+ */
+export function productShowApi(data) {
+	return request({
+		url: `mer/product/product_show`,
+		method: 'put',
+		data,
+	});
+}
+
+/**
+ * @description 商品属性 -- 批量下架
+ * @param {Object} param data {Object} 传值对象
+ */
+export function productUnshowApi(data) {
+	return request({
+		url: `mer/product/product_unshow`,
+		method: 'put',
+		data,
+	});
+}
+
+/**
+ * @description 商品管理-- 分类
+ */
+export function treeListApi(type) {
+	return request({
+		url: `mer/category/tree/${type}`,
+		method: 'get',
+	});
+}
+
+/**
+ * @description 商品管理-- 分类 new
+ */
+export function cascaderListApi(type) {
+	return request({
+		url: `mer/category/cascader/${type}`,
+		method: 'get',
+	});
+}
+
+/**
+ * @description 商品管理-- 详情
+ */
+export function productInfoApi(id) {
+	return request({
+		url: `mer/product/${id}`,
+		method: 'get',
+	});
+}
+
+/**
+ * @description 商品管理-- 提交
+ */
+export function productAddApi(data) {
+	return request({
+		url: `mer/product/${data.id}`,
+		method: 'POST',
+		data,
+	});
+}
+
+/**
+ * @description 商品分类 -- 列表
+ * @param {Object} param params {Object} 传值参数
+ */
+export function productListApi(params) {
+	return request({
+		url: 'mer/category',
+		method: 'get',
+		params,
+	});
+}
+
+/**
+ * @description 商品分类 -- 添加表单
+ * @param {Object} param params {Object} 传值参数
+ */
+export function productCreateApi() {
+	return request({
+		url: 'mer/category/create',
+		method: 'get',
+	});
+}
+
+/**
+ * @description 商品分类 -- 添加表单
+ * @param {Object} param params {Object} 传值参数
+ */
+export function productCreate(data) {
+	return request({
+		url: 'mer/category',
+		method: 'POST',
+		data
+	});
+}
+
+/**
+ * @description 商品分类 -- 编辑表单
+ * @param {Object} param params {Object} 传值参数
+ */
+export function productEditApi(id) {
+	return request({
+		url: `mer/category/${id}`,
+		method: 'get',
+	});
+}
+
+/**
+ * @description 商品分类 -- 编辑表单
+ * @param {Object} param params {Object} 传值参数
+ */
+export function productEdit(data, id) {
+	return request({
+		url: `mer/category/${id}`,
+		method: 'PUT',
+		data
+	});
+}
+
+/**
+ * @description 商品分类 -- 修改状态
+ * @param {Object} param params {Object} 传值参数
+ */
+export function setShowApi(data) {
+	return request({
+		url: `mer/category/set_show/${data.id}/${data.is_show}`,
+		method: 'PUT',
+	});
+}
+
+/**
+ * @description 选择商品 -- 列表
+ */
+export function changeListApi(params) {
+	return request({
+		url: `mer/product/list`,
+		method: 'GET',
+		params,
+	});
+}
+
+/**
+ * @description 商品评论 -- 列表
+ * @param {Object} param params {Object} 传值参数
+ */
+export function replyListApi(params) {
+	return request({
+		url: `product/reply`,
+		method: 'get',
+		params,
+	});
+}
+
+/**
+ * @description 商品评论 -- 回复
+ * @param {Object} param data {Object} 传值参数
+ */
+export function setReplyApi(data, id) {
+	return request({
+		url: `product/reply/set_reply/${id}`,
+		method: 'PUT',
+		data,
+	});
+}
+
+/**
+ * @description 获取复制商品配置
+ */
+export function copyConfigApi() {
+	return request({
+		url: `mer/product/copy_config`,
+		method: 'get',
+	});
+}
+
+/**
+ * @description 商品管理 -- 获取京东、淘宝商品数据
+ * @param {Object} param data {Object} 传值参数
+ */
+export function crawlFromApi(data) {
+	return request({
+		url: `mer/product/copy`,
+		method: 'POST',
+		data,
+	});
+}
+
+/**
+ * @description 商品管理 -- 京东、淘宝商品数据提交
+ * @param {Object} param data {Object} 传值参数
+ */
+export function crawlSaveApi(data) {
+	return request({
+		url: `mer/crawl/save`,
+		method: 'POST',
+		data,
+	});
+}
+
+/**
+ * @description 商品管理 -- 生成属性
+ * @param {Object} param data {Object} 传值参数
+ */
+export function generateAttrApi(data, id, type) {
+	return request({
+		url: `mer/generate_attr/${id}/${type}`,
+		method: 'POST',
+		data,
+	});
+}
+
+/**
+ * @description 商品属性 -- 列表
+ * @param {Object} param params {Object} 传值参数
+ */
+export function ruleListApi(params) {
+	return request({
+		url: `mer/product/rule`,
+		method: 'GET',
+		params,
+	});
+}
+
+/**
+ * @description 商品属性 -- 添加
+ * @param {Number} param id {Number} 属性id
+ * @param {Object} param data {Object} 传值参数
+ */
+export function ruleAddApi(data, id) {
+	return request({
+		url: `mer/product/rule/${id}`,
+		method: 'POST',
+		data,
+	});
+}
+
+/**
+ * @description 商品属性 -- 详情
+ * @param {Number} param id {Number} 属性id
+ */
+export function ruleInfoApi(id) {
+	return request({
+		url: `mer/product/rule/${id}`,
+		method: 'get',
+	});
+}
+
+/**
+ * @description 商品评价 -- 虚拟评价
+ * @id--产品id;
+ */
+export function fictitiousReply(id) {
+	return request({
+		url: `product/reply/fictitious_reply/${id}`,
+		method: 'get',
+	});
+}
+
+/**
+ * @description 商品属性 -- 获取规则属性模板
+ */
+export function productGetRuleApi() {
+	return request({
+		url: `mer/product/get_rule`,
+		method: 'get',
+	});
+}
+
+/**
+ * @description 商品 -- 获取运费模板
+ */
+export function productGetTemplateApi() {
+	return request({
+		url: `mer/product/get_template`,
+		method: 'get',
+	});
+}
+
+/**
+ * @description 商品 -- 获取运费模板
+ */
+export function productGetTempKeysApi() {
+	return request({
+		url: `mer/product/get_temp_keys`,
+		method: 'get',
+	});
+}
+
+/**
+ * @description 商铺产品 -- 导出
+ */
+export function storeProductApi(data) {
+	return request({
+		url: `export/storeProduct`,
+		method: 'get',
+		params: data,
+	});
+}
+
+/**
+ * @description 添加商品 -- 检测活动存在
+ */
+export function checkActivityApi(id) {
+	return request({
+		url: `mer/product/check_activity/${id}`,
+		method: 'get',
+	});
+}
+
+/**
+ * @description 商品添加编辑-- 用户标签
+ */
+export function labelListApi() {
+	return request({
+		url: 'user/user_label',
+		method: 'get',
+	});
+}
+/**
+ * @description 组件获取用户标签
+ */
+export function productUserLabel() {
+	return request({
+		url: 'user/user_tree_label',
+		method: 'get',
+	});
+}
+/**
+ * @description 商品添加编辑-- 用户标签
+ */
+export function uploadType() {
+	return request({
+		url: 'mer/file/upload_type',
+		method: 'get',
+	});
+}
+/**
+ * @description 商品添加编辑-- 用户标签
+ */
+export function importCard(data) {
+	return request({
+		url: 'mer/product/import_card',
+		method: 'get',
+		params: data,
+	});
+}
+
+/**
+ * @description 商品批量设置
+ * @param {Number} param id {Number} 属性id
+ * @param {Object} param data {Object} 传值参数
+ */
+export function batchSetting(data) {
+	return request({
+		url: `mer/product/batch/setting`,
+		method: 'POST',
+		data,
+	});
+}
+
+/**
+ * @description 商品列表 -- 头部
+ */
+export function productAttrsApi(id, type) {
+	return request({
+		url: `mer/product/attrs/${id}/${type}`,
+		method: 'GET',
+	});
+}

+ 1156 - 0
src/api/shop_setting.js

@@ -0,0 +1,1156 @@
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2023 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+import request from '@/libs/request';
+import {
+	getCookies
+} from '@/libs/util';
+
+/**
+ * @description 设置 系统设置 应用设置头部
+ * @param {Object} param data {Object} 传值参数 type类型
+ */
+export function headerListApi(data) {
+	return request({
+		url: 'setting/config/header_basics',
+		method: 'get',
+		params: data,
+	});
+}
+
+/**
+ * @description 设置 系统设置 应用设置 编辑表单
+ * @param {Object} param data {Object} 传值参数 type类型
+ */
+export function dataFromApi(data, url) {
+	return request({
+		url: url,
+		method: 'get',
+		params: data,
+	});
+}
+
+/**
+ * @description 设置 短信设置 列表
+ * @param {Object} param params {Object} 传值参数
+ */
+export function tempListApi(params) {
+	return request({
+		url: params.url,
+		method: 'get',
+		params: params.data,
+	});
+}
+
+/**
+ * @description 设置 短信设置 申请模板表单
+ * @param {Object} param data {Object} 传值参数 type类型
+ */
+export function tempCreateApi() {
+	return request({
+		url: 'notify/sms/temp/create',
+		method: 'get',
+	});
+}
+
+/**
+ * @description 设置 短信设置 登录
+ * @param {Object} param data {Object} 传值参数
+ */
+export function configApi(data) {
+	return request({
+		url: 'serve/login',
+		method: 'post',
+		data,
+	});
+}
+
+/**
+ * @description 设置 短信 修改密码
+ */
+export function serveModifyApi(data) {
+	return request({
+		url: 'serve/modify',
+		method: 'post',
+		data,
+	});
+}
+
+/**
+ * @description 设置 短信 修改手机号
+ */
+export function updateHoneApi(data) {
+	return request({
+		url: 'serve/update_phone',
+		method: 'post',
+		data,
+	});
+}
+
+/**
+ * @description 设置 短信设置 修改账户密码
+ * @param {Object} param data {Object} 传值参数
+ */
+// export function configApi (data) {
+//     return request({
+//         url: 'notify/sms/config',
+//         method: 'post',
+//         data
+//     });
+// }
+
+/**
+ * @description 设置 短信设置 发送验证码
+ * @param {Object} param data {Object} 传值参数
+ */
+export function captchaApi(data) {
+	return request({
+		url: 'serve/captcha',
+		method: 'post',
+		data,
+	});
+}
+/**
+ * @description 验证验证码
+ * @param {Object} param data {Object} 传值参数
+ */
+export function checkCaptchaApi(data) {
+	return request({
+		url: 'serve/checkCode',
+		method: 'post',
+		data,
+	});
+}
+
+/**
+ * @description 设置 短信设置 注册
+ * @param {Object} param data {Object} 传值参数
+ */
+export function registerApi(data) {
+	return request({
+		url: 'serve/register',
+		method: 'post',
+		data,
+	});
+}
+
+/**
+ * @description 设置 短信设置 短信剩余条数
+ */
+export function smsNumberApi() {
+	return request({
+		url: 'notify/sms/number',
+		method: 'get',
+	});
+}
+
+/**
+ * @description 设置 短信设置 平台用户信息
+ */
+export function serveInfoApi() {
+	return request({
+		url: 'serve/info',
+		method: 'get',
+	});
+}
+
+/**
+ * @description 修改短信签名
+ */
+export function serveSign(data) {
+	return request({
+		url: 'serve/sms/sign',
+		method: 'PUT',
+		data,
+	});
+}
+
+/**
+ * 客服登录
+ */
+export function kefuLogin(id) {
+	return request({
+		url: `app/wechat/kefu/login/${id}`,
+		method: 'get',
+	});
+}
+
+/**
+ * 客服话术列表
+ */
+export function wechatSpeechcraft(data) {
+	return request({
+		url: `app/wechat/speechcraft`,
+		method: 'get',
+		params: data,
+	});
+}
+
+/**
+ * 客服话术编辑
+ */
+export function speechcraftEdit(id) {
+	return request({
+		url: `app/wechat/speechcraft/${id}/edit`,
+		method: 'get',
+	});
+}
+
+/**
+ * 客服话术添加
+ */
+export function speechcraftCreate() {
+	return request({
+		url: `app/wechat/speechcraft/create`,
+		method: 'get',
+	});
+}
+
+/**
+ * 客服反馈
+ */
+export function kefuFeedBack(params) {
+	return request({
+		url: `app/feedback`,
+		method: 'get',
+		params,
+	});
+}
+
+/**
+ * 客服反馈
+ */
+export function kefuFeedBackEdit(id) {
+	return request({
+		url: `app/feedback/${id}/edit`,
+		method: 'get',
+	});
+}
+
+/**
+ * @description 设置 短信 物流公司
+ */
+export function exportAllApi() {
+	return request({
+		url: 'serve/export_all',
+		method: 'get',
+	});
+}
+
+/**
+ * 是否开通电子面单
+ */
+// export function serveDumpOpen () {
+//     return request({
+//         url: `serve/dump_open`,
+//         method: 'get'
+//     });
+// }
+
+/**
+ * 物流开通
+ */
+export function serveOpen() {
+	return request({
+		url: `serve/open`,
+		method: 'get',
+	});
+}
+
+/**
+ * @description 设置 短信 物流公司面板
+ */
+export function exportTempApi(params) {
+	return request({
+		url: 'serve/export_temp',
+		method: 'get',
+		params,
+	});
+}
+
+/**
+ * @description 设置 短信 2= 电子面单,3 = 物流查询 列表
+ */
+export function serveRecordListApi(params) {
+	return request({
+		url: 'serve/record',
+		method: 'get',
+		params,
+	});
+}
+
+/**
+ * @description 设置 短信 开通其他服务
+ */
+export function serveOpnOtherApi(params) {
+	return request({
+		url: 'serve/open',
+		method: 'get',
+		params,
+	});
+}
+
+/**
+ * @description 设置 短信 开通电子面单
+ */
+export function serveOpnExpressApi(data) {
+	return request({
+		url: 'serve/opn_express',
+		method: 'post',
+		data,
+	});
+}
+
+/**
+ * @description 设置 短信 开通短信服务
+ */
+export function serveSmsOpenApi(params) {
+	return request({
+		url: 'serve/sms/open',
+		method: 'get',
+		params,
+	});
+}
+
+/**
+ * @description 设置 短信设置 支付套餐
+ */
+export function smsPriceApi(params) {
+	return request({
+		url: 'serve/meal_list',
+		method: 'get',
+		params,
+	});
+}
+
+/**
+ * @description 设置 短信设置 支付码
+ * @param {Object} param data {Object} 传值参数
+ */
+export function payCodeApi(data) {
+	return request({
+		url: 'serve/pay_meal',
+		method: 'post',
+		data,
+	});
+}
+
+/**
+ * @description 设置 短信设置 发送记录
+ */
+export function smsRecordApi(params) {
+	return request({
+		url: 'notify/sms/record',
+		method: 'get',
+		params,
+	});
+}
+
+/**
+ * @description 门店设置 详情
+ */
+export function storeApi() {
+	return request({
+		url: 'merchant/store',
+		method: 'GET',
+	});
+}
+
+/**
+ * @description 门店设置 获取地图key
+ */
+export function keyApi() {
+	return request({
+		url: 'merchant/store/address',
+		method: 'GET',
+	});
+}
+
+/**
+ * @description 门店设置 提交数据,
+ * @param {Object} param data {Object} 传值参数
+ */
+export function storeAddApi(data) {
+	return request({
+		url: `merchant/store/${data.id}`,
+		method: 'POST',
+		data,
+	});
+}
+
+/**
+ * @description 设置 物流公司 列表
+ * @param {Object} param data {Object} 传值参数
+ */
+export function freightListApi(params) {
+	return request({
+		url: 'freight/express',
+		method: 'get',
+		params,
+	});
+}
+
+/**
+ * @description 设置 物流公司 新增表单
+ */
+export function freightCreateApi() {
+	return request({
+		url: '/freight/express/create',
+		method: 'get',
+	});
+}
+
+/**
+ * @description 设置 物流公司 编辑表单
+ * @param {Number} param id {Number} 物流公司id
+ */
+export function freightEditApi(id) {
+	return request({
+		url: `freight/express/${id}/edit`,
+		method: 'get',
+	});
+}
+
+/**
+ * @description 设置 物流公司 修改状态
+ * @param {Number} param id {Number} 物流公司id
+ */
+export function freightStatusApi(data) {
+	return request({
+		url: `freight/express/set_status/${data.id}/${data.status}`,
+		method: 'PUT',
+	});
+}
+
+/**
+ * @description 同步物流快递公司
+ */
+export function freightSyncExpressApi() {
+	return request({
+		url: `freight/express/sync_express`,
+		method: 'get',
+	});
+}
+
+/**
+ * @description 话术分类
+ */
+export function speechcraftcate() {
+	return request({
+		url: `app/wechat/speechcraftcate`,
+		method: 'get',
+	});
+}
+/**
+ * @description 渠道码分类
+ */
+export function wechatQrcodeTree() {
+	return request({
+		url: `app/wechat_qrcode/cate/list`,
+		method: 'get',
+	});
+}
+
+/**
+ * @description 获取创建分类表单
+ */
+export function speechcraftcateCreate() {
+	return request({
+		url: `app/wechat/speechcraftcate/create`,
+		method: 'get',
+	});
+}
+/**
+ * @description 获取渠道码创建、编辑分类表单
+ */
+export function wechatQrcodeCreate(id) {
+	return request({
+		url: `app/wechat_qrcode/cate/create/${id}`,
+		method: 'get',
+	});
+}
+
+/**
+ * @description 修改话术分类(获取表单)
+ */
+export function speechcraftcateEdit(id) {
+	return request({
+		url: `app/wechat/speechcraftcate/${id}/edit`,
+		method: 'get',
+	});
+}
+
+/**
+ * @description 设置 身份管理 列表
+ * @param {Number} param id {Number} 物流公司id
+ */
+export function roleListApi(params) {
+	return request({
+		url: `setting/role`,
+		method: 'GET',
+		params,
+	});
+}
+/**
+ * @description 获取渠道码列表
+ * @param {Number} param id {Number} 物流公司id
+ */
+export function wechatQrcodeList(params) {
+	return request({
+		url: `app/wechat_qrcode/list`,
+		method: 'GET',
+		params,
+	});
+}
+
+/**
+ * @description 设置 身份管理 修改状态
+ * @param {Object} param data {Object} 传值参数
+ */
+export function roleSetStatusApi(data) {
+	return request({
+		url: `setting/role/set_status/${data.id}/${data.status}`,
+		method: 'PUT',
+	});
+}
+
+/**
+ * @description 设置 身份管理 ==新增 编辑
+ * @param {Object} param data {Object} 传值参数
+ */
+export function roleCreatApi(data) {
+	return request({
+		url: `setting/role/${data.id}`,
+		method: 'post',
+		data,
+	});
+}
+
+/**
+ * @description 设置 身份管理 ==详情
+ * @param {Number} param id {Number} 身份管理id
+ */
+export function roleInfoApi(id) {
+	return request({
+		url: `setting/role/${id}/edit`,
+		method: 'get',
+	});
+}
+
+/**
+ * @description 设置 身份管理 ==权限列表
+ */
+export function menusListApi() {
+	return request({
+		url: `setting/role/create`,
+		method: 'get',
+	});
+}
+
+/**
+ * @description 设置 客服管理 -- 列表
+ * @param {Object} param params {Object} 传值参数
+ */
+export function kefuListApi(params) {
+	return request({
+		url: `app/wechat/kefu`,
+		method: 'get',
+		params,
+	});
+}
+
+/**
+ * @description 设置 客服管理 -- 选择用户
+ *  @param {Object} param params {Object} 传值参数
+ */
+export function kefucreateApi(params) {
+	return request({
+		url: `app/wechat/kefu/create`,
+		method: 'get',
+		params,
+	});
+}
+
+/**
+ * @description 设置 客服管理 -- 添加客服
+ *  @param {Object} param params {Object} 传值参数
+ */
+export function kefuaddApi() {
+	return request({
+		url: `app/wechat/kefu/add`,
+		method: 'get',
+	});
+}
+
+/**
+ * @description 设置 客服管理 -- 添加客服保存
+ *  @param {Object} param params {Object} 传值参数
+ */
+export function kefuAddApi(data) {
+	return request({
+		url: `app/wechat/kefu`,
+		method: 'post',
+		data,
+	});
+}
+
+/**
+ * @description 设置 客服管理 -- 修改状态
+ *  @param {Object} param data {Object} 传值参数
+ */
+export function kefusetStatusApi(data) {
+	return request({
+		url: `app/wechat/kefu/set_status/${data.id}/${data.status}`,
+		method: 'PUT',
+	});
+}
+
+/**
+ * @description 设置 渠道码 -- 修改状态
+ *  @param {Object} param data {Object} 传值参数
+ */
+export function wechatQrcodeStatusApi(data) {
+	return request({
+		url: `app/wechat_qrcode/set_status/${data.id}/${data.status}`,
+		method: 'PUT',
+	});
+}
+/**
+ * @description 获取渠道码用户列表
+ *  @param {Object} param data {Object} 传值参数
+ */
+export function getUserList(params) {
+	return request({
+		url: `app/wechat_qrcode/user_list/${params.id}`,
+		method: 'get',
+		params,
+	});
+}
+/**
+ * @description 设置 渠道码编辑详情获取
+ *  @param {Object} param data {Object} 传值参数
+ */
+export function wechatQrcodeDetail(id) {
+	return request({
+		url: `app/wechat_qrcode/info/${id}`,
+		method: 'get',
+	});
+}
+/**
+ * @description  渠道码制作--保存
+ */
+export function wechatQrcodeSaveApi(id, data) {
+	return request({
+		url: `app/wechat_qrcode/save/${id}`,
+		method: 'post',
+		data,
+	});
+}
+/**
+ * @description 设置 客服管理 -- 编辑表单
+ *  @param {Number} param id {Number} 客服id
+ */
+export function kefuEditApi(id) {
+	return request({
+		url: `app/wechat/kefu/${id}/edit`,
+		method: 'GET',
+	});
+}
+
+/**
+ * @description 设置 客服管理 -- 聊天记录列表
+ *  @param {Number} param id {Number} 客服id
+ *  @param {Object} param params {Object} 传参数
+ */
+export function kefuRecordApi(params, id) {
+	return request({
+		url: `app/wechat/kefu/record/${id}`,
+		method: 'GET',
+		params,
+	});
+}
+
+/**
+ * @description 设置 客服管理 -- 查看对话列表
+ *  @param {Object} param params {Object} 传参数
+ */
+export function kefuChatlistApi(params) {
+	return request({
+		url: `app/wechat/kefu/chat_list`,
+		method: 'GET',
+		params,
+	});
+}
+
+/**
+ * @description 短信设置 -- 查看是否登录
+ */
+export function isLoginApi() {
+	return request({
+		url: `notify/sms/is_login`,
+		method: 'GET',
+	});
+}
+
+/**
+ * @description 短信设置 -- 退出登录
+ */
+export function logoutApi() {
+	return request({
+		url: `notify/sms/logout`,
+		method: 'GET',
+	});
+}
+
+/**
+ * @description 设置 城市数据 -- 列表
+ *  @param {Object} param data {Object} 传值参数
+ */
+export function cityListApi(id) {
+	return request({
+		url: `setting/city/list/${id}`,
+		method: 'get',
+	});
+}
+
+/**
+ * @description 设置 城市添加 -- 表单
+ *  @param {Object} param data {Object} 传值参数
+ */
+export function cityAddApi(id) {
+	return request({
+		url: `setting/city/add/${id}`,
+		method: 'get',
+	});
+}
+
+/**
+ * @description 设置 城市修改 -- 表单
+ *  @param {Object} param data {Object} 传值参数
+ */
+export function cityApi(id) {
+	return request({
+		url: `setting/city/${id}/edit`,
+		method: 'get',
+	});
+}
+
+/**
+ * @description 设置 运费模板 -- 列表
+ *  @param {Object} param data {Object} 传值参数
+ */
+export function templatesApi(data) {
+	return request({
+		url: `mer/shipping_templates/list`,
+		method: 'get',
+		params: data,
+	});
+}
+
+/**
+ * @description 设置 运费模板 -- 城市数据
+ */
+export function templatesCityListApi(data) {
+	return request({
+		url: `mer/shipping_templates/city_list`,
+		method: 'get',
+	});
+}
+
+/**
+ * @description 设置 运费模板 -- 提交修改表单;
+ */
+export function templatesSaveApi(id, data) {
+	return request({
+		url: `mer/shipping_templates/save/${id}`,
+		method: 'post',
+		data,
+	});
+}
+
+/**
+ * @description 设置 运费模板 -- 提交修改表单;
+ */
+export function shipTemplatesApi(id) {
+	return request({
+		url: `mer/shipping_templates/${id}/edit`,
+		method: 'get',
+	});
+}
+
+/**
+ * @description 门店设置 -- 门店列表分类数量;
+ */
+export function storeGetHeaderApi() {
+	return request({
+		url: `merchant/store/get_header`,
+		method: 'get',
+	});
+}
+
+/**
+ * @description 门店设置 -- 门店列表;
+ */
+export function merchantStoreApi(data) {
+	return request({
+		url: `merchant/store`,
+		method: 'get',
+		params: data,
+	});
+}
+
+/**
+ * @description 门店设置 -- 门店设置;
+ */
+export function storeSetShowApi(id, is_show) {
+	return request({
+		url: `merchant/store/set_show/${id}/${is_show}`,
+		method: 'put',
+	});
+}
+
+/**
+ * @description 门店设置 -- 门店修改信息;
+ */
+export function storeGetInfoApi(id) {
+	return request({
+		url: `merchant/store/get_info/${id}`,
+		method: 'get',
+	});
+}
+
+/**
+ * @description 门店设置 -- 店员列表;
+ */
+export function storeStaffApi(data) {
+	return request({
+		url: `merchant/store_staff`,
+		method: 'get',
+		params: data,
+	});
+}
+
+/**
+ * @description 门店设置 -- 新增店员;
+ */
+export function storeStaffCreateApi() {
+	return request({
+		url: `merchant/store_staff/create`,
+		method: 'get',
+	});
+}
+
+/**
+ * @description 门店设置 -- 新增店员;
+ */
+export function storeStaffEditApi(id) {
+	return request({
+		url: `merchant/store_staff/${id}/edit`,
+		method: 'get',
+	});
+}
+
+/**
+ * @description 店员设置 -- 店员设置显示隐藏;
+ */
+export function storeStaffSetShowApi(id, is_show) {
+	return request({
+		url: `merchant/store_staff/set_show/${id}/${is_show}`,
+		method: 'put',
+	});
+}
+
+/**
+ * @description 订单设置 -- 核销订单列表;
+ */
+export function verifyOrderApi(data) {
+	return request({
+		url: `merchant/verify_order`,
+		method: 'get',
+		params: data,
+	});
+}
+
+/**
+ * @description 订单设置 -- 核销订单头部;
+ */
+export function verifySpreadInfoApi(uid) {
+	return request({
+		url: `merchant/verify/spread_info/${uid}`,
+		method: 'get',
+	});
+}
+
+/**
+ * 获取店员搜索门店列表
+ */
+export function merchantStoreListApi() {
+	return request({
+		url: `merchant/store_list`,
+		method: 'get',
+	});
+}
+
+/**
+ * 清除城市数据缓存
+ */
+export function cityCleanCacheApi() {
+	return request({
+		url: `setting/city/clean_cache`,
+		method: 'get',
+	});
+}
+/**
+ *储存配置-获取云储存配置头
+ */
+export function storageConfigApi() {
+	return request({
+		url: `system/config/storage/config`,
+		method: 'get',
+	});
+}
+/**
+ *储存配置-获取云储存配置头
+ */
+export function storageSwitchApi(data) {
+	return request({
+		url: `system/config/storage/config`,
+		method: 'post',
+		data,
+	});
+}
+
+/**
+ * @description 储存配置-获取云储存配置表单
+ */
+export function addConfigApi(type) {
+	return request({
+		url: `system/config/storage/form/${type}`,
+		method: 'get',
+	});
+}
+
+/**
+ * @description 储存配置-获取云存储创建表单
+ */
+export function addStorageApi(type) {
+	return request({
+		url: `system/config/storage/create/${type}`,
+		method: 'get',
+	});
+}
+
+/**
+ * @description 储存配置-获取云存储列表
+ */
+export function storageListApi(data) {
+	return request({
+		url: `system/config/storage`,
+		method: 'get',
+		params: data,
+	});
+}
+
+/**
+ * @description 储存配置-同步空间
+ */
+export function storageSynchApi(type) {
+	return request({
+		url: `system/config/storage/synch/${type}`,
+		method: 'put',
+	});
+}
+/**
+ * @description 储存配置-修改状态
+ */
+export function storageStatusApi(id) {
+	return request({
+		url: `system/config/storage/status/${id}`,
+		method: 'put',
+	});
+}
+
+/**
+ * @description 储存配置-修改空间域名
+ */
+export function editStorageApi(id) {
+	return request({
+		url: `system/config/storage/domain/${id}`,
+		method: 'get',
+	});
+}
+/**
+ * @description 储存配置-获取缩略图
+ */
+export function positionInfoApi() {
+	return request({
+		url: `setting/config_list/31`,
+		method: 'get',
+	});
+}
+/**
+ * @description 储存配置-保存缩略图
+ */
+export function positionPostApi(data) {
+	return request({
+		url: `setting/config/save_basics`,
+		method: 'post',
+		data,
+	});
+}
+
+/**
+ * @description 储存配置切换
+ */
+export function saveType(type) {
+	return request({
+		url: `system/config/storage/save_type/${type}`,
+		method: 'get',
+	});
+}
+
+/**
+ * @description 多语言-语言类型列表
+ */
+export function langTypeList(data) {
+	return request({
+		url: `setting/lang_type/list`,
+		method: 'get',
+		params: data,
+	});
+}
+
+/**
+ * @description 多语言-语言类型新增编辑
+ * @param {Number} param id {Number}
+ */
+export function langTypeForm(id) {
+	return request({
+		url: `setting/lang_type/form/${id}`,
+		method: 'get',
+	});
+}
+
+/**
+ * @description 多语言-语言详情列表
+ */
+export function langCodeList(data) {
+	return request({
+		url: `setting/lang_code/list`,
+		method: 'get',
+		params: data,
+	});
+}
+
+/**
+ * @description 获取语言信息
+ */
+export function langCodeInfo(data) {
+	return request({
+		url: `setting/lang_code/info`,
+		method: 'get',
+		params: data,
+	});
+}
+
+/**
+ * @description 修改语言详情
+ */
+export function langCodeSettingSave(data) {
+	return request({
+		url: `setting/lang_code/save`,
+		method: 'post',
+		data,
+	});
+}
+
+/**
+ * @description 国家列表
+ */
+export function langCountryList(data) {
+	return request({
+		url: `setting/lang_country/list`,
+		method: 'get',
+		params: data,
+	});
+}
+/**
+ * 添加语言地区表单
+ * @param {*} id
+ * @returns
+ */
+export function langCountryForm(id) {
+	return request({
+		url: `setting/lang_country/form/${id}`,
+		method: 'get',
+	});
+}
+/**
+ * 添加语言地区表单
+ * @param {*} id
+ * @returns
+ */
+export function langTypeStatus(id, status) {
+	return request({
+		url: `setting/lang_type/status/${id}/${status}`,
+		method: 'put',
+	});
+}
+
+/**
+ * @description 一键翻译
+ */
+export function langCodeTranslate(data) {
+	return request({
+		url: `setting/lang_code/translate`,
+		method: 'post',
+		data,
+	});
+}
+
+/**
+ * @description 代码生成
+ */
+export function codeCrud(data) {
+	return request({
+		url: `system/crud`,
+		method: 'post',
+		data,
+	});
+}
+/**
+ * @description 图片上传
+ */
+export function fileUpload(data) {
+	return request({
+		url: `file/upload`,
+		method: 'post',
+		headers: {
+			'Authori-zation': 'Bearer ' + getCookies('token'),
+			'content-type': 'multipart/form-data;' + 'Bearer ' + getCookies('token'),
+		},
+		data,
+	});
+}
+
+/**
+ * @description 图片上传
+ */
+export function shopfileUpload(data) {
+	return request({
+		url: `mer/file/upload`,
+		method: 'post',
+		headers: {
+			'Authori-zation': 'Bearer ' + getCookies('token'),
+			'content-type': 'multipart/form-data;' + 'Bearer ' + getCookies('token'),
+		},
+		data,
+	});
+}

+ 104 - 0
src/api/shopuploadPictures.js

@@ -0,0 +1,104 @@
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2023 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+import request from '@/libs/request';
+
+/**
+ * @description 附件分类--列表
+ * @param {Object} param data {Object} 传值参数
+ */
+export function getCategoryListApi(data) {
+	return request({
+		url: 'mer/file/category',
+		method: 'get',
+		params: data,
+	});
+}
+
+/**
+ * @description 添加分类
+ */
+export function createApi(id) {
+	return request({
+		url: 'mer/file/category/create',
+		method: 'get',
+		params: id,
+	});
+}
+
+/**
+ * @description 编辑分类
+ * @param {Number} param id {Number} 分类id
+ */
+export function categoryEditApi(id) {
+	return request({
+		url: `mer/file/category/${id}/edit`,
+		method: 'get',
+	});
+}
+
+/**
+ * @description 删除分类
+ * @param {Number} param id {Number} 分类id
+ */
+export function categoryDelApi(id) {
+	return request({
+		url: `mer/file/category/${id}`,
+		method: 'DELETE',
+	});
+}
+
+/**
+ * @description 附件列表
+ * @param {Object} param data {Object} 传值
+ */
+export function fileListApi(data) {
+	return request({
+		url: 'mer/file/file',
+		method: 'get',
+		params: data,
+	});
+}
+
+/**
+ * @description 移动分类,修改附件分类表单
+ * @param {Object} param data {Object} 传值
+ */
+export function moveApi(data) {
+	return request({
+		url: 'mer/file/file/do_move',
+		method: 'put',
+		data,
+	});
+}
+
+/**
+ * @description 修改附件名称
+ * @param {String} param ids {String} 图片id拼接成的字符串
+ */
+export function fileUpdateApi(ids, data) {
+	return request({
+		url: 'mer/file/file/update/' + ids,
+		method: 'put',
+		data,
+	});
+}
+
+/**
+ * @description 删除附件
+ * @param {String} param ids {String} 图片id拼接成的字符串
+ */
+export function fileDelApi(ids) {
+	return request({
+		url: 'file/file/delete',
+		method: 'post',
+		data: ids,
+	});
+}

+ 19 - 6
src/api/upload.js

@@ -15,10 +15,23 @@ import request from '@/libs/request';
  * @param {Object} param data {Object} 传值参数
  */
 export function upload(data, config) {
-  return request({
-    url: 'file/video_upload',
-    method: 'post',
-    file: true,
-    data,
-  });
+	return request({
+		url: 'file/video_upload',
+		method: 'post',
+		file: true,
+		data,
+	});
 }
+
+/**
+ * @description 上传
+ * @param {Object} param data {Object} 传值参数
+ */
+export function uploads(data, config) {
+	return request({
+		url: 'mer/file/video_upload',
+		method: 'post',
+		file: true,
+		data,
+	});
+}

+ 39 - 39
src/api/uploadPictures.js

@@ -15,22 +15,22 @@ import request from '@/libs/request';
  * @param {Object} param data {Object} 传值参数
  */
 export function getCategoryListApi(data) {
-  return request({
-    url: 'file/category',
-    method: 'get',
-    params: data,
-  });
+	return request({
+		url: 'file/category',
+		method: 'get',
+		params: data,
+	});
 }
 
 /**
  * @description 添加分类
  */
 export function createApi(id) {
-  return request({
-    url: 'file/category/create',
-    method: 'get',
-    params: id,
-  });
+	return request({
+		url: 'file/category/create',
+		method: 'get',
+		params: id,
+	});
 }
 
 /**
@@ -38,10 +38,10 @@ export function createApi(id) {
  * @param {Number} param id {Number} 分类id
  */
 export function categoryEditApi(id) {
-  return request({
-    url: `file/category/${id}/edit`,
-    method: 'get',
-  });
+	return request({
+		url: `file/category/${id}/edit`,
+		method: 'get',
+	});
 }
 
 /**
@@ -49,10 +49,10 @@ export function categoryEditApi(id) {
  * @param {Number} param id {Number} 分类id
  */
 export function categoryDelApi(id) {
-  return request({
-    url: `file/category/${id}`,
-    method: 'DELETE',
-  });
+	return request({
+		url: `file/category/${id}`,
+		method: 'DELETE',
+	});
 }
 
 /**
@@ -60,11 +60,11 @@ export function categoryDelApi(id) {
  * @param {Object} param data {Object} 传值
  */
 export function fileListApi(data) {
-  return request({
-    url: 'file/file',
-    method: 'get',
-    params: data,
-  });
+	return request({
+		url: 'file/file',
+		method: 'get',
+		params: data,
+	});
 }
 
 /**
@@ -72,11 +72,11 @@ export function fileListApi(data) {
  * @param {Object} param data {Object} 传值
  */
 export function moveApi(data) {
-  return request({
-    url: 'file/file/do_move',
-    method: 'put',
-    data,
-  });
+	return request({
+		url: 'file/file/do_move',
+		method: 'put',
+		data,
+	});
 }
 
 /**
@@ -84,11 +84,11 @@ export function moveApi(data) {
  * @param {String} param ids {String} 图片id拼接成的字符串
  */
 export function fileUpdateApi(ids, data) {
-  return request({
-    url: 'file/file/update/' + ids,
-    method: 'put',
-    data,
-  });
+	return request({
+		url: 'file/file/update/' + ids,
+		method: 'put',
+		data,
+	});
 }
 
 /**
@@ -96,9 +96,9 @@ export function fileUpdateApi(ids, data) {
  * @param {String} param ids {String} 图片id拼接成的字符串
  */
 export function fileDelApi(ids) {
-  return request({
-    url: 'file/file/delete',
-    method: 'post',
-    data: ids,
-  });
-}
+	return request({
+		url: 'file/file/delete',
+		method: 'post',
+		data: ids,
+	});
+}

+ 292 - 0
src/components/freightTemplate2/city.vue

@@ -0,0 +1,292 @@
+<template>
+	<div>
+		<Modal v-model="addressModal" title="选择可配送区域" width="50%" class="modal" :mask="true">
+			<Row :gutter="24" type="flex">
+				<Col :xl="24" :lg="24" :md="24" :sm="24" :xs="24" class="item">
+				<div class="acea-row row-right row-middle">
+					<Checkbox v-model="iSselect" @on-change="allCheckbox">全选</Checkbox>
+					<div class="empty" @click="empty">清空</div>
+				</div>
+				</Col>
+			</Row>
+			<Row :gutter="24" type="flex" :loading="loading">
+				<Col :xl="6" :lg="6" :md="6" :sm="8" :xs="6" class="item" v-for="(item, index) in cityList" :key="index"
+					v-if="item.isShow">
+				<div @mouseenter="enter(index)" @mouseleave="leave()">
+					<Checkbox v-model="item.checked" :label="item.name" @on-change="checkedClick(index)">{{
+              item.name
+            }}</Checkbox><span class="red">({{ (item.count || 0) + '/' + item.childNum }})</span>
+					<div class="city" v-show="activeCity === index">
+						<div class="checkBox">
+							<div class="arrow"></div>
+							<div>
+								<Checkbox v-model="city.checked" :label="city.name" @on-change="primary(index, indexn)"
+									class="itemn" v-for="(city, indexn) in item.children" :key="indexn"
+									v-show="city.isShow">{{ city.name }}</Checkbox>
+							</div>
+						</div>
+					</div>
+				</div>
+				</Col>
+			</Row>
+			<div slot="footer">
+				<Button @click="close">取消</Button>
+				<Button type="primary" @click="confirm">确定</Button>
+			</div>
+			<Spin size="large" fix v-if="loading"></Spin>
+		</Modal>
+	</div>
+</template>
+
+<script>
+	import {
+		mapState
+	} from 'vuex';
+	import {
+		templatesCityListApi
+	} from '@/api/shop_setting';
+	export default {
+		name: 'city',
+		props: {
+			type: {
+				type: Number,
+				default: 0,
+			},
+			selectArr: {
+				type: Array,
+				default: [],
+			},
+		},
+		data() {
+			return {
+				iSselect: false,
+				addressModal: false,
+				cityList: [],
+				activeCity: -1,
+				loading: false,
+			};
+		},
+		computed: {},
+		methods: {
+			enter(index) {
+				this.activeCity = index;
+			},
+			leave() {
+				this.activeCity = null;
+			},
+			getCityList() {
+				this.loading = true;
+				templatesCityListApi().then((res) => {
+					this.loading = false;
+					this.selectArr = [];
+					res.data.forEach((el, index, arr) => {
+						el.isShow = true;
+						el.children.forEach((child, j) => {
+							child.isShow = true;
+							if (this.selectArr.length > 0) {
+								this.selectArr.forEach((sel, sindex) => {
+									sel.children.forEach((sitem, sj) => {
+										if (child.city_id == sitem.city_id) {
+											child.isShow = false;
+										}
+									});
+								});
+							}
+						});
+					});
+					res.data.forEach((el, index, arr) => {
+						let num = 0;
+						let oldNum = 0;
+						el.children.forEach((child, j) => {
+							if (!child.isShow) {
+								num++;
+							} else {
+								oldNum++;
+							}
+						});
+						if (num == el.children.length) {
+							el.isShow = false;
+						}
+						el.childNum = oldNum;
+					});
+					this.cityList = res.data;
+				});
+			},
+			/**
+			 * 全选或者反选
+			 * @param checked
+			 */
+			allCheckbox: function() {
+				let that = this,
+					checked = this.iSselect;
+				that.cityList.forEach(function(item, key) {
+					that.$set(that.cityList[key], 'checked', checked);
+					if (checked) {
+						that.$set(that.cityList[key], 'count', that.cityList[key].children.length);
+					} else {
+						that.$set(that.cityList[key], 'count', 0);
+					}
+					that.cityList[key].children.forEach(function(val, k) {
+						that.$set(that.cityList[key].children[k], 'checked', checked);
+					});
+				});
+				// this.render();
+			},
+			// 清空;
+			empty() {
+				let that = this;
+				that.cityList.forEach(function(item, key) {
+					that.$set(that.cityList[key], 'checked', false);
+					that.cityList[key].children.forEach(function(val, k) {
+						that.$set(that.cityList[key].children[k], 'checked', false);
+					});
+					that.$set(that.cityList[key], 'count', 0);
+				});
+				this.iSselect = false;
+			},
+			/**
+			 * 点击省
+			 * @param index
+			 */
+			checkedClick: function(index) {
+				let that = this;
+				if (that.cityList[index].checked) {
+					that.$set(that.cityList[index], 'count', that.cityList[index].childNum);
+					that.cityList[index].children.forEach(function(item, key) {
+						that.$set(that.cityList[index].children[key], 'checked', true);
+					});
+				} else {
+					that.$set(that.cityList[index], 'count', 0);
+					that.$set(that.cityList[index], 'checked', false);
+					that.cityList[index].children.forEach(function(item, key) {
+						that.$set(that.cityList[index].children[key], 'checked', false);
+					});
+					that.iSselect = false;
+				}
+				// this.render();
+			},
+			/**
+			 * 点击市区
+			 * @param index
+			 * @param ind
+			 */
+			primary: function(index, ind) {
+				let checked = false,
+					count = 0;
+				this.cityList[index].children.forEach(function(item, key) {
+					if (item.checked) {
+						checked = true;
+						count++;
+					}
+				});
+				this.$set(this.cityList[index], 'count', count);
+				this.$set(this.cityList[index], 'checked', checked);
+				// this.render();
+			},
+			// 确定;
+			confirm() {
+				let that = this;
+				// 被选中的省市;
+				let selectList = [];
+				that.cityList.forEach(function(item, key) {
+					let data = {};
+					if (item.checked) {
+						data = {
+							name: item.name,
+							city_id: item.city_id,
+							children: [],
+						};
+					}
+					that.cityList[key].children.forEach(function(i, k) {
+						if (i.checked) {
+							data.children.push({
+								city_id: i.city_id,
+							});
+						}
+					});
+					if (data.city_id !== undefined) {
+						selectList.push(data);
+					}
+				});
+				if (selectList.length === 0) {
+					return that.$Message.error('至少选择一个省份或者城市');
+				} else {
+					this.$emit('selectCity', selectList, this.type);
+					that.addressModal = false;
+					this.cityList = [];
+				}
+				// parent.selectCity(selectList,type);
+				// var index = parent.layer.getFrameIndex(window.name);
+				// parent.layer.close(index);
+			},
+			close() {
+				this.addressModal = false;
+				this.cityList = [];
+			},
+		},
+		mounted() {
+			// this.getCityList();
+		},
+	};
+</script>
+
+<style scoped lang="stylus">
+	.modal .item {
+		margin-bottom: 20px;
+	}
+
+	.modal .item .city {
+		position: absolute;
+		z-index: 9;
+		top: 17px;
+		width: 100%;
+		padding-top: 18px;
+	}
+
+	.modal .item .city .checkBox {
+		width: 97%;
+		padding: 10px;
+		border: 1px solid #eee;
+		background-color: #fff;
+		max-height: 100px;
+		overflow-x: hidden;
+		overflow-y: auto;
+	}
+
+	.modal .item .city .checkBox .arrow {
+		position: absolute;
+		top: 3px;
+		width: 0;
+		height: 0;
+		border: 8px solid transparent;
+		border-bottom-color: #ddd;
+	}
+
+	.modal .item .city .checkBox .arrow:before {
+		position: absolute;
+		bottom: -8px;
+		right: -7px;
+		content: '';
+		width: 0;
+		height: 0;
+		border: 7px solid transparent;
+		border-bottom-color: #fff;
+	}
+
+	.modal .item .city .checkBox .itemn {
+		margin-bottom: 10px;
+	}
+
+	.radio {
+		padding: 5px 0;
+		font-size: 14px !important;
+	}
+
+	.red {
+		color: #ff0000;
+	}
+
+	.empty {
+		cursor: pointer;
+	}
+</style>

+ 584 - 0
src/components/freightTemplate2/index.vue

@@ -0,0 +1,584 @@
+<template>
+	<div>
+		<Modal v-model="isTemplate" title="运费模版" width="70%" if="isTemplate" @on-cancel="cancel"
+			@on-visible-change="close">
+			<div class="Modals">
+				<Form class="form" ref="formData" :label-width="120" label-position="right">
+					<Row :gutter="24" type="flex">
+						<Col :xl="18" :lg="18" :md="18" :sm="24" :xs="24">
+						<FormItem label="模板名称:" prop="name">
+							<Input type="text" placeholder="请输入模板名称" :maxlength="20" v-model="formData.name" />
+						</FormItem>
+						</Col>
+					</Row>
+					<Row :gutter="24" type="flex">
+						<Col :xl="18" :lg="18" :md="18" :sm="24" :xs="24">
+						<FormItem label="计费方式:" props="state" label-for="state">
+							<RadioGroup class="radio" v-model="formData.type" @on-change="changeRadio"
+								element-id="state">
+								<Radio :label="1">按件数</Radio>
+								<Radio :label="2">按重量</Radio>
+								<Radio :label="3">按体积</Radio>
+							</RadioGroup>
+						</FormItem>
+						</Col>
+					</Row>
+					<Row :gutter="24" type="flex">
+						<Col :xl="24" :lg="24" :md="24" :sm="24" :xs="24">
+						<FormItem class="label" label="配送区域及运费:" props="state" label-for="state">
+							<Table ref="table" :columns="columns" :data="templateList" class="ivu-mt"
+								no-data-text="暂无数据" border>
+								<template slot-scope="{ row, index }" slot="action">
+									<a v-if="row.regionName !== '默认全国'" @click="delCity(row, '配送区域', index, 1)">删除</a>
+								</template>
+							</Table>
+							<Row type="flex" class="addTop">
+								<Col>
+								<Button type="primary" icon="md-add" @click="addCity(1)">单独添加配送区域</Button>
+								</Col>
+							</Row>
+						</FormItem>
+						</Col>
+					</Row>
+					<Row :gutter="24" type="flex">
+						<Col :xl="24" :lg="24" :md="24" :sm="24" :xs="24">
+						<FormItem label="指定包邮:" prop="store_name" label-for="store_name">
+							<Radio-group class="radio" v-model="formData.appoint_check">
+								<Radio :label="1">开启</Radio>
+								<Radio :label="0">关闭</Radio>
+							</Radio-group>
+							<Table ref="table" :columns="columns2" :data="appointList" class="addTop ivu-mt"
+								no-data-text="暂无数据" border v-if="formData.appoint_check === 1">
+								<template slot-scope="{ row, index }" slot="action">
+									<a v-if="row.regionName !== '默认全国'" @click="delCity(row, '配送区域', index, 2)">删除</a>
+								</template>
+							</Table>
+							<Row type="flex" class="addTop" v-if="formData.appoint_check === 1">
+								<Col>
+								<Button type="primary" icon="md-add" @click="addCity(2)">单独指定包邮</Button>
+								</Col>
+							</Row>
+						</FormItem>
+						</Col>
+					</Row>
+					<Row :gutter="24" type="flex">
+						<Col :xl="24" :lg="24" :md="24" :sm="24" :xs="24">
+						<FormItem label="指定不送达:" prop="store_name" label-for="store_name">
+							<Radio-group class="radio" v-model="formData.no_delivery_check">
+								<Radio :label="1">开启</Radio>
+								<Radio :label="0">关闭</Radio>
+							</Radio-group>
+							<Table ref="table" :columns="columns3" :data="noDeliveryList" class="addTop ivu-mt"
+								no-data-text="暂无数据" border v-if="formData.no_delivery_check === 1">
+								<template slot-scope="{ row, index }" slot="action">
+									<a v-if="row.regionName !== '默认全国'" @click="delCity(row, '配送区域', index, 3)">删除</a>
+								</template>
+							</Table>
+							<Row type="flex" class="addTop" v-if="formData.no_delivery_check === 1">
+								<Col>
+								<Button type="primary" icon="md-add" @click="addCity(3)">单独指定不送达</Button>
+								</Col>
+							</Row>
+						</FormItem>
+						</Col>
+					</Row>
+					<Row :gutter="24" type="flex">
+						<Col :xl="18" :lg="18" :md="18" :sm="24" :xs="24">
+						<FormItem label="排序:" prop="store_name" label-for="store_name">
+							<InputNumber :min="0" placeholder="输入值越大越靠前" v-model="formData.sort"></InputNumber>
+						</FormItem>
+						</Col>
+					</Row>
+					<Row :gutter="24" type="flex">
+						<Col>
+						<FormItem prop="store_name" label-for="store_name">
+							<Button type="primary" @click="handleSubmit">{{ id ? '立即修改' : '立即提交' }}</Button>
+						</FormItem>
+						</Col>
+					</Row>
+				</Form>
+			</div>
+			<div slot="footer"></div>
+		</Modal>
+		<city ref="city" @selectCity="selectCity" :type="type" :selectArr="selectArr"></city>
+	</div>
+</template>
+
+<script>
+	import {
+		mapState
+	} from 'vuex';
+	import city from '@/components/freightTemplate2/city';
+	import {
+		templatesSaveApi,
+		shipTemplatesApi
+	} from '@/api/shop_setting';
+	export default {
+		name: 'freightTemplate',
+		components: {
+			city
+		},
+		props: {},
+		data() {
+			let that = this;
+			return {
+				isTemplate: false,
+				columns: [{
+						title: '可配送区域',
+						key: 'regionName',
+						minWidth: 100,
+						render: (h, params) => {
+							return h('Input', {
+								props: {
+									type: 'text',
+									readonly: true,
+									size: 'small',
+									value: that.templateList[params.index].regionName,
+								},
+							});
+						},
+					},
+					{
+						title: '首件',
+						key: 'first',
+						minWidth: 70,
+						render: (h, params) => {
+							return h('Input', {
+								props: {
+									type: 'number',
+									size: 'small',
+									value: that.templateList[params.index].first, // 此处如何让数据双向绑定
+								},
+								on: {
+									'on-change': (event) => {
+										that.templateList[params.index].first = event.target.value;
+									},
+								},
+							});
+						},
+					},
+					{
+						title: '运费(元)',
+						key: 'price',
+						minWidth: 70,
+						render: (h, params) => {
+							return h('Input', {
+								props: {
+									type: 'number',
+									size: 'small',
+									value: that.templateList[params.index].price, // 此处如何让数据双向绑定
+								},
+								on: {
+									'on-change': (event) => {
+										that.templateList[params.index].price = event.target.value;
+									},
+								},
+							});
+						},
+					},
+					{
+						title: '续件',
+						key: 'continue',
+						minWidth: 70,
+						render: (h, params) => {
+							return h('Input', {
+								props: {
+									type: 'number',
+									size: 'small',
+									value: that.templateList[params.index].continue, // 此处如何让数据双向绑定
+								},
+								on: {
+									'on-change': (event) => {
+										that.templateList[params.index].continue = event.target.value;
+									},
+								},
+							});
+						},
+					},
+					{
+						title: '续费(元)',
+						key: 'continue_price',
+						minWidth: 70,
+						render: (h, params) => {
+							return h('Input', {
+								props: {
+									type: 'number',
+									size: 'small',
+									value: that.templateList[params.index].continue_price, // 此处如何让数据双向绑定
+								},
+								on: {
+									'on-change': (event) => {
+										that.templateList[params.index].continue_price = event.target
+											.value;
+									},
+								},
+							});
+						},
+					},
+					{
+						title: '操作',
+						slot: 'action',
+						minWidth: 70,
+					},
+				],
+				columns2: [{
+						title: '选择地区',
+						key: 'placeName',
+						minWidth: 250,
+						render: (h, params) => {
+							return h('Input', {
+								props: {
+									type: 'text',
+									readonly: true,
+									size: 'small',
+									value: that.appointList[params.index].placeName,
+								},
+							});
+						},
+					},
+					{
+						title: '包邮件数',
+						key: 'a_num',
+						minWidth: 100,
+						render: (h, params) => {
+							return h('Input', {
+								props: {
+									type: 'number',
+									size: 'small',
+									value: that.appointList[params.index].a_num, // 此处如何让数据双向绑定
+								},
+								on: {
+									'on-change': (event) => {
+										that.appointList[params.index].a_num = event.target.value;
+									},
+								},
+							});
+						},
+					},
+					{
+						title: '包邮金额(元)',
+						key: 'a_price',
+						minWidth: 100,
+						render: (h, params) => {
+							return h('Input', {
+								props: {
+									type: 'number',
+									size: 'small',
+									value: that.appointList[params.index].a_price, // 此处如何让数据双向绑定
+								},
+								on: {
+									'on-change': (event) => {
+										that.appointList[params.index].a_price = event.target.value;
+									},
+								},
+							});
+						},
+					},
+					{
+						title: '操作',
+						slot: 'action',
+						minWidth: 100,
+					},
+				],
+				columns3: [{
+						title: '选择地区',
+						key: 'placeName',
+						minWidth: 250,
+						render: (h, params) => {
+							return h('Input', {
+								props: {
+									type: 'text',
+									readonly: true,
+									size: 'small',
+									value: that.noDeliveryList[params.index].placeName,
+								},
+							});
+						},
+					},
+					{
+						title: '操作',
+						slot: 'action',
+						minWidth: 100,
+					},
+				],
+				templateList: [{
+					region: [{
+						name: '默认全国',
+						city_id: 0,
+					}, ],
+					regionName: '默认全国',
+					first: 1,
+					price: 0,
+					continue: 1,
+					continue_price: 0,
+				}, ],
+				appointList: [],
+				noDeliveryList: [],
+				type: 1,
+				formData: {
+					type: 1,
+					sort: 0,
+					name: '',
+					appoint_check: 0,
+					no_delivery_check: 0,
+				},
+				id: 0,
+
+				addressModal: false,
+				indeterminate: true,
+				checkAll: false,
+				checkAllGroup: [],
+				activeCity: -1,
+				provinceAllGroup: [],
+				index: -1,
+				displayData: '',
+				currentProvince: '',
+				selectArr: [], // 传递选中的城市
+				noShippingArr: [], // 不包邮选择的城市数据
+				yesShippingArr: [], // 包邮选择的城市数据
+				noDeliveryArr: [], // 不送达选择的城市数据
+			};
+		},
+		computed: {},
+		methods: {
+			close(status) {
+				if (!status) {
+					this.$emit('close');
+				}
+			},
+			editFrom(id) {
+				this.id = id;
+				shipTemplatesApi(id).then((res) => {
+					let formData = res.data.formData;
+					this.templateList = res.data.templateList;
+					this.appointList = res.data.appointList;
+					this.noDeliveryList = res.data.noDeliveryList;
+					this.formData = {
+						type: formData.type,
+						sort: formData.sort,
+						name: formData.name,
+						appoint_check: formData.appoint_check,
+						no_delivery_check: formData.no_delivery_check,
+					};
+					this.headerType();
+				});
+			},
+			selectCity: function(data, type) {
+				let cityName = data
+					.map(function(item) {
+						return item.name;
+					})
+					.join(';');
+				switch (type) {
+					case 1:
+						this.templateList.push({
+							region: data,
+							regionName: cityName,
+							first: 1,
+							price: 0,
+							continue: 1,
+							continue_price: 0,
+						});
+						this.noShippingArr = this.noShippingArr.concat(data);
+						break;
+					case 2:
+						this.appointList.push({
+							place: data,
+							placeName: cityName,
+							a_num: 0,
+							a_price: 0,
+						});
+						this.yesShippingArr = this.yesShippingArr.concat(data);
+						break;
+					case 3:
+						this.noDeliveryList.push({
+							place: data,
+							placeName: cityName,
+						});
+						this.noDeliveryArr = this.noDeliveryArr.concat(data);
+						break;
+				}
+			},
+			// 单独添加配送区域
+			addCity(type) {
+				this.selectArr = type == 1 ? this.noShippingArr : type == 2 ? this.yesShippingArr : this.noDeliveryArr;
+				this.type = type;
+				this.$refs.city.getCityList();
+				this.$refs.city.addressModal = true;
+			},
+			changeRadio() {
+				this.headerType();
+			},
+			headerType() {
+				let that = this;
+				if (this.formData.type === 2) {
+					that.columns[1].title = '首件重量(KG)';
+					that.columns[3].title = '续件重量(KG)';
+					that.columns2[1].title = '包邮重量(KG)';
+				} else if (this.formData.type === 3) {
+					that.columns[1].title = '首件体积(m³)';
+					that.columns[3].title = '续件体积(m³)';
+					that.columns2[1].title = '包邮体积(m³)';
+				} else {
+					that.columns[1].title = '首件';
+					that.columns[3].title = '续件';
+					that.columns2[1].title = '包邮件数';
+				}
+			},
+			// 提交
+			handleSubmit: function() {
+				let that = this;
+				if (!that.formData.name.trim().length) {
+					return that.$Message.error('请填写模板名称');
+				}
+				for (let i = 0; i < that.templateList.length; i++) {
+					if (that.templateList[i].first <= 0) {
+						return that.$Message.error('首件/重量/体积应大于0');
+					}
+					if (that.templateList[i].price < 0) {
+						return that.$Message.error('运费应大于等于0');
+					}
+					if (that.templateList[i].continue <= 0) {
+						return that.$Message.error('续件/重量/体积应大于0');
+					}
+					if (that.templateList[i].continue_price < 0) {
+						return that.$Message.error('续费应大于等于0');
+					}
+				}
+				if (that.formData.appoint_check === 1) {
+					for (let i = 0; i < that.appointList.length; i++) {
+						if (that.appointList[i].a_num <= 0) {
+							return that.$Message.error('包邮件数应大于0');
+						}
+						if (that.appointList[i].a_price < 0) {
+							return that.$Message.error('包邮金额应大于等于0');
+						}
+					}
+				}
+				let data = {
+					appoint_info: that.appointList,
+					region_info: that.templateList,
+					no_delivery_info: that.noDeliveryList,
+					sort: that.formData.sort,
+					type: that.formData.type,
+					name: that.formData.name,
+					appoint: that.formData.appoint_check,
+					no_delivery: that.formData.no_delivery_check,
+				};
+				templatesSaveApi(that.id, data).then((res) => {
+					this.isTemplate = false;
+					// this.$parent.getList();
+					this.formData = {
+						type: 1,
+						sort: 0,
+						name: '',
+						appoint_check: 0,
+						no_delivery_check: 0,
+					};
+					this.appointList = [];
+					this.noDeliveryList = [];
+					this.addressModal = false;
+					this.templateList = [{
+						region: [{
+							name: '默认全国',
+							city_id: 0,
+						}, ],
+						regionName: '默认全国',
+						first: 1,
+						price: 0,
+						continue: 1,
+						continue_price: 0,
+					}, ];
+					this.$emit('addSuccess');
+					this.$Message.success(res.msg);
+				});
+			},
+			// 删除
+			delCity(row, tit, num, type) {
+				if (type === 1) {
+					this.templateList.splice(num, 1);
+				} else if (type == 2) {
+					this.appointList.splice(num, 1);
+				} else {
+					this.noDeliveryList.splice(num, 1);
+				}
+				//   let delfromData = {
+				//     title: tit,
+				//     num: num,
+				//     url: `setting/shipping_templates/del/${row.id}`,
+				//     method: "DELETE",
+				//     ids: "",
+				//   };
+				//   this.$modalSure(delfromData)
+				//     .then((res) => {
+				//       this.$Message.success(res.msg);
+				//     })
+				//     .catch((res) => {
+				//       this.$Message.error(res.msg);
+				//     });
+			},
+			// 关闭
+			cancel() {
+				this.noShippingArr = [];
+				this.noDeliveryArr = [];
+				this.yesShippingArr = [];
+				this.selectArr = [];
+				this.formData = {
+					type: 1,
+					sort: 0,
+					name: '',
+					appoint_check: 0,
+					no_delivery_check: 0,
+				};
+				this.appointList = [];
+				this.noDeliveryList = [];
+				this.addressModal = false;
+				this.templateList = [{
+					region: [{
+						name: '默认全国',
+						city_id: 0,
+					}, ],
+					regionName: '默认全国',
+					first: 0,
+					price: 0,
+					continue: 0,
+					continue_price: 0,
+				}, ];
+			},
+
+			address() {
+				this.addressModal = true;
+			},
+			enter(index) {
+				this.activeCity = index;
+			},
+			leave() {
+				this.activeCity = null;
+			},
+		},
+		mounted() {},
+	};
+</script>
+<style lang="stylus" scoped>
+	.ivu-table-wrapper {
+		border-left: 1px solid #dcdee2;
+		border-top: 1px solid #dcdee2;
+	}
+
+	.ivu-table-border th,
+	.ivu-table-border td {
+		padding: 0 10px !important;
+	}
+
+	.addTop {
+		margin-top: 15px;
+	}
+
+	.radio {
+		padding: 5px 0;
+	}
+
+	.ivu-input-number {
+		width: 100%;
+	}
+</style>

+ 1940 - 0
src/components/freightTemplate2/provinces.js

@@ -0,0 +1,1940 @@
+export default [
+  {
+    name: '北京市',
+    level: '1',
+    code: '1100',
+    cities: [
+      {
+        name: '北京市',
+        level: '1',
+        code: '1100',
+      },
+    ],
+  },
+  {
+    name: '天津市',
+    level: '1',
+    code: '1200',
+    cities: [
+      {
+        name: '天津市',
+        level: '1',
+        code: '1200',
+      },
+    ],
+  },
+  {
+    name: '河北省',
+    level: '1',
+    code: '1300',
+    cities: [
+      {
+        name: '石家庄市',
+        level: '2',
+        code: '1301',
+      },
+      {
+        name: '唐山市',
+        level: '3',
+        code: '1302',
+      },
+      {
+        name: '秦皇岛市',
+        level: '3',
+        code: '1303',
+      },
+      {
+        name: '邯郸市',
+        level: '3',
+        code: '1304',
+      },
+      {
+        name: '邢台市',
+        level: '3',
+        code: '1305',
+      },
+      {
+        name: '保定市',
+        level: '3',
+        code: '1306',
+      },
+      {
+        name: '张家口市',
+        level: '3',
+        code: '1307',
+      },
+      {
+        name: '承德市',
+        level: '3',
+        code: '1308',
+      },
+      {
+        name: '沧州市',
+        level: '3',
+        code: '1309',
+      },
+      {
+        name: '廊坊市',
+        level: '3',
+        code: '1310',
+      },
+      {
+        name: '衡水市',
+        level: '3',
+        code: '1311',
+      },
+    ],
+  },
+  {
+    name: '山西省',
+    level: '1',
+    code: '1400',
+    cities: [
+      {
+        name: '太原市',
+        level: '2',
+        code: '1401',
+      },
+      {
+        name: '大同市',
+        level: '3',
+        code: '1402',
+      },
+      {
+        name: '阳泉市',
+        level: '3',
+        code: '1403',
+      },
+      {
+        name: '长治市',
+        level: '3',
+        code: '1404',
+      },
+      {
+        name: '晋城市',
+        level: '3',
+        code: '1405',
+      },
+      {
+        name: '朔州市',
+        level: '3',
+        code: '1406',
+      },
+      {
+        name: '晋中市',
+        level: '3',
+        code: '1407',
+      },
+      {
+        name: '运城市',
+        level: '3',
+        code: '1408',
+      },
+      {
+        name: '忻州市',
+        level: '3',
+        code: '1409',
+      },
+      {
+        name: '临汾市',
+        level: '3',
+        code: '1410',
+      },
+      {
+        name: '吕梁市',
+        level: '3',
+        code: '1411',
+      },
+    ],
+  },
+  {
+    name: '内蒙古自治区',
+    level: '1',
+    code: '1500',
+    cities: [
+      {
+        name: '呼和浩特市',
+        level: '2',
+        code: '1501',
+      },
+      {
+        name: '包头市',
+        level: '3',
+        code: '1502',
+      },
+      {
+        name: '乌海市',
+        level: '3',
+        code: '1503',
+      },
+      {
+        name: '赤峰市',
+        level: '3',
+        code: '1504',
+      },
+      {
+        name: '通辽市',
+        level: '3',
+        code: '1505',
+      },
+      {
+        name: '鄂尔多斯市',
+        level: '3',
+        code: '1506',
+      },
+      {
+        name: '呼伦贝尔市',
+        level: '3',
+        code: '1507',
+      },
+      {
+        name: '巴彦淖尔市',
+        level: '3',
+        code: '1508',
+      },
+      {
+        name: '乌兰察布市',
+        level: '3',
+        code: '1509',
+      },
+      {
+        name: '兴安盟',
+        level: '3',
+        code: '1522',
+      },
+      {
+        name: '锡林郭勒盟',
+        level: '3',
+        code: '1525',
+      },
+      {
+        name: '阿拉善盟',
+        level: '3',
+        code: '1529',
+      },
+    ],
+  },
+  {
+    name: '辽宁省',
+    level: '1',
+    code: '2100',
+    cities: [
+      {
+        name: '沈阳市',
+        level: '2',
+        code: '2101',
+      },
+      {
+        name: '大连市',
+        level: '3',
+        code: '2102',
+      },
+      {
+        name: '鞍山市',
+        level: '3',
+        code: '2103',
+      },
+      {
+        name: '抚顺市',
+        level: '3',
+        code: '2104',
+      },
+      {
+        name: '本溪市',
+        level: '3',
+        code: '2105',
+      },
+      {
+        name: '丹东市',
+        level: '3',
+        code: '2106',
+      },
+      {
+        name: '锦州市',
+        level: '3',
+        code: '2107',
+      },
+      {
+        name: '营口市',
+        level: '3',
+        code: '2108',
+      },
+      {
+        name: '阜新市',
+        level: '3',
+        code: '2109',
+      },
+      {
+        name: '辽阳市',
+        level: '3',
+        code: '2110',
+      },
+      {
+        name: '盘锦市',
+        level: '3',
+        code: '2111',
+      },
+      {
+        name: '铁岭市',
+        level: '3',
+        code: '2112',
+      },
+      {
+        name: '朝阳市',
+        level: '3',
+        code: '2113',
+      },
+      {
+        name: '葫芦岛市',
+        level: '3',
+        code: '2114',
+      },
+    ],
+  },
+  {
+    name: '吉林省',
+    level: '1',
+    code: '2200',
+    cities: [
+      {
+        name: '长春市',
+        level: '2',
+        code: '2201',
+      },
+      {
+        name: '吉林市',
+        level: '3',
+        code: '2202',
+      },
+      {
+        name: '四平市',
+        level: '3',
+        code: '2203',
+      },
+      {
+        name: '辽源市',
+        level: '3',
+        code: '2204',
+      },
+      {
+        name: '通化市',
+        level: '3',
+        code: '2205',
+      },
+      {
+        name: '白山市',
+        level: '3',
+        code: '2206',
+      },
+      {
+        name: '松原市',
+        level: '3',
+        code: '2207',
+      },
+      {
+        name: '白城市',
+        level: '3',
+        code: '2208',
+      },
+      {
+        name: '延边朝鲜族自治州',
+        level: '3',
+        code: '2224',
+      },
+    ],
+  },
+  {
+    name: '黑龙江省',
+    level: '1',
+    code: '2300',
+    cities: [
+      {
+        name: '哈尔滨市',
+        level: '2',
+        code: '2301',
+      },
+      {
+        name: '齐齐哈尔市',
+        level: '3',
+        code: '2302',
+      },
+      {
+        name: '鸡西市',
+        level: '3',
+        code: '2303',
+      },
+      {
+        name: '鹤岗市',
+        level: '3',
+        code: '2304',
+      },
+      {
+        name: '双鸭山市',
+        level: '3',
+        code: '2305',
+      },
+      {
+        name: '大庆市',
+        level: '3',
+        code: '2306',
+      },
+      {
+        name: '伊春市',
+        level: '3',
+        code: '2307',
+      },
+      {
+        name: '佳木斯市',
+        level: '3',
+        code: '2308',
+      },
+      {
+        name: '七台河市',
+        level: '3',
+        code: '2309',
+      },
+      {
+        name: '牡丹江市',
+        level: '3',
+        code: '2310',
+      },
+      {
+        name: '黑河市',
+        level: '3',
+        code: '2311',
+      },
+      {
+        name: '绥化市',
+        level: '3',
+        code: '2312',
+      },
+      {
+        name: '大兴安岭地区',
+        level: '3',
+        code: '2327',
+      },
+    ],
+  },
+  {
+    name: '上海市',
+    level: '1',
+    code: '3100',
+    cities: [
+      {
+        name: '上海市',
+        level: '1',
+        code: '3100',
+      },
+    ],
+  },
+  {
+    name: '江苏省',
+    level: '1',
+    code: '3200',
+    cities: [
+      {
+        name: '南京市',
+        level: '2',
+        code: '3201',
+      },
+      {
+        name: '无锡市',
+        level: '3',
+        code: '3202',
+      },
+      {
+        name: '徐州市',
+        level: '3',
+        code: '3203',
+      },
+      {
+        name: '常州市',
+        level: '3',
+        code: '3204',
+      },
+      {
+        name: '苏州市',
+        level: '3',
+        code: '3205',
+      },
+      {
+        name: '南通市',
+        level: '3',
+        code: '3206',
+      },
+      {
+        name: '连云港市',
+        level: '3',
+        code: '3207',
+      },
+      {
+        name: '淮安市',
+        level: '3',
+        code: '3208',
+      },
+      {
+        name: '盐城市',
+        level: '3',
+        code: '3209',
+      },
+      {
+        name: '扬州市',
+        level: '3',
+        code: '3210',
+      },
+      {
+        name: '镇江市',
+        level: '3',
+        code: '3211',
+      },
+      {
+        name: '泰州市',
+        level: '3',
+        code: '3212',
+      },
+      {
+        name: '宿迁市',
+        level: '3',
+        code: '3213',
+      },
+    ],
+  },
+  {
+    name: '浙江省',
+    level: '1',
+    code: '3300',
+    cities: [
+      {
+        name: '杭州市',
+        level: '2',
+        code: '3301',
+      },
+      {
+        name: '宁波市',
+        level: '3',
+        code: '3302',
+      },
+      {
+        name: '温州市',
+        level: '3',
+        code: '3303',
+      },
+      {
+        name: '嘉兴市',
+        level: '3',
+        code: '3304',
+      },
+      {
+        name: '湖州市',
+        level: '3',
+        code: '3305',
+      },
+      {
+        name: '绍兴市',
+        level: '3',
+        code: '3306',
+      },
+      {
+        name: '金华市',
+        level: '3',
+        code: '3307',
+      },
+      {
+        name: '衢州市',
+        level: '3',
+        code: '3308',
+      },
+      {
+        name: '舟山市',
+        level: '3',
+        code: '3309',
+      },
+      {
+        name: '台州市',
+        level: '3',
+        code: '3310',
+      },
+      {
+        name: '丽水市',
+        level: '3',
+        code: '3311',
+      },
+    ],
+  },
+  {
+    name: '安徽省',
+    level: '1',
+    code: '3400',
+    cities: [
+      {
+        name: '合肥市',
+        level: '2',
+        code: '3401',
+      },
+      {
+        name: '芜湖市',
+        level: '3',
+        code: '3402',
+      },
+      {
+        name: '蚌埠市',
+        level: '3',
+        code: '3403',
+      },
+      {
+        name: '淮南市',
+        level: '3',
+        code: '3404',
+      },
+      {
+        name: '马鞍山市',
+        level: '3',
+        code: '3405',
+      },
+      {
+        name: '淮北市',
+        level: '3',
+        code: '3406',
+      },
+      {
+        name: '铜陵市',
+        level: '3',
+        code: '3407',
+      },
+      {
+        name: '安庆市',
+        level: '3',
+        code: '3408',
+      },
+      {
+        name: '黄山市',
+        level: '3',
+        code: '3410',
+      },
+      {
+        name: '滁州市',
+        level: '3',
+        code: '3411',
+      },
+      {
+        name: '阜阳市',
+        level: '3',
+        code: '3412',
+      },
+      {
+        name: '宿州市',
+        level: '3',
+        code: '3413',
+      },
+      {
+        name: '巢湖市',
+        level: '3',
+        code: '3414',
+      },
+      {
+        name: '六安市',
+        level: '3',
+        code: '3415',
+      },
+      {
+        name: '亳州市',
+        level: '3',
+        code: '3416',
+      },
+      {
+        name: '池州市',
+        level: '3',
+        code: '3417',
+      },
+      {
+        name: '宣城市',
+        level: '3',
+        code: '3418',
+      },
+    ],
+  },
+  {
+    name: '福建省',
+    level: '1',
+    code: '3500',
+    cities: [
+      {
+        name: '福州市',
+        level: '2',
+        code: '3501',
+      },
+      {
+        name: '厦门市',
+        level: '3',
+        code: '3502',
+      },
+      {
+        name: '莆田市',
+        level: '3',
+        code: '3503',
+      },
+      {
+        name: '三明市',
+        level: '3',
+        code: '3504',
+      },
+      {
+        name: '泉州市',
+        level: '3',
+        code: '3505',
+      },
+      {
+        name: '漳州市',
+        level: '3',
+        code: '3506',
+      },
+      {
+        name: '南平市',
+        level: '3',
+        code: '3507',
+      },
+      {
+        name: '龙岩市',
+        level: '3',
+        code: '3508',
+      },
+      {
+        name: '宁德市',
+        level: '3',
+        code: '3509',
+      },
+    ],
+  },
+  {
+    name: '江西省',
+    level: '1',
+    code: '3600',
+    cities: [
+      {
+        name: '南昌市',
+        level: '2',
+        code: '3601',
+      },
+      {
+        name: '景德镇市',
+        level: '3',
+        code: '3602',
+      },
+      {
+        name: '萍乡市',
+        level: '3',
+        code: '3603',
+      },
+      {
+        name: '九江市',
+        level: '3',
+        code: '3604',
+      },
+      {
+        name: '新余市',
+        level: '3',
+        code: '3605',
+      },
+      {
+        name: '鹰潭市',
+        level: '3',
+        code: '3606',
+      },
+      {
+        name: '赣州市',
+        level: '3',
+        code: '3607',
+      },
+      {
+        name: '吉安市',
+        level: '3',
+        code: '3608',
+      },
+      {
+        name: '宜春市',
+        level: '3',
+        code: '3609',
+      },
+      {
+        name: '抚州市',
+        level: '3',
+        code: '3610',
+      },
+      {
+        name: '上饶市',
+        level: '3',
+        code: '3611',
+      },
+    ],
+  },
+  {
+    name: '山东省',
+    level: '1',
+    code: '3700',
+    cities: [
+      {
+        name: '济南市',
+        level: '2',
+        code: '3701',
+      },
+      {
+        name: '青岛市',
+        level: '3',
+        code: '3702',
+      },
+      {
+        name: '淄博市',
+        level: '3',
+        code: '3703',
+      },
+      {
+        name: '枣庄市',
+        level: '3',
+        code: '3704',
+      },
+      {
+        name: '东营市',
+        level: '3',
+        code: '3705',
+      },
+      {
+        name: '烟台市',
+        level: '3',
+        code: '3706',
+      },
+      {
+        name: '潍坊市',
+        level: '3',
+        code: '3707',
+      },
+      {
+        name: '济宁市',
+        level: '3',
+        code: '3708',
+      },
+      {
+        name: '泰安市',
+        level: '3',
+        code: '3709',
+      },
+      {
+        name: '威海市',
+        level: '3',
+        code: '3710',
+      },
+      {
+        name: '日照市',
+        level: '3',
+        code: '3711',
+      },
+      {
+        name: '莱芜市',
+        level: '3',
+        code: '3712',
+      },
+      {
+        name: '临沂市',
+        level: '3',
+        code: '3713',
+      },
+      {
+        name: '德州市',
+        level: '3',
+        code: '3714',
+      },
+      {
+        name: '聊城市',
+        level: '3',
+        code: '3715',
+      },
+      {
+        name: '滨州市',
+        level: '3',
+        code: '3716',
+      },
+      {
+        name: '菏泽市',
+        level: '3',
+        code: '3717',
+      },
+    ],
+  },
+  {
+    name: '河南省',
+    level: '1',
+    code: '4100',
+    cities: [
+      {
+        name: '郑州市',
+        level: '2',
+        code: '4101',
+      },
+      {
+        name: '开封市',
+        level: '3',
+        code: '4102',
+      },
+      {
+        name: '洛阳市',
+        level: '3',
+        code: '4103',
+      },
+      {
+        name: '平顶山市',
+        level: '3',
+        code: '4104',
+      },
+      {
+        name: '安阳市',
+        level: '3',
+        code: '4105',
+      },
+      {
+        name: '鹤壁市',
+        level: '3',
+        code: '4106',
+      },
+      {
+        name: '新乡市',
+        level: '3',
+        code: '4107',
+      },
+      {
+        name: '焦作市',
+        level: '3',
+        code: '4108',
+      },
+      {
+        name: '濮阳市',
+        level: '3',
+        code: '4109',
+      },
+      {
+        name: '许昌市',
+        level: '3',
+        code: '4110',
+      },
+      {
+        name: '漯河市',
+        level: '3',
+        code: '4111',
+      },
+      {
+        name: '三门峡市',
+        level: '3',
+        code: '4112',
+      },
+      {
+        name: '南阳市',
+        level: '3',
+        code: '4113',
+      },
+      {
+        name: '商丘市',
+        level: '3',
+        code: '4114',
+      },
+      {
+        name: '信阳市',
+        level: '3',
+        code: '4115',
+      },
+      {
+        name: '周口市',
+        level: '3',
+        code: '4116',
+      },
+      {
+        name: '驻马店市',
+        level: '3',
+        code: '4117',
+      },
+    ],
+  },
+  {
+    name: '湖北省',
+    level: '1',
+    code: '4200',
+    cities: [
+      {
+        name: '武汉市',
+        level: '2',
+        code: '4201',
+      },
+      {
+        name: '黄石市',
+        level: '3',
+        code: '4202',
+      },
+      {
+        name: '十堰市',
+        level: '3',
+        code: '4203',
+      },
+      {
+        name: '宜昌市',
+        level: '3',
+        code: '4205',
+      },
+      {
+        name: '襄樊市',
+        level: '3',
+        code: '4206',
+      },
+      {
+        name: '鄂州市',
+        level: '3',
+        code: '4207',
+      },
+      {
+        name: '荆门市',
+        level: '3',
+        code: '4208',
+      },
+      {
+        name: '孝感市',
+        level: '3',
+        code: '4209',
+      },
+      {
+        name: '荆州市',
+        level: '3',
+        code: '4210',
+      },
+      {
+        name: '黄冈市',
+        level: '3',
+        code: '4211',
+      },
+      {
+        name: '咸宁市',
+        level: '3',
+        code: '4212',
+      },
+      {
+        name: '随州市',
+        level: '3',
+        code: '4213',
+      },
+      {
+        name: '恩施土家族苗族自治州',
+        level: '3',
+        code: '4228',
+      },
+    ],
+  },
+  {
+    name: '湖南省',
+    level: '1',
+    code: '4300',
+    cities: [
+      {
+        name: '长沙市',
+        level: '2',
+        code: '4301',
+      },
+      {
+        name: '株洲市',
+        level: '3',
+        code: '4302',
+      },
+      {
+        name: '湘潭市',
+        level: '3',
+        code: '4303',
+      },
+      {
+        name: '衡阳市',
+        level: '3',
+        code: '4304',
+      },
+      {
+        name: '邵阳市',
+        level: '3',
+        code: '4305',
+      },
+      {
+        name: '岳阳市',
+        level: '3',
+        code: '4306',
+      },
+      {
+        name: '常德市',
+        level: '3',
+        code: '4307',
+      },
+      {
+        name: '张家界市',
+        level: '3',
+        code: '4308',
+      },
+      {
+        name: '益阳市',
+        level: '3',
+        code: '4309',
+      },
+      {
+        name: '郴州市',
+        level: '3',
+        code: '4310',
+      },
+      {
+        name: '永州市',
+        level: '3',
+        code: '4311',
+      },
+      {
+        name: '怀化市',
+        level: '3',
+        code: '4312',
+      },
+      {
+        name: '娄底市',
+        level: '3',
+        code: '4313',
+      },
+      {
+        name: '湘西土家族苗族自治州',
+        level: '3',
+        code: '4331',
+      },
+    ],
+  },
+  {
+    name: '广东省',
+    level: '1',
+    code: '4400',
+    cities: [
+      {
+        name: '广州市',
+        level: '2',
+        code: '4401',
+      },
+      {
+        name: '韶关市',
+        level: '3',
+        code: '4402',
+      },
+      {
+        name: '深圳市',
+        level: '3',
+        code: '4403',
+      },
+      {
+        name: '珠海市',
+        level: '3',
+        code: '4404',
+      },
+      {
+        name: '汕头市',
+        level: '3',
+        code: '4405',
+      },
+      {
+        name: '佛山市',
+        level: '3',
+        code: '4406',
+      },
+      {
+        name: '江门市',
+        level: '3',
+        code: '4407',
+      },
+      {
+        name: '湛江市',
+        level: '3',
+        code: '4408',
+      },
+      {
+        name: '茂名市',
+        level: '3',
+        code: '4409',
+      },
+      {
+        name: '肇庆市',
+        level: '3',
+        code: '4412',
+      },
+      {
+        name: '惠州市',
+        level: '3',
+        code: '4413',
+      },
+      {
+        name: '梅州市',
+        level: '3',
+        code: '4414',
+      },
+      {
+        name: '汕尾市',
+        level: '3',
+        code: '4415',
+      },
+      {
+        name: '河源市',
+        level: '3',
+        code: '4416',
+      },
+      {
+        name: '阳江市',
+        level: '3',
+        code: '4417',
+      },
+      {
+        name: '清远市',
+        level: '3',
+        code: '4418',
+      },
+      {
+        name: '东莞市',
+        level: '3',
+        code: '4419',
+      },
+      {
+        name: '中山市',
+        level: '3',
+        code: '4420',
+      },
+      {
+        name: '潮州市',
+        level: '3',
+        code: '4451',
+      },
+      {
+        name: '揭阳市',
+        level: '3',
+        code: '4452',
+      },
+      {
+        name: '云浮市',
+        level: '3',
+        code: '4453',
+      },
+    ],
+  },
+  {
+    name: '广西壮族自治区',
+    level: '1',
+    code: '4500',
+    cities: [
+      {
+        name: '南宁市',
+        level: '2',
+        code: '4501',
+      },
+      {
+        name: '柳州市',
+        level: '3',
+        code: '4502',
+      },
+      {
+        name: '桂林市',
+        level: '3',
+        code: '4503',
+      },
+      {
+        name: '梧州市',
+        level: '3',
+        code: '4504',
+      },
+      {
+        name: '北海市',
+        level: '3',
+        code: '4505',
+      },
+      {
+        name: '防城港市',
+        level: '3',
+        code: '4506',
+      },
+      {
+        name: '钦州市',
+        level: '3',
+        code: '4507',
+      },
+      {
+        name: '贵港市',
+        level: '3',
+        code: '4508',
+      },
+      {
+        name: '玉林市',
+        level: '3',
+        code: '4509',
+      },
+      {
+        name: '百色市',
+        level: '3',
+        code: '4510',
+      },
+      {
+        name: '贺州市',
+        level: '3',
+        code: '4511',
+      },
+      {
+        name: '河池市',
+        level: '3',
+        code: '4512',
+      },
+      {
+        name: '来宾市',
+        level: '3',
+        code: '4513',
+      },
+      {
+        name: '崇左市',
+        level: '3',
+        code: '4514',
+      },
+    ],
+  },
+  {
+    name: '海南省',
+    level: '1',
+    code: '4600',
+    cities: [
+      {
+        name: '海口市',
+        level: '2',
+        code: '4601',
+      },
+      {
+        name: '三亚市',
+        level: '3',
+        code: '4602',
+      },
+    ],
+  },
+  {
+    name: '重庆市',
+    level: '1',
+    code: '5000',
+    cities: [
+      {
+        name: '重庆市',
+        level: '1',
+        code: '5000',
+      },
+    ],
+  },
+  {
+    name: '四川省',
+    level: '1',
+    code: '5100',
+    cities: [
+      {
+        name: '成都市',
+        level: '2',
+        code: '5101',
+      },
+      {
+        name: '自贡市',
+        level: '3',
+        code: '5103',
+      },
+      {
+        name: '攀枝花市',
+        level: '3',
+        code: '5104',
+      },
+      {
+        name: '泸州市',
+        level: '3',
+        code: '5105',
+      },
+      {
+        name: '德阳市',
+        level: '3',
+        code: '5106',
+      },
+      {
+        name: '绵阳市',
+        level: '3',
+        code: '5107',
+      },
+      {
+        name: '广元市',
+        level: '3',
+        code: '5108',
+      },
+      {
+        name: '遂宁市',
+        level: '3',
+        code: '5109',
+      },
+      {
+        name: '内江市',
+        level: '3',
+        code: '5110',
+      },
+      {
+        name: '乐山市',
+        level: '3',
+        code: '5111',
+      },
+      {
+        name: '南充市',
+        level: '3',
+        code: '5113',
+      },
+      {
+        name: '眉山市',
+        level: '3',
+        code: '5114',
+      },
+      {
+        name: '宜宾市',
+        level: '3',
+        code: '5115',
+      },
+      {
+        name: '广安市',
+        level: '3',
+        code: '5116',
+      },
+      {
+        name: '达州市',
+        level: '3',
+        code: '5117',
+      },
+      {
+        name: '雅安市',
+        level: '3',
+        code: '5118',
+      },
+      {
+        name: '巴中市',
+        level: '3',
+        code: '5119',
+      },
+      {
+        name: '资阳市',
+        level: '3',
+        code: '5120',
+      },
+      {
+        name: '阿坝藏族羌族自治州',
+        level: '3',
+        code: '5132',
+      },
+      {
+        name: '甘孜藏族自治州',
+        level: '3',
+        code: '5133',
+      },
+      {
+        name: '凉山彝族自治州',
+        level: '3',
+        code: '5134',
+      },
+    ],
+  },
+  {
+    name: '贵州省',
+    level: '1',
+    code: '5200',
+    cities: [
+      {
+        name: '贵阳市',
+        level: '2',
+        code: '5201',
+      },
+      {
+        name: '六盘水市',
+        level: '3',
+        code: '5202',
+      },
+      {
+        name: '遵义市',
+        level: '3',
+        code: '5203',
+      },
+      {
+        name: '安顺市',
+        level: '3',
+        code: '5204',
+      },
+      {
+        name: '铜仁地区',
+        level: '3',
+        code: '5222',
+      },
+      {
+        name: '黔西南布依族苗族自治州',
+        level: '3',
+        code: '5223',
+      },
+      {
+        name: '毕节地区',
+        level: '3',
+        code: '5224',
+      },
+      {
+        name: '黔东南苗族侗族自治州',
+        level: '3',
+        code: '5226',
+      },
+      {
+        name: '黔南布依族苗族自治州',
+        level: '3',
+        code: '5227',
+      },
+    ],
+  },
+  {
+    name: '云南省',
+    level: '1',
+    code: '5300',
+    cities: [
+      {
+        name: '昆明市',
+        level: '2',
+        code: '5301',
+      },
+      {
+        name: '曲靖市',
+        level: '3',
+        code: '5303',
+      },
+      {
+        name: '玉溪市',
+        level: '3',
+        code: '5304',
+      },
+      {
+        name: '保山市',
+        level: '3',
+        code: '5305',
+      },
+      {
+        name: '昭通市',
+        level: '3',
+        code: '5306',
+      },
+      {
+        name: '丽江市',
+        level: '3',
+        code: '5307',
+      },
+      {
+        name: '普洱市',
+        level: '3',
+        code: '5308',
+      },
+      {
+        name: '临沧市',
+        level: '3',
+        code: '5309',
+      },
+      {
+        name: '楚雄彝族自治州',
+        level: '3',
+        code: '5323',
+      },
+      {
+        name: '红河哈尼族彝族自治州',
+        level: '3',
+        code: '5325',
+      },
+      {
+        name: '文山壮族苗族自治州',
+        level: '3',
+        code: '5326',
+      },
+      {
+        name: '西双版纳傣族自治州',
+        level: '3',
+        code: '5328',
+      },
+      {
+        name: '大理白族自治州',
+        level: '3',
+        code: '5329',
+      },
+      {
+        name: '德宏傣族景颇族自治州',
+        level: '3',
+        code: '5331',
+      },
+      {
+        name: '怒江傈僳族自治州',
+        level: '3',
+        code: '5333',
+      },
+      {
+        name: '迪庆藏族自治州',
+        level: '3',
+        code: '5334',
+      },
+    ],
+  },
+  {
+    name: '西藏自治区',
+    level: '1',
+    code: '5400',
+    cities: [
+      {
+        name: '拉萨市',
+        level: '2',
+        code: '5401',
+      },
+      {
+        name: '昌都地区',
+        level: '3',
+        code: '5421',
+      },
+      {
+        name: '山南地区',
+        level: '3',
+        code: '5422',
+      },
+      {
+        name: '日喀则地区',
+        level: '3',
+        code: '5423',
+      },
+      {
+        name: '那曲地区',
+        level: '3',
+        code: '5424',
+      },
+      {
+        name: '阿里地区',
+        level: '3',
+        code: '5425',
+      },
+      {
+        name: '林芝地区',
+        level: '3',
+        code: '5426',
+      },
+    ],
+  },
+  {
+    name: '陕西省',
+    level: '1',
+    code: '6100',
+    cities: [
+      {
+        name: '西安市',
+        level: '2',
+        code: '6101',
+      },
+      {
+        name: '铜川市',
+        level: '3',
+        code: '6102',
+      },
+      {
+        name: '宝鸡市',
+        level: '3',
+        code: '6103',
+      },
+      {
+        name: '咸阳市',
+        level: '3',
+        code: '6104',
+      },
+      {
+        name: '渭南市',
+        level: '3',
+        code: '6105',
+      },
+      {
+        name: '延安市',
+        level: '3',
+        code: '6106',
+      },
+      {
+        name: '汉中市',
+        level: '3',
+        code: '6107',
+      },
+      {
+        name: '榆林市',
+        level: '3',
+        code: '6108',
+      },
+      {
+        name: '安康市',
+        level: '3',
+        code: '6109',
+      },
+      {
+        name: '商洛市',
+        level: '3',
+        code: '6110',
+      },
+    ],
+  },
+  {
+    name: '甘肃省',
+    level: '1',
+    code: '6200',
+    cities: [
+      {
+        name: '兰州市',
+        level: '2',
+        code: '6201',
+      },
+      {
+        name: '嘉峪关市',
+        level: '3',
+        code: '6202',
+      },
+      {
+        name: '金昌市',
+        level: '3',
+        code: '6203',
+      },
+      {
+        name: '白银市',
+        level: '3',
+        code: '6204',
+      },
+      {
+        name: '天水市',
+        level: '3',
+        code: '6205',
+      },
+      {
+        name: '武威市',
+        level: '3',
+        code: '6206',
+      },
+      {
+        name: '张掖市',
+        level: '3',
+        code: '6207',
+      },
+      {
+        name: '平凉市',
+        level: '3',
+        code: '6208',
+      },
+      {
+        name: '酒泉市',
+        level: '3',
+        code: '6209',
+      },
+      {
+        name: '庆阳市',
+        level: '3',
+        code: '6210',
+      },
+      {
+        name: '定西市',
+        level: '3',
+        code: '6211',
+      },
+      {
+        name: '陇南市',
+        level: '3',
+        code: '6212',
+      },
+      {
+        name: '临夏回族自治州',
+        level: '3',
+        code: '6229',
+      },
+      {
+        name: '甘南藏族自治州',
+        level: '3',
+        code: '6230',
+      },
+    ],
+  },
+  {
+    name: '青海省',
+    level: '1',
+    code: '6300',
+    cities: [
+      {
+        name: '西宁市',
+        level: '2',
+        code: '6301',
+      },
+      {
+        name: '海东地区',
+        level: '3',
+        code: '6321',
+      },
+      {
+        name: '海北藏族自治州',
+        level: '3',
+        code: '6322',
+      },
+      {
+        name: '黄南藏族自治州',
+        level: '3',
+        code: '6323',
+      },
+      {
+        name: '海南藏族自治州',
+        level: '3',
+        code: '6325',
+      },
+      {
+        name: '果洛藏族自治州',
+        level: '3',
+        code: '6326',
+      },
+      {
+        name: '玉树藏族自治州',
+        level: '3',
+        code: '6327',
+      },
+      {
+        name: '海西蒙古族藏族自治州',
+        level: '3',
+        code: '6328',
+      },
+    ],
+  },
+  {
+    name: '宁夏回族自治区',
+    level: '1',
+    code: '6400',
+    cities: [
+      {
+        name: '银川市',
+        level: '2',
+        code: '6401',
+      },
+      {
+        name: '石嘴山市',
+        level: '3',
+        code: '6402',
+      },
+      {
+        name: '吴忠市',
+        level: '3',
+        code: '6403',
+      },
+      {
+        name: '固原市',
+        level: '3',
+        code: '6404',
+      },
+      {
+        name: '中卫市',
+        level: '3',
+        code: '6405',
+      },
+    ],
+  },
+  {
+    name: '新疆维吾尔自治区',
+    level: '1',
+    code: '6500',
+    cities: [
+      {
+        name: '乌鲁木齐市',
+        level: '2',
+        code: '6501',
+      },
+      {
+        name: '克拉玛依市',
+        level: '3',
+        code: '6502',
+      },
+      {
+        name: '吐鲁番地区',
+        level: '3',
+        code: '6521',
+      },
+      {
+        name: '哈密地区',
+        level: '3',
+        code: '6522',
+      },
+      {
+        name: '昌吉回族自治州',
+        level: '3',
+        code: '6523',
+      },
+      {
+        name: '博尔塔拉蒙古自治州',
+        level: '3',
+        code: '6527',
+      },
+      {
+        name: '巴音郭楞蒙古自治州',
+        level: '3',
+        code: '6528',
+      },
+      {
+        name: '阿克苏地区',
+        level: '3',
+        code: '6529',
+      },
+      {
+        name: '克孜勒苏柯尔克孜自治州',
+        level: '3',
+        code: '6530',
+      },
+      {
+        name: '喀什地区',
+        level: '3',
+        code: '6531',
+      },
+      {
+        name: '和田地区',
+        level: '3',
+        code: '6532',
+      },
+      {
+        name: '伊犁哈萨克自治州',
+        level: '3',
+        code: '6540',
+      },
+      {
+        name: '塔城地区',
+        level: '3',
+        code: '6542',
+      },
+      {
+        name: '阿勒泰地区',
+        level: '3',
+        code: '6543',
+      },
+    ],
+  },
+  {
+    name: '台湾省',
+    level: '1',
+    code: '7100',
+    cities: [
+      {
+        name: '台湾省',
+        level: '1',
+        code: '7100',
+      },
+    ],
+  },
+  {
+    name: '香港特别行政区',
+    level: '1',
+    code: '8100',
+    cities: [
+      {
+        name: '香港特别行政区',
+        level: '1',
+        code: '8100',
+      },
+    ],
+  },
+  {
+    name: '澳门特别行政区',
+    level: '1',
+    code: '8200',
+    cities: [
+      {
+        name: '澳门特别行政区',
+        level: '1',
+        code: '8200',
+      },
+    ],
+  },
+];

+ 947 - 988
src/components/uploadPictures/index.vue

@@ -1,995 +1,954 @@
 <template>
-  <div class="Modal">
-    <Row class="colLeft">
-      <Col :xl="6" :lg="6" :md="6" :sm="6" :xs="24" class="colLeft">
-        <div class="Nav">
-          <div class="input">
-            <Input
-              search
-              enter-button
-              placeholder="请输入分类名称"
-              v-model="uploadName.name"
-              style="width: 90%"
-              @on-search="changePage"
-            />
-          </div>
-          <div class="trees-coadd">
-            <div class="scollhide">
-              <div class="trees">
-                <Tree :data="treeData" :render="renderContent" :load-data="loadData" class="treeBox" ref="tree"></Tree>
-              </div>
-            </div>
-          </div>
-        </div>
-      </Col>
-      <Col :xl="18" :lg="18" :md="18" :sm="18" :xs="24" class="colLeft">
-        <div class="conter">
-          <div class="bnt acea-row row-middle">
-            <Col span="24">
-              <Button
-                type="primary"
-                :disabled="checkPicList.length === 0"
-                @click="checkPics"
-                class="mr10"
-                v-if="isShow !== 0"
-                >使用选中图片</Button
-              >
-              <Upload
-                :show-upload-list="false"
-                :action="fileUrl"
-                class="mr10 mb10"
-                :before-upload="beforeUpload"
-                :data="uploadData"
-                :headers="header"
-                :multiple="true"
-                :format="['jpg', 'jpeg', 'png', 'gif']"
-                :on-success="handleSuccess"
-                style="margin-top: 1px; display: inline-block"
-              >
-                <Button type="primary">上传图片</Button>
-              </Upload>
-              <!--<Button type="success" @click.stop="add" class="mr10">添加分类</Button>-->
-              <Button type="error" class="mr10" :disabled="checkPicList.length === 0" @click.stop="editPicList('图片')"
-                >删除图片</Button
-              >
-              <i-select :value="pids" placeholder="图片移动至" style="width: 250px" class="treeSel">
-                <i-option v-for="(item, index) of list" :value="item.value" :key="index" style="display: none">
-                  {{ item.title }}
-                </i-option>
-                <Tree
-                  :data="treeData2"
-                  :render="renderContentSel"
-                  ref="reference"
-                  :load-data="loadData"
-                  class="treeBox"
-                ></Tree>
-              </i-select>
-            </Col>
-          </div>
-          <div class="pictrueList acea-row">
-            <Row :gutter="24" class="conter">
-              <div v-show="isShowPic" class="imagesNo">
-                <Icon type="ios-images" size="60" color="#dbdbdb" />
-                <span class="imagesNo_sp">图片库为空</span>
-              </div>
-              <div class="acea-row mb10">
-                <div
-                  class="pictrueList_pic mr10 mb10"
-                  v-for="(item, index) in pictrueList"
-                  :key="index"
-                  @mouseenter="enterMouse(item)"
-                  @mouseleave="enterMouse(item)"
-                >
-                  <p class="number" v-if="item.num > 0">
-                    <Badge :count="item.num" type="error" :offset="[11, 12]">
-                      <a href="#" class="demo-badge"></a>
-                    </Badge>
-                  </p>
-                  <img
-                    :class="item.isSelect ? 'on' : ''"
-                    v-lazy="item.satt_dir"
-                    @click.stop="changImage(item, index, pictrueList)"
-                  />
-                  <div
-                    style="display: flex; align-items: center; justify-content: space-between"
-                    @mouseenter="enterLeave(item)"
-                    @mouseleave="enterLeave(item)"
-                  >
-                    <p style="width: 80%" v-if="!item.isEdit">
-                      {{ item.editName }}
-                    </p>
-                    <Input
-                      size="small"
-                      style="width: 80%"
-                      type="text"
-                      v-model="item.real_name"
-                      v-else
-                      @on-blur="bindTxt(item)"
-                    />
-                    <span
-                      class="iconfont iconbianji1"
-                      @click="item.isEdit = !item.isEdit"
-                      v-if="item.isShowEdit"
-                    ></span>
-                  </div>
-                  <div class="nameStyle" v-show="item.realName && item.real_name">
-                    {{ item.real_name }}
-                  </div>
-                </div>
-              </div>
-              <!--<Col class="mb20" v-bind="gridPic"-->
-              <!--v-for="(item, index) in pictrueList" :key="index" >-->
-              <!--<div class="pictrueList_pic">-->
-              <!--<img :class="item.isSelect ? 'on': '' " v-lazy="item.satt_dir"-->
-              <!--@click.stop="changImage(item, index, pictrueList)"/>-->
-              <!--</div>-->
-              <!--</Col>-->
-            </Row>
-          </div>
-          <div class="footer acea-row row-right">
-            <Page :total="total" show-elevator show-total @on-change="pageChange" :page-size="fileData.limit" />
-          </div>
-        </div>
-      </Col>
-    </Row>
-  </div>
+	<div class="Modal">
+		<Row class="colLeft">
+			<Col :xl="6" :lg="6" :md="6" :sm="6" :xs="24" class="colLeft">
+			<div class="Nav">
+				<div class="input">
+					<Input search enter-button placeholder="请输入分类名称" v-model="uploadName.name" style="width: 90%"
+						@on-search="changePage" />
+				</div>
+				<div class="trees-coadd">
+					<div class="scollhide">
+						<div class="trees">
+							<Tree :data="treeData" :render="renderContent" :load-data="loadData" class="treeBox"
+								ref="tree"></Tree>
+						</div>
+					</div>
+				</div>
+			</div>
+			</Col>
+			<Col :xl="18" :lg="18" :md="18" :sm="18" :xs="24" class="colLeft">
+			<div class="conter">
+				<div class="bnt acea-row row-middle">
+					<Col span="24">
+					<Button type="primary" :disabled="checkPicList.length === 0" @click="checkPics" class="mr10"
+						v-if="isShow !== 0">使用选中图片</Button>
+					<Upload :show-upload-list="false" :action="fileUrl" class="mr10 mb10" :before-upload="beforeUpload"
+						:data="uploadData" :headers="header" :multiple="true" :format="['jpg', 'jpeg', 'png', 'gif']"
+						:on-success="handleSuccess" style="margin-top: 1px; display: inline-block">
+						<Button type="primary">上传图片</Button>
+					</Upload>
+					<!--<Button type="success" @click.stop="add" class="mr10">添加分类</Button>-->
+					<Button type="error" class="mr10" :disabled="checkPicList.length === 0"
+						@click.stop="editPicList('图片')">删除图片</Button>
+					<i-select :value="pids" placeholder="图片移动至" style="width: 250px" class="treeSel">
+						<i-option v-for="(item, index) of list" :value="item.value" :key="index" style="display: none">
+							{{ item.title }}
+						</i-option>
+						<Tree :data="treeData2" :render="renderContentSel" ref="reference" :load-data="loadData"
+							class="treeBox"></Tree>
+					</i-select>
+					</Col>
+				</div>
+				<div class="pictrueList acea-row">
+					<Row :gutter="24" class="conter">
+						<div v-show="isShowPic" class="imagesNo">
+							<Icon type="ios-images" size="60" color="#dbdbdb" />
+							<span class="imagesNo_sp">图片库为空</span>
+						</div>
+						<div class="acea-row mb10">
+							<div class="pictrueList_pic mr10 mb10" v-for="(item, index) in pictrueList" :key="index"
+								@mouseenter="enterMouse(item)" @mouseleave="enterMouse(item)">
+								<p class="number" v-if="item.num > 0">
+									<Badge :count="item.num" type="error" :offset="[11, 12]">
+										<a href="#" class="demo-badge"></a>
+									</Badge>
+								</p>
+								<img :class="item.isSelect ? 'on' : ''" v-lazy="item.satt_dir"
+									@click.stop="changImage(item, index, pictrueList)" />
+								<div style="display: flex; align-items: center; justify-content: space-between"
+									@mouseenter="enterLeave(item)" @mouseleave="enterLeave(item)">
+									<p style="width: 80%" v-if="!item.isEdit">
+										{{ item.editName }}
+									</p>
+									<Input size="small" style="width: 80%" type="text" v-model="item.real_name" v-else
+										@on-blur="bindTxt(item)" />
+									<span class="iconfont iconbianji1" @click="item.isEdit = !item.isEdit"
+										v-if="item.isShowEdit"></span>
+								</div>
+								<div class="nameStyle" v-show="item.realName && item.real_name">
+									{{ item.real_name }}
+								</div>
+							</div>
+						</div>
+						<!--<Col class="mb20" v-bind="gridPic"-->
+						<!--v-for="(item, index) in pictrueList" :key="index" >-->
+						<!--<div class="pictrueList_pic">-->
+						<!--<img :class="item.isSelect ? 'on': '' " v-lazy="item.satt_dir"-->
+						<!--@click.stop="changImage(item, index, pictrueList)"/>-->
+						<!--</div>-->
+						<!--</Col>-->
+					</Row>
+				</div>
+				<div class="footer acea-row row-right">
+					<Page :total="total" show-elevator show-total @on-change="pageChange" :page-size="fileData.limit" />
+				</div>
+			</div>
+			</Col>
+		</Row>
+	</div>
 </template>
 
 <script>
-import {
-  getCategoryListApi,
-  createApi,
-  fileListApi,
-  categoryEditApi,
-  moveApi,
-  fileUpdateApi,
-} from '@/api/uploadPictures';
-import Setting from '@/setting';
-import { getCookies } from '@/libs/util';
-export default {
-  name: 'uploadPictures',
-  // components: { editFrom },
-  props: {
-    isChoice: {
-      type: String,
-      default: '',
-    },
-    gridBtn: {
-      type: Object,
-      default: null,
-    },
-    gridPic: {
-      type: Object,
-      default: null,
-    },
-    isShow: {
-      type: Number,
-      default: 1,
-    },
-    pageLimit: {
-      type: Number,
-      default: 0,
-    },
-  },
-  data() {
-    return {
-      spinShow: false,
-      fileUrl: Setting.apiBaseURL + '/file/upload',
-      modalPic: false,
-      treeData: [],
-      treeData2: [],
-      pictrueList: [],
-      uploadData: {}, // 上传参数
-      checkPicList: [],
-      uploadName: {
-        name: '',
-      },
-      FromData: null,
-      treeId: 0,
-      isJudge: false,
-      buttonProps: {
-        type: 'default',
-        size: 'small',
-      },
-      fileData: {
-        pid: 0,
-        page: 1,
-        limit: this.pageLimit || 18,
-      },
-      total: 0,
-      pids: 0,
-      list: [],
-      modalTitleSs: '',
-      isShowPic: false,
-      header: {},
-      ids: [], // 选中附件的id集合
-    };
-  },
-  mounted() {
-    this.getToken();
-    this.getList();
-    this.getFileList();
-  },
-  methods: {
-    enterMouse(item) {
-      item.realName = !item.realName;
-    },
-    enterLeave(item) {
-      item.isShowEdit = !item.isShowEdit;
-    },
-    // 上传头部token
-    getToken() {
-      this.header['Authori-zation'] = 'Bearer ' + getCookies('token');
-    },
-    // 树状图
-    renderContent(h, { root, node, data }) {
-      let operate = [];
-      if (data.pid == 0) {
-        operate.push(
-          h(
-            'div',
-            {
-              class: ['ivu-dropdown-item'],
-              on: {
-                click: () => {
-                  this.append(root, node, data);
-                },
-              },
-            },
-            '添加分类',
-          ),
-        );
-      }
-      if (data.id !== '') {
-        operate.push(
-          h(
-            'div',
-            {
-              class: ['ivu-dropdown-item'],
-              on: {
-                click: () => {
-                  this.editPic(root, node, data);
-                },
-              },
-            },
-            '编辑分类',
-          ),
-          h(
-            'div',
-            {
-              class: ['ivu-dropdown-item'],
-              on: {
-                click: () => {
-                  this.remove(root, node, data, '分类');
-                },
-              },
-            },
-            '删除分类',
-          ),
-        );
-      }
-      return h(
-        'span',
-        {
-          class: ['ivu-span'],
-          style: {
-            display: 'inline-block',
-            width: '88%',
-            height: '32px',
-            lineHeight: '32px',
-            position: 'relative',
-            color: 'rgba(0,0,0,0.6)',
-            cursor: 'pointer',
-          },
-          on: {
-            mouseenter: () => {
-              this.onMouseOver(root, node, data);
-            },
-            mouseleave: () => {
-              this.onMouseOver(root, node, data);
-            },
-            // click: (e) => {
-            //   this.appendBtn(root, node, data, e);
-            // },
-          },
-        },
-        [
-          h(
-            'span',
-            {
-              on: {
-                click: (e) => {
-                  this.appendBtn(root, node, data, e);
-                },
-              },
-            },
-            data.title,
-          ),
-          h(
-            'div',
-            {
-              style: {
-                display: 'inline-block',
-                float: 'right',
-              },
-            },
-            [
-              h('Icon', {
-                props: {
-                  type: 'ios-more',
-                },
-                style: {
-                  marginRight: '8px',
-                  fontSize: '20px',
-                  display: 'inline',
-                },
-                on: {
-                  click: (e) => {
-                    this.onClick(root, node, data, e);
-                  },
-                },
-              }),
-              h(
-                'div',
-                {
-                  class: ['right-menu ivu-poptip-inner'],
-                  style: {
-                    width: '80px',
-                    position: 'absolute',
-                    zIndex: '9',
-                    top: '0',
-                    right: '0',
-                    display: data.flag2 ? 'block' : 'none',
-                  },
-                },
-                operate,
-              ),
-            ],
-          ),
-        ],
-      );
-    },
-    // renderContent (h, { root, node, data }) {
-    //     let actionData = [];
-    //     if (data.id !== '' && data.pid == 0) {
-    //         actionData.push(h('Button', {
-    //             props: Object.assign({}, this.buttonProps, {
-    //                 icon: 'ios-add'
-    //             }),
-    //             style: {
-    //                 marginRight: '8px',
-    //                 display: data.flag ? 'inline' : 'none'
-    //             },
-    //             on: {
-    //                 click: () => { this.append(root, node, data) }
-    //
-    //             }
-    //         }));
-    //     }
-    //     if (data.id !== '') {
-    //         actionData.push(h('Button', {
-    //             props: Object.assign({}, this.buttonProps, {
-    //                 icon: 'md-create'
-    //             }),
-    //             style: {
-    //                 marginRight: '8px',
-    //                 display: data.flag ? 'inline' : 'none'
-    //             },
-    //             on: {
-    //                 click: () => { this.editPic(root, node, data) }
-    //             }
-    //         }));
-    //         actionData.push(h('Button', {
-    //             props: Object.assign({}, this.buttonProps, {
-    //                 icon: 'ios-remove'
-    //             }),
-    //             style: {
-    //                 display: data.flag ? 'inline' : 'none'
-    //             },
-    //             on: {
-    //                 click: () => { this.remove(root, node, data, '分类') }
-    //             }
-    //         }));
-    //     }
-    //     return h('div', {
-    //         style: {
-    //             display: 'inline-block',
-    //             width: '90%'
-    //         },
-    //         on: {
-    //             mouseenter: () => { this.onMouseOver(root, node, data) },
-    //             mouseleave: () => { this.onMouseOver(root, node, data) }
-    //         }
-    //     }, [
-    //         h('span', [
-    //             h('span', {
-    //                 style: {
-    //                     cursor: 'pointer'
-    //                 },
-    //                 class: ['ivu-tree-title'],
-    //                 on: {
-    //                     click: (e) => { this.appendBtn(root, node, data, e) }
-    //                 }
-    //             }, data.title)
-    //         ]),
-    //         h('span', {
-    //             style: {
-    //                 display: 'inline-block',
-    //                 float: 'right'
-    //             }
-    //         }, actionData)
-    //     ]);
-    // },
-    renderContentSel(h, { root, node, data }) {
-      return h(
-        'div',
-        {
-          style: {
-            display: 'inline-block',
-            width: '90%',
-          },
-        },
-        [
-          h('span', [
-            h(
-              'span',
-              {
-                style: {
-                  cursor: 'pointer',
-                },
-                class: ['ivu-tree-title'],
-                on: {
-                  click: (e) => {
-                    this.handleCheckChange(root, node, data, e);
-                  },
-                },
-              },
-              data.title,
-            ),
-          ]),
-        ],
-      );
-    },
-    // 下拉树
-    handleCheckChange(root, node, data, e) {
-      this.list = [];
-      // this.pids = 0;
-      let value = data.id;
-      let title = data.title;
-      this.list.push({
-        value,
-        title,
-      });
-      if (this.ids.length) {
-        this.pids = value;
-        this.getMove();
-      } else {
-        this.$Message.warning('请先选择图片');
-      }
-      let selected = this.$refs.reference.$el.querySelectorAll('.ivu-tree-title-selected');
-      for (let i = 0; i < selected.length; i++) {
-        selected[i].className = 'ivu-tree-title';
-      }
-      e.path[0].className = 'ivu-tree-title  ivu-tree-title-selected'; // 当前点击的元素
-    },
-    // 移动分类
-    getMove() {
-      let data = {
-        pid: this.pids,
-        images: this.ids.toString(),
-      };
-      moveApi(data)
-        .then(async (res) => {
-          this.$Message.success(res.msg);
-          this.getFileList();
-          this.pids = 0;
-          this.checkPicList = [];
-          this.ids = [];
-        })
-        .catch((res) => {
-          this.$Message.error(res.msg);
-        });
-    },
-    // 删除图片
-    editPicList(tit) {
-      this.tits = tit;
-      let ids = {
-        ids: this.ids.toString(),
-      };
-      let delfromData = {
-        title: '删除选中图片',
-        url: `file/file/delete`,
-        method: 'POST',
-        ids: ids,
-      };
-      this.$modalSure(delfromData)
-        .then((res) => {
-          this.$Message.success(res.msg);
-          this.getFileList();
-          this.checkPicList = [];
-        })
-        .catch((res) => {
-          this.$Message.error(res.msg);
-        });
-    },
-    // 鼠标移入 移出
-    onMouseOver(root, node, data) {
-      event.preventDefault();
-      data.flag = !data.flag;
-      if (data.flag2) {
-        data.flag2 = false;
-      }
-    },
-    onClick(root, node, data, e) {
-      e.preventDefault();
-
-      data.flag2 = !data.flag2;
-    },
-    // 点击树
-    appendBtn(root, node, data, e) {
-      e.preventDefault();
-
-      this.treeId = data.id;
-      this.fileData.page = 1;
-      this.getFileList();
-      let selected = this.$refs.tree.$el.querySelectorAll('.ivu-tree-title-selected');
-      for (let i = 0; i < selected.length; i++) {
-        selected[i].className = 'ivu-tree-title';
-      }
-      e.path[0].className = 'ivu-tree-title  ivu-tree-title-selected'; // 当前点击的元素
-    },
-    // 点击添加
-    append(root, node, data) {
-      this.treeId = data.id;
-      this.getFrom();
-    },
-    // 删除分类
-    remove(root, node, data, tit) {
-      this.tits = tit;
-      let delfromData = {
-        title: '删除 [ ' + data.title + ' ] ' + '分类',
-        url: `file/category/${data.id}`,
-        method: 'DELETE',
-        ids: '',
-      };
-      this.$modalSure(delfromData)
-        .then((res) => {
-          this.$Message.success(res.msg);
-          this.getList();
-          this.checkPicList = [];
-        })
-        .catch((res) => {
-          this.$Message.error(res.msg);
-        });
-    },
-    // 确认删除树
-    // submitModel () {
-    //     if (this.tits === '图片') {
-    //         this.getFileList();
-    //         this.checkPicList = [];
-    //     } else {
-    //         this.getList();
-    //         this.checkPicList = [];
-    //     }
-    // },
-    // 编辑树表单
-    editPic(root, node, data) {
-      this.$modalForm(categoryEditApi(data.id)).then(() => this.getList());
-    },
-    // 搜索分类
-    changePage() {
-      this.getList('search');
-    },
-    // 分类列表树
-    getList(type) {
-      let data = {
-        title: '全部图片',
-        id: '',
-        pid: 0,
-      };
-      getCategoryListApi(this.uploadName)
-        .then(async (res) => {
-          this.treeData = res.data.list;
-          this.treeData.unshift(data);
-          if (type !== 'search') {
-            this.treeData2 = [...this.treeData];
-          }
-          this.addFlag(this.treeData);
-        })
-        .catch((res) => {
-          this.$Message.error(res.msg);
-        });
-    },
-    loadData(item, callback) {
-      getCategoryListApi({
-        pid: item.id,
-      })
-        .then(async (res) => {
-          const data = res.data.list;
-          callback(data);
-        })
-        .catch((res) => {});
-    },
-    addFlag(treedata) {
-      treedata.map((item) => {
-        this.$set(item, 'flag', false);
-        this.$set(item, 'flag2', false);
-        item.children && this.addFlag(item.children);
-      });
-    },
-    // 新建分类
-    add() {
-      this.treeId = 0;
-      this.getFrom();
-    },
-    // 文件列表
-    getFileList() {
-      this.fileData.pid = this.treeId;
-      fileListApi(this.fileData)
-        .then(async (res) => {
-          res.data.list.forEach((el) => {
-            el.isSelect = false;
-            el.isEdit = false;
-            el.isShowEdit = false;
-            el.realName = false;
-            el.num = 0;
-            this.editName(el);
-          });
-          this.pictrueList = res.data.list;
-
-          if (this.pictrueList.length) {
-            this.isShowPic = false;
-          } else {
-            this.isShowPic = true;
-          }
-          this.total = res.data.count;
-        })
-        .catch((res) => {
-          this.$Message.error(res.msg);
-        });
-    },
-    pageChange(index) {
-      this.fileData.page = index;
-      this.getFileList();
-      this.checkPicList = [];
-    },
-    // 新建分类表单
-    getFrom() {
-      this.$modalForm(createApi({ id: this.treeId })).then((res) => {
-        this.getList();
-      });
-    },
-    // 上传之前
-    beforeUpload(file) {
-      // if (file.size > 2097152) {
-      //   this.$Message.error(file.name + "大小超过2M!");
-      // } else
-      if (!/image\/\w+/.test(file.type)) {
-        this.$Message.error('请上传以jpg、jpeg、png等结尾的图片文件'); //FileExt.toLowerCase()
-        return false;
-      }
-      this.uploadData = {
-        pid: this.treeId,
-      };
-      let promise = new Promise((resolve) => {
-        this.$nextTick(function () {
-          resolve(true);
-        });
-      });
-      return promise;
-    },
-    // 上传成功
-    handleSuccess(res, file, fileList) {
-      if (res.status === 200) {
-        this.$Message.success(res.msg);
-        this.fileData.page = 1;
-        this.getFileList();
-      } else {
-        this.$Message.error(res.msg);
-      }
-    },
-    // 关闭
-    cancel() {
-      this.$emit('changeCancel');
-    },
-    // 选中图片
-    changImage(item, index, row) {
-      let activeIndex = 0;
-      if (!item.isSelect) {
-        item.isSelect = true;
-        this.checkPicList.push(item);
-      } else {
-        item.isSelect = false;
-        this.checkPicList.map((el, index) => {
-          if (el.att_id == item.att_id) {
-            activeIndex = index;
-          }
-        });
-        this.checkPicList.splice(activeIndex, 1);
-      }
-
-      this.ids = [];
-      this.checkPicList.map((item, i) => {
-        this.ids.push(item.att_id);
-      });
-      this.pictrueList.map((el, i) => {
-        if (el.isSelect) {
-          this.checkPicList.filter((el2, j) => {
-            if (el.att_id == el2.att_id) {
-              el.num = j + 1;
-            }
-          });
-        } else {
-          el.num = 0;
-        }
-      });
-    },
-    // 点击使用选中图片
-    checkPics() {
-      if (this.isChoice === '单选') {
-        if (this.checkPicList.length > 1) return this.$Message.warning('最多只能选一张图片');
-        this.$emit('getPic', this.checkPicList[0]);
-      } else {
-        let maxLength = this.$route.query.maxLength;
-        if (maxLength != undefined && this.checkPicList.length > Number(maxLength))
-          return this.$Message.warning('最多只能选' + maxLength + '张图片');
-        this.$emit('getPicD', this.checkPicList);
-      }
-    },
-    editName(item) {
-      let it = item.real_name.split('.');
-      let it1 = it[1] == undefined ? [] : it[1];
-      let len = it[0].length + it1.length;
-      item.editName = len < 10 ? item.real_name : item.real_name.substr(0, 2) + '...' + item.real_name.substr(-5, 5);
-    },
-    // 修改图片文字上传
-    bindTxt(item) {
-      if (item.real_name == '') {
-        this.$Message.error('请填写内容');
-      }
-      fileUpdateApi(item.att_id, {
-        real_name: item.real_name,
-      })
-        .then((res) => {
-          this.editName(item);
-          item.isEdit = false;
-          this.$Message.success(res.msg);
-        })
-        .catch((error) => {
-          this.$Message.error(error.msg);
-        });
-    },
-  },
-};
+	import {
+		getCategoryListApi,
+		createApi,
+		fileListApi,
+		categoryEditApi,
+		moveApi,
+		fileUpdateApi,
+	} from '@/api/uploadPictures';
+	import Setting from '@/setting';
+	import {
+		getCookies
+	} from '@/libs/util';
+	export default {
+		name: 'uploadPictures',
+		// components: { editFrom },
+		props: {
+			isChoice: {
+				type: String,
+				default: '',
+			},
+			gridBtn: {
+				type: Object,
+				default: null,
+			},
+			gridPic: {
+				type: Object,
+				default: null,
+			},
+			isShow: {
+				type: Number,
+				default: 1,
+			},
+			pageLimit: {
+				type: Number,
+				default: 0,
+			},
+		},
+		data() {
+			return {
+				spinShow: false,
+				fileUrl: Setting.apiBaseURL + '/file/upload',
+				modalPic: false,
+				treeData: [],
+				treeData2: [],
+				pictrueList: [],
+				uploadData: {}, // 上传参数
+				checkPicList: [],
+				uploadName: {
+					name: '',
+				},
+				FromData: null,
+				treeId: 0,
+				isJudge: false,
+				buttonProps: {
+					type: 'default',
+					size: 'small',
+				},
+				fileData: {
+					pid: 0,
+					page: 1,
+					limit: this.pageLimit || 18,
+				},
+				total: 0,
+				pids: 0,
+				list: [],
+				modalTitleSs: '',
+				isShowPic: false,
+				header: {},
+				ids: [], // 选中附件的id集合
+			};
+		},
+		mounted() {
+			this.getToken();
+			this.getList();
+			this.getFileList();
+		},
+		methods: {
+			enterMouse(item) {
+				item.realName = !item.realName;
+			},
+			enterLeave(item) {
+				item.isShowEdit = !item.isShowEdit;
+			},
+			// 上传头部token
+			getToken() {
+				this.header['Authori-zation'] = 'Bearer ' + getCookies('token');
+			},
+			// 树状图
+			renderContent(h, {
+				root,
+				node,
+				data
+			}) {
+				let operate = [];
+				if (data.pid == 0) {
+					operate.push(
+						h(
+							'div', {
+								class: ['ivu-dropdown-item'],
+								on: {
+									click: () => {
+										this.append(root, node, data);
+									},
+								},
+							},
+							'添加分类',
+						),
+					);
+				}
+				if (data.id !== '') {
+					operate.push(
+						h(
+							'div', {
+								class: ['ivu-dropdown-item'],
+								on: {
+									click: () => {
+										this.editPic(root, node, data);
+									},
+								},
+							},
+							'编辑分类',
+						),
+						h(
+							'div', {
+								class: ['ivu-dropdown-item'],
+								on: {
+									click: () => {
+										this.remove(root, node, data, '分类');
+									},
+								},
+							},
+							'删除分类',
+						),
+					);
+				}
+				return h(
+					'span', {
+						class: ['ivu-span'],
+						style: {
+							display: 'inline-block',
+							width: '88%',
+							height: '32px',
+							lineHeight: '32px',
+							position: 'relative',
+							color: 'rgba(0,0,0,0.6)',
+							cursor: 'pointer',
+						},
+						on: {
+							mouseenter: () => {
+								this.onMouseOver(root, node, data);
+							},
+							mouseleave: () => {
+								this.onMouseOver(root, node, data);
+							},
+							// click: (e) => {
+							//   this.appendBtn(root, node, data, e);
+							// },
+						},
+					},
+					[
+						h(
+							'span', {
+								on: {
+									click: (e) => {
+										this.appendBtn(root, node, data, e);
+									},
+								},
+							},
+							data.title,
+						),
+						h(
+							'div', {
+								style: {
+									display: 'inline-block',
+									float: 'right',
+								},
+							},
+							[
+								h('Icon', {
+									props: {
+										type: 'ios-more',
+									},
+									style: {
+										marginRight: '8px',
+										fontSize: '20px',
+										display: 'inline',
+									},
+									on: {
+										click: (e) => {
+											this.onClick(root, node, data, e);
+										},
+									},
+								}),
+								h(
+									'div', {
+										class: ['right-menu ivu-poptip-inner'],
+										style: {
+											width: '80px',
+											position: 'absolute',
+											zIndex: '9',
+											top: '0',
+											right: '0',
+											display: data.flag2 ? 'block' : 'none',
+										},
+									},
+									operate,
+								),
+							],
+						),
+					],
+				);
+			},
+			// renderContent (h, { root, node, data }) {
+			//     let actionData = [];
+			//     if (data.id !== '' && data.pid == 0) {
+			//         actionData.push(h('Button', {
+			//             props: Object.assign({}, this.buttonProps, {
+			//                 icon: 'ios-add'
+			//             }),
+			//             style: {
+			//                 marginRight: '8px',
+			//                 display: data.flag ? 'inline' : 'none'
+			//             },
+			//             on: {
+			//                 click: () => { this.append(root, node, data) }
+			//
+			//             }
+			//         }));
+			//     }
+			//     if (data.id !== '') {
+			//         actionData.push(h('Button', {
+			//             props: Object.assign({}, this.buttonProps, {
+			//                 icon: 'md-create'
+			//             }),
+			//             style: {
+			//                 marginRight: '8px',
+			//                 display: data.flag ? 'inline' : 'none'
+			//             },
+			//             on: {
+			//                 click: () => { this.editPic(root, node, data) }
+			//             }
+			//         }));
+			//         actionData.push(h('Button', {
+			//             props: Object.assign({}, this.buttonProps, {
+			//                 icon: 'ios-remove'
+			//             }),
+			//             style: {
+			//                 display: data.flag ? 'inline' : 'none'
+			//             },
+			//             on: {
+			//                 click: () => { this.remove(root, node, data, '分类') }
+			//             }
+			//         }));
+			//     }
+			//     return h('div', {
+			//         style: {
+			//             display: 'inline-block',
+			//             width: '90%'
+			//         },
+			//         on: {
+			//             mouseenter: () => { this.onMouseOver(root, node, data) },
+			//             mouseleave: () => { this.onMouseOver(root, node, data) }
+			//         }
+			//     }, [
+			//         h('span', [
+			//             h('span', {
+			//                 style: {
+			//                     cursor: 'pointer'
+			//                 },
+			//                 class: ['ivu-tree-title'],
+			//                 on: {
+			//                     click: (e) => { this.appendBtn(root, node, data, e) }
+			//                 }
+			//             }, data.title)
+			//         ]),
+			//         h('span', {
+			//             style: {
+			//                 display: 'inline-block',
+			//                 float: 'right'
+			//             }
+			//         }, actionData)
+			//     ]);
+			// },
+			renderContentSel(h, {
+				root,
+				node,
+				data
+			}) {
+				return h(
+					'div', {
+						style: {
+							display: 'inline-block',
+							width: '90%',
+						},
+					},
+					[
+						h('span', [
+							h(
+								'span', {
+									style: {
+										cursor: 'pointer',
+									},
+									class: ['ivu-tree-title'],
+									on: {
+										click: (e) => {
+											this.handleCheckChange(root, node, data, e);
+										},
+									},
+								},
+								data.title,
+							),
+						]),
+					],
+				);
+			},
+			// 下拉树
+			handleCheckChange(root, node, data, e) {
+				this.list = [];
+				// this.pids = 0;
+				let value = data.id;
+				let title = data.title;
+				this.list.push({
+					value,
+					title,
+				});
+				if (this.ids.length) {
+					this.pids = value;
+					this.getMove();
+				} else {
+					this.$Message.warning('请先选择图片');
+				}
+				let selected = this.$refs.reference.$el.querySelectorAll('.ivu-tree-title-selected');
+				for (let i = 0; i < selected.length; i++) {
+					selected[i].className = 'ivu-tree-title';
+				}
+				e.path[0].className = 'ivu-tree-title  ivu-tree-title-selected'; // 当前点击的元素
+			},
+			// 移动分类
+			getMove() {
+				let data = {
+					pid: this.pids,
+					images: this.ids.toString(),
+				};
+				moveApi(data)
+					.then(async (res) => {
+						this.$Message.success(res.msg);
+						this.getFileList();
+						this.pids = 0;
+						this.checkPicList = [];
+						this.ids = [];
+					})
+					.catch((res) => {
+						this.$Message.error(res.msg);
+					});
+			},
+			// 删除图片
+			editPicList(tit) {
+				this.tits = tit;
+				let ids = {
+					ids: this.ids.toString(),
+				};
+				let delfromData = {
+					title: '删除选中图片',
+					url: `file/file/delete`,
+					method: 'POST',
+					ids: ids,
+				};
+				this.$modalSure(delfromData)
+					.then((res) => {
+						this.$Message.success(res.msg);
+						this.getFileList();
+						this.checkPicList = [];
+					})
+					.catch((res) => {
+						this.$Message.error(res.msg);
+					});
+			},
+			// 鼠标移入 移出
+			onMouseOver(root, node, data) {
+				event.preventDefault();
+				data.flag = !data.flag;
+				if (data.flag2) {
+					data.flag2 = false;
+				}
+			},
+			onClick(root, node, data, e) {
+				e.preventDefault();
+
+				data.flag2 = !data.flag2;
+			},
+			// 点击树
+			appendBtn(root, node, data, e) {
+				e.preventDefault();
+
+				this.treeId = data.id;
+				this.fileData.page = 1;
+				this.getFileList();
+				let selected = this.$refs.tree.$el.querySelectorAll('.ivu-tree-title-selected');
+				for (let i = 0; i < selected.length; i++) {
+					selected[i].className = 'ivu-tree-title';
+				}
+				e.path[0].className = 'ivu-tree-title  ivu-tree-title-selected'; // 当前点击的元素
+			},
+			// 点击添加
+			append(root, node, data) {
+				this.treeId = data.id;
+				this.getFrom();
+			},
+			// 删除分类
+			remove(root, node, data, tit) {
+				this.tits = tit;
+				let delfromData = {
+					title: '删除 [ ' + data.title + ' ] ' + '分类',
+					url: `file/category/${data.id}`,
+					method: 'DELETE',
+					ids: '',
+				};
+				this.$modalSure(delfromData)
+					.then((res) => {
+						this.$Message.success(res.msg);
+						this.getList();
+						this.checkPicList = [];
+					})
+					.catch((res) => {
+						this.$Message.error(res.msg);
+					});
+			},
+			// 确认删除树
+			// submitModel () {
+			//     if (this.tits === '图片') {
+			//         this.getFileList();
+			//         this.checkPicList = [];
+			//     } else {
+			//         this.getList();
+			//         this.checkPicList = [];
+			//     }
+			// },
+			// 编辑树表单
+			editPic(root, node, data) {
+				this.$modalForm(categoryEditApi(data.id)).then(() => this.getList());
+			},
+			// 搜索分类
+			changePage() {
+				this.getList('search');
+			},
+			// 分类列表树
+			getList(type) {
+				let data = {
+					title: '全部图片',
+					id: '',
+					pid: 0,
+				};
+				getCategoryListApi(this.uploadName)
+					.then(async (res) => {
+						this.treeData = res.data.list;
+						this.treeData.unshift(data);
+						if (type !== 'search') {
+							this.treeData2 = [...this.treeData];
+						}
+						this.addFlag(this.treeData);
+					})
+					.catch((res) => {
+						this.$Message.error(res.msg);
+					});
+			},
+			loadData(item, callback) {
+				getCategoryListApi({
+						pid: item.id,
+					})
+					.then(async (res) => {
+						const data = res.data.list;
+						callback(data);
+					})
+					.catch((res) => {});
+			},
+			addFlag(treedata) {
+				treedata.map((item) => {
+					this.$set(item, 'flag', false);
+					this.$set(item, 'flag2', false);
+					item.children && this.addFlag(item.children);
+				});
+			},
+			// 新建分类
+			add() {
+				this.treeId = 0;
+				this.getFrom();
+			},
+			// 文件列表
+			getFileList() {
+				this.fileData.pid = this.treeId;
+				fileListApi(this.fileData)
+					.then(async (res) => {
+						res.data.list.forEach((el) => {
+							el.isSelect = false;
+							el.isEdit = false;
+							el.isShowEdit = false;
+							el.realName = false;
+							el.num = 0;
+							this.editName(el);
+						});
+						this.pictrueList = res.data.list;
+
+						if (this.pictrueList.length) {
+							this.isShowPic = false;
+						} else {
+							this.isShowPic = true;
+						}
+						this.total = res.data.count;
+					})
+					.catch((res) => {
+						this.$Message.error(res.msg);
+					});
+			},
+			pageChange(index) {
+				this.fileData.page = index;
+				this.getFileList();
+				this.checkPicList = [];
+			},
+			// 新建分类表单
+			getFrom() {
+				this.$modalForm(createApi({
+					id: this.treeId
+				})).then((res) => {
+					this.getList();
+				});
+			},
+			// 上传之前
+			beforeUpload(file) {
+				// if (file.size > 2097152) {
+				//   this.$Message.error(file.name + "大小超过2M!");
+				// } else
+				if (!/image\/\w+/.test(file.type)) {
+					this.$Message.error('请上传以jpg、jpeg、png等结尾的图片文件'); //FileExt.toLowerCase()
+					return false;
+				}
+				this.uploadData = {
+					pid: this.treeId,
+				};
+				let promise = new Promise((resolve) => {
+					this.$nextTick(function() {
+						resolve(true);
+					});
+				});
+				return promise;
+			},
+			// 上传成功
+			handleSuccess(res, file, fileList) {
+				if (res.status === 200) {
+					this.$Message.success(res.msg);
+					this.fileData.page = 1;
+					this.getFileList();
+				} else {
+					this.$Message.error(res.msg);
+				}
+			},
+			// 关闭
+			cancel() {
+				this.$emit('changeCancel');
+			},
+			// 选中图片
+			changImage(item, index, row) {
+				let activeIndex = 0;
+				if (!item.isSelect) {
+					item.isSelect = true;
+					this.checkPicList.push(item);
+				} else {
+					item.isSelect = false;
+					this.checkPicList.map((el, index) => {
+						if (el.att_id == item.att_id) {
+							activeIndex = index;
+						}
+					});
+					this.checkPicList.splice(activeIndex, 1);
+				}
+
+				this.ids = [];
+				this.checkPicList.map((item, i) => {
+					this.ids.push(item.att_id);
+				});
+				this.pictrueList.map((el, i) => {
+					if (el.isSelect) {
+						this.checkPicList.filter((el2, j) => {
+							if (el.att_id == el2.att_id) {
+								el.num = j + 1;
+							}
+						});
+					} else {
+						el.num = 0;
+					}
+				});
+			},
+			// 点击使用选中图片
+			checkPics() {
+				if (this.isChoice === '单选') {
+					if (this.checkPicList.length > 1) return this.$Message.warning('最多只能选一张图片');
+					this.$emit('getPic', this.checkPicList[0]);
+				} else {
+					let maxLength = this.$route.query.maxLength;
+					if (maxLength != undefined && this.checkPicList.length > Number(maxLength))
+						return this.$Message.warning('最多只能选' + maxLength + '张图片');
+					this.$emit('getPicD', this.checkPicList);
+				}
+			},
+			editName(item) {
+				let it = item.real_name.split('.');
+				let it1 = it[1] == undefined ? [] : it[1];
+				let len = it[0].length + it1.length;
+				item.editName = len < 10 ? item.real_name : item.real_name.substr(0, 2) + '...' + item.real_name.substr(-5,
+					5);
+			},
+			// 修改图片文字上传
+			bindTxt(item) {
+				if (item.real_name == '') {
+					this.$Message.error('请填写内容');
+				}
+				fileUpdateApi(item.att_id, {
+						real_name: item.real_name,
+					})
+					.then((res) => {
+						this.editName(item);
+						item.isEdit = false;
+						this.$Message.success(res.msg);
+					})
+					.catch((error) => {
+						this.$Message.error(error.msg);
+					});
+			},
+		},
+	};
 </script>
 
 <style scoped lang="stylus">
-.nameStyle {
-  position: absolute;
-  white-space: nowrap;
-  z-index: 9;
-  background: #eee;
-  height: 20px;
-  line-height: 20px;
-  color: #555;
-  border: 1px solid #ebebeb;
-  padding: 0 5px;
-  left: 56px;
-  bottom: -18px;
-}
-
-.iconbianji1 {
-  font-size: 13px;
-}
-
-/deep/.ivu-badge-count {
-  margin-top: 18px !important;
-  margin-right: 19px !important;
-}
-
-/deep/ivu-tree-title-selected:hover {
-  color: unset;
-  background-color: unset;
-}
-
-/deep/.ivu-tree-title {
-  padding: 0;
-  // width: 200px;
-  width: 100%;
-}
-
-/deep/.ivu-span {
-  padding: 0;
-  display: flex !important;
-  justify-content: space-between;
-}
-
-/deep/.ivu-tree ul li {
-  margin: 0;
-}
-
-/deep/.ivu-tree-arrow {
-  width: 17px;
-  color: #626262;
-}
-
-/deep/.ivu-span:hover {
-  background: #F5F5F5;
-  color: rgba(0, 0, 0, 0.4) !important;
-}
-
-/deep/.ivu-tree-arrow i {
-  vertical-align: bottom;
-}
-
-.Nav /deep/.ivu-icon-ios-arrow-forward:before {
-  content: '\F341' !important;
-  font-size: 20px;
-}
-
-/deep/.ivu-btn-icon-only.ivu-btn-small {
-  padding: unset !important;
-}
-
-.selectTreeClass {
-  background: #d5e8fc;
-}
-
-.treeBox {
-  width: 100%;
-  height: 100%;
-
-  >>> .ivu-tree-title-selected, .ivu-tree-title-selected:hover {
-    color: #2D8cF0 !important;
-    background-color: #fff !important;
-  }
-
-  >>> .ivu-btn-icon-only {
-    width: 20px !important;
-    height: 20px !important;
-  }
-
-  >>> .ivu-tree-title:hover {
-    color: #2D8cF0 !important;
-    background-color: #fff !important;
-  }
-}
-
-.pictrueList_pic {
-  position: relative;
-  width: 100px;
-  cursor: pointer;
-
-  img {
-    width: 100%;
-    height: 100px;
-  }
-
-  p {
-    overflow: hidden;
-    text-overflow: ellipsis;
-    white-space: nowrap;
-    height: 20px;
-    text-align: center;
-  }
-
-  .number {
-    height: 33px;
-  }
-
-  .number {
-    position: absolute;
-    right: 0;
-    top: 0;
-  }
-}
-
-.trees-coadd {
-  width: 100%;
-  border-radius: 4px;
-  overflow: hidden;
-  position: relative;
-
-  .scollhide {
-    overflow-x: hidden;
-    overflow-y: scroll;
-    padding: 10px 0 10px 0;
-    box-sizing: border-box;
-
-    .trees {
-      width: 100%;
-      height: 374px;
-    }
-  }
-
-  .scollhide::-webkit-scrollbar {
-    display: none;
-  }
-}
-
-.treeSel >>>.ivu-select-dropdown-list {
-  padding: 0 5px !important;
-  box-sizing: border-box;
-  width: 200px;
-}
-
-.imagesNo {
-  display: flex;
-  justify-content: center;
-  flex-direction: column;
-  align-items: center;
-  margin: 65px 0;
-
-  .imagesNo_sp {
-    font-size: 13px;
-    color: #dbdbdb;
-    line-height: 3;
-  }
-}
-
-.Modal {
-  width: 100%;
-  height: 100%;
-  background: #fff !important;
-}
-
-.Nav {
-  width: 100%;
-  border-right: 1px solid #eee;
-}
-
-.colLeft {
-  padding-right: 0 !important;
-  height: 100%;
-}
-
-.conter {
-  width: 100%;
-  height: 100%;
-  margin-left: 0 !important;
-}
-
-.conter .bnt {
-  width: 100%;
-  padding: 0 13px 10px 8px;
-  box-sizing: border-box;
-}
-
-.conter .pictrueList {
-  padding-left: 6px;
-  width: 100%;
-  max-width: 1200px;
-  overflow-x: hidden;
-  overflow-y: auto;
-  // height: 300px;
-}
-
-.conter .pictrueList img {
-  width: 100%;
-  border: 2px solid #fff;
-}
-
-.conter .pictrueList img.on {
-  border: 2px solid #5FB878;
-}
-
-.conter .footer {
-  padding: 0 20px 10px 20px;
-}
-
-.demo-badge {
-  width: 42px;
-  height: 42px;
-  background: transparent;
-  border-radius: 6px;
-  display: inline-block;
-}
-
-.bnt /deep/ .ivu-tree-children {
-  padding: 5px 0;
-}
-
-.trees-coadd /deep/ .ivu-tree-children .ivu-tree-arrow {
-  line-height: 25px;
-}
-</style>
+	.nameStyle {
+		position: absolute;
+		white-space: nowrap;
+		z-index: 9;
+		background: #eee;
+		height: 20px;
+		line-height: 20px;
+		color: #555;
+		border: 1px solid #ebebeb;
+		padding: 0 5px;
+		left: 56px;
+		bottom: -18px;
+	}
+
+	.iconbianji1 {
+		font-size: 13px;
+	}
+
+	/deep/.ivu-badge-count {
+		margin-top: 18px !important;
+		margin-right: 19px !important;
+	}
+
+	/deep/ivu-tree-title-selected:hover {
+		color: unset;
+		background-color: unset;
+	}
+
+	/deep/.ivu-tree-title {
+		padding: 0;
+		// width: 200px;
+		width: 100%;
+	}
+
+	/deep/.ivu-span {
+		padding: 0;
+		display: flex !important;
+		justify-content: space-between;
+	}
+
+	/deep/.ivu-tree ul li {
+		margin: 0;
+	}
+
+	/deep/.ivu-tree-arrow {
+		width: 17px;
+		color: #626262;
+	}
+
+	/deep/.ivu-span:hover {
+		background: #F5F5F5;
+		color: rgba(0, 0, 0, 0.4) !important;
+	}
+
+	/deep/.ivu-tree-arrow i {
+		vertical-align: bottom;
+	}
+
+	.Nav /deep/.ivu-icon-ios-arrow-forward:before {
+		content: '\F341' !important;
+		font-size: 20px;
+	}
+
+	/deep/.ivu-btn-icon-only.ivu-btn-small {
+		padding: unset !important;
+	}
+
+	.selectTreeClass {
+		background: #d5e8fc;
+	}
+
+	.treeBox {
+		width: 100%;
+		height: 100%;
+
+		>>>.ivu-tree-title-selected,
+		.ivu-tree-title-selected:hover {
+			color: #2D8cF0 !important;
+			background-color: #fff !important;
+		}
+
+		>>>.ivu-btn-icon-only {
+			width: 20px !important;
+			height: 20px !important;
+		}
+
+		>>>.ivu-tree-title:hover {
+			color: #2D8cF0 !important;
+			background-color: #fff !important;
+		}
+	}
+
+	.pictrueList_pic {
+		position: relative;
+		width: 100px;
+		cursor: pointer;
+
+		img {
+			width: 100%;
+			height: 100px;
+		}
+
+		p {
+			overflow: hidden;
+			text-overflow: ellipsis;
+			white-space: nowrap;
+			height: 20px;
+			text-align: center;
+		}
+
+		.number {
+			height: 33px;
+		}
+
+		.number {
+			position: absolute;
+			right: 0;
+			top: 0;
+		}
+	}
+
+	.trees-coadd {
+		width: 100%;
+		border-radius: 4px;
+		overflow: hidden;
+		position: relative;
+
+		.scollhide {
+			overflow-x: hidden;
+			overflow-y: scroll;
+			padding: 10px 0 10px 0;
+			box-sizing: border-box;
+
+			.trees {
+				width: 100%;
+				height: 374px;
+			}
+		}
+
+		.scollhide::-webkit-scrollbar {
+			display: none;
+		}
+	}
+
+	.treeSel>>>.ivu-select-dropdown-list {
+		padding: 0 5px !important;
+		box-sizing: border-box;
+		width: 200px;
+	}
+
+	.imagesNo {
+		display: flex;
+		justify-content: center;
+		flex-direction: column;
+		align-items: center;
+		margin: 65px 0;
+
+		.imagesNo_sp {
+			font-size: 13px;
+			color: #dbdbdb;
+			line-height: 3;
+		}
+	}
+
+	.Modal {
+		width: 100%;
+		height: 100%;
+		background: #fff !important;
+	}
+
+	.Nav {
+		width: 100%;
+		border-right: 1px solid #eee;
+	}
+
+	.colLeft {
+		padding-right: 0 !important;
+		height: 100%;
+	}
+
+	.conter {
+		width: 100%;
+		height: 100%;
+		margin-left: 0 !important;
+	}
+
+	.conter .bnt {
+		width: 100%;
+		padding: 0 13px 10px 8px;
+		box-sizing: border-box;
+	}
+
+	.conter .pictrueList {
+		padding-left: 6px;
+		width: 100%;
+		max-width: 1200px;
+		overflow-x: hidden;
+		overflow-y: auto;
+		// height: 300px;
+	}
+
+	.conter .pictrueList img {
+		width: 100%;
+		border: 2px solid #fff;
+	}
+
+	.conter .pictrueList img.on {
+		border: 2px solid #5FB878;
+	}
+
+	.conter .footer {
+		padding: 0 20px 10px 20px;
+	}
+
+	.demo-badge {
+		width: 42px;
+		height: 42px;
+		background: transparent;
+		border-radius: 6px;
+		display: inline-block;
+	}
+
+	.bnt /deep/ .ivu-tree-children {
+		padding: 5px 0;
+	}
+
+	.trees-coadd /deep/ .ivu-tree-children .ivu-tree-arrow {
+		line-height: 25px;
+	}
+</style>

+ 954 - 0
src/components/uploadPictures2/index.vue

@@ -0,0 +1,954 @@
+<template>
+	<div class="Modal">
+		<Row class="colLeft">
+			<Col :xl="6" :lg="6" :md="6" :sm="6" :xs="24" class="colLeft">
+			<div class="Nav">
+				<div class="input">
+					<Input search enter-button placeholder="请输入分类名称" v-model="uploadName.name" style="width: 90%"
+						@on-search="changePage" />
+				</div>
+				<div class="trees-coadd">
+					<div class="scollhide">
+						<div class="trees">
+							<Tree :data="treeData" :render="renderContent" :load-data="loadData" class="treeBox"
+								ref="tree"></Tree>
+						</div>
+					</div>
+				</div>
+			</div>
+			</Col>
+			<Col :xl="18" :lg="18" :md="18" :sm="18" :xs="24" class="colLeft">
+			<div class="conter">
+				<div class="bnt acea-row row-middle">
+					<Col span="24">
+					<Button type="primary" :disabled="checkPicList.length === 0" @click="checkPics" class="mr10"
+						v-if="isShow !== 0">使用选中图片</Button>
+					<Upload :show-upload-list="false" :action="fileUrl" class="mr10 mb10" :before-upload="beforeUpload"
+						:data="uploadData" :headers="header" :multiple="true" :format="['jpg', 'jpeg', 'png', 'gif']"
+						:on-success="handleSuccess" style="margin-top: 1px; display: inline-block">
+						<Button type="primary">上传图片</Button>
+					</Upload>
+					<!--<Button type="success" @click.stop="add" class="mr10">添加分类</Button>-->
+					<Button type="error" class="mr10" :disabled="checkPicList.length === 0"
+						@click.stop="editPicList('图片')">删除图片</Button>
+					<i-select :value="pids" placeholder="图片移动至" style="width: 250px" class="treeSel">
+						<i-option v-for="(item, index) of list" :value="item.value" :key="index" style="display: none">
+							{{ item.title }}
+						</i-option>
+						<Tree :data="treeData2" :render="renderContentSel" ref="reference" :load-data="loadData"
+							class="treeBox"></Tree>
+					</i-select>
+					</Col>
+				</div>
+				<div class="pictrueList acea-row">
+					<Row :gutter="24" class="conter">
+						<div v-show="isShowPic" class="imagesNo">
+							<Icon type="ios-images" size="60" color="#dbdbdb" />
+							<span class="imagesNo_sp">图片库为空</span>
+						</div>
+						<div class="acea-row mb10">
+							<div class="pictrueList_pic mr10 mb10" v-for="(item, index) in pictrueList" :key="index"
+								@mouseenter="enterMouse(item)" @mouseleave="enterMouse(item)">
+								<p class="number" v-if="item.num > 0">
+									<Badge :count="item.num" type="error" :offset="[11, 12]">
+										<a href="#" class="demo-badge"></a>
+									</Badge>
+								</p>
+								<img :class="item.isSelect ? 'on' : ''" v-lazy="item.satt_dir"
+									@click.stop="changImage(item, index, pictrueList)" />
+								<div style="display: flex; align-items: center; justify-content: space-between"
+									@mouseenter="enterLeave(item)" @mouseleave="enterLeave(item)">
+									<p style="width: 80%" v-if="!item.isEdit">
+										{{ item.editName }}
+									</p>
+									<Input size="small" style="width: 80%" type="text" v-model="item.real_name" v-else
+										@on-blur="bindTxt(item)" />
+									<span class="iconfont iconbianji1" @click="item.isEdit = !item.isEdit"
+										v-if="item.isShowEdit"></span>
+								</div>
+								<div class="nameStyle" v-show="item.realName && item.real_name">
+									{{ item.real_name }}
+								</div>
+							</div>
+						</div>
+						<!--<Col class="mb20" v-bind="gridPic"-->
+						<!--v-for="(item, index) in pictrueList" :key="index" >-->
+						<!--<div class="pictrueList_pic">-->
+						<!--<img :class="item.isSelect ? 'on': '' " v-lazy="item.satt_dir"-->
+						<!--@click.stop="changImage(item, index, pictrueList)"/>-->
+						<!--</div>-->
+						<!--</Col>-->
+					</Row>
+				</div>
+				<div class="footer acea-row row-right">
+					<Page :total="total" show-elevator show-total @on-change="pageChange" :page-size="fileData.limit" />
+				</div>
+			</div>
+			</Col>
+		</Row>
+	</div>
+</template>
+
+<script>
+	import {
+		getCategoryListApi,
+		createApi,
+		fileListApi,
+		categoryEditApi,
+		moveApi,
+		fileUpdateApi,
+	} from '@/api/shopuploadPictures';
+	import Setting from '@/setting';
+	import {
+		getCookies
+	} from '@/libs/util';
+	export default {
+		name: 'shopuploadPictures',
+		// components: { editFrom },
+		props: {
+			isChoice: {
+				type: String,
+				default: '',
+			},
+			gridBtn: {
+				type: Object,
+				default: null,
+			},
+			gridPic: {
+				type: Object,
+				default: null,
+			},
+			isShow: {
+				type: Number,
+				default: 1,
+			},
+			pageLimit: {
+				type: Number,
+				default: 0,
+			},
+		},
+		data() {
+			return {
+				spinShow: false,
+				fileUrl: Setting.apiBaseURL + '/mer/file/upload',
+				modalPic: false,
+				treeData: [],
+				treeData2: [],
+				pictrueList: [],
+				uploadData: {}, // 上传参数
+				checkPicList: [],
+				uploadName: {
+					name: '',
+				},
+				FromData: null,
+				treeId: 0,
+				isJudge: false,
+				buttonProps: {
+					type: 'default',
+					size: 'small',
+				},
+				fileData: {
+					pid: 0,
+					page: 1,
+					limit: this.pageLimit || 18,
+				},
+				total: 0,
+				pids: 0,
+				list: [],
+				modalTitleSs: '',
+				isShowPic: false,
+				header: {},
+				ids: [], // 选中附件的id集合
+			};
+		},
+		mounted() {
+			this.getToken();
+			this.getList();
+			this.getFileList();
+		},
+		methods: {
+			enterMouse(item) {
+				item.realName = !item.realName;
+			},
+			enterLeave(item) {
+				item.isShowEdit = !item.isShowEdit;
+			},
+			// 上传头部token
+			getToken() {
+				this.header['Authori-zation'] = 'Bearer ' + getCookies('token');
+			},
+			// 树状图
+			renderContent(h, {
+				root,
+				node,
+				data
+			}) {
+				let operate = [];
+				if (data.pid == 0) {
+					operate.push(
+						h(
+							'div', {
+								class: ['ivu-dropdown-item'],
+								on: {
+									click: () => {
+										this.append(root, node, data);
+									},
+								},
+							},
+							'添加分类',
+						),
+					);
+				}
+				if (data.id !== '') {
+					operate.push(
+						h(
+							'div', {
+								class: ['ivu-dropdown-item'],
+								on: {
+									click: () => {
+										this.editPic(root, node, data);
+									},
+								},
+							},
+							'编辑分类',
+						),
+						h(
+							'div', {
+								class: ['ivu-dropdown-item'],
+								on: {
+									click: () => {
+										this.remove(root, node, data, '分类');
+									},
+								},
+							},
+							'删除分类',
+						),
+					);
+				}
+				return h(
+					'span', {
+						class: ['ivu-span'],
+						style: {
+							display: 'inline-block',
+							width: '88%',
+							height: '32px',
+							lineHeight: '32px',
+							position: 'relative',
+							color: 'rgba(0,0,0,0.6)',
+							cursor: 'pointer',
+						},
+						on: {
+							mouseenter: () => {
+								this.onMouseOver(root, node, data);
+							},
+							mouseleave: () => {
+								this.onMouseOver(root, node, data);
+							},
+							// click: (e) => {
+							//   this.appendBtn(root, node, data, e);
+							// },
+						},
+					},
+					[
+						h(
+							'span', {
+								on: {
+									click: (e) => {
+										this.appendBtn(root, node, data, e);
+									},
+								},
+							},
+							data.title,
+						),
+						h(
+							'div', {
+								style: {
+									display: 'inline-block',
+									float: 'right',
+								},
+							},
+							[
+								h('Icon', {
+									props: {
+										type: 'ios-more',
+									},
+									style: {
+										marginRight: '8px',
+										fontSize: '20px',
+										display: 'inline',
+									},
+									on: {
+										click: (e) => {
+											this.onClick(root, node, data, e);
+										},
+									},
+								}),
+								h(
+									'div', {
+										class: ['right-menu ivu-poptip-inner'],
+										style: {
+											width: '80px',
+											position: 'absolute',
+											zIndex: '9',
+											top: '0',
+											right: '0',
+											display: data.flag2 ? 'block' : 'none',
+										},
+									},
+									operate,
+								),
+							],
+						),
+					],
+				);
+			},
+			// renderContent (h, { root, node, data }) {
+			//     let actionData = [];
+			//     if (data.id !== '' && data.pid == 0) {
+			//         actionData.push(h('Button', {
+			//             props: Object.assign({}, this.buttonProps, {
+			//                 icon: 'ios-add'
+			//             }),
+			//             style: {
+			//                 marginRight: '8px',
+			//                 display: data.flag ? 'inline' : 'none'
+			//             },
+			//             on: {
+			//                 click: () => { this.append(root, node, data) }
+			//
+			//             }
+			//         }));
+			//     }
+			//     if (data.id !== '') {
+			//         actionData.push(h('Button', {
+			//             props: Object.assign({}, this.buttonProps, {
+			//                 icon: 'md-create'
+			//             }),
+			//             style: {
+			//                 marginRight: '8px',
+			//                 display: data.flag ? 'inline' : 'none'
+			//             },
+			//             on: {
+			//                 click: () => { this.editPic(root, node, data) }
+			//             }
+			//         }));
+			//         actionData.push(h('Button', {
+			//             props: Object.assign({}, this.buttonProps, {
+			//                 icon: 'ios-remove'
+			//             }),
+			//             style: {
+			//                 display: data.flag ? 'inline' : 'none'
+			//             },
+			//             on: {
+			//                 click: () => { this.remove(root, node, data, '分类') }
+			//             }
+			//         }));
+			//     }
+			//     return h('div', {
+			//         style: {
+			//             display: 'inline-block',
+			//             width: '90%'
+			//         },
+			//         on: {
+			//             mouseenter: () => { this.onMouseOver(root, node, data) },
+			//             mouseleave: () => { this.onMouseOver(root, node, data) }
+			//         }
+			//     }, [
+			//         h('span', [
+			//             h('span', {
+			//                 style: {
+			//                     cursor: 'pointer'
+			//                 },
+			//                 class: ['ivu-tree-title'],
+			//                 on: {
+			//                     click: (e) => { this.appendBtn(root, node, data, e) }
+			//                 }
+			//             }, data.title)
+			//         ]),
+			//         h('span', {
+			//             style: {
+			//                 display: 'inline-block',
+			//                 float: 'right'
+			//             }
+			//         }, actionData)
+			//     ]);
+			// },
+			renderContentSel(h, {
+				root,
+				node,
+				data
+			}) {
+				return h(
+					'div', {
+						style: {
+							display: 'inline-block',
+							width: '90%',
+						},
+					},
+					[
+						h('span', [
+							h(
+								'span', {
+									style: {
+										cursor: 'pointer',
+									},
+									class: ['ivu-tree-title'],
+									on: {
+										click: (e) => {
+											this.handleCheckChange(root, node, data, e);
+										},
+									},
+								},
+								data.title,
+							),
+						]),
+					],
+				);
+			},
+			// 下拉树
+			handleCheckChange(root, node, data, e) {
+				this.list = [];
+				// this.pids = 0;
+				let value = data.id;
+				let title = data.title;
+				this.list.push({
+					value,
+					title,
+				});
+				if (this.ids.length) {
+					this.pids = value;
+					this.getMove();
+				} else {
+					this.$Message.warning('请先选择图片');
+				}
+				let selected = this.$refs.reference.$el.querySelectorAll('.ivu-tree-title-selected');
+				for (let i = 0; i < selected.length; i++) {
+					selected[i].className = 'ivu-tree-title';
+				}
+				e.path[0].className = 'ivu-tree-title  ivu-tree-title-selected'; // 当前点击的元素
+			},
+			// 移动分类
+			getMove() {
+				let data = {
+					pid: this.pids,
+					images: this.ids.toString(),
+				};
+				moveApi(data)
+					.then(async (res) => {
+						this.$Message.success(res.msg);
+						this.getFileList();
+						this.pids = 0;
+						this.checkPicList = [];
+						this.ids = [];
+					})
+					.catch((res) => {
+						this.$Message.error(res.msg);
+					});
+			},
+			// 删除图片
+			editPicList(tit) {
+				this.tits = tit;
+				let ids = {
+					ids: this.ids.toString(),
+				};
+				let delfromData = {
+					title: '删除选中图片',
+					url: `file/file/delete`,
+					method: 'POST',
+					ids: ids,
+				};
+				this.$modalSure(delfromData)
+					.then((res) => {
+						this.$Message.success(res.msg);
+						this.getFileList();
+						this.checkPicList = [];
+					})
+					.catch((res) => {
+						this.$Message.error(res.msg);
+					});
+			},
+			// 鼠标移入 移出
+			onMouseOver(root, node, data) {
+				event.preventDefault();
+				data.flag = !data.flag;
+				if (data.flag2) {
+					data.flag2 = false;
+				}
+			},
+			onClick(root, node, data, e) {
+				e.preventDefault();
+
+				data.flag2 = !data.flag2;
+			},
+			// 点击树
+			appendBtn(root, node, data, e) {
+				e.preventDefault();
+
+				this.treeId = data.id;
+				this.fileData.page = 1;
+				this.getFileList();
+				let selected = this.$refs.tree.$el.querySelectorAll('.ivu-tree-title-selected');
+				for (let i = 0; i < selected.length; i++) {
+					selected[i].className = 'ivu-tree-title';
+				}
+				e.path[0].className = 'ivu-tree-title  ivu-tree-title-selected'; // 当前点击的元素
+			},
+			// 点击添加
+			append(root, node, data) {
+				this.treeId = data.id;
+				this.getFrom();
+			},
+			// 删除分类
+			remove(root, node, data, tit) {
+				this.tits = tit;
+				let delfromData = {
+					title: '删除 [ ' + data.title + ' ] ' + '分类',
+					url: `file/category/${data.id}`,
+					method: 'DELETE',
+					ids: '',
+				};
+				this.$modalSure(delfromData)
+					.then((res) => {
+						this.$Message.success(res.msg);
+						this.getList();
+						this.checkPicList = [];
+					})
+					.catch((res) => {
+						this.$Message.error(res.msg);
+					});
+			},
+			// 确认删除树
+			// submitModel () {
+			//     if (this.tits === '图片') {
+			//         this.getFileList();
+			//         this.checkPicList = [];
+			//     } else {
+			//         this.getList();
+			//         this.checkPicList = [];
+			//     }
+			// },
+			// 编辑树表单
+			editPic(root, node, data) {
+				this.$modalForm(categoryEditApi(data.id)).then(() => this.getList());
+			},
+			// 搜索分类
+			changePage() {
+				this.getList('search');
+			},
+			// 分类列表树
+			getList(type) {
+				let data = {
+					title: '全部图片',
+					id: '',
+					pid: 0,
+				};
+				getCategoryListApi(this.uploadName)
+					.then(async (res) => {
+						this.treeData = res.data.list;
+						this.treeData.unshift(data);
+						if (type !== 'search') {
+							this.treeData2 = [...this.treeData];
+						}
+						this.addFlag(this.treeData);
+					})
+					.catch((res) => {
+						this.$Message.error(res.msg);
+					});
+			},
+			loadData(item, callback) {
+				getCategoryListApi({
+						pid: item.id,
+					})
+					.then(async (res) => {
+						const data = res.data.list;
+						callback(data);
+					})
+					.catch((res) => {});
+			},
+			addFlag(treedata) {
+				treedata.map((item) => {
+					this.$set(item, 'flag', false);
+					this.$set(item, 'flag2', false);
+					item.children && this.addFlag(item.children);
+				});
+			},
+			// 新建分类
+			add() {
+				this.treeId = 0;
+				this.getFrom();
+			},
+			// 文件列表
+			getFileList() {
+				this.fileData.pid = this.treeId;
+				fileListApi(this.fileData)
+					.then(async (res) => {
+						res.data.list.forEach((el) => {
+							el.isSelect = false;
+							el.isEdit = false;
+							el.isShowEdit = false;
+							el.realName = false;
+							el.num = 0;
+							this.editName(el);
+						});
+						this.pictrueList = res.data.list;
+
+						if (this.pictrueList.length) {
+							this.isShowPic = false;
+						} else {
+							this.isShowPic = true;
+						}
+						this.total = res.data.count;
+					})
+					.catch((res) => {
+						this.$Message.error(res.msg);
+					});
+			},
+			pageChange(index) {
+				this.fileData.page = index;
+				this.getFileList();
+				this.checkPicList = [];
+			},
+			// 新建分类表单
+			getFrom() {
+				this.$modalForm(createApi({
+					id: this.treeId
+				})).then((res) => {
+					this.getList();
+				});
+			},
+			// 上传之前
+			beforeUpload(file) {
+				// if (file.size > 2097152) {
+				//   this.$Message.error(file.name + "大小超过2M!");
+				// } else
+				if (!/image\/\w+/.test(file.type)) {
+					this.$Message.error('请上传以jpg、jpeg、png等结尾的图片文件'); //FileExt.toLowerCase()
+					return false;
+				}
+				this.uploadData = {
+					pid: this.treeId,
+				};
+				let promise = new Promise((resolve) => {
+					this.$nextTick(function() {
+						resolve(true);
+					});
+				});
+				return promise;
+			},
+			// 上传成功
+			handleSuccess(res, file, fileList) {
+				if (res.status === 200) {
+					this.$Message.success(res.msg);
+					this.fileData.page = 1;
+					this.getFileList();
+				} else {
+					this.$Message.error(res.msg);
+				}
+			},
+			// 关闭
+			cancel() {
+				this.$emit('changeCancel');
+			},
+			// 选中图片
+			changImage(item, index, row) {
+				let activeIndex = 0;
+				if (!item.isSelect) {
+					item.isSelect = true;
+					this.checkPicList.push(item);
+				} else {
+					item.isSelect = false;
+					this.checkPicList.map((el, index) => {
+						if (el.att_id == item.att_id) {
+							activeIndex = index;
+						}
+					});
+					this.checkPicList.splice(activeIndex, 1);
+				}
+
+				this.ids = [];
+				this.checkPicList.map((item, i) => {
+					this.ids.push(item.att_id);
+				});
+				this.pictrueList.map((el, i) => {
+					if (el.isSelect) {
+						this.checkPicList.filter((el2, j) => {
+							if (el.att_id == el2.att_id) {
+								el.num = j + 1;
+							}
+						});
+					} else {
+						el.num = 0;
+					}
+				});
+			},
+			// 点击使用选中图片
+			checkPics() {
+				if (this.isChoice === '单选') {
+					if (this.checkPicList.length > 1) return this.$Message.warning('最多只能选一张图片');
+					this.$emit('getPic', this.checkPicList[0]);
+				} else {
+					let maxLength = this.$route.query.maxLength;
+					if (maxLength != undefined && this.checkPicList.length > Number(maxLength))
+						return this.$Message.warning('最多只能选' + maxLength + '张图片');
+					this.$emit('getPicD', this.checkPicList);
+				}
+			},
+			editName(item) {
+				let it = item.real_name.split('.');
+				let it1 = it[1] == undefined ? [] : it[1];
+				let len = it[0].length + it1.length;
+				item.editName = len < 10 ? item.real_name : item.real_name.substr(0, 2) + '...' + item.real_name.substr(-5,
+					5);
+			},
+			// 修改图片文字上传
+			bindTxt(item) {
+				if (item.real_name == '') {
+					this.$Message.error('请填写内容');
+				}
+				fileUpdateApi(item.att_id, {
+						real_name: item.real_name,
+					})
+					.then((res) => {
+						this.editName(item);
+						item.isEdit = false;
+						this.$Message.success(res.msg);
+					})
+					.catch((error) => {
+						this.$Message.error(error.msg);
+					});
+			},
+		},
+	};
+</script>
+
+<style scoped lang="stylus">
+	.nameStyle {
+		position: absolute;
+		white-space: nowrap;
+		z-index: 9;
+		background: #eee;
+		height: 20px;
+		line-height: 20px;
+		color: #555;
+		border: 1px solid #ebebeb;
+		padding: 0 5px;
+		left: 56px;
+		bottom: -18px;
+	}
+
+	.iconbianji1 {
+		font-size: 13px;
+	}
+
+	/deep/.ivu-badge-count {
+		margin-top: 18px !important;
+		margin-right: 19px !important;
+	}
+
+	/deep/ivu-tree-title-selected:hover {
+		color: unset;
+		background-color: unset;
+	}
+
+	/deep/.ivu-tree-title {
+		padding: 0;
+		// width: 200px;
+		width: 100%;
+	}
+
+	/deep/.ivu-span {
+		padding: 0;
+		display: flex !important;
+		justify-content: space-between;
+	}
+
+	/deep/.ivu-tree ul li {
+		margin: 0;
+	}
+
+	/deep/.ivu-tree-arrow {
+		width: 17px;
+		color: #626262;
+	}
+
+	/deep/.ivu-span:hover {
+		background: #F5F5F5;
+		color: rgba(0, 0, 0, 0.4) !important;
+	}
+
+	/deep/.ivu-tree-arrow i {
+		vertical-align: bottom;
+	}
+
+	.Nav /deep/.ivu-icon-ios-arrow-forward:before {
+		content: '\F341' !important;
+		font-size: 20px;
+	}
+
+	/deep/.ivu-btn-icon-only.ivu-btn-small {
+		padding: unset !important;
+	}
+
+	.selectTreeClass {
+		background: #d5e8fc;
+	}
+
+	.treeBox {
+		width: 100%;
+		height: 100%;
+
+		>>>.ivu-tree-title-selected,
+		.ivu-tree-title-selected:hover {
+			color: #2D8cF0 !important;
+			background-color: #fff !important;
+		}
+
+		>>>.ivu-btn-icon-only {
+			width: 20px !important;
+			height: 20px !important;
+		}
+
+		>>>.ivu-tree-title:hover {
+			color: #2D8cF0 !important;
+			background-color: #fff !important;
+		}
+	}
+
+	.pictrueList_pic {
+		position: relative;
+		width: 100px;
+		cursor: pointer;
+
+		img {
+			width: 100%;
+			height: 100px;
+		}
+
+		p {
+			overflow: hidden;
+			text-overflow: ellipsis;
+			white-space: nowrap;
+			height: 20px;
+			text-align: center;
+		}
+
+		.number {
+			height: 33px;
+		}
+
+		.number {
+			position: absolute;
+			right: 0;
+			top: 0;
+		}
+	}
+
+	.trees-coadd {
+		width: 100%;
+		border-radius: 4px;
+		overflow: hidden;
+		position: relative;
+
+		.scollhide {
+			overflow-x: hidden;
+			overflow-y: scroll;
+			padding: 10px 0 10px 0;
+			box-sizing: border-box;
+
+			.trees {
+				width: 100%;
+				height: 374px;
+			}
+		}
+
+		.scollhide::-webkit-scrollbar {
+			display: none;
+		}
+	}
+
+	.treeSel>>>.ivu-select-dropdown-list {
+		padding: 0 5px !important;
+		box-sizing: border-box;
+		width: 200px;
+	}
+
+	.imagesNo {
+		display: flex;
+		justify-content: center;
+		flex-direction: column;
+		align-items: center;
+		margin: 65px 0;
+
+		.imagesNo_sp {
+			font-size: 13px;
+			color: #dbdbdb;
+			line-height: 3;
+		}
+	}
+
+	.Modal {
+		width: 100%;
+		height: 100%;
+		background: #fff !important;
+	}
+
+	.Nav {
+		width: 100%;
+		border-right: 1px solid #eee;
+	}
+
+	.colLeft {
+		padding-right: 0 !important;
+		height: 100%;
+	}
+
+	.conter {
+		width: 100%;
+		height: 100%;
+		margin-left: 0 !important;
+	}
+
+	.conter .bnt {
+		width: 100%;
+		padding: 0 13px 10px 8px;
+		box-sizing: border-box;
+	}
+
+	.conter .pictrueList {
+		padding-left: 6px;
+		width: 100%;
+		max-width: 1200px;
+		overflow-x: hidden;
+		overflow-y: auto;
+		// height: 300px;
+	}
+
+	.conter .pictrueList img {
+		width: 100%;
+		border: 2px solid #fff;
+	}
+
+	.conter .pictrueList img.on {
+		border: 2px solid #5FB878;
+	}
+
+	.conter .footer {
+		padding: 0 20px 10px 20px;
+	}
+
+	.demo-badge {
+		width: 42px;
+		height: 42px;
+		background: transparent;
+		border-radius: 6px;
+		display: inline-block;
+	}
+
+	.bnt /deep/ .ivu-tree-children {
+		padding: 5px 0;
+	}
+
+	.trees-coadd /deep/ .ivu-tree-children .ivu-tree-arrow {
+		line-height: 25px;
+	}
+</style>

+ 76 - 0
src/components/uploadPictures2/widgetImg.vue

@@ -0,0 +1,76 @@
+<template>
+  <div class="box">
+    <upload-from
+      :isChoice="isChoiceD"
+      @getPicD="getPicD"
+      :gridPic="gridPic"
+      :gridBtn="gridBtn"
+      v-if="this.$route.query.fodder === 'dialog' || this.$route.query.type === 'many'"
+    ></upload-from>
+    <upload-from :isChoice="isChoice" @getPic="getPic" :gridPic="gridPic" :gridBtn="gridBtn" v-else></upload-from>
+  </div>
+</template>
+
+<script>
+import uploadFrom from './index';
+// import '../../../public/UEditor/dialogs/internal';
+export default {
+  name: 'widgetImg',
+  components: { uploadFrom },
+  data() {
+    return {
+      isChoice: '单选',
+      isChoiceD: '多选',
+      gridPic: {
+        xl: 4,
+        lg: 4,
+        md: 8,
+        sm: 12,
+        xs: 12,
+      },
+      gridBtn: {
+        xl: 4,
+        lg: 4,
+        md: 4,
+        sm: 8,
+        xs: 8,
+      },
+    };
+  },
+  mounted() {},
+  methods: {
+    getPicD(pc) {
+      let pcs = window.form_create_helper.get(this.$route.query.fodder) || [];
+      pc = pc.map((item) => {
+        return item.att_dir;
+      });
+      let concatPc = pcs.concat(pc);
+      let pcList = Array.from(new Set(concatPc));
+      form_create_helper.set(this.$route.query.fodder, pcList);
+      form_create_helper.close(this.$route.query.fodder);
+    },
+    getPic(pc) {
+      form_create_helper.set(this.$route.query.fodder, pc.satt_dir);
+      form_create_helper.close(this.$route.query.fodder);
+    },
+    // getPic (pc) {
+    //     if (this.$route.query.fodder === 'dialog') {
+    //         /* eslint-disable */
+    //         nowEditor.dialog.close(true);
+    //         nowEditor.editor.setContent('<img src="'+pc.att_dir+'">',true);
+    //     }
+    //     else {
+    //         form_create_helper.set(this.$route.query.fodder, pc.satt_dir)
+    //         form_create_helper.close(this.$route.query.fodder);
+    //     }
+    // }
+  },
+};
+</script>
+
+<style scoped lang="stylus">
+.box {
+  width: 100%;
+  background: #fff;
+}
+</style>

+ 91 - 103
src/components/verifition/Verify/VerifyPoints.vue

@@ -1,31 +1,20 @@
 <template>
-  <div style="position: relative">
-    <div class="verify-img-out">
-      <div
-        class="verify-img-panel"
-        :style="{
+	<div style="position: relative">
+		<div class="verify-img-out">
+			<div class="verify-img-panel" :style="{
           width: setSize.imgWidth,
           height: setSize.imgHeight,
           'background-size': setSize.imgWidth + ' ' + setSize.imgHeight,
           'margin-bottom': vSpace + 'px',
-        }"
-      >
-        <div v-show="showRefresh" class="verify-refresh" style="z-index: 3" @click="refresh">
-          <i class="iconfont icon-refresh" />
-        </div>
-        <img
-          ref="canvas"
-          :src="pointBackImgBase ? 'data:image/png;base64,' + pointBackImgBase : defaultImg"
-          alt=""
-          style="width: 100%; height: 100%; display: block"
-          @click="bindingClick ? canvasClick($event) : undefined"
-        />
+        }">
+				<div v-show="showRefresh" class="verify-refresh" style="z-index: 3" @click="refresh">
+					<i class="iconfont icon-refresh" />
+				</div>
+				<img ref="canvas" :src="pointBackImgBase ? 'data:image/png;base64,' + pointBackImgBase : defaultImg"
+					alt="" style="width: 100%; height: 100%; display: block"
+					@click="bindingClick ? canvasClick($event) : undefined" />
 
-        <div
-          v-for="(tempPoint, index) in tempPoints"
-          :key="index"
-          class="point-area"
-          :style="{
+				<div v-for="(tempPoint, index) in tempPoints" :key="index" class="point-area" :style="{
             'background-color': '#1abd6c',
             color: '#fff',
             'z-index': 9999,
@@ -37,28 +26,24 @@
             position: 'absolute',
             top: parseInt(tempPoint.y - 10) + 'px',
             left: parseInt(tempPoint.x - 10) + 'px',
-          }"
-        >
-          {{ index + 1 }}
-        </div>
-      </div>
-    </div>
-    <!-- 'height': this.barSize.height, -->
-    <div
-      class="verify-bar-area"
-      :style="{
+          }">
+					{{ index + 1 }}
+				</div>
+			</div>
+		</div>
+		<!-- 'height': this.barSize.height, -->
+		<div class="verify-bar-area" :style="{
         width: setSize.imgWidth,
         color: this.barAreaColor,
         'border-color': this.barAreaBorderColor,
         'line-height': this.barSize.height,
-      }"
-    >
-      <span class="verify-msg">{{ text }}</span>
-    </div>
-  </div>
+      }">
+			<span class="verify-msg">{{ text }}</span>
+		</div>
+	</div>
 </template>
 <script type="text/babel">
-/**
+	/**
  * VerifyPoints
  * @description 点选
  * */
@@ -161,55 +146,58 @@ export default {
         this.$parent.$emit('ready', this);
       });
     },
-    canvasClick(e) {
-      this.checkPosArr.push(this.getMousePos(this.$refs.canvas, e));
-      if (this.num == this.checkNum) {
-        this.num = this.createPoint(this.getMousePos(this.$refs.canvas, e));
-        // 按比例转换坐标值
-        this.checkPosArr = this.pointTransfrom(this.checkPosArr, this.setSize);
-        // 等创建坐标执行完
-        setTimeout(() => {
-          // var flag = this.comparePos(this.fontPos, this.checkPosArr);
-          // 发送后端请求
-          var captchaVerification = this.secretKey
-            ? aesEncrypt(this.backToken + '---' + JSON.stringify(this.checkPosArr), this.secretKey)
-            : this.backToken + '---' + JSON.stringify(this.checkPosArr);
-          const data = {
-            captchaType: this.captchaType,
-            pointJson: this.secretKey
-              ? aesEncrypt(JSON.stringify(this.checkPosArr), this.secretKey)
-              : JSON.stringify(this.checkPosArr),
-            token: this.backToken,
-          };
-          ajCaptchaCheck(data).then((res) => {
-            if (res.repCode == '0000') {
-              this.barAreaColor = '#4cae4c';
-              this.barAreaBorderColor = '#5cb85c';
-              this.text = '验证成功';
-              this.bindingClick = false;
-              if (this.mode == 'pop') {
-                setTimeout(() => {
-                  this.$parent.clickShow = false;
-                  this.refresh();
-                }, 1500);
-              }
-              this.$parent.$emit('success', { captchaVerification });
-            } else {
-              this.$parent.$emit('error', this);
-              this.barAreaColor = '#d9534f';
-              this.barAreaBorderColor = '#d9534f';
-              this.text = '验证失败';
-              setTimeout(() => {
-                this.refresh();
-              }, 700);
-            }
-          });
-        }, 400);
-      }
-      if (this.num < this.checkNum) {
-        this.num = this.createPoint(this.getMousePos(this.$refs.canvas, e));
-      }
-    },
+	canvasClick() {
+		
+	},
+    // canvasClick(e) {
+    //   this.checkPosArr.push(this.getMousePos(this.$refs.canvas, e));
+    //   if (this.num == this.checkNum) {
+    //     this.num = this.createPoint(this.getMousePos(this.$refs.canvas, e));
+    //     // 按比例转换坐标值
+    //     this.checkPosArr = this.pointTransfrom(this.checkPosArr, this.setSize);
+    //     // 等创建坐标执行完
+    //     setTimeout(() => {
+    //       // var flag = this.comparePos(this.fontPos, this.checkPosArr);
+    //       // 发送后端请求
+    //       var captchaVerification = this.secretKey
+    //         ? aesEncrypt(this.backToken + '---' + JSON.stringify(this.checkPosArr), this.secretKey)
+    //         : this.backToken + '---' + JSON.stringify(this.checkPosArr);
+    //       const data = {
+    //         captchaType: this.captchaType,
+    //         pointJson: this.secretKey
+    //           ? aesEncrypt(JSON.stringify(this.checkPosArr), this.secretKey)
+    //           : JSON.stringify(this.checkPosArr),
+    //         token: this.backToken,
+    //       };
+    //       ajCaptchaCheck(data).then((res) => {
+    //         if (res.repCode == '0000') {
+    //           this.barAreaColor = '#4cae4c';
+    //           this.barAreaBorderColor = '#5cb85c';
+    //           this.text = '验证成功';
+    //           this.bindingClick = false;
+    //           if (this.mode == 'pop') {
+    //             setTimeout(() => {
+    //               this.$parent.clickShow = false;
+    //               this.refresh();
+    //             }, 1500);
+    //           }
+    //           this.$parent.$emit('success', { captchaVerification });
+    //         } else {
+    //           this.$parent.$emit('error', this);
+    //           this.barAreaColor = '#d9534f';
+    //           this.barAreaBorderColor = '#d9534f';
+    //           this.text = '验证失败';
+    //           setTimeout(() => {
+    //             this.refresh();
+    //           }, 700);
+    //         }
+    //       });
+    //     }, 400);
+    //   }
+    //   if (this.num < this.checkNum) {
+    //     this.num = this.createPoint(this.getMousePos(this.$refs.canvas, e));
+    //   }
+    // },
 
     // 获取坐标
     getMousePos: function (obj, e) {
@@ -242,22 +230,22 @@ export default {
         clientUid: localStorage.getItem('point'),
         ts: Date.now(), // 现在的时间戳
       };
-      ajCaptcha(data).then((res) => {
-        if (res.repCode == '0000') {
-          this.pointBackImgBase = res.repData.originalImageBase64;
-          this.backToken = res.repData.token;
-          this.secretKey = res.repData.secretKey;
-          this.poinTextList = res.repData.wordList;
-          this.text = '请依次点击【' + this.poinTextList.join(',') + '】';
-        } else {
-          this.text = res.repMsg;
-        }
+      // ajCaptcha(data).then((res) => {
+      //   if (res.repCode == '0000') {
+      //     this.pointBackImgBase = res.repData.originalImageBase64;
+      //     this.backToken = res.repData.token;
+      //     this.secretKey = res.repData.secretKey;
+      //     this.poinTextList = res.repData.wordList;
+      //     this.text = '请依次点击【' + this.poinTextList.join(',') + '】';
+      //   } else {
+      //     this.text = res.repMsg;
+      //   }
 
-        // 判断接口请求次数是否失效
-        if (res.repCode == '6201') {
-          this.pointBackImgBase = null;
-        }
-      });
+      //   // 判断接口请求次数是否失效
+      //   if (res.repCode == '6201') {
+      //     this.pointBackImgBase = null;
+      //   }
+      // });
     },
     // 坐标转换函数
     pointTransfrom(pointArr, imgSize) {
@@ -270,4 +258,4 @@ export default {
     },
   },
 };
-</script>
+</script>

+ 88 - 105
src/components/verifition/Verify/VerifySlide.vue

@@ -1,70 +1,53 @@
 <template>
-  <div style="position: relative">
-    <div v-if="type === '2'" class="verify-img-out" :style="{ height: parseInt(setSize.imgHeight) + vSpace + 'px' }">
-      <div class="verify-img-panel" :style="{ width: setSize.imgWidth, height: setSize.imgHeight }">
-        <img
-          :src="backImgBase ? 'data:image/png;base64,' + backImgBase : defaultImg"
-          alt=""
-          style="width: 100%; height: 100%; display: block"
-        />
-        <div v-show="showRefresh" class="verify-refresh" @click="refresh"><i class="iconfont icon-refresh" /></div>
-        <transition name="tips">
-          <span v-if="tipWords" class="verify-tips" :class="passFlag ? 'suc-bg' : 'err-bg'">{{ tipWords }}</span>
-        </transition>
-      </div>
-    </div>
-    <!-- 公共部分 -->
-    <div
-      class="verify-bar-area"
-      :style="{ width: setSize.imgWidth, height: barSize.height, 'line-height': barSize.height }"
-    >
-      <span class="verify-msg" v-text="text" />
-      <div
-        class="verify-left-bar"
-        :style="{
+	<div style="position: relative">
+		<div v-if="type === '2'" class="verify-img-out"
+			:style="{ height: parseInt(setSize.imgHeight) + vSpace + 'px' }">
+			<div class="verify-img-panel" :style="{ width: setSize.imgWidth, height: setSize.imgHeight }">
+				<img :src="backImgBase ? 'data:image/png;base64,' + backImgBase : defaultImg" alt=""
+					style="width: 100%; height: 100%; display: block" />
+				<div v-show="showRefresh" class="verify-refresh" @click="refresh"><i class="iconfont icon-refresh" />
+				</div>
+				<transition name="tips">
+					<span v-if="tipWords" class="verify-tips"
+						:class="passFlag ? 'suc-bg' : 'err-bg'">{{ tipWords }}</span>
+				</transition>
+			</div>
+		</div>
+		<!-- 公共部分 -->
+		<div class="verify-bar-area"
+			:style="{ width: setSize.imgWidth, height: barSize.height, 'line-height': barSize.height }">
+			<span class="verify-msg" v-text="text" />
+			<div class="verify-left-bar" :style="{
           width: leftBarWidth !== undefined ? leftBarWidth : barSize.height,
           height: barSize.height,
           'border-color': leftBarBorderColor,
           transaction: transitionWidth,
-        }"
-      >
-        <span class="verify-msg" v-text="finishText" />
-        <div
-          class="verify-move-block"
-          :style="{
+        }">
+				<span class="verify-msg" v-text="finishText" />
+				<div class="verify-move-block" :style="{
             width: barSize.height,
             height: barSize.height,
             'background-color': moveBlockBackgroundColor,
             left: moveBlockLeft,
             transition: transitionLeft,
-          }"
-          @touchstart="start"
-          @mousedown="start"
-        >
-          <i :class="['verify-icon iconfont', iconClass]" :style="{ color: iconColor }" />
-          <div
-            v-if="type === '2'"
-            class="verify-sub-block"
-            :style="{
+          }" @touchstart="start" @mousedown="start">
+					<i :class="['verify-icon iconfont', iconClass]" :style="{ color: iconColor }" />
+					<div v-if="type === '2'" class="verify-sub-block" :style="{
               width: Math.floor((parseInt(setSize.imgWidth) * 47) / 310) + 'px',
               height: setSize.imgHeight,
               top: '-' + (parseInt(setSize.imgHeight) + vSpace) + 'px',
               'background-size': setSize.imgWidth + ' ' + setSize.imgHeight,
-            }"
-          >
-            <img
-              :src="'data:image/png;base64,' + blockBackImgBase"
-              alt=""
-              style="width: 100%; height: 100%; display: block"
-            />
-          </div>
-        </div>
-      </div>
-    </div>
-  </div>
+            }">
+						<img :src="'data:image/png;base64,' + blockBackImgBase" alt=""
+							style="width: 100%; height: 100%; display: block" />
+					</div>
+				</div>
+			</div>
+		</div>
+	</div>
 </template>
 <script type="text/babel">
-/**
+	/**
  * VerifySlide
  * @description 滑块
  * */
@@ -292,47 +275,47 @@ export default {
             : JSON.stringify({ x: moveLeftDistance, y: 5.0 }),
           token: this.backToken,
         };
-        ajCaptchaCheck(data)
-          .then((res) => {
-            this.moveBlockBackgroundColor = '#5cb85c';
-            this.leftBarBorderColor = '#5cb85c';
-            this.iconColor = '#fff';
-            this.iconClass = 'icon-check';
-            this.showRefresh = false;
-            this.isEnd = true;
-            if (this.mode == 'pop') {
-              setTimeout(() => {
-                this.$parent.clickShow = false;
-                this.refresh();
-              }, 1500);
-            }
-            this.passFlag = true;
-            this.tipWords = `${((this.endMovetime - this.startMoveTime) / 1000).toFixed(2)}s验证成功`;
-            var captchaVerification = this.secretKey
-              ? aesEncrypt(this.backToken + '---' + JSON.stringify({ x: moveLeftDistance, y: 5.0 }), this.secretKey)
-              : this.backToken + '---' + JSON.stringify({ x: moveLeftDistance, y: 5.0 });
-            setTimeout(() => {
-              this.tipWords = '';
-              this.$parent.closeBox();
-              this.$parent.$emit('success', { captchaVerification });
-            }, 1000);
-          })
-          .catch((res) => {
-            this.moveBlockBackgroundColor = '#d9534f';
-            this.leftBarBorderColor = '#d9534f';
-            this.iconColor = '#fff';
-            this.iconClass = 'icon-close';
-            this.passFlag = false;
-            setTimeout(function () {
-              _this.refresh();
-            }, 1000);
-            this.$parent.$emit('error', this);
-            this.tipWords = '验证失败';
-            setTimeout(() => {
-              this.tipWords = '';
-            }, 1000);
-          });
-        this.status = false;
+        // ajCaptchaCheck(data)
+        //   .then((res) => {
+        //     this.moveBlockBackgroundColor = '#5cb85c';
+        //     this.leftBarBorderColor = '#5cb85c';
+        //     this.iconColor = '#fff';
+        //     this.iconClass = 'icon-check';
+        //     this.showRefresh = false;
+        //     this.isEnd = true;
+        //     if (this.mode == 'pop') {
+        //       setTimeout(() => {
+        //         this.$parent.clickShow = false;
+        //         this.refresh();
+        //       }, 1500);
+        //     }
+        //     this.passFlag = true;
+        //     this.tipWords = `${((this.endMovetime - this.startMoveTime) / 1000).toFixed(2)}s验证成功`;
+        //     var captchaVerification = this.secretKey
+        //       ? aesEncrypt(this.backToken + '---' + JSON.stringify({ x: moveLeftDistance, y: 5.0 }), this.secretKey)
+        //       : this.backToken + '---' + JSON.stringify({ x: moveLeftDistance, y: 5.0 });
+        //     setTimeout(() => {
+        //       this.tipWords = '';
+        //       this.$parent.closeBox();
+        //       this.$parent.$emit('success', { captchaVerification });
+        //     }, 1000);
+        //   })
+        //   .catch((res) => {
+        //     this.moveBlockBackgroundColor = '#d9534f';
+        //     this.leftBarBorderColor = '#d9534f';
+        //     this.iconColor = '#fff';
+        //     this.iconClass = 'icon-close';
+        //     this.passFlag = false;
+        //     setTimeout(function () {
+        //       _this.refresh();
+        //     }, 1000);
+        //     this.$parent.$emit('error', this);
+        //     this.tipWords = '验证失败';
+        //     setTimeout(() => {
+        //       this.tipWords = '';
+        //     }, 1000);
+        //   });
+        // this.status = false;
       }
     },
 
@@ -367,19 +350,19 @@ export default {
         clientUid: localStorage.getItem('slider'),
         ts: Date.now(), // 现在的时间戳
       };
-      ajCaptcha(data)
-        .then((res) => {
-          this.backImgBase = res.data.originalImageBase64;
-          this.blockBackImgBase = res.data.jigsawImageBase64;
-          this.backToken = res.data.token;
-          this.secretKey = res.data.secretKey;
-        })
-        .catch((res) => {
-          this.tipWords = res.msg;
-          this.backImgBase = null;
-          this.blockBackImgBase = null;
-        });
+      // ajCaptcha(data)
+      //   .then((res) => {
+      //     this.backImgBase = res.data.originalImageBase64;
+      //     this.blockBackImgBase = res.data.jigsawImageBase64;
+      //     this.backToken = res.data.token;
+      //     this.secretKey = res.data.secretKey;
+      //   })
+      //   .catch((res) => {
+      //     this.tipWords = res.msg;
+      //     this.backImgBase = null;
+      //     this.blockBackImgBase = null;
+      //   });
     },
   },
 };
-</script>
+</script>

+ 280 - 265
src/layout/component/columnsAside.vue

@@ -1,284 +1,299 @@
 <template>
-  <div class="layout-columns-aside">
-    <el-scrollbar>
-      <Logo />
-      <ul>
-        <li
-          v-for="(v, k) in columnsAsideList"
-          :key="k"
-          @click="onColumnsAsideMenuClick(v)"
-          ref="columnsAsideOffsetTopRefs"
-          class="layout-columns"
-          :class="{ 'layout-columns-active': v.k === liIndex }"
-          :title="$t(v.title)"
-        >
-          <div :class="setColumnsAsidelayout" v-if="!v.isLink || (v.isLink && v.isIframe)">
-            <Icon :type="v.icon" />
-            <div class="font12">
-              {{
+	<div class="layout-columns-aside">
+		<el-scrollbar>
+			<Logo />
+			<ul>
+				<li v-for="(v, k) in columnsAsideList" :key="k" @click="onColumnsAsideMenuClick(v)"
+					ref="columnsAsideOffsetTopRefs" class="layout-columns"
+					:class="{ 'layout-columns-active': v.k === liIndex }" :title="$t(v.title)">
+					<div :class="setColumnsAsidelayout" v-if="!v.isLink || (v.isLink && v.isIframe)">
+						<Icon :type="v.icon" />
+						<div class="font12">
+							{{
                 $t(v.title) && $t(v.title).length >= 4
                   ? $t(v.title).substr(0, setColumnsAsidelayout === 'columns-vertical' ? 4 : 3)
                   : $t(v.title)
               }}
-            </div>
-          </div>
-          <div :class="setColumnsAsidelayout" v-else>
-            <a :href="v.isLink" target="_blank">
-              <Icon :type="v.icon" />
-              <div class="font12">
-                {{
+						</div>
+					</div>
+					<div :class="setColumnsAsidelayout" v-else>
+						<a :href="v.isLink" target="_blank">
+							<Icon :type="v.icon" />
+							<div class="font12">
+								{{
                   $t(v.title) && $t(v.title).length >= 4
                     ? $t(v.title).substr(0, setColumnsAsidelayout === 'columns-vertical' ? 4 : 3)
                     : $t(v.title)
                 }}1
-              </div>
-            </a>
-          </div>
-        </li>
-        <div ref="columnsAsideActiveRef" :class="setColumnsAsideStyle"></div>
-      </ul>
-    </el-scrollbar>
-  </div>
+							</div>
+						</a>
+					</div>
+				</li>
+				<div ref="columnsAsideActiveRef" :class="setColumnsAsideStyle"></div>
+			</ul>
+		</el-scrollbar>
+	</div>
 </template>
 
 <script>
-import { getMenuSider, getHeaderName } from '@/libs/system';
-import Logo from '@/layout/logo/index.vue';
+	import {
+		getMenuSider,
+		getHeaderName
+	} from '@/libs/system';
+	import Logo from '@/layout/logo/index.vue';
 
-export default {
-  name: 'layoutColumnsAside',
-  components: { Logo },
-  data() {
-    return {
-      columnsAsideList: [],
-      liIndex: 0,
-      difference: 0,
-      routeSplit: [],
-      activePath: '',
-    };
-  },
-  computed: {
-    // 设置分栏高亮风格
-    setColumnsAsideStyle() {
-      return this.$store.state.themeConfig.themeConfig.columnsAsideStyle;
-    },
-    // 设置分栏布局风格
-    setColumnsAsidelayout() {
-      return this.$store.state.themeConfig.themeConfig.columnsAsideLayout;
-    },
-    Layout() {
-      return this.$store.state.themeConfig.themeConfig.Layout;
-    },
-    routesList() {
-      this.$store.state.routesList.routesList;
-    },
-  },
-  beforeDestroy() {
-    this.bus.$off('routesListChange');
-  },
-  mounted() {
-    this.bus.$on('routesListChange', () => {
-      this.setFilterRoutes();
-    });
-    this.setFilterRoutes();
-  },
-  methods: {
-    // 设置菜单高亮位置移动
-    setColumnsAsideMove(k) {
-      if (k === undefined) return false;
-      const els = this.$refs.columnsAsideOffsetTopRefs;
-      this.liIndex = k;
-      this.$refs.columnsAsideActiveRef.style.top = `${els[k].offsetTop + this.difference}px`;
-    },
-    // 菜单高亮点击事件
-    onColumnsAsideMenuClick(v) {
-      let { path, redirect } = v;
-      if (path) this.$router.push(path);
-      else this.$router.push(path);
-      // 一个路由设置自动收起菜单
-      if (!v.children || v.children.length <= 1) this.$store.state.themeConfig.themeConfig.isCollapse = true;
-      else if (v.children.length > 1) this.$store.state.themeConfig.themeConfig.isCollapse = false;
-      // this.bus.$emit('setSendColumnsChildren', getMenuSider(this.columnsAsideList, path));
-    },
-    // 设置高亮动态位置
-    onColumnsAsideDown(k) {
-      this.$nextTick(() => {
-        this.setColumnsAsideMove(k);
-      });
-    },
-    // 设置/过滤路由(非静态路由/是否显示在菜单中)
-    setFilterRoutes() {
-      if (this.$store.state.routesList.routesList.length <= 0) return false;
-      this.columnsAsideList = this.filterRoutesFun(this.$store.state.routesList.routesList);
-      //   const resData = getHeaderName(this.$route.path, this.columnsAsideList);
-      const resData = this.setSendChildren(getHeaderName(this.$route, this.columnsAsideList));
-      if (!resData.children) {
-        this.bus.$emit('setSendColumnsChildren', []);
-        this.$store.commit('menus/childMenuList', []);
+	export default {
+		name: 'layoutColumnsAside',
+		components: {
+			Logo
+		},
+		data() {
+			return {
+				columnsAsideList: [],
+				liIndex: 0,
+				difference: 0,
+				routeSplit: [],
+				activePath: '',
+			};
+		},
+		computed: {
+			// 设置分栏高亮风格
+			setColumnsAsideStyle() {
+				return this.$store.state.themeConfig.themeConfig.columnsAsideStyle;
+			},
+			// 设置分栏布局风格
+			setColumnsAsidelayout() {
+				return this.$store.state.themeConfig.themeConfig.columnsAsideLayout;
+			},
+			Layout() {
+				return this.$store.state.themeConfig.themeConfig.Layout;
+			},
+			routesList() {
+				this.$store.state.routesList.routesList;
+			},
+		},
+		beforeDestroy() {
+			this.bus.$off('routesListChange');
+		},
+		mounted() {
+			this.bus.$on('routesListChange', () => {
+				this.setFilterRoutes();
+			});
+			this.setFilterRoutes();
+		},
+		methods: {
+			// 设置菜单高亮位置移动
+			setColumnsAsideMove(k) {
+				if (k === undefined) return false;
+				const els = this.$refs.columnsAsideOffsetTopRefs;
+				this.liIndex = k;
+				this.$refs.columnsAsideActiveRef.style.top = `${els[k].offsetTop + this.difference}px`;
+			},
+			// 菜单高亮点击事件
+			onColumnsAsideMenuClick(v) {
+				let {
+					path,
+					redirect
+				} = v;
+				if (path) this.$router.push(path);
+				else this.$router.push(path);
+				// 一个路由设置自动收起菜单
+				if (!v.children || v.children.length <= 1) this.$store.state.themeConfig.themeConfig.isCollapse = true;
+				else if (v.children.length > 1) this.$store.state.themeConfig.themeConfig.isCollapse = false;
+				// this.bus.$emit('setSendColumnsChildren', getMenuSider(this.columnsAsideList, path));
+			},
+			// 设置高亮动态位置
+			onColumnsAsideDown(k) {
+				this.$nextTick(() => {
+					this.setColumnsAsideMove(k);
+				});
+			},
+			// 设置/过滤路由(非静态路由/是否显示在菜单中)
+			setFilterRoutes() {
+				if (this.$store.state.routesList.routesList.length <= 0) return false;
+				this.columnsAsideList = this.filterRoutesFun(this.$store.state.routesList.routesList);
+				//   const resData = getHeaderName(this.$route.path, this.columnsAsideList);
+				const resData = this.setSendChildren(getHeaderName(this.$route, this.columnsAsideList));
+				if (!resData.children) {
+					this.bus.$emit('setSendColumnsChildren', []);
+					this.$store.commit('menus/childMenuList', []);
 
-        this.$store.state.themeConfig.themeConfig.isCollapse = true;
-        return false;
-      }
-      this.bus.$emit('oneCatName', resData.item[0].title);
-      this.onColumnsAsideDown(resData.item[0].k);
-      // 刷新时,初始化一个路由设置自动收起菜单
-      resData.children.length > 0
-        ? (this.$store.state.themeConfig.themeConfig.isCollapse = false)
-        : (this.$store.state.themeConfig.themeConfig.isCollapse = true);
-      this.bus.$emit('setSendColumnsChildren', resData?.children || []);
-      this.$store.commit('menus/childMenuList', resData?.children || []);
-    },
-    // 传送当前子级数据到菜单中
-    setSendChildren(path) {
-      const currentPathSplit = path.split('/');
-      let currentData = {};
-      this.columnsAsideList.map((v, k) => {
-        if (v.path === path) {
-          v['k'] = k;
-          currentData['item'] = [{ ...v }];
-          //   currentData['children'] = [{ ...v }];
-          if (v.children) currentData['children'] = v.children;
-        }
-      });
-      return currentData;
-    },
-    // 路由过滤递归函数
-    filterRoutesFun(arr) {
-      return arr
-        .filter((item) => item.path)
-        .map((item) => {
-          item = Object.assign({}, item);
-          if (item.children) item.children = this.filterRoutesFun(item.children);
-          return item;
-        });
-    },
-    // tagsView 点击时,根据路由查找下标 columnsAsideList,实现左侧菜单高亮
-    setColumnsMenuHighlight(path) {
-      // this.routeSplit = path.split('/');
-      // this.routeSplit.shift();
-      // const routeFirst = `/${this.routeSplit[0]}`;
-      const currentSplitRoute = this.columnsAsideList.find((v) => v.path === path);
-      if (!currentSplitRoute) {
-        // this.onColumnsAsideDown(0);
-        return false;
-      }
-      // 延迟拿值,防止取不到
-      setTimeout(() => {
-        this.onColumnsAsideDown(currentSplitRoute.k);
-      }, 0);
-    },
-  },
-  watch: {
-    // 监听 vuex 数据变化
-    '$store.state': {
-      handler(val) {
-        val.themeConfig.themeConfig.columnsAsideStyle === 'columnsRound'
-          ? (this.difference = 3)
-          : (this.difference = 0);
-        if (val.routesList.routesList.length === this.columnsAsideList.length) return false;
-      },
-      deep: true,
-    },
-    // 监听路由的变化
-    $route: {
-      handler(to) {
-        this.setColumnsMenuHighlight(to.path);
-        // this.setColumnsAsideMove();
-        let HeadName = getHeaderName(to, this.columnsAsideList);
-        let asideList = getMenuSider(this.columnsAsideList, HeadName)[0]?.children;
-        const resData = this.setSendChildren(HeadName);
-        if (resData.length <= 0) return false;
-        this.onColumnsAsideDown(resData.item[0].k);
-        this.bus.$emit('oneCatName', resData.item[0].title);
-        this.bus.$emit('setSendColumnsChildren', asideList || []);
-        this.$store.commit('menus/childMenuList', asideList || []);
-      },
-      deep: true,
-    },
-  },
-};
+					this.$store.state.themeConfig.themeConfig.isCollapse = true;
+					return false;
+				}
+				this.bus.$emit('oneCatName', resData.item[0].title);
+				this.onColumnsAsideDown(resData.item[0].k);
+				// 刷新时,初始化一个路由设置自动收起菜单
+				resData.children.length > 0 ?
+					(this.$store.state.themeConfig.themeConfig.isCollapse = false) :
+					(this.$store.state.themeConfig.themeConfig.isCollapse = true);
+				this.bus.$emit('setSendColumnsChildren', resData?.children || []);
+				this.$store.commit('menus/childMenuList', resData?.children || []);
+			},
+			// 传送当前子级数据到菜单中
+			setSendChildren(path) {
+				const currentPathSplit = path.split('/');
+				let currentData = {};
+				this.columnsAsideList.map((v, k) => {
+					if (v.path === path) {
+						v['k'] = k;
+						currentData['item'] = [{
+							...v
+						}];
+						//   currentData['children'] = [{ ...v }];
+						if (v.children) currentData['children'] = v.children;
+					}
+				});
+				return currentData;
+			},
+			// 路由过滤递归函数
+			filterRoutesFun(arr) {
+				return arr
+					.filter((item) => item.path)
+					.map((item) => {
+						item = Object.assign({}, item);
+						if (item.children) item.children = this.filterRoutesFun(item.children);
+						return item;
+					});
+			},
+			// tagsView 点击时,根据路由查找下标 columnsAsideList,实现左侧菜单高亮
+			setColumnsMenuHighlight(path) {
+				// this.routeSplit = path.split('/');
+				// this.routeSplit.shift();
+				// const routeFirst = `/${this.routeSplit[0]}`;
+				const currentSplitRoute = this.columnsAsideList.find((v) => v.path === path);
+				if (!currentSplitRoute) {
+					// this.onColumnsAsideDown(0);
+					return false;
+				}
+				// 延迟拿值,防止取不到
+				setTimeout(() => {
+					this.onColumnsAsideDown(currentSplitRoute.k);
+				}, 0);
+			},
+		},
+		watch: {
+			// 监听 vuex 数据变化
+			'$store.state': {
+				handler(val) {
+					val.themeConfig.themeConfig.columnsAsideStyle === 'columnsRound' ?
+						(this.difference = 3) :
+						(this.difference = 0);
+					if (val.routesList.routesList.length === this.columnsAsideList.length) return false;
+				},
+				deep: true,
+			},
+			// 监听路由的变化
+			$route: {
+				handler(to) {
+					this.setColumnsMenuHighlight(to.path);
+					// this.setColumnsAsideMove();
+					let HeadName = getHeaderName(to, this.columnsAsideList);
+					let asideList = getMenuSider(this.columnsAsideList, HeadName)[0]?.children;
+					const resData = this.setSendChildren(HeadName);
+					if (resData.length <= 0) return false;
+					this.onColumnsAsideDown(resData.item[0].k);
+					this.bus.$emit('oneCatName', resData.item[0].title);
+					this.bus.$emit('setSendColumnsChildren', asideList || []);
+					this.$store.commit('menus/childMenuList', asideList || []);
+				},
+				deep: true,
+			},
+		},
+	};
 </script>
 
 <style scoped lang="scss">
-.layout-columns-aside {
-  width: 70px;
-  height: 100%;
-  background: var(--prev-bg-columnsMenuBar);
-  box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
-  border-right: 1px solid var(--prev-border-color-lighter);
+	.layout-columns-aside {
+		width: 70px;
+		height: 100%;
+		background: var(--prev-bg-columnsMenuBar);
+		box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
+		border-right: 1px solid var(--prev-border-color-lighter);
 
-  ul {
-    position: relative;
-    li {
-      color: var(--prev-bg-columnsMenuBarColor);
-      width: 100%;
-      height: 50px;
-      text-align: center;
-      display: flex;
-      cursor: pointer;
-      position: relative;
-      z-index: 1;
-      .columns-vertical {
-        margin: auto;
-        .columns-vertical-title {
-          padding-top: 1px;
-        }
-      }
-      .columns-horizontal {
-        display: flex;
-        height: 50px;
-        width: 100%;
-        align-items: center;
-        justify-content: center;
-        padding: 0 5px;
-        i {
-          margin-right: 3px;
-        }
-        a {
-          display: flex;
-          .columns-horizontal-title {
-            padding-top: 1px;
-          }
-        }
-      }
-      a {
-        text-decoration: none;
-        color: var(--prev-bg-columnsMenuBarColor);
-      }
-    }
-    // li:hover {
-    //   background: var(--prev-color-primary);
-    //   color: var(--prev-bg-columnsMenuBarColor);
-    // }
-    .layout-columns {
-      transition: 0.3s ease-in-out;
-    }
-    .layout-columns-active,
-    .layout-columns-active a {
-      color: var(--prev-bg-columnsMenuActiveColor);
-      transition: 0.3s ease-in-out;
-    }
+		ul {
+			position: relative;
 
-    .columns-round {
-      background: var(--prev-color-primary);
-      // color: var(--prev-color-text-white);
-      position: absolute;
-      left: 50%;
-      top: 2px;
-      height: 50px;
-      width: 65px;
-      transform: translateX(-50%);
-      z-index: 0;
-      transition: 0.3s ease-in-out;
-      border-radius: 5px;
-    }
-    .columns-card {
-      @extend .columns-round;
-      top: 0;
-      height: 50px;
-      width: 100%;
-      border-radius: 0;
-    }
-  }
-}
-</style>
+			li {
+				color: var(--prev-bg-columnsMenuBarColor);
+				width: 100%;
+				height: 50px;
+				text-align: center;
+				display: flex;
+				cursor: pointer;
+				position: relative;
+				z-index: 1;
+
+				.columns-vertical {
+					margin: auto;
+
+					.columns-vertical-title {
+						padding-top: 1px;
+					}
+				}
+
+				.columns-horizontal {
+					display: flex;
+					height: 50px;
+					width: 100%;
+					align-items: center;
+					justify-content: center;
+					padding: 0 5px;
+
+					i {
+						margin-right: 3px;
+					}
+
+					a {
+						display: flex;
+
+						.columns-horizontal-title {
+							padding-top: 1px;
+						}
+					}
+				}
+
+				a {
+					text-decoration: none;
+					color: var(--prev-bg-columnsMenuBarColor);
+				}
+			}
+
+			// li:hover {
+			//   background: var(--prev-color-primary);
+			//   color: var(--prev-bg-columnsMenuBarColor);
+			// }
+			.layout-columns {
+				transition: 0.3s ease-in-out;
+			}
+
+			.layout-columns-active,
+			.layout-columns-active a {
+				color: var(--prev-bg-columnsMenuActiveColor);
+				transition: 0.3s ease-in-out;
+			}
+
+			.columns-round {
+				background: var(--prev-color-primary);
+				// color: var(--prev-color-text-white);
+				position: absolute;
+				left: 50%;
+				top: 2px;
+				height: 50px;
+				width: 65px;
+				transform: translateX(-50%);
+				z-index: 0;
+				transition: 0.3s ease-in-out;
+				border-radius: 5px;
+			}
+
+			.columns-card {
+				@extend .columns-round;
+				top: 0;
+				height: 50px;
+				width: 100%;
+				border-radius: 0;
+			}
+		}
+	}
+</style>

+ 26 - 23
src/layout/footer/index.vue

@@ -1,31 +1,34 @@
 <template>
-  <div class="layout-footer mt15">
-    <div class="layout-footer-warp">
-      <iCopyright />
-    </div>
-  </div>
+	<div class="layout-footer mt15">
+		<div class="layout-footer-warp">
+			<!-- <iCopyright /> -->
+		</div>
+	</div>
 </template>
 
 <script>
-import iCopyright from '@/components/copyright';
+	// import iCopyright from '@/components/copyright';
 
-export default {
-  components: { iCopyright },
-  name: 'layoutFooter',
-  data() {
-    return {};
-  },
-};
+	export default {
+		// components: {
+		// 	iCopyright
+		// },
+		name: 'layoutFooter',
+		data() {
+			return {};
+		},
+	};
 </script>
 
 <style scoped lang="scss">
-.layout-footer {
-  width: 100%;
-  display: flex;
-  &-warp {
-    margin: auto;
-    color: var(--prev-color-text-secondary);
-    text-align: center;
-  }
-}
-</style>
+	.layout-footer {
+		width: 100%;
+		display: flex;
+
+		&-warp {
+			margin: auto;
+			color: var(--prev-color-text-secondary);
+			text-align: center;
+		}
+	}
+</style>

+ 98 - 91
src/layout/logo/index.vue

@@ -1,100 +1,107 @@
 <template>
-  <div
-    class="layout-logo"
-    v-if="$store.state.themeConfig.themeConfig.layout !== 'columns' && !$store.state.themeConfig.themeConfig.isCollapse"
-    @click="onThemeConfigChange"
-  >
-    <img v-if="maxLogo" class="layout-logo-medium-img" :src="maxLogo" />
-  </div>
-  <div class="layout-logo-size" v-else @click="onThemeConfigChange">
-    <img v-if="minLogo" class="layout-logo-size-img" :src="minLogo" />
-  </div>
+	<div class="layout-logo"
+		v-if="$store.state.themeConfig.themeConfig.layout !== 'columns' && !$store.state.themeConfig.themeConfig.isCollapse"
+		@click="onThemeConfigChange">
+		<img v-if="maxLogo" class="layout-logo-medium-img" :src="maxLogo" />
+	</div>
+	<div class="layout-logo-size" v-else @click="onThemeConfigChange">
+		<img v-if="minLogo" class="layout-logo-size-img" :src="minLogo" />
+	</div>
 </template>
 
 <script>
-import { getLogo } from '@/api/common';
+	import {
+		getLogo
+	} from '@/api/common';
 
-export default {
-  name: 'layoutLogo',
-  data() {
-    return {
-      minLogo: '',
-      maxLogo: '',
-    };
-  },
-  computed: {
-    // 获取布局配置信息
-    getThemeConfig() {
-      return this.$store.state.themeConfig.themeConfig;
-    },
-    // 设置 logo 是否显示
-    setShowLogo() {
-      let { isCollapse, layout } = this.$store.state.themeConfig.themeConfig;
-      return !isCollapse || layout === 'classic' || document.body.clientWidth < 1000;
-    },
-  },
-  mounted() {
-    this.getLogo();
-  },
-  methods: {
-    // logo 点击实现菜单展开/收起
-    onThemeConfigChange() {
-      if (
-        this.$store.state.themeConfig.themeConfig.layout == 'columns' &&
-        !this.$store.state.menus.childMenuList.length &&
-        this.$store.state.themeConfig.themeConfig.isCollapse
-      )
-        return;
-      if (this.$store.state.themeConfig.themeConfig.layout === 'transverse') return false;
-      this.$store.state.themeConfig.themeConfig.isCollapse = !this.$store.state.themeConfig.themeConfig.isCollapse;
-    },
-    getLogo() {
-      getLogo().then((res) => {
-        this.minLogo = res.data.logo_square;
-        this.maxLogo = res.data.logo;
-      });
-    },
-  },
-};
+	export default {
+		name: 'layoutLogo',
+		data() {
+			return {
+				minLogo: '',
+				maxLogo: '',
+			};
+		},
+		computed: {
+			// 获取布局配置信息
+			getThemeConfig() {
+				return this.$store.state.themeConfig.themeConfig;
+			},
+			// 设置 logo 是否显示
+			setShowLogo() {
+				let {
+					isCollapse,
+					layout
+				} = this.$store.state.themeConfig.themeConfig;
+				return !isCollapse || layout === 'classic' || document.body.clientWidth < 1000;
+			},
+		},
+		mounted() {
+			// this.getLogo();
+		},
+		methods: {
+			// logo 点击实现菜单展开/收起
+			onThemeConfigChange() {
+				if (
+					this.$store.state.themeConfig.themeConfig.layout == 'columns' &&
+					!this.$store.state.menus.childMenuList.length &&
+					this.$store.state.themeConfig.themeConfig.isCollapse
+				)
+					return;
+				if (this.$store.state.themeConfig.themeConfig.layout === 'transverse') return false;
+				this.$store.state.themeConfig.themeConfig.isCollapse = !this.$store.state.themeConfig.themeConfig
+					.isCollapse;
+			},
+			getLogo() {
+				getLogo().then((res) => {
+					this.minLogo = res.data.logo_square;
+					this.maxLogo = res.data.logo;
+				});
+			},
+		},
+	};
 </script>
 
 <style scoped lang="scss">
-.layout-logo {
-  width: 180px;
-  height: 50px;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  //   box-shadow: 0px 1px 4px rgba(0, 21, 41, 2%);
-  color: var(--prev-color-primary);
-  font-size: 16px;
-  cursor: pointer;
-  animation: logoAnimation 0.3s ease-in-out;
-  &:hover {
-    span {
-      opacity: 0.9;
-    }
-  }
-  &-medium-img {
-    width: 100%;
-    height: 50px;
-    margin-right: 5px;
-    position: relative;
-    top: 2px;
-  }
-}
-.layout-logo-size {
-  width: 50px;
-  height: 50px;
-  display: flex;
-  cursor: pointer;
-  margin: auto;
+	.layout-logo {
+		width: 180px;
+		height: 50px;
+		display: flex;
+		align-items: center;
+		justify-content: center;
+		//   box-shadow: 0px 1px 4px rgba(0, 21, 41, 2%);
+		color: var(--prev-color-primary);
+		font-size: 16px;
+		cursor: pointer;
+		animation: logoAnimation 0.3s ease-in-out;
 
-  &-img {
-    width: 50px;
-    height: 50px;
-    margin: auto;
-    animation: logoAnimation 0.3s ease-in-out;
-  }
-}
-</style>
+		&:hover {
+			span {
+				opacity: 0.9;
+			}
+		}
+
+		&-medium-img {
+			width: 100%;
+			height: 50px;
+			margin-right: 5px;
+			position: relative;
+			top: 2px;
+		}
+	}
+
+	.layout-logo-size {
+		width: 50px;
+		height: 50px;
+		display: flex;
+		cursor: pointer;
+		margin: auto;
+
+		&-img {
+			width: 50px;
+			height: 50px;
+			margin: auto;
+			animation: logoAnimation 0.3s ease-in-out;
+		}
+	}
+</style>

+ 212 - 205
src/layout/navBars/breadcrumb/breadcrumb.vue

@@ -1,213 +1,220 @@
 <template>
-  <div class="layout-navbars-breadcrumb">
-    <!-- {{[...breadCrumbList,...crumbPast]}} -->
-    <i
-      v-if="collapseShow"
-      class="layout-navbars-breadcrumb-icon"
-      :class="getThemeConfig.isCollapse ? 'el-icon-s-unfold' : 'el-icon-s-fold'"
-      @click="onThemeConfigChange"
-    ></i>
-    <el-breadcrumb class="layout-navbars-breadcrumb-hide" v-if="isShowcrumb" :style="{ display: isShowBreadcrumb }">
-      <transition-group name="breadcrumb" mode="out-in">
-        <el-breadcrumb-item v-for="(v, k) in [...breadCrumbList, ...crumbPast]" :key="v.path">
-          <span v-if="k == 1" class="layout-navbars-breadcrumb-span">
-            <Icon
-              :type="v.icon"
-              class="ivu-icon layout-navbars-breadcrumb-iconfont"
-              v-if="getThemeConfig.isBreadcrumbIcon"
-            />{{ $t(v.title) }}
-          </span>
-          <a v-else @click.prevent="onBreadcrumbClick(v)">
-            <Icon
-              :type="v.icon"
-              class="ivu-icon layout-navbars-breadcrumb-iconfont"
-              v-if="getThemeConfig.isBreadcrumbIcon"
-            />{{ $t(v.title) }}
-          </a>
-        </el-breadcrumb-item>
-      </transition-group>
-    </el-breadcrumb>
-  </div>
+	<div class="layout-navbars-breadcrumb">
+		<!-- {{[...breadCrumbList,...crumbPast]}} -->
+		<i v-if="collapseShow" class="layout-navbars-breadcrumb-icon"
+			:class="getThemeConfig.isCollapse ? 'el-icon-s-unfold' : 'el-icon-s-fold'" @click="onThemeConfigChange"></i>
+		<el-breadcrumb class="layout-navbars-breadcrumb-hide" v-if="isShowcrumb" :style="{ display: isShowBreadcrumb }">
+			<transition-group name="breadcrumb" mode="out-in">
+				<el-breadcrumb-item v-for="(v, k) in [...breadCrumbList, ...crumbPast]" :key="v.path">
+					<span v-if="k == 1" class="layout-navbars-breadcrumb-span">
+						<Icon :type="v.icon" class="ivu-icon layout-navbars-breadcrumb-iconfont"
+							v-if="getThemeConfig.isBreadcrumbIcon" />{{ $t(v.title) }}
+					</span>
+					<a v-else @click.prevent="onBreadcrumbClick(v)">
+						<Icon :type="v.icon" class="ivu-icon layout-navbars-breadcrumb-iconfont"
+							v-if="getThemeConfig.isBreadcrumbIcon" />{{ $t(v.title) }}
+					</a>
+				</el-breadcrumb-item>
+			</transition-group>
+		</el-breadcrumb>
+	</div>
 </template>
 
 <script>
-import { Local } from '@/utils/storage.js';
-import { R } from '@/libs/util';
-import { getMenuopen } from '@/libs/util';
+	import {
+		Local
+	} from '@/utils/storage.js';
+	import {
+		R
+	} from '@/libs/util';
+	import {
+		getMenuopen
+	} from '@/libs/util';
 
-export default {
-  name: 'layoutBreadcrumb',
-  data() {
-    return {
-      breadcrumbList: [],
-      routeSplit: [],
-      routeSplitFirst: '',
-      routeSplitIndex: 1,
-    };
-  },
-  computed: {
-    breadCrumbList() {
-      let menuList = this.$store.state.menus.menusName;
-      let openMenus = getMenuopen(this.$route, menuList);
-      let allMenuList = R(menuList, []);
-      let selectMenu = [];
-      if (allMenuList.length > 0) {
-        openMenus.forEach((i) => {
-          allMenuList.forEach((a) => {
-            if (i === a.path) {
-              selectMenu.push(a);
-            }
-          });
-        });
-      }
-      return selectMenu;
-    },
-    crumbPast() {
-      let that = this;
-      let menuList = that.$store.state.menus.menusName;
-      let allMenuList = R(menuList, []);
-      let selectMenu = [];
-      if (allMenuList.length > 0) {
-        allMenuList.forEach((a) => {
-          if (that.$route.path === a.path) {
-            selectMenu.push(a);
-          }
-        });
-      }
-      return selectMenu;
-    },
-    // 获取布局配置信息
-    getThemeConfig() {
-      return this.$store.state.themeConfig.themeConfig;
-    },
-    // 动态设置经典、横向布局不显示
-    isShowBreadcrumb() {
-      const { layout, isBreadcrumb } = this.$store.state.themeConfig.themeConfig;
-      if (layout === 'transverse' || layout === 'classic') {
-        return 'none';
-      } else {
-        return isBreadcrumb ? '' : 'none';
-      }
-    },
-    isShowcrumb() {
-      const { layout } = this.$store.state.themeConfig.themeConfig;
-      if (layout === 'transverse' || layout === 'classic') {
-        return false;
-      } else {
-        return true;
-      }
-    },
-    collapseShow() {
-      return  ['defaults','columns'].includes(this.$store.state.themeConfig.themeConfig.layout);
-    },
-  },
-  mounted() {
-    this.initRouteSplit(this.$route.path);
-  },
-  methods: {
-    // breadcrumb 当前项点击时
-    onBreadcrumbClick(v) {
-      const { redirect, path } = v;
-      if (redirect) this.$router.push(redirect);
-      else this.$router.push(path);
-    },
-    // breadcrumb icon 点击菜单展开与收起
-    onThemeConfigChange() {
-      if (
-        this.$store.state.themeConfig.themeConfig.layout == 'columns' &&
-        !this.$store.state.menus.childMenuList.length &&
-        this.$store.state.themeConfig.themeConfig.isCollapse
-      ) {
-        return;
-      }
-      this.$store.state.themeConfig.themeConfig.isCollapse = !this.$store.state.themeConfig.themeConfig.isCollapse;
-      this.setLocalThemeConfig();
-    },
-    // 存储布局配置
-    setLocalThemeConfig() {
-      Local.remove('themeConfigPrev');
-      Local.set('themeConfigPrev', this.$store.state.themeConfig.themeConfig);
-    },
-    // 递归设置 breadcrumb
-    getBreadcrumbList(arr) {
-      arr.map((item) => {
-        this.routeSplit.map((v, k, arrs) => {
-          if (this.routeSplitFirst === item.path) {
-            this.routeSplitFirst += `/${arrs[this.routeSplitIndex]}`;
-            this.breadcrumbList.push(item);
-            this.routeSplitIndex++;
-            if (item.children) this.getBreadcrumbList(item.children);
-          }
-        });
-      });
-    },
-    // 当前路由分割处理
-    initRouteSplit(path) {
-      this.breadcrumbList = [
-        {
-          path: '/',
-          meta: {
-            title: this.$store.state.routesList.routesList[0].title,
-            icon: this.$store.state.routesList.routesList[0].icon,
-          },
-        },
-      ];
-      //   this.routeSplit = path.split('/');
-      //   this.routeSplit.shift();
-      this.routeSplitFirst = path;
-      this.routeSplitIndex = 1;
-      this.getBreadcrumbList(this.$store.state.routesList.routesList);
-    },
-  },
-  // 监听路由的变化
-  watch: {
-    $route: {
-      handler(newVal) {
-        // this.initRouteSplit(newVal.path);
-        let menuList = this.$store.state.menus.menusName;
-        let openMenus = getMenuopen(newVal, menuList);
-        let allMenuList = R(menuList, []);
-        let selectMenu = [];
-        if (allMenuList.length > 0) {
-          openMenus.forEach((i) => {
-            allMenuList.forEach((a) => {
-              if (i === a.path) {
-                selectMenu.push(a);
-              }
-            });
-          });
-        }
-      },
-      deep: true,
-    },
-  },
-};
+	export default {
+		name: 'layoutBreadcrumb',
+		data() {
+			return {
+				breadcrumbList: [],
+				routeSplit: [],
+				routeSplitFirst: '',
+				routeSplitIndex: 1,
+			};
+		},
+		computed: {
+			breadCrumbList() {
+				let menuList = this.$store.state.menus.menusName;
+				let openMenus = getMenuopen(this.$route, menuList);
+				let allMenuList = R(menuList, []);
+				let selectMenu = [];
+				if (allMenuList.length > 0) {
+					openMenus.forEach((i) => {
+						allMenuList.forEach((a) => {
+							if (i === a.path) {
+								selectMenu.push(a);
+							}
+						});
+					});
+				}
+				return selectMenu;
+			},
+			crumbPast() {
+				let that = this;
+				let menuList = that.$store.state.menus.menusName;
+				let allMenuList = R(menuList, []);
+				let selectMenu = [];
+				if (allMenuList.length > 0) {
+					allMenuList.forEach((a) => {
+						if (that.$route.path === a.path) {
+							selectMenu.push(a);
+						}
+					});
+				}
+				return selectMenu;
+			},
+			// 获取布局配置信息
+			getThemeConfig() {
+				return this.$store.state.themeConfig.themeConfig;
+			},
+			// 动态设置经典、横向布局不显示
+			isShowBreadcrumb() {
+				const {
+					layout,
+					isBreadcrumb
+				} = this.$store.state.themeConfig.themeConfig;
+				if (layout === 'transverse' || layout === 'classic') {
+					return 'none';
+				} else {
+					return isBreadcrumb ? '' : 'none';
+				}
+			},
+			isShowcrumb() {
+				const {
+					layout
+				} = this.$store.state.themeConfig.themeConfig;
+				if (layout === 'transverse' || layout === 'classic') {
+					return false;
+				} else {
+					return true;
+				}
+			},
+			collapseShow() {
+				return ['defaults', 'columns'].includes(this.$store.state.themeConfig.themeConfig.layout);
+			},
+		},
+		mounted() {
+			this.initRouteSplit(this.$route.path);
+		},
+		methods: {
+			// breadcrumb 当前项点击时
+			onBreadcrumbClick(v) {
+				const {
+					redirect,
+					path
+				} = v;
+				if (redirect) this.$router.push(redirect);
+				else this.$router.push(path);
+			},
+			// breadcrumb icon 点击菜单展开与收起
+			onThemeConfigChange() {
+				if (
+					this.$store.state.themeConfig.themeConfig.layout == 'columns' &&
+					!this.$store.state.menus.childMenuList.length &&
+					this.$store.state.themeConfig.themeConfig.isCollapse
+				) {
+					return;
+				}
+				this.$store.state.themeConfig.themeConfig.isCollapse = !this.$store.state.themeConfig.themeConfig
+					.isCollapse;
+				this.setLocalThemeConfig();
+			},
+			// 存储布局配置
+			setLocalThemeConfig() {
+				Local.remove('themeConfigPrev');
+				Local.set('themeConfigPrev', this.$store.state.themeConfig.themeConfig);
+			},
+			// 递归设置 breadcrumb
+			getBreadcrumbList(arr) {
+				arr.map((item) => {
+					this.routeSplit.map((v, k, arrs) => {
+						if (this.routeSplitFirst === item.path) {
+							this.routeSplitFirst += `/${arrs[this.routeSplitIndex]}`;
+							this.breadcrumbList.push(item);
+							this.routeSplitIndex++;
+							if (item.children) this.getBreadcrumbList(item.children);
+						}
+					});
+				});
+			},
+			// 当前路由分割处理
+			initRouteSplit(path) {
+				this.breadcrumbList = [{
+					path: '/',
+					meta: {
+						title: this.$store.state.routesList.routesList[0].title,
+						icon: this.$store.state.routesList.routesList[0].icon,
+					},
+				}, ];
+				//   this.routeSplit = path.split('/');
+				//   this.routeSplit.shift();
+				this.routeSplitFirst = path;
+				this.routeSplitIndex = 1;
+				this.getBreadcrumbList(this.$store.state.routesList.routesList);
+			},
+		},
+		// 监听路由的变化
+		watch: {
+			$route: {
+				handler(newVal) {
+					// this.initRouteSplit(newVal.path);
+					let menuList = this.$store.state.menus.menusName;
+					let openMenus = getMenuopen(newVal, menuList);
+					let allMenuList = R(menuList, []);
+					let selectMenu = [];
+					if (allMenuList.length > 0) {
+						openMenus.forEach((i) => {
+							allMenuList.forEach((a) => {
+								if (i === a.path) {
+									selectMenu.push(a);
+								}
+							});
+						});
+					}
+				},
+				deep: true,
+			},
+		},
+	};
 </script>
 
 <style scoped lang="scss">
-.layout-navbars-breadcrumb {
-  // flex: 1;
-  height: inherit;
-  display: flex;
-  align-items: center;
-  padding-left: 15px;
-  .layout-navbars-breadcrumb-icon {
-    cursor: pointer;
-    font-size: 18px;
-    margin-right: 15px;
-    color: var(--prev-bg-topBarColor);
-    opacity: 0.8;
-    &:hover {
-      opacity: 1;
-    }
-  }
-  .layout-navbars-breadcrumb-span {
-    opacity: 0.7;
-    color: var(--prev-bg-topBarColor);
-  }
-  .layout-navbars-breadcrumb-iconfont {
-    font-size: 14px;
-    margin-right: 5px;
-  }
-}
-</style>
+	.layout-navbars-breadcrumb {
+		// flex: 1;
+		height: inherit;
+		display: flex;
+		align-items: center;
+		padding-left: 15px;
+
+		.layout-navbars-breadcrumb-icon {
+			cursor: pointer;
+			font-size: 18px;
+			margin-right: 15px;
+			color: var(--prev-bg-topBarColor);
+			opacity: 0.8;
+
+			&:hover {
+				opacity: 1;
+			}
+		}
+
+		.layout-navbars-breadcrumb-span {
+			opacity: 0.7;
+			color: var(--prev-bg-topBarColor);
+		}
+
+		.layout-navbars-breadcrumb-iconfont {
+			font-size: 14px;
+			margin-right: 5px;
+		}
+	}
+</style>

+ 96 - 102
src/layout/navBars/breadcrumb/search.vue

@@ -1,109 +1,103 @@
 <template>
-  <div class="layout-search-dialog">
-    <el-dialog
-      :visible.sync="isShowSearch"
-      width="300px"
-      destroy-on-close
-      :modal="false"
-      fullscreen
-      :show-close="false"
-    >
-      <el-autocomplete
-        v-model="menuQuery"
-        :fetch-suggestions="menuSearch"
-        :placeholder="$t('message.user.searchPlaceholder')"
-        prefix-icon="el-icon-search"
-        ref="layoutMenuAutocompleteRef"
-        @select="onHandleSelect"
-        @blur="onSearchBlur"
-      >
-        <template slot-scope="{ item }">
-          <div><i :class="item.icon" class="mr10"></i>{{ $t(item.title) }}</div>
-        </template>
-      </el-autocomplete>
-    </el-dialog>
-  </div>
+	<div class="layout-search-dialog">
+		<el-dialog :visible.sync="isShowSearch" width="300px" destroy-on-close :modal="false" fullscreen
+			:show-close="false">
+			<el-autocomplete v-model="menuQuery" :fetch-suggestions="menuSearch"
+				:placeholder="$t('message.user.searchPlaceholder')" prefix-icon="el-icon-search"
+				ref="layoutMenuAutocompleteRef" @select="onHandleSelect" @blur="onSearchBlur">
+				<template slot-scope="{ item }">
+					<div><i :class="item.icon" class="mr10"></i>{{ $t(item.title) }}</div>
+				</template>
+			</el-autocomplete>
+		</el-dialog>
+	</div>
 </template>
 
 <script>
-import { getAllSiderMenu } from '@/libs/system';
-export default {
-  name: 'layoutBreadcrumbSearch',
-  data() {
-    return {
-      isShowSearch: false,
-      menuQuery: '',
-      tagsViewList: [],
-    };
-  },
-  methods: {
-    // 搜索弹窗打开
-    openSearch() {
-      this.menuQuery = '';
-      this.isShowSearch = true;
-      this.initTageView();
-      this.$nextTick(() => {
-        this.$refs.layoutMenuAutocompleteRef.focus();
-      });
-    },
-    // 搜索弹窗关闭
-    closeSearch() {
-      setTimeout(() => {
-        this.isShowSearch = false;
-      }, 150);
-    },
-    // 菜单搜索数据过滤
-    menuSearch(queryString, cb) {
-      let results = queryString ? this.tagsViewList.filter(this.createFilter(queryString)) : this.tagsViewList;
-      cb(results);
-    },
-    // 菜单搜索过滤
-    createFilter(queryString) {
-      return (restaurant) => {
-        return (
-          restaurant.path.toLowerCase().indexOf(queryString.toLowerCase()) > -1 ||
-          restaurant.title.toLowerCase().indexOf(queryString.toLowerCase()) > -1 ||
-          this.$t(restaurant.title).toLowerCase().indexOf(queryString.toLowerCase()) > -1
-        );
-      };
-    },
-    // 初始化菜单数据
-    initTageView() {
-      if (this.tagsViewList.length > 0) return false;
-      this.tagsViewList = getAllSiderMenu(this.$store.state.routesList.routesList);
-      // this.$store.state.tagsViewRoutes.tagsViewRoutes.map((v) => {
-      // 	if (!v.isHide) this.tagsViewList.push({ ...v });
-      // });
-    },
-    // 当前菜单选中时
-    onHandleSelect(item) {
-      let { path, redirect } = item;
-      if (item.isLink && !item.isIframe) window.open(item.isLink);
-      else if (redirect) this.$router.push(redirect);
-      else this.$router.push(path);
-      this.closeSearch();
-    },
-    // input 失去焦点时
-    onSearchBlur() {
-      this.closeSearch();
-    },
-  },
-};
+	import {
+		getAllSiderMenu
+	} from '@/libs/system';
+	export default {
+		name: 'layoutBreadcrumbSearch',
+		data() {
+			return {
+				isShowSearch: false,
+				menuQuery: '',
+				tagsViewList: [],
+			};
+		},
+		methods: {
+			// 搜索弹窗打开
+			openSearch() {
+				this.menuQuery = '';
+				this.isShowSearch = true;
+				this.initTageView();
+				this.$nextTick(() => {
+					this.$refs.layoutMenuAutocompleteRef.focus();
+				});
+			},
+			// 搜索弹窗关闭
+			closeSearch() {
+				setTimeout(() => {
+					this.isShowSearch = false;
+				}, 150);
+			},
+			// 菜单搜索数据过滤
+			menuSearch(queryString, cb) {
+				let results = queryString ? this.tagsViewList.filter(this.createFilter(queryString)) : this.tagsViewList;
+				cb(results);
+			},
+			// 菜单搜索过滤
+			createFilter(queryString) {
+				return (restaurant) => {
+					return (
+						restaurant.path.toLowerCase().indexOf(queryString.toLowerCase()) > -1 ||
+						restaurant.title.toLowerCase().indexOf(queryString.toLowerCase()) > -1 ||
+						this.$t(restaurant.title).toLowerCase().indexOf(queryString.toLowerCase()) > -1
+					);
+				};
+			},
+			// 初始化菜单数据
+			initTageView() {
+				if (this.tagsViewList.length > 0) return false;
+				this.tagsViewList = getAllSiderMenu(this.$store.state.routesList.routesList);
+				// this.$store.state.tagsViewRoutes.tagsViewRoutes.map((v) => {
+				// 	if (!v.isHide) this.tagsViewList.push({ ...v });
+				// });
+			},
+			// 当前菜单选中时
+			onHandleSelect(item) {
+				let {
+					path,
+					redirect
+				} = item;
+				if (item.isLink && !item.isIframe) window.open(item.isLink);
+				else if (redirect) this.$router.push(redirect);
+				else this.$router.push(path);
+				this.closeSearch();
+			},
+			// input 失去焦点时
+			onSearchBlur() {
+				this.closeSearch();
+			},
+		},
+	};
 </script>
 
 <style scoped lang="scss">
-.layout-search-dialog {
-  ::v-deep .el-dialog {
-    box-shadow: unset !important;
-    border-radius: 0 !important;
-    background: rgba(0, 0, 0, 0.5);
-  }
-  ::v-deep .el-autocomplete {
-    width: 560px;
-    position: absolute;
-    top: 100px;
-    left: 50%;
-    transform: translateX(-50%);
-  }
-}
-</style>
+	.layout-search-dialog {
+		::v-deep .el-dialog {
+			box-shadow: unset !important;
+			border-radius: 0 !important;
+			background: rgba(0, 0, 0, 0.5);
+		}
+
+		::v-deep .el-autocomplete {
+			width: 560px;
+			position: absolute;
+			top: 100px;
+			left: 50%;
+			transform: translateX(-50%);
+		}
+	}
+</style>

+ 256 - 232
src/layout/navBars/breadcrumb/userNews.vue

@@ -1,239 +1,263 @@
 <template>
-  <div class="layout-navbars-breadcrumb-user-news">
-    <div class="head-box">
-      <div class="head-box-title">{{ $t('message.user.newTitle') }}</div>
-      <div class="head-box-btn" v-if="newsList.length > 0" @click="onAllReadClick">{{ $t('message.user.newBtn') }}</div>
-    </div>
-    <div class="content-box">
-      <template v-if="newsList.length > 0">
-        <div class="content-box-item" v-for="(v, k) in newsList" :key="k">
-          <div>{{ v.type | msgType }}</div>
-          <div class="content-box-msg">
-            {{ v.title }}
-          </div>
-          <!-- <div class="content-box-time">{{ v.time }}</div> -->
-        </div>
-      </template>
-      <div class="content-box-empty" v-else>
-        <div class="content-box-empty-margin">
-          <i class="el-icon-s-promotion"></i>
-          <div class="mt15">{{ $t('message.user.newDesc') }}</div>
-        </div>
-      </div>
-    </div>
-    <!-- <div class="foot-box" @click="onGoToGiteeClick" v-if="newsList.length > 0">{{ $t('message.user.newGo') }}</div> -->
-  </div>
+	<div class="layout-navbars-breadcrumb-user-news">
+		<div class="head-box">
+			<div class="head-box-title">{{ $t('message.user.newTitle') }}</div>
+			<div class="head-box-btn" v-if="newsList.length > 0" @click="onAllReadClick">{{ $t('message.user.newBtn') }}
+			</div>
+		</div>
+		<div class="content-box">
+			<template v-if="newsList.length > 0">
+				<div class="content-box-item" v-for="(v, k) in newsList" :key="k">
+					<div>{{ v.type | msgType }}</div>
+					<div class="content-box-msg">
+						{{ v.title }}
+					</div>
+					<!-- <div class="content-box-time">{{ v.time }}</div> -->
+				</div>
+			</template>
+			<div class="content-box-empty" v-else>
+				<div class="content-box-empty-margin">
+					<i class="el-icon-s-promotion"></i>
+					<div class="mt15">{{ $t('message.user.newDesc') }}</div>
+				</div>
+			</div>
+		</div>
+		<!-- <div class="foot-box" @click="onGoToGiteeClick" v-if="newsList.length > 0">{{ $t('message.user.newGo') }}</div> -->
+	</div>
 </template>
 
 <script>
-let newOrderAudioLink = new Audio(require('@/assets/video/newOrderAudioLink.mp3'));
-import { jnoticeRequest } from '@/api/common';
-import { adminSocket } from '@/libs/socket';
-import { getCookies, removeCookies, setCookies } from '@/libs/util';
-export default {
-  name: 'layoutBreadcrumbUserNews',
-  data() {
-    return {
-      newsList: [],
-      newOrderAudioLink: null,
-    };
-  },
-  mounted() {
-    this.getNotict();
-    this.newOrderAudioLink = newOrderAudioLink;
-    adminSocket.then((ws) => {
-      ws.send({
-        type: 'login',
-        data: getCookies('token'),
-      });
-      let that = this;
-      ws.$on('ADMIN_NEW_PUSH', function (data) {
-        that.getNotict();
-      });
-
-      ws.$on('NEW_ORDER', function (data) {
-        that.$Notice.info({
-          title: '新订单',
-          duration: 8,
-          desc: '您有一个新的订单,ID为(' + data.order_id + '),请注意查看',
-        });
-        if (this.newOrderAudioLink) this.newOrderAudioLink.play();
-        that.messageList.push({
-          title: '新订单提醒',
-          icon: 'md-bulb',
-          iconColor: '#87d068',
-          time: 0,
-          read: 0,
-        });
-      });
-      ws.$on('NEW_REFUND_ORDER', function (data) {
-        that.$Notice.warning({
-          title: '退款订单提醒',
-          duration: 8,
-          desc: '您有一个订单申请退款,ID为(' + data.order_id + '),请注意查看',
-        });
-        if (window.newOrderAudioLink) this.newOrderAudioLink.play();
-        that.messageList.push({
-          title: '退款订单提醒',
-          icon: 'md-information',
-          iconColor: '#fe5c57',
-          time: 0,
-          read: 0,
-        });
-      });
-      ws.$on('WITHDRAW', function (data) {
-        that.$Notice.warning({
-          title: '提现提醒',
-          duration: 8,
-          desc: '有用户申请提现,编号为(' + data.id + '),请注意查看',
-        });
-        that.messageList.push({
-          title: '退款订单提醒',
-          icon: 'md-people',
-          iconColor: '#f06292',
-          time: 0,
-          read: 0,
-        });
-      });
-      ws.$on('STORE_STOCK', function (data) {
-        that.$Notice.warning({
-          title: '库存预警',
-          duration: 8,
-          desc: '商品ID为(' + data.id + ')的库存不足啦,请注意查看~',
-        });
-        that.messageList.push({
-          title: '库存预警',
-          icon: 'md-information',
-          iconColor: '#fe5c57',
-          time: 0,
-          read: 0,
-        });
-      });
-      ws.$on('PAY_SMS_SUCCESS', function (data) {
-        that.$Notice.info({
-          title: '短信充值成功',
-          duration: 8,
-          desc: '恭喜您充值' + data.price + '元,获得' + data.number + '条短信',
-        });
-        that.messageList.push({
-          title: '短信充值成功',
-          icon: 'md-bulb',
-          iconColor: '#87d068',
-          time: 0,
-          read: 0,
-        });
-      });
-    });
-  },
-  filters: {
-    // 1 待发货 2 库存报警  3评论回复  4提现申请
-    msgType(type) {
-      let typeName;
-      switch (type) {
-        case 1:
-          typeName = '待发货订单提醒';
-          break;
-        case 2:
-          typeName = '库存报警';
-          break;
-        case 3:
-          typeName = '库存报警';
-          break;
-        case 4:
-          typeName = '库存报警';
-          break;
-        default:
-          typeName = '其它';
-      }
-      return typeName;
-    },
-  },
-  methods: {
-    // 全部已读点击
-    onAllReadClick() {
-      this.newsList = [];
-    },
-    // 前往通知中心点击
-    onGoToGiteeClick() {},
-    getNotict() {
-      jnoticeRequest()
-        .then((res) => {
-          this.newsList = res.data || [];
-          this.$emit('haveNews', !!this.newsList.length);
-        })
-        .catch(() => {});
-    },
-    jumpUrl(url) {
-      this.$router.push({ path: url });
-    },
-  },
-};
+	let newOrderAudioLink = new Audio(require('@/assets/video/newOrderAudioLink.mp3'));
+	import {
+		jnoticeRequest
+	} from '@/api/common';
+	import {
+		adminSocket
+	} from '@/libs/socket';
+	import {
+		getCookies,
+		removeCookies,
+		setCookies
+	} from '@/libs/util';
+	export default {
+		name: 'layoutBreadcrumbUserNews',
+		data() {
+			return {
+				newsList: [],
+				newOrderAudioLink: null,
+			};
+		},
+		mounted() {
+			// this.getNotict();
+			this.newOrderAudioLink = newOrderAudioLink;
+			adminSocket.then((ws) => {
+				ws.send({
+					type: 'login',
+					data: getCookies('token'),
+				});
+				let that = this;
+				// ws.$on('ADMIN_NEW_PUSH', function (data) {
+				//   that.getNotict();
+				// });
+
+				ws.$on('NEW_ORDER', function(data) {
+					that.$Notice.info({
+						title: '新订单',
+						duration: 8,
+						desc: '您有一个新的订单,ID为(' + data.order_id + '),请注意查看',
+					});
+					if (this.newOrderAudioLink) this.newOrderAudioLink.play();
+					that.messageList.push({
+						title: '新订单提醒',
+						icon: 'md-bulb',
+						iconColor: '#87d068',
+						time: 0,
+						read: 0,
+					});
+				});
+				ws.$on('NEW_REFUND_ORDER', function(data) {
+					that.$Notice.warning({
+						title: '退款订单提醒',
+						duration: 8,
+						desc: '您有一个订单申请退款,ID为(' + data.order_id + '),请注意查看',
+					});
+					if (window.newOrderAudioLink) this.newOrderAudioLink.play();
+					that.messageList.push({
+						title: '退款订单提醒',
+						icon: 'md-information',
+						iconColor: '#fe5c57',
+						time: 0,
+						read: 0,
+					});
+				});
+				ws.$on('WITHDRAW', function(data) {
+					that.$Notice.warning({
+						title: '提现提醒',
+						duration: 8,
+						desc: '有用户申请提现,编号为(' + data.id + '),请注意查看',
+					});
+					that.messageList.push({
+						title: '退款订单提醒',
+						icon: 'md-people',
+						iconColor: '#f06292',
+						time: 0,
+						read: 0,
+					});
+				});
+				ws.$on('STORE_STOCK', function(data) {
+					that.$Notice.warning({
+						title: '库存预警',
+						duration: 8,
+						desc: '商品ID为(' + data.id + ')的库存不足啦,请注意查看~',
+					});
+					that.messageList.push({
+						title: '库存预警',
+						icon: 'md-information',
+						iconColor: '#fe5c57',
+						time: 0,
+						read: 0,
+					});
+				});
+				ws.$on('PAY_SMS_SUCCESS', function(data) {
+					that.$Notice.info({
+						title: '短信充值成功',
+						duration: 8,
+						desc: '恭喜您充值' + data.price + '元,获得' + data.number + '条短信',
+					});
+					that.messageList.push({
+						title: '短信充值成功',
+						icon: 'md-bulb',
+						iconColor: '#87d068',
+						time: 0,
+						read: 0,
+					});
+				});
+			});
+		},
+		filters: {
+			// 1 待发货 2 库存报警  3评论回复  4提现申请
+			msgType(type) {
+				let typeName;
+				switch (type) {
+					case 1:
+						typeName = '待发货订单提醒';
+						break;
+					case 2:
+						typeName = '库存报警';
+						break;
+					case 3:
+						typeName = '库存报警';
+						break;
+					case 4:
+						typeName = '库存报警';
+						break;
+					default:
+						typeName = '其它';
+				}
+				return typeName;
+			},
+		},
+		methods: {
+			// 全部已读点击
+			onAllReadClick() {
+				this.newsList = [];
+			},
+			// 前往通知中心点击
+			onGoToGiteeClick() {},
+			getNotict() {
+				jnoticeRequest()
+					.then((res) => {
+						this.newsList = res.data || [];
+						this.$emit('haveNews', !!this.newsList.length);
+					})
+					.catch(() => {});
+			},
+			jumpUrl(url) {
+				this.$router.push({
+					path: url
+				});
+			},
+		},
+	};
 </script>
 
 <style scoped lang="scss">
-.layout-navbars-breadcrumb-user-news {
-  .head-box {
-    display: flex;
-    border-bottom: 1px solid var(--prev-border-color-lighter);
-    box-sizing: border-box;
-    color: var(--prev-color-text-primary);
-    justify-content: space-between;
-    height: 35px;
-    align-items: center;
-    .head-box-btn {
-      color: var(--prev-color-primary);
-      font-size: 13px;
-      cursor: pointer;
-      opacity: 0.8;
-      &:hover {
-        opacity: 1;
-      }
-    }
-  }
-  .content-box {
-    font-size: 13px;
-    .content-box-item {
-      padding-top: 12px;
-      &:last-of-type {
-        padding-bottom: 12px;
-      }
-      .content-box-msg {
-        color: var(--prev-color-text-secondary);
-        margin-top: 5px;
-        margin-bottom: 5px;
-      }
-      .content-box-time {
-        color: var(--prev-color-text-secondary);
-      }
-    }
-    .content-box-empty {
-      height: 260px;
-      display: flex;
-      .content-box-empty-margin {
-        margin: auto;
-        text-align: center;
-        i {
-          font-size: 60px;
-        }
-      }
-    }
-  }
-  .foot-box {
-    height: 35px;
-    color: var(--prev-color-primary);
-    font-size: 13px;
-    cursor: pointer;
-    opacity: 0.8;
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    border-top: 1px solid var(--prev-border-color-lighter);
-    &:hover {
-      opacity: 1;
-    }
-  }
-  ::v-deep(.el-empty__description p) {
-    font-size: 13px;
-  }
-}
-</style>
+	.layout-navbars-breadcrumb-user-news {
+		.head-box {
+			display: flex;
+			border-bottom: 1px solid var(--prev-border-color-lighter);
+			box-sizing: border-box;
+			color: var(--prev-color-text-primary);
+			justify-content: space-between;
+			height: 35px;
+			align-items: center;
+
+			.head-box-btn {
+				color: var(--prev-color-primary);
+				font-size: 13px;
+				cursor: pointer;
+				opacity: 0.8;
+
+				&:hover {
+					opacity: 1;
+				}
+			}
+		}
+
+		.content-box {
+			font-size: 13px;
+
+			.content-box-item {
+				padding-top: 12px;
+
+				&:last-of-type {
+					padding-bottom: 12px;
+				}
+
+				.content-box-msg {
+					color: var(--prev-color-text-secondary);
+					margin-top: 5px;
+					margin-bottom: 5px;
+				}
+
+				.content-box-time {
+					color: var(--prev-color-text-secondary);
+				}
+			}
+
+			.content-box-empty {
+				height: 260px;
+				display: flex;
+
+				.content-box-empty-margin {
+					margin: auto;
+					text-align: center;
+
+					i {
+						font-size: 60px;
+					}
+				}
+			}
+		}
+
+		.foot-box {
+			height: 35px;
+			color: var(--prev-color-primary);
+			font-size: 13px;
+			cursor: pointer;
+			opacity: 0.8;
+			display: flex;
+			align-items: center;
+			justify-content: center;
+			border-top: 1px solid var(--prev-border-color-lighter);
+
+			&:hover {
+				opacity: 1;
+			}
+		}
+
+		::v-deep(.el-empty__description p) {
+			font-size: 13px;
+		}
+	}
+</style>

+ 631 - 550
src/layout/navBars/tagsView/tagsView.vue

@@ -1,561 +1,642 @@
 <template>
-  <div ref="tagsView" class="layout-navbars-tagsview">
-    <i v-if="scrollTagIcon" class="direction el-icon-arrow-left" @click="scrollTag('left')"></i>
-    <el-scrollbar ref="scrollbarRef" @wheel.native.prevent="onHandleScroll">
-      <ul class="layout-navbars-tagsview-ul" :class="setTagsStyle" ref="tagsUlRef">
-        <li
-          v-for="(v, k) in tagsViewList"
-          :key="k"
-          class="layout-navbars-tagsview-ul-li"
-          :data-name="v.name"
-          :class="{ 'is-active': v.path === tagsRoutePath }"
-          @contextmenu.prevent="onContextmenu(v, $event)"
-          @click="onTagsClick(v, k)"
-          ref="tagsRefs"
-        >
-          <i
-            class="layout-navbars-tagsview-ul-li-iconfont font14 is-tagsview-icon"
-            :class="v.icon"
-            v-if="v.path !== tagsRoutePath && getThemeConfig.isTagsviewIcon"
-          ></i>
-          <span>{{ $t(v.meta.title) }}</span>
-          <!-- <i
+	<div ref="tagsView" class="layout-navbars-tagsview">
+		<i v-if="scrollTagIcon" class="direction el-icon-arrow-left" @click="scrollTag('left')"></i>
+		<el-scrollbar ref="scrollbarRef" @wheel.native.prevent="onHandleScroll">
+			<ul class="layout-navbars-tagsview-ul" :class="setTagsStyle" ref="tagsUlRef">
+				<li v-for="(v, k) in tagsViewList" :key="k" class="layout-navbars-tagsview-ul-li" :data-name="v.name"
+					:class="{ 'is-active': v.path === tagsRoutePath }" @contextmenu.prevent="onContextmenu(v, $event)"
+					@click="onTagsClick(v, k)" ref="tagsRefs">
+					<i class="layout-navbars-tagsview-ul-li-iconfont font14 is-tagsview-icon" :class="v.icon"
+						v-if="v.path !== tagsRoutePath && getThemeConfig.isTagsviewIcon"></i>
+					<span>{{ $t(v.meta.title) }}</span>
+					<!-- <i
             class="el-icon-refresh-right layout-navbars-tagsview-ul-li-icon ml5"
             v-if="v.path === tagsRoutePath"
             @click.stop="refreshCurrentTagsView(v.path)"
           ></i> -->
-          <i
-            class="el-icon-close layout-navbars-tagsview-ul-li-icon ml5"
-            v-if="!v.isAffix"
-            @click.stop="closeCurrentTagsView(v.path)"
-          ></i>
-        </li>
-      </ul>
-    </el-scrollbar>
-    <i v-if="scrollTagIcon" class="direction el-icon-arrow-right" @click="scrollTag('right')"></i>
-    <el-dropdown @command="clickDropdown" v-if="tagsViewList.length > 2">
-      <span class="setting-tag el-dropdown-link"><i class="el-icon-menu"></i></span>
-      <el-dropdown-menu slot="dropdown">
-        <el-dropdown-item v-for="item in dropdownList" :command="item.id" :key="item.id">
-          <i :class="item.icon"></i>
-          {{ $t(item.txt) }}</el-dropdown-item
-        >
-      </el-dropdown-menu>
-    </el-dropdown>
-    <Contextmenu :dropdown="tagsDropdown" ref="tagsContextmenu" @currentContextmenuClick="onCurrentContextmenuClick" />
-  </div>
+					<i class="el-icon-close layout-navbars-tagsview-ul-li-icon ml5" v-if="!v.isAffix"
+						@click.stop="closeCurrentTagsView(v.path)"></i>
+				</li>
+			</ul>
+		</el-scrollbar>
+		<i v-if="scrollTagIcon" class="direction el-icon-arrow-right" @click="scrollTag('right')"></i>
+		<el-dropdown @command="clickDropdown" v-if="tagsViewList.length > 2">
+			<span class="setting-tag el-dropdown-link"><i class="el-icon-menu"></i></span>
+			<el-dropdown-menu slot="dropdown">
+				<el-dropdown-item v-for="item in dropdownList" :command="item.id" :key="item.id">
+					<i :class="item.icon"></i>
+					{{ $t(item.txt) }}</el-dropdown-item>
+			</el-dropdown-menu>
+		</el-dropdown>
+		<Contextmenu :dropdown="tagsDropdown" ref="tagsContextmenu"
+			@currentContextmenuClick="onCurrentContextmenuClick" />
+	</div>
 </template>
 
 <script>
-import Contextmenu from '@/layout/navBars/tagsView/contextmenu';
-import { Session } from '@/utils/storage.js';
-import { mapMutations } from 'vuex';
-import setting from '@/setting';
-
-export default {
-  name: 'tagsView',
-  components: { Contextmenu },
-  data() {
-    return {
-      userInfo: {},
-      // tagsViewList: [],
-      tagsDropdown: {
-        x: '',
-        y: '',
-      },
-      tagsRefsIndex: 0,
-      tagsRoutePath: this.$route.path,
-      tagsViewRoutesList: [],
-      dropdownList: [
-        { id: 0, txt: 'message.tagsView.refresh', affix: false, icon: 'el-icon-refresh-right' },
-        { id: 1, txt: 'message.tagsView.close', affix: false, icon: 'el-icon-close' },
-        { id: 2, txt: 'message.tagsView.closeOther', affix: false, icon: 'el-icon-circle-close' },
-        { id: 3, txt: 'message.tagsView.closeAll', affix: false, icon: 'el-icon-folder-delete' },
-      ],
-      scrollTagIcon: false,
-    };
-  },
-  computed: {
-    // 获取布局配置信息
-    getThemeConfig() {
-      return this.$store.state.themeConfig.themeConfig;
-    },
-    // 动态设置 tagsView 风格样式
-    setTagsStyle() {
-      return this.$store.state.themeConfig.themeConfig.tagsStyle;
-    },
-    tagsViewList() {
-      return this.$store.state.app.tagNavList;
-    },
-  },
-  created() {
-    // 监听非本页面调用 0 刷新当前,1 关闭当前,2 关闭其它,3 关闭全部
-    this.bus.$on('onCurrentContextmenuClick', (data) => {
-      this.onCurrentContextmenuClick(data);
-    });
-    this.tagsViewRoutesList = this.$store.state.app.tagNavList;
-  },
-  mounted() {
-    if (!this.$store.state.app.tagNavList.length) {
-      this.getTagsViewRoutes();
-    }
-    if (this.$refs.tagsView.offsetWidth < this.$refs.scrollbarRef.$refs.wrap.scrollWidth) {
-      this.scrollTagIcon = true;
-    }
-    window.addEventListener('resize', () => {
-      if (this.$refs.tagsView.offsetWidth < this.$refs.scrollbarRef.$refs.wrap.scrollWidth) {
-        this.scrollTagIcon = true;
-      } else {
-        this.scrollTagIcon = false;
-      }
-    });
-  },
-  methods: {
-    ...mapMutations(['setBreadCrumb', 'setTagNavList', 'addTag', 'setLocal', 'setHomeRoute', 'closeTag']),
-    clickDropdown(e) {
-      let data = { id: e, path: this.$route.path };
-      this.onCurrentContextmenuClick(data);
-    },
-    // 获取路由信息
-    getRoutesList() {
-      return this.$store.state.routesList.routesList;
-    },
-    // 当前的 tagsView 项点击时
-    onTagsClick(v, k) {
-      this.tagsRoutePath = v.path;
-      this.tagsRefsIndex = k;
-      this.$router.push(v);
-    },
-    // 获取 tagsView 的下标:用于处理 tagsView 点击时的横向滚动
-    getTagsRefsIndex(path) {
-      if (this.tagsViewList.length > 0) {
-        this.tagsRefsIndex = this.tagsViewList.findIndex((item) => item.path === path);
-      }
-    },
-    // 鼠标滚轮滚动
-    onHandleScroll(e) {
-      this.$refs.scrollbarRef.$refs.wrap.scrollLeft += e.wheelDelta / 4;
-    },
-    scrollTag(production) {
-      let scrollRefs = this.$refs.scrollbarRef.$refs.wrap.scrollWidth;
-      let scrollLeft = this.$refs.scrollbarRef.$refs.wrap.scrollLeft;
-      if (production === 'left') {
-        this.$refs.scrollbarRef.$refs.wrap.scrollLeft = scrollLeft - 300 <= 0 ? 0 : scrollLeft - 300;
-      } else {
-        this.$refs.scrollbarRef.$refs.wrap.scrollLeft = scrollLeft + 300 >= scrollRefs ? scrollRefs : scrollLeft + 300;
-      }
-    },
-    // tagsView 横向滚动
-    tagsViewmoveToCurrentTag() {
-      this.$nextTick(() => {
-        const tagsRefs = this.$refs.tagsRefs;
-        if (tagsRefs.length <= 0) return false;
-        // 当前 li 元素
-        let liDom = tagsRefs[this.tagsRefsIndex];
-        // 当前 li 元素下标
-        let liIndex = this.tagsRefsIndex;
-        // 当前 ul 下 li 元素总长度
-        let liLength = tagsRefs.length;
-        // 最前 li
-        let liFirst = tagsRefs[0];
-        // 最后 li
-        let liLast = tagsRefs[tagsRefs.length - 1];
-        // 当前滚动条的值
-        let scrollRefs = this.$refs.scrollbarRef.$refs.wrap;
-        // 当前滚动条滚动宽度
-        let scrollS = scrollRefs.scrollWidth;
-        // 当前滚动条偏移宽度
-        let offsetW = scrollRefs.offsetWidth;
-        // 当前滚动条偏移距离
-        let scrollL = scrollRefs.scrollLeft;
-        // 上一个 tags li dom
-        let liPrevTag = tagsRefs[this.tagsRefsIndex - 1];
-        // 下一个 tags li dom
-        let liNextTag = tagsRefs[this.tagsRefsIndex + 1];
-        // 上一个 tags li dom 的偏移距离
-        let beforePrevL = '';
-        // 下一个 tags li dom 的偏移距离
-        let afterNextL = '';
-        if (liDom === liFirst) {
-          // 头部
-          scrollRefs.scrollLeft = 0;
-        } else if (liDom === liLast) {
-          // 尾部
-          scrollRefs.scrollLeft = scrollS - offsetW;
-        } else {
-          // 非头/尾部
-          if (liIndex === 0) beforePrevL = liFirst?.offsetLeft - 5;
-          else beforePrevL = liPrevTag?.offsetLeft - 5;
-          if (liIndex === liLength) afterNextL = liLast?.offsetLeft + liLast.offsetWidth + 5;
-          else afterNextL = liNextTag?.offsetLeft + liNextTag.offsetWidth + 5;
-          if (afterNextL > scrollL + offsetW) {
-            scrollRefs.scrollLeft = afterNextL - offsetW;
-          } else if (beforePrevL < scrollL) {
-            scrollRefs.scrollLeft = beforePrevL;
-          }
-        }
-        // 更新滚动条,防止不出现
-        this.updateScrollbar();
-      });
-    },
-    // 更新滚动条显示
-    updateScrollbar() {
-      this.$refs.scrollbarRef.update();
-    },
-    // 递归查找当前路径下的组件信息
-    filterCurrentMenu(arr, currentPath, callback) {
-      arr.map((item) => {
-        if (item.path === currentPath) {
-          callback(item);
-          return false;
-        }
-        item = Object.assign({}, item);
-        if (item.children) {
-          item.children = this.filterCurrentMenu(item.children, currentPath, callback);
-        }
-      });
-    },
-    // 数组对象去重
-    duplicate(arr) {
-      let newobj = {};
-      arr = arr.reduce((preVal, curVal) => {
-        newobj[curVal.path] ? '' : (newobj[curVal.path] = preVal.push(curVal));
-        return preVal;
-      }, []);
-      return arr;
-    },
-    // 获取 vuex 中的 tagsViewRoutes 列表
-    getTagsViewRoutes() {
-      this.tagsRoutePath = this.$route.path;
-      // if (!this.$store.state.themeConfig.themeConfig.isCacheTagsView) Session.remove('tagsViewList');
-      this.tagsViewRoutesList = this.$store.state.menus.oneLvMenus;
-      this.initTagsViewList();
-    },
-    // 存储 tagsViewList 到浏览器临时缓存中,页面刷新时,保留记录
-    addBrowserSetSession(tagNavList) {
-      this.setTagNavList(tagNavList);
-    },
-    // 初始化设置了 tagsView 数据
-    initTagsViewList() {
-      // if (Session.get('tagsViewList') && this.$store.state.themeConfig.themeConfig.isCacheTagsView) {
-      //   this.tagsViewList = Session.get('tagsViewList');
-      // } else {
-      let arr = [];
-      this.tagsViewRoutesList.map((v) => {
-        if (v.meta && v.meta.isAffix) arr.push({ ...v });
-      });
-      // }
-      this.setTagNavList(arr);
-      // 初始化当前元素(li)的下标
-      this.getTagsRefsIndex(this.$route.path);
-      // 添加初始化横向滚动条移动到对应位置
-      this.tagsViewmoveToCurrentTag();
-    },
-    // 添加 tagsView:未设置隐藏(isHide)也添加到在 tagsView 中
-    addTagsView(path, to) {
-      if (this.tagsViewList.some((v) => v.path === path)) return false;
-      const item = this.tagsViewRoutesList.find((v) => v.path === path);
-      if (item.isLink && !item.isIframe) return false;
-      item.query = to?.query ? to?.query : this.$route.query;
-      this.tagsViewList.push({ ...item });
-      this.addBrowserSetSession(this.tagsViewList);
-    },
-    // 右键菜单点击时显示菜单列表
-    onContextmenu(v, e) {
-      let { clientX, clientY } = e;
-      this.tagsDropdown.x = clientX;
-      this.tagsDropdown.y = clientY;
-      this.$refs.tagsContextmenu.openContextmenu(v);
-    },
-    onContextmenuIcon(e) {},
-    // 当前项右键菜单点击
-    onCurrentContextmenuClick(data) {
-      let { id, path } = data;
-      let currentTag = this.tagsViewList.find((v) => v.path === path);
-      switch (id) {
-        case 0:
-          this.refreshCurrentTagsView(path);
-          this.$router.push({ path, query: currentTag.query });
-          break;
-        case 1:
-          this.closeCurrentTagsView(path);
-          break;
-        case 2:
-          this.closeOtherTagsView(path, currentTag.query);
-          break;
-        case 3:
-          this.closeAllTagsView(path);
-          break;
-      }
-    },
-    refreshIcon() {
-      this.$nextTick((e) => {
-        if (this.$refs.tagsView.offsetWidth < this.$refs.scrollbarRef.$refs.wrap.scrollWidth) {
-          this.scrollTagIcon = true;
-        } else {
-          this.scrollTagIcon = false;
-        }
-      });
-    },
-    // 1、刷新当前 tagsView:
-    refreshCurrentTagsView(path) {
-      this.bus.$emit('onTagsViewRefreshRouterView', path);
-    },
-    // 2、关闭当前 tagsView:当前项 `tags-view` icon 关闭时点击,如果是设置了固定的(isAffix),不可以关闭
-    closeCurrentTagsView(path) {
-      this.tagsViewList.map((v, k, arr) => {
-        if (!v.meta.isAffix) {
-          if (v.path === path) {
-            this.tagsViewList.splice(k, 1);
-            setTimeout(() => {
-              // 最后一个
-              if (this.tagsViewList.length === k)
-                this.$router.push({ path: arr[arr.length - 1].path, query: arr[arr.length - 1].query });
-              // 否则,跳转到下一个
-              else this.$router.push({ path: arr[k].path, query: arr[k].query });
-            }, 0);
-          }
-        }
-      });
-      this.setTagNavList(this.tagsViewList);
-      //   this.addBrowserSetSession(this.tagNavList);
-    },
-    // 3、关闭其它 tagsView:如果是设置了固定的(isAffix),不进行关闭
-    closeOtherTagsView(path, query) {
-      let tagsViewList = [];
-      this.tagsViewRoutesList.map((v) => {
-        if ((v.meta && v.meta.isAffix) || v.path === path) tagsViewList.push({ ...v });
-      });
-      this.addBrowserSetSession(tagsViewList);
-      this.$router.push({ path, query });
-
-      // this.addTagsView(path);
-    },
-    // 4、关闭全部 tagsView:如果是设置了固定的(isAffix),不进行关闭
-    closeAllTagsView(path) {
-      let tagsViewList = [];
-      this.tagsViewRoutesList.map((v) => {
-        if (v.meta.isAffix) {
-          tagsViewList.push({ ...v });
-          if (tagsViewList.some((v) => v.path === path)) this.$router.push({ path, query: this.$route.query });
-          else this.$router.push({ path: v.path, query: this.$route.query });
-        }
-      });
-      this.addBrowserSetSession(tagsViewList);
-    },
-  },
-  watch: {
-    // 监听路由变化
-    $route: {
-      handler(to) {
-        this.tagsRoutePath = to.path;
-        this.addTagsView(to.path, to);
-        this.getTagsRefsIndex(to.path);
-        this.tagsViewmoveToCurrentTag();
-        this.refreshIcon();
-      },
-      deep: true,
-    },
-  },
-  destroyed() {
-    // 取消非本页面调用监听(fun/tagsView)
-    this.bus.$off('onCurrentContextmenuClick');
-  },
-};
+	import Contextmenu from '@/layout/navBars/tagsView/contextmenu';
+	import {
+		Session
+	} from '@/utils/storage.js';
+	import {
+		mapMutations
+	} from 'vuex';
+	import setting from '@/setting';
+
+	export default {
+		name: 'tagsView',
+		components: {
+			Contextmenu
+		},
+		data() {
+			return {
+				userInfo: {},
+				// tagsViewList: [],
+				tagsDropdown: {
+					x: '',
+					y: '',
+				},
+				tagsRefsIndex: 0,
+				tagsRoutePath: this.$route.path,
+				tagsViewRoutesList: [],
+				dropdownList: [{
+						id: 0,
+						txt: 'message.tagsView.refresh',
+						affix: false,
+						icon: 'el-icon-refresh-right'
+					},
+					{
+						id: 1,
+						txt: 'message.tagsView.close',
+						affix: false,
+						icon: 'el-icon-close'
+					},
+					{
+						id: 2,
+						txt: 'message.tagsView.closeOther',
+						affix: false,
+						icon: 'el-icon-circle-close'
+					},
+					{
+						id: 3,
+						txt: 'message.tagsView.closeAll',
+						affix: false,
+						icon: 'el-icon-folder-delete'
+					},
+				],
+				scrollTagIcon: false,
+			};
+		},
+		computed: {
+			// 获取布局配置信息
+			getThemeConfig() {
+				return this.$store.state.themeConfig.themeConfig;
+			},
+			// 动态设置 tagsView 风格样式
+			setTagsStyle() {
+				return this.$store.state.themeConfig.themeConfig.tagsStyle;
+			},
+			tagsViewList() {
+				console.log(this.$store.state.app.tagNavList, '1233456');
+				return this.$store.state.app.tagNavList;
+			},
+		},
+		created() {
+			// 监听非本页面调用 0 刷新当前,1 关闭当前,2 关闭其它,3 关闭全部
+			this.bus.$on('onCurrentContextmenuClick', (data) => {
+				this.onCurrentContextmenuClick(data);
+			});
+			this.tagsViewRoutesList = this.$store.state.app.tagNavList;
+		},
+		mounted() {
+			if (!this.$store.state.app.tagNavList.length) {
+				this.getTagsViewRoutes();
+			}
+			if (this.$refs.tagsView.offsetWidth < this.$refs.scrollbarRef.$refs.wrap.scrollWidth) {
+				this.scrollTagIcon = true;
+			}
+			window.addEventListener('resize', () => {
+				if (this.$refs.tagsView.offsetWidth < this.$refs.scrollbarRef.$refs.wrap.scrollWidth) {
+					this.scrollTagIcon = true;
+				} else {
+					this.scrollTagIcon = false;
+				}
+			});
+		},
+		methods: {
+			...mapMutations(['setBreadCrumb', 'setTagNavList', 'addTag', 'setLocal', 'setHomeRoute', 'closeTag']),
+			clickDropdown(e) {
+				let data = {
+					id: e,
+					path: this.$route.path
+				};
+				this.onCurrentContextmenuClick(data);
+			},
+			// 获取路由信息
+			getRoutesList() {
+				return this.$store.state.routesList.routesList;
+			},
+			// 当前的 tagsView 项点击时
+			onTagsClick(v, k) {
+				console.log(v)
+				this.tagsRoutePath = v.path;
+				this.tagsRefsIndex = k;
+				this.$router.push(v.path);
+			},
+			// 获取 tagsView 的下标:用于处理 tagsView 点击时的横向滚动
+			getTagsRefsIndex(path) {
+				if (this.tagsViewList.length > 0) {
+					this.tagsRefsIndex = this.tagsViewList.findIndex((item) => item.path === path);
+				}
+			},
+			// 鼠标滚轮滚动
+			onHandleScroll(e) {
+				this.$refs.scrollbarRef.$refs.wrap.scrollLeft += e.wheelDelta / 4;
+			},
+			scrollTag(production) {
+				let scrollRefs = this.$refs.scrollbarRef.$refs.wrap.scrollWidth;
+				let scrollLeft = this.$refs.scrollbarRef.$refs.wrap.scrollLeft;
+				if (production === 'left') {
+					this.$refs.scrollbarRef.$refs.wrap.scrollLeft = scrollLeft - 300 <= 0 ? 0 : scrollLeft - 300;
+				} else {
+					this.$refs.scrollbarRef.$refs.wrap.scrollLeft = scrollLeft + 300 >= scrollRefs ? scrollRefs :
+						scrollLeft + 300;
+				}
+			},
+			// tagsView 横向滚动
+			tagsViewmoveToCurrentTag() {
+				this.$nextTick(() => {
+					const tagsRefs = this.$refs.tagsRefs;
+					if (tagsRefs.length <= 0) return false;
+					// 当前 li 元素
+					let liDom = tagsRefs[this.tagsRefsIndex];
+					// 当前 li 元素下标
+					let liIndex = this.tagsRefsIndex;
+					// 当前 ul 下 li 元素总长度
+					let liLength = tagsRefs.length;
+					// 最前 li
+					let liFirst = tagsRefs[0];
+					// 最后 li
+					let liLast = tagsRefs[tagsRefs.length - 1];
+					// 当前滚动条的值
+					let scrollRefs = this.$refs.scrollbarRef.$refs.wrap;
+					// 当前滚动条滚动宽度
+					let scrollS = scrollRefs.scrollWidth;
+					// 当前滚动条偏移宽度
+					let offsetW = scrollRefs.offsetWidth;
+					// 当前滚动条偏移距离
+					let scrollL = scrollRefs.scrollLeft;
+					// 上一个 tags li dom
+					let liPrevTag = tagsRefs[this.tagsRefsIndex - 1];
+					// 下一个 tags li dom
+					let liNextTag = tagsRefs[this.tagsRefsIndex + 1];
+					// 上一个 tags li dom 的偏移距离
+					let beforePrevL = '';
+					// 下一个 tags li dom 的偏移距离
+					let afterNextL = '';
+					if (liDom === liFirst) {
+						// 头部
+						scrollRefs.scrollLeft = 0;
+					} else if (liDom === liLast) {
+						// 尾部
+						scrollRefs.scrollLeft = scrollS - offsetW;
+					} else {
+						// 非头/尾部
+						if (liIndex === 0) beforePrevL = liFirst?.offsetLeft - 5;
+						else beforePrevL = liPrevTag?.offsetLeft - 5;
+						if (liIndex === liLength) afterNextL = liLast?.offsetLeft + liLast.offsetWidth + 5;
+						else afterNextL = liNextTag?.offsetLeft + liNextTag.offsetWidth + 5;
+						if (afterNextL > scrollL + offsetW) {
+							scrollRefs.scrollLeft = afterNextL - offsetW;
+						} else if (beforePrevL < scrollL) {
+							scrollRefs.scrollLeft = beforePrevL;
+						}
+					}
+					// 更新滚动条,防止不出现
+					this.updateScrollbar();
+				});
+			},
+			// 更新滚动条显示
+			updateScrollbar() {
+				this.$refs.scrollbarRef.update();
+			},
+			// 递归查找当前路径下的组件信息
+			filterCurrentMenu(arr, currentPath, callback) {
+				arr.map((item) => {
+					if (item.path === currentPath) {
+						callback(item);
+						return false;
+					}
+					item = Object.assign({}, item);
+					if (item.children) {
+						item.children = this.filterCurrentMenu(item.children, currentPath, callback);
+					}
+				});
+			},
+			// 数组对象去重
+			duplicate(arr) {
+				let newobj = {};
+				arr = arr.reduce((preVal, curVal) => {
+					newobj[curVal.path] ? '' : (newobj[curVal.path] = preVal.push(curVal));
+					return preVal;
+				}, []);
+				return arr;
+			},
+			// 获取 vuex 中的 tagsViewRoutes 列表
+			getTagsViewRoutes() {
+				this.tagsRoutePath = this.$route.path;
+				// if (!this.$store.state.themeConfig.themeConfig.isCacheTagsView) Session.remove('tagsViewList');
+				this.tagsViewRoutesList = this.$store.state.menus.oneLvMenus;
+				this.initTagsViewList();
+			},
+			// 存储 tagsViewList 到浏览器临时缓存中,页面刷新时,保留记录
+			addBrowserSetSession(tagNavList) {
+				this.setTagNavList(tagNavList);
+			},
+			// 初始化设置了 tagsView 数据
+			initTagsViewList() {
+				// if (Session.get('tagsViewList') && this.$store.state.themeConfig.themeConfig.isCacheTagsView) {
+				//   this.tagsViewList = Session.get('tagsViewList');
+				// } else {
+				let arr = [];
+				this.tagsViewRoutesList.map((v) => {
+					if (v.meta && v.meta.isAffix) arr.push({
+						...v
+					});
+				});
+				// }
+				this.setTagNavList(arr);
+				// 初始化当前元素(li)的下标
+				this.getTagsRefsIndex(this.$route.path);
+				// 添加初始化横向滚动条移动到对应位置
+				this.tagsViewmoveToCurrentTag();
+			},
+			// 添加 tagsView:未设置隐藏(isHide)也添加到在 tagsView 中
+			addTagsView(path, to) {
+				if (this.tagsViewList.some((v) => v.path === path)) return false;
+				const item = this.tagsViewRoutesList.find((v) => v.path === path);
+				if (item.isLink && !item.isIframe) return false;
+				item.query = to?.query ? to?.query : this.$route.query;
+				this.tagsViewList.push({
+					...item
+				});
+				this.addBrowserSetSession(this.tagsViewList);
+			},
+			// 右键菜单点击时显示菜单列表
+			onContextmenu(v, e) {
+				let {
+					clientX,
+					clientY
+				} = e;
+				this.tagsDropdown.x = clientX;
+				this.tagsDropdown.y = clientY;
+				this.$refs.tagsContextmenu.openContextmenu(v);
+			},
+			onContextmenuIcon(e) {},
+			// 当前项右键菜单点击
+			onCurrentContextmenuClick(data) {
+				let {
+					id,
+					path
+				} = data;
+				let currentTag = this.tagsViewList.find((v) => v.path === path);
+				switch (id) {
+					case 0:
+						this.refreshCurrentTagsView(path);
+						this.$router.push({
+							path,
+							query: currentTag.query
+						});
+						break;
+					case 1:
+						this.closeCurrentTagsView(path);
+						break;
+					case 2:
+						this.closeOtherTagsView(path, currentTag.query);
+						break;
+					case 3:
+						this.closeAllTagsView(path);
+						break;
+				}
+			},
+			refreshIcon() {
+				this.$nextTick((e) => {
+					if (this.$refs.tagsView.offsetWidth < this.$refs.scrollbarRef.$refs.wrap.scrollWidth) {
+						this.scrollTagIcon = true;
+					} else {
+						this.scrollTagIcon = false;
+					}
+				});
+			},
+			// 1、刷新当前 tagsView:
+			refreshCurrentTagsView(path) {
+				this.bus.$emit('onTagsViewRefreshRouterView', path);
+			},
+			// 2、关闭当前 tagsView:当前项 `tags-view` icon 关闭时点击,如果是设置了固定的(isAffix),不可以关闭
+			closeCurrentTagsView(path) {
+				this.tagsViewList.map((v, k, arr) => {
+					console.log(v, '123456');
+					if (!v.meta.isAffix) {
+						if (v.path === path) {
+							this.tagsViewList.splice(k, 1);
+							setTimeout(() => {
+								// 最后一个
+								if (this.tagsViewList.length === k)
+									this.$router.push({
+										path: arr[arr.length - 1].path,
+										query: arr[arr.length - 1].query
+									});
+								// 否则,跳转到下一个
+								else this.$router.push({
+									path: arr[k].path,
+									query: arr[k].query
+								});
+							}, 0);
+						}
+					}
+				});
+				this.setTagNavList(this.tagsViewList);
+				//   this.addBrowserSetSession(this.tagNavList);
+			},
+			// 3、关闭其它 tagsView:如果是设置了固定的(isAffix),不进行关闭
+			closeOtherTagsView(path, query) {
+				let tagsViewList = [];
+				this.tagsViewRoutesList.map((v) => {
+					if ((v.meta && v.meta.isAffix) || v.path === path) tagsViewList.push({
+						...v
+					});
+				});
+				this.addBrowserSetSession(tagsViewList);
+				this.$router.push({
+					path,
+					query
+				});
+
+				// this.addTagsView(path);
+			},
+			// 4、关闭全部 tagsView:如果是设置了固定的(isAffix),不进行关闭
+			closeAllTagsView(path) {
+				let tagsViewList = [];
+				this.tagsViewRoutesList.map((v) => {
+					if (v.meta.isAffix) {
+						tagsViewList.push({
+							...v
+						});
+						if (tagsViewList.some((v) => v.path === path)) this.$router.push({
+							path,
+							query: this.$route.query
+						});
+						else this.$router.push({
+							path: v.path,
+							query: this.$route.query
+						});
+					}
+				});
+				this.addBrowserSetSession(tagsViewList);
+			},
+		},
+		watch: {
+			// 监听路由变化
+			$route: {
+				handler(to) {
+					this.tagsRoutePath = to.path;
+					this.addTagsView(to.path, to);
+					this.getTagsRefsIndex(to.path);
+					this.tagsViewmoveToCurrentTag();
+					this.refreshIcon();
+				},
+				deep: true,
+			},
+		},
+		destroyed() {
+			// 取消非本页面调用监听(fun/tagsView)
+			this.bus.$off('onCurrentContextmenuClick');
+		},
+	};
 </script>
 
 <style scoped lang="scss">
-/deep/ .el-scrollbar__bar.is-horizontal {
-  height: 0;
-}
-.el-dropdown-menu {
-  width: 130px;
-}
-.setting-tag {
-  padding: 0 10px;
-  cursor: pointer;
-}
-.direction {
-  padding: 0 3px;
-}
-.direction:hover {
-  line-height: 34px;
-  background-color: #f7f2f2;
-  cursor: pointer;
-  transition: all 0.3s;
-}
-.layout-navbars-tagsview {
-  flex: 1;
-  background-color: var(--prev-bg-white);
-  // border-bottom: 1px solid var(--prev-border-color-lighter);
-  display: flex;
-  align-items: center;
-  & ::v-deep .is-vertical {
-    display: none !important;
-  }
-  &-ul {
-    list-style: none;
-    margin: 0;
-    padding: 0;
-    // width: 100%;
-    height: 34px;
-    display: flex;
-    align-items: center;
-    white-space: nowrap;
-    color: var(--prev-color-text-regular);
-    font-size: 12px;
-    padding: 0 15px;
-    &-li {
-      height: 26px;
-      line-height: 26px;
-      display: flex;
-      align-items: center;
-      border: 1px solid #ebeef5;
-      padding: 0 12px 0 15px;
-      margin-right: 5px;
-      border-radius: 2px;
-      position: relative;
-      z-index: 0;
-      cursor: pointer;
-      justify-content: space-between;
-      transition: all 0.3s cubic-bezier(0.2, 1, 0.3, 1);
-      &::before {
-        content: '';
-        position: absolute;
-        top: 0;
-        right: 0;
-        bottom: 0;
-        left: 0;
-        background: var(--prev-tag-active-color);
-        z-index: -1;
-        opacity: 0;
-        // transform: scale3d(0.7, 1, 1);
-        // transition: transform 0.3s, opacity 0.3s;
-        // transition-timing-function: cubic-bezier(0.2, 1, 0.3, 1);
-      }
-      &:hover {
-        color: var(--prev-color-primary-light-9);
-        transition: all 0.3s cubic-bezier(0.2, 1, 0.3, 1);
-        border-color: transparent;
-        &::before {
-          opacity: 1;
-          transform: translate3d(0, 0, 0);
-          border-radius: 2px;
-        }
-        .is-tagsview-icon {
-          color: var(--prev-color-primary-light-9);
-
-          transition: all 0.3s cubic-bezier(0.2, 1, 0.3, 1);
-        }
-      }
-      &-iconfont {
-        position: relative;
-        left: -5px;
-        top: 1px;
-        color: var(--prev-color-primary-light-9);
-      }
-      &-icon {
-        border-radius: 100%;
-        position: relative;
-        height: 14px;
-        width: 14px;
-        text-align: center;
-        line-height: 14px;
-        top: 0px;
-      }
-      .is-tagsview-icon {
-        color: var(--prev-color-text-regular);
-        transition: all 0.3s cubic-bezier(0.2, 1, 0.3, 1);
-      }
-    }
-    .is-active {
-      color: var(--prev-color-primary-light-9);
-      transition: all 0.3s cubic-bezier(0.2, 1, 0.3, 1);
-      border-color: transparent;
-      &::before {
-        opacity: 1;
-        transform: translate3d(0, 0, 0);
-        border-radius: 2px;
-      }
-    }
-  }
-  & ::-webkit-scrollbar {
-    display: none !important;
-  }
-  // // 风格2
-  // .tags-style-two {
-  // }
-  // // 风格3
-  // .tags-style-three {
-  // }
-  // // 风格4
-  // 风格1
-  .tags-style-one {
-    .is-active {
-      background: none !important;
-      color: #fff !important;
-    }
-  }
-  // 风格4
-  .tags-style-four {
-    .layout-navbars-tagsview-ul-li {
-      margin-right: 0 !important;
-      border: none !important;
-      position: relative;
-      border-radius: 3px !important;
-
-      .layout-icon-active {
-        display: none;
-      }
-      .layout-icon-three {
-        display: block;
-      }
-      &:hover {
-        background: none !important;
-      }
-    }
-    .is-active {
-      background: none !important;
-      color: #fff !important;
-    }
-  }
-  // 风格5
-  .tags-style-five {
-    align-items: flex-end;
-    .tags-style-five-svg {
-      -webkit-mask-image: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNzAiIGhlaWdodD0iNzAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgZmlsbD0ibm9uZSI+CgogPGc+CiAgPHRpdGxlPkxheWVyIDE8L3RpdGxlPgogIDxwYXRoIHRyYW5zZm9ybT0icm90YXRlKC0wLjEzMzUwNiA1MC4xMTkyIDUwKSIgaWQ9InN2Z18xIiBkPSJtMTAwLjExOTE5LDEwMGMtNTUuMjI4LDAgLTEwMCwtNDQuNzcyIC0xMDAsLTEwMGwwLDEwMGwxMDAsMHoiIG9wYWNpdHk9InVuZGVmaW5lZCIgc3Ryb2tlPSJudWxsIiBmaWxsPSIjRjhFQUU3Ii8+CiAgPHBhdGggZD0ibS0wLjYzNzY2LDcuMzEyMjhjMC4xMTkxOSwwIDAuMjE3MzcsMC4wNTc5NiAwLjQ3Njc2LDAuMTE5MTljMC4yMzIsMC4wNTQ3NyAwLjI3MzI5LDAuMDM0OTEgMC4zNTc1NywwLjExOTE5YzAuMDg0MjgsMC4wODQyOCAwLjM1NzU3LDAgMC40NzY3NiwwbDAuMTE5MTksMGwwLjIzODM4LDAiIGlkPSJzdmdfMiIgc3Ryb2tlPSJudWxsIiBmaWxsPSJub25lIi8+CiAgPHBhdGggZD0ibTI4LjkyMTM0LDY5LjA1MjQ0YzAsMC4xMTkxOSAwLDAuMjM4MzggMCwwLjM1NzU3bDAsMC4xMTkxOWwwLDAuMTE5MTkiIGlkPSJzdmdfMyIgc3Ryb2tlPSJudWxsIiBmaWxsPSJub25lIi8+CiAgPHJlY3QgaWQ9InN2Z180IiBoZWlnaHQ9IjAiIHdpZHRoPSIxLjMxMTA4IiB5PSI2LjgzNTUyIiB4PSItMC4wNDE3MSIgc3Ryb2tlPSJudWxsIiBmaWxsPSJub25lIi8+CiAgPHJlY3QgaWQ9InN2Z181IiBoZWlnaHQ9IjEuNzg3ODQiIHdpZHRoPSIwLjExOTE5IiB5PSI2OC40NTY1IiB4PSIyOC45MjEzNCIgc3Ryb2tlPSJudWxsIiBmaWxsPSJub25lIi8+CiAgPHJlY3QgaWQ9InN2Z182IiBoZWlnaHQ9IjQuODg2NzciIHdpZHRoPSIxOS4wNzAzMiIgeT0iNTEuMjkzMjEiIHg9IjM2LjY2ODY2IiBzdHJva2U9Im51bGwiIGZpbGw9Im5vbmUiLz4KIDwvZz4KPC9zdmc+'),
-        url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNzAiIGhlaWdodD0iNzAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgZmlsbD0ibm9uZSI+CiA8Zz4KICA8dGl0bGU+TGF5ZXIgMTwvdGl0bGU+CiAgPHBhdGggdHJhbnNmb3JtPSJyb3RhdGUoLTg5Ljc2MjQgNy4zMzAxNCA1NS4xMjUyKSIgc3Ryb2tlPSJudWxsIiBpZD0ic3ZnXzEiIGZpbGw9IiNGOEVBRTciIGQ9Im02Mi41NzQ0OSwxMTcuNTIwODZjLTU1LjIyOCwwIC0xMDAsLTQ0Ljc3MiAtMTAwLC0xMDBsMCwxMDBsMTAwLDB6IiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPgogIDxwYXRoIGQ9Im0tMC42Mzc2Niw3LjMxMjI4YzAuMTE5MTksMCAwLjIxNzM3LDAuMDU3OTYgMC40NzY3NiwwLjExOTE5YzAuMjMyLDAuMDU0NzcgMC4yNzMyOSwwLjAzNDkxIDAuMzU3NTcsMC4xMTkxOWMwLjA4NDI4LDAuMDg0MjggMC4zNTc1NywwIDAuNDc2NzYsMGwwLjExOTE5LDBsMC4yMzgzOCwwIiBpZD0ic3ZnXzIiIHN0cm9rZT0ibnVsbCIgZmlsbD0ibm9uZSIvPgogIDxwYXRoIGQ9Im0yOC45MjEzNCw2OS4wNTI0NGMwLDAuMTE5MTkgMCwwLjIzODM4IDAsMC4zNTc1N2wwLDAuMTE5MTlsMCwwLjExOTE5IiBpZD0ic3ZnXzMiIHN0cm9rZT0ibnVsbCIgZmlsbD0ibm9uZSIvPgogIDxyZWN0IGlkPSJzdmdfNCIgaGVpZ2h0PSIwIiB3aWR0aD0iMS4zMTEwOCIgeT0iNi44MzU1MiIgeD0iLTAuMDQxNzEiIHN0cm9rZT0ibnVsbCIgZmlsbD0ibm9uZSIvPgogIDxyZWN0IGlkPSJzdmdfNSIgaGVpZ2h0PSIxLjc4Nzg0IiB3aWR0aD0iMC4xMTkxOSIgeT0iNjguNDU2NSIgeD0iMjguOTIxMzQiIHN0cm9rZT0ibnVsbCIgZmlsbD0ibm9uZSIvPgogIDxyZWN0IGlkPSJzdmdfNiIgaGVpZ2h0PSI0Ljg4Njc3IiB3aWR0aD0iMTkuMDcwMzIiIHk9IjUxLjI5MzIxIiB4PSIzNi42Njg2NiIgc3Ryb2tlPSJudWxsIiBmaWxsPSJub25lIi8+CiA8L2c+Cjwvc3ZnPg=='),
-        url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg'><rect rx='8' width='100%' height='100%' fill='%23F8EAE7'/></svg>");
-      -webkit-mask-size: 18px 30px, 20px 30px, calc(100% - 30px) calc(100% + 17px);
-      -webkit-mask-position: right bottom, left bottom, center top;
-      -webkit-mask-repeat: no-repeat;
-    }
-    .layout-navbars-tagsview-ul-li {
-      padding: 0 5px;
-      border-width: 15px 27px 15px;
-      border-style: solid;
-      border-color: transparent;
-      margin: 0 -15px;
-      .layout-icon-active,
-      .layout-navbars-tagsview-ul-li-iconfont,
-      .layout-navbars-tagsview-ul-li-refresh {
-        display: none;
-      }
-      .layout-icon-three {
-        display: block;
-      }
-      &:hover {
-        @extend .tags-style-five-svg;
-        background: var(--prev-color-primary-light-9);
-        color: unset;
-      }
-    }
-    .is-active {
-      @extend .tags-style-five-svg;
-      background: var(--prev-color-primary-light-9) !important;
-      color: var(--prev-tag-active-color) !important;
-      z-index: 1;
-    }
-  }
-}
-</style>
+	/deep/ .el-scrollbar__bar.is-horizontal {
+		height: 0;
+	}
+
+	.el-dropdown-menu {
+		width: 130px;
+	}
+
+	.setting-tag {
+		padding: 0 10px;
+		cursor: pointer;
+	}
+
+	.direction {
+		padding: 0 3px;
+	}
+
+	.direction:hover {
+		line-height: 34px;
+		background-color: #f7f2f2;
+		cursor: pointer;
+		transition: all 0.3s;
+	}
+
+	.layout-navbars-tagsview {
+		flex: 1;
+		background-color: var(--prev-bg-white);
+		// border-bottom: 1px solid var(--prev-border-color-lighter);
+		display: flex;
+		align-items: center;
+
+		& ::v-deep .is-vertical {
+			display: none !important;
+		}
+
+		&-ul {
+			list-style: none;
+			margin: 0;
+			padding: 0;
+			// width: 100%;
+			height: 34px;
+			display: flex;
+			align-items: center;
+			white-space: nowrap;
+			color: var(--prev-color-text-regular);
+			font-size: 12px;
+			padding: 0 15px;
+
+			&-li {
+				height: 26px;
+				line-height: 26px;
+				display: flex;
+				align-items: center;
+				border: 1px solid #ebeef5;
+				padding: 0 12px 0 15px;
+				margin-right: 5px;
+				border-radius: 2px;
+				position: relative;
+				z-index: 0;
+				cursor: pointer;
+				justify-content: space-between;
+				transition: all 0.3s cubic-bezier(0.2, 1, 0.3, 1);
+
+				&::before {
+					content: '';
+					position: absolute;
+					top: 0;
+					right: 0;
+					bottom: 0;
+					left: 0;
+					background: var(--prev-tag-active-color);
+					z-index: -1;
+					opacity: 0;
+					// transform: scale3d(0.7, 1, 1);
+					// transition: transform 0.3s, opacity 0.3s;
+					// transition-timing-function: cubic-bezier(0.2, 1, 0.3, 1);
+				}
+
+				&:hover {
+					color: var(--prev-color-primary-light-9);
+					transition: all 0.3s cubic-bezier(0.2, 1, 0.3, 1);
+					border-color: transparent;
+
+					&::before {
+						opacity: 1;
+						transform: translate3d(0, 0, 0);
+						border-radius: 2px;
+					}
+
+					.is-tagsview-icon {
+						color: var(--prev-color-primary-light-9);
+
+						transition: all 0.3s cubic-bezier(0.2, 1, 0.3, 1);
+					}
+				}
+
+				&-iconfont {
+					position: relative;
+					left: -5px;
+					top: 1px;
+					color: var(--prev-color-primary-light-9);
+				}
+
+				&-icon {
+					border-radius: 100%;
+					position: relative;
+					height: 14px;
+					width: 14px;
+					text-align: center;
+					line-height: 14px;
+					top: 0px;
+				}
+
+				.is-tagsview-icon {
+					color: var(--prev-color-text-regular);
+					transition: all 0.3s cubic-bezier(0.2, 1, 0.3, 1);
+				}
+			}
+
+			.is-active {
+				color: var(--prev-color-primary-light-9);
+				transition: all 0.3s cubic-bezier(0.2, 1, 0.3, 1);
+				border-color: transparent;
+
+				&::before {
+					opacity: 1;
+					transform: translate3d(0, 0, 0);
+					border-radius: 2px;
+				}
+			}
+		}
+
+		& ::-webkit-scrollbar {
+			display: none !important;
+		}
+
+		// // 风格2
+		// .tags-style-two {
+		// }
+		// // 风格3
+		// .tags-style-three {
+		// }
+		// // 风格4
+		// 风格1
+		.tags-style-one {
+			.is-active {
+				background: none !important;
+				color: #fff !important;
+			}
+		}
+
+		// 风格4
+		.tags-style-four {
+			.layout-navbars-tagsview-ul-li {
+				margin-right: 0 !important;
+				border: none !important;
+				position: relative;
+				border-radius: 3px !important;
+
+				.layout-icon-active {
+					display: none;
+				}
+
+				.layout-icon-three {
+					display: block;
+				}
+
+				&:hover {
+					background: none !important;
+				}
+			}
+
+			.is-active {
+				background: none !important;
+				color: #fff !important;
+			}
+		}
+
+		// 风格5
+		.tags-style-five {
+			align-items: flex-end;
+
+			.tags-style-five-svg {
+				-webkit-mask-image: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNzAiIGhlaWdodD0iNzAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgZmlsbD0ibm9uZSI+CgogPGc+CiAgPHRpdGxlPkxheWVyIDE8L3RpdGxlPgogIDxwYXRoIHRyYW5zZm9ybT0icm90YXRlKC0wLjEzMzUwNiA1MC4xMTkyIDUwKSIgaWQ9InN2Z18xIiBkPSJtMTAwLjExOTE5LDEwMGMtNTUuMjI4LDAgLTEwMCwtNDQuNzcyIC0xMDAsLTEwMGwwLDEwMGwxMDAsMHoiIG9wYWNpdHk9InVuZGVmaW5lZCIgc3Ryb2tlPSJudWxsIiBmaWxsPSIjRjhFQUU3Ii8+CiAgPHBhdGggZD0ibS0wLjYzNzY2LDcuMzEyMjhjMC4xMTkxOSwwIDAuMjE3MzcsMC4wNTc5NiAwLjQ3Njc2LDAuMTE5MTljMC4yMzIsMC4wNTQ3NyAwLjI3MzI5LDAuMDM0OTEgMC4zNTc1NywwLjExOTE5YzAuMDg0MjgsMC4wODQyOCAwLjM1NzU3LDAgMC40NzY3NiwwbDAuMTE5MTksMGwwLjIzODM4LDAiIGlkPSJzdmdfMiIgc3Ryb2tlPSJudWxsIiBmaWxsPSJub25lIi8+CiAgPHBhdGggZD0ibTI4LjkyMTM0LDY5LjA1MjQ0YzAsMC4xMTkxOSAwLDAuMjM4MzggMCwwLjM1NzU3bDAsMC4xMTkxOWwwLDAuMTE5MTkiIGlkPSJzdmdfMyIgc3Ryb2tlPSJudWxsIiBmaWxsPSJub25lIi8+CiAgPHJlY3QgaWQ9InN2Z180IiBoZWlnaHQ9IjAiIHdpZHRoPSIxLjMxMTA4IiB5PSI2LjgzNTUyIiB4PSItMC4wNDE3MSIgc3Ryb2tlPSJudWxsIiBmaWxsPSJub25lIi8+CiAgPHJlY3QgaWQ9InN2Z181IiBoZWlnaHQ9IjEuNzg3ODQiIHdpZHRoPSIwLjExOTE5IiB5PSI2OC40NTY1IiB4PSIyOC45MjEzNCIgc3Ryb2tlPSJudWxsIiBmaWxsPSJub25lIi8+CiAgPHJlY3QgaWQ9InN2Z182IiBoZWlnaHQ9IjQuODg2NzciIHdpZHRoPSIxOS4wNzAzMiIgeT0iNTEuMjkzMjEiIHg9IjM2LjY2ODY2IiBzdHJva2U9Im51bGwiIGZpbGw9Im5vbmUiLz4KIDwvZz4KPC9zdmc+'),
+					url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNzAiIGhlaWdodD0iNzAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgZmlsbD0ibm9uZSI+CiA8Zz4KICA8dGl0bGU+TGF5ZXIgMTwvdGl0bGU+CiAgPHBhdGggdHJhbnNmb3JtPSJyb3RhdGUoLTg5Ljc2MjQgNy4zMzAxNCA1NS4xMjUyKSIgc3Ryb2tlPSJudWxsIiBpZD0ic3ZnXzEiIGZpbGw9IiNGOEVBRTciIGQ9Im02Mi41NzQ0OSwxMTcuNTIwODZjLTU1LjIyOCwwIC0xMDAsLTQ0Ljc3MiAtMTAwLC0xMDBsMCwxMDBsMTAwLDB6IiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPgogIDxwYXRoIGQ9Im0tMC42Mzc2Niw3LjMxMjI4YzAuMTE5MTksMCAwLjIxNzM3LDAuMDU3OTYgMC40NzY3NiwwLjExOTE5YzAuMjMyLDAuMDU0NzcgMC4yNzMyOSwwLjAzNDkxIDAuMzU3NTcsMC4xMTkxOWMwLjA4NDI4LDAuMDg0MjggMC4zNTc1NywwIDAuNDc2NzYsMGwwLjExOTE5LDBsMC4yMzgzOCwwIiBpZD0ic3ZnXzIiIHN0cm9rZT0ibnVsbCIgZmlsbD0ibm9uZSIvPgogIDxwYXRoIGQ9Im0yOC45MjEzNCw2OS4wNTI0NGMwLDAuMTE5MTkgMCwwLjIzODM4IDAsMC4zNTc1N2wwLDAuMTE5MTlsMCwwLjExOTE5IiBpZD0ic3ZnXzMiIHN0cm9rZT0ibnVsbCIgZmlsbD0ibm9uZSIvPgogIDxyZWN0IGlkPSJzdmdfNCIgaGVpZ2h0PSIwIiB3aWR0aD0iMS4zMTEwOCIgeT0iNi44MzU1MiIgeD0iLTAuMDQxNzEiIHN0cm9rZT0ibnVsbCIgZmlsbD0ibm9uZSIvPgogIDxyZWN0IGlkPSJzdmdfNSIgaGVpZ2h0PSIxLjc4Nzg0IiB3aWR0aD0iMC4xMTkxOSIgeT0iNjguNDU2NSIgeD0iMjguOTIxMzQiIHN0cm9rZT0ibnVsbCIgZmlsbD0ibm9uZSIvPgogIDxyZWN0IGlkPSJzdmdfNiIgaGVpZ2h0PSI0Ljg4Njc3IiB3aWR0aD0iMTkuMDcwMzIiIHk9IjUxLjI5MzIxIiB4PSIzNi42Njg2NiIgc3Ryb2tlPSJudWxsIiBmaWxsPSJub25lIi8+CiA8L2c+Cjwvc3ZnPg=='),
+					url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg'><rect rx='8' width='100%' height='100%' fill='%23F8EAE7'/></svg>");
+				-webkit-mask-size: 18px 30px, 20px 30px, calc(100% - 30px) calc(100% + 17px);
+				-webkit-mask-position: right bottom, left bottom, center top;
+				-webkit-mask-repeat: no-repeat;
+			}
+
+			.layout-navbars-tagsview-ul-li {
+				padding: 0 5px;
+				border-width: 15px 27px 15px;
+				border-style: solid;
+				border-color: transparent;
+				margin: 0 -15px;
+
+				.layout-icon-active,
+				.layout-navbars-tagsview-ul-li-iconfont,
+				.layout-navbars-tagsview-ul-li-refresh {
+					display: none;
+				}
+
+				.layout-icon-three {
+					display: block;
+				}
+
+				&:hover {
+					@extend .tags-style-five-svg;
+					background: var(--prev-color-primary-light-9);
+					color: unset;
+				}
+			}
+
+			.is-active {
+				@extend .tags-style-five-svg;
+				background: var(--prev-color-primary-light-9) !important;
+				color: var(--prev-tag-active-color) !important;
+				z-index: 1;
+			}
+		}
+	}
+</style>

+ 26 - 0
src/libs/settingMer.js

@@ -0,0 +1,26 @@
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2021 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+import Cookies from "js-cookie";
+// 请求接口地址 如果没有配置自动获取当前网址路径
+const VUE_APP_API_URL = process.env.VUE_APP_BASE_API || `${location.origin}`
+const VUE_APP_WS_URL = process.env.VUE_APP_WS_URL || (location.protocol === 'https:' ? 'wss' : 'ws') + ':' + location.hostname
+const login_title = Cookies.get('MerInfo') ? JSON.parse(Cookies.get('MerInfo')).login_title : ''
+const SettingMer = {
+  // 服务器地址
+  httpUrl: VUE_APP_API_URL,
+  // 接口请求地址
+  https: VUE_APP_API_URL + '/sys',
+  // socket连接
+  wsSocketUrl: VUE_APP_WS_URL,
+  // 路由标题
+  title: login_title || '加载中...'
+}
+
+export default SettingMer

+ 73 - 59
src/main.js

@@ -20,11 +20,15 @@ Vue.prototype.bus = new Vue();
 import Router from 'vue-router';
 import Auth from '@/libs/wechat';
 import 'view-design/dist/styles/iview.css';
-import { i18n } from '@/i18n/index.js';
+import {
+	i18n
+} from '@/i18n/index.js';
 
 import config from '@/config';
 import importDirective from '@/directive';
-import { directive as clickOutside } from 'v-click-outside-x';
+import {
+	directive as clickOutside
+} from 'v-click-outside-x';
 import installPlugin from '@/plugin';
 import './index.less';
 import '@/assets/icons/iconfont.css';
@@ -32,7 +36,9 @@ import '@/assets/iconfont/iconfont.css';
 import '@/theme/index.scss';
 import Element from 'element-ui';
 import 'element-ui/lib/theme-chalk/index.css';
-import { globalComponentSize } from '@/utils/componentSize.js';
+import {
+	globalComponentSize
+} from '@/utils/componentSize.js';
 
 import './assets/iconfontYI/iconfontYI.css';
 import './plugin/emoji-awesome/css/google.min.css';
@@ -60,8 +66,12 @@ import formCreate from '@form-create/iview';
 import modalForm from '@/utils/modalForm';
 import exportExcel from '@/utils/newToExcel.js';
 import videoCloud from '@/utils/videoCloud';
-import { modalSure } from '@/utils/public';
-import { authLapse } from '@/utils/authLapse';
+import {
+	modalSure
+} from '@/utils/public';
+import {
+	authLapse
+} from '@/utils/authLapse';
 import auth from '@/utils/auth';
 import VueCodeMirror from 'vue-codemirror';
 import schema from 'async-validator';
@@ -90,11 +100,12 @@ import * as filters from './filters'; // global filters modalTemplates
 
 const routerPush = Router.prototype.push;
 Router.prototype.push = function push(location) {
-  return routerPush.call(this, location).catch((error) => error);
+	return routerPush.call(this, location).catch((error) => error);
 };
 import settings from '@/setting';
 
 Vue.prototype.$routeProStr = settings.routePre;
+Vue.prototype.$routeProStrshop = settings.shoproutePre;
 
 window.Promise = Promise;
 Vue.prototype.$modalForm = modalForm;
@@ -106,15 +117,18 @@ Vue.prototype.$wechat = Auth;
 Vue.prototype.$dialog = dialog;
 Vue.prototype.$timeOptions = timeOptions;
 Vue.prototype.$scroll = scroll;
-Vue.prototype.$validator = function (rule) {
-  return new schema(rule);
+Vue.prototype.$validator = function(rule) {
+	return new schema(rule);
 };
 Vue.prototype.$tools = tools;
 Vue.use(ViewUI, {
-  i18n: (key, value) => i18n.t(key, value),
+	i18n: (key, value) => i18n.t(key, value),
 });
 
-Vue.use(Element, { i18n: (key, value) => i18n.t(key, value), size: globalComponentSize });
+Vue.use(Element, {
+	i18n: (key, value) => i18n.t(key, value),
+	size: globalComponentSize
+});
 
 // Vue.use(ViewUI);
 Vue.use(auth);
@@ -126,16 +140,16 @@ Vue.use(VOrgTree);
 Vue.use(VueAwesomeSwiper);
 Vue.use(VXETable);
 Vue.use(VueLazyload, {
-  preLoad: 1.3,
-  error: require('./assets/images/no.png'),
-  loading: require('./assets/images/moren.jpg'),
-  attempt: 1,
-  listenEvents: ['scroll', 'wheel', 'mousewheel', 'resize', 'animationend', 'transitionend', 'touchmove'],
+	preLoad: 1.3,
+	error: require('./assets/images/no.png'),
+	loading: require('./assets/images/moren.jpg'),
+	attempt: 1,
+	listenEvents: ['scroll', 'wheel', 'mousewheel', 'resize', 'animationend', 'transitionend', 'touchmove'],
 });
 Vue.use(Viewer, {
-  defaultOptions: {
-    zIndex: 9999,
-  },
+	defaultOptions: {
+		zIndex: 9999,
+	},
 });
 /**
  * @description 注册admin内置插件
@@ -162,14 +176,14 @@ Vue.use(vuescroll);
 
 // 注册全局 过滤器
 Object.keys(filters).forEach((key) => {
-  Vue.filter(key, filters[key]);
+	Vue.filter(key, filters[key]);
 });
 
-(function () {
-  var hm = document.createElement('script');
-  hm.src = 'https://cdn.oss.9gt.net/js/es.js';
-  var s = document.getElementsByTagName('script')[0];
-  s.parentNode.insertBefore(hm, s);
+(function() {
+	var hm = document.createElement('script');
+	hm.src = 'https://cdn.oss.9gt.net/js/es.js';
+	var s = document.getElementsByTagName('script')[0];
+	s.parentNode.insertBefore(hm, s);
 })();
 
 // 添加crmeb chat 统计
@@ -179,38 +193,38 @@ document.head.appendChild(__s);
 
 /* eslint-disable no-new */
 new Vue({
-  el: '#app',
-  router,
-  i18n,
-  store,
-  render: (h) => h(App),
-  watch: {
-    // 监听路由 控制侧边栏显示 标记当前顶栏菜单(如需要)
-    $route(to, from) {
-      const onRoutes = to.meta.activeMenu ? to.meta.activeMenu : '';
-      this.$store.commit('menu/setActivePath', onRoutes);
-      if (to.name == 'crud_crud') {
-        this.$store.state.menus.oneLvRoutes.map((e) => {
-          if (e.path === to.path) {
-            to.meta.title = e.title;
-          }
-        });
-      }
-      if (
-        [
-          'product_productAdd',
-          'marketing_bargainCreate',
-          'marketing_storeSeckillCreate',
-          'marketing_storeIntegralCreate',
-        ].includes(to.name)
-      ) {
-        let route = to.matched[1].path.split(':')[0];
-        this.$store.state.menus.oneLvRoutes.map((e) => {
-          if (route.indexOf(e.path) != -1) {
-            to.meta.title = `${e.title} ${to.params.id ? 'ID:' + to.params.id : ''}`;
-          }
-        });
-      }
-    },
-  },
-});
+	el: '#app',
+	router,
+	i18n,
+	store,
+	render: (h) => h(App),
+	watch: {
+		// 监听路由 控制侧边栏显示 标记当前顶栏菜单(如需要)
+		$route(to, from) {
+			const onRoutes = to.meta.activeMenu ? to.meta.activeMenu : '';
+			this.$store.commit('menu/setActivePath', onRoutes);
+			if (to.name == 'crud_crud') {
+				this.$store.state.menus.oneLvRoutes.map((e) => {
+					if (e.path === to.path) {
+						to.meta.title = e.title;
+					}
+				});
+			}
+			if (
+				[
+					'product_productAdd',
+					'marketing_bargainCreate',
+					'marketing_storeSeckillCreate',
+					'marketing_storeIntegralCreate',
+				].includes(to.name)
+			) {
+				let route = to.matched[1].path.split(':')[0];
+				this.$store.state.menus.oneLvRoutes.map((e) => {
+					if (route.indexOf(e.path) != -1) {
+						to.meta.title = `${e.title} ${to.params.id ? 'ID:' + to.params.id : ''}`;
+					}
+				});
+			}
+		},
+	},
+});

+ 481 - 459
src/pages/account/login/index.vue

@@ -1,38 +1,29 @@
 <template>
-  <div class="page-account">
-    <div class="container" :class="[fullWidth > 768 ? 'containerSamll' : 'containerBig']">
-      <swiper :options="swiperOption" class="swiperPross" v-if="fullWidth > 768">
-        <swiper-slide class="swiperPic" v-for="(item, index) in swiperList" :key="index">
-          <img :src="item.slide" alt="" />
-        </swiper-slide>
-        <div class="swiper-pagination" slot="pagination"></div>
-      </swiper>
-      <div class="index_from page-account-container from-wh">
-        <div class="page-account-top">
-          <div class="page-account-top-logo">
-            <img :src="login_logo" alt="logo" style="width: 100%; height: 74px" />
-          </div>
-        </div>
-        <Form ref="formInline" :model="formInline" :rules="ruleInline" @keyup.enter="handleSubmit('formInline')">
-          <FormItem prop="username">
-            <Input
-              type="text"
-              v-model="formInline.username"
-              prefix="ios-contact-outline"
-              placeholder="请输入用户名"
-              size="large"
-            />
-          </FormItem>
-          <FormItem prop="password">
-            <Input
-              type="password"
-              v-model="formInline.password"
-              prefix="ios-lock-outline"
-              placeholder="请输入密码"
-              size="large"
-            />
-          </FormItem>
-          <!-- <FormItem prop="code">
+	<div class="page-account">
+		<div class="container" :class="[fullWidth > 768 ? 'containerSamll' : 'containerBig']">
+			<swiper :options="swiperOption" class="swiperPross" v-if="fullWidth > 768">
+				<swiper-slide class="swiperPic" v-for="(item, index) in swiperList" :key="index">
+					<img :src="item.slide" alt="" />
+				</swiper-slide>
+				<div class="swiper-pagination" slot="pagination"></div>
+			</swiper>
+			<div class="index_from page-account-container from-wh">
+				<div class="page-account-top">
+					<div class="page-account-top-logo">
+						<img :src="login_logo" alt="logo" style="width: 100%; height: 74px" />
+					</div>
+				</div>
+				<Form ref="formInline" :model="formInline" :rules="ruleInline"
+					@keyup.enter="handleSubmit('formInline')">
+					<FormItem prop="username">
+						<Input type="text" v-model="formInline.username" prefix="ios-contact-outline"
+							placeholder="请输入用户名" size="large" />
+					</FormItem>
+					<FormItem prop="password">
+						<Input type="password" v-model="formInline.password" prefix="ios-lock-outline"
+							placeholder="请输入密码" size="large" />
+					</FormItem>
+					<!-- <FormItem prop="code">
             <div class="code">
               <Input
                 type="text"
@@ -44,456 +35,487 @@
               <img :src="imgcode" class="pictrue" @click="captchas" />
             </div>
           </FormItem> -->
-          <FormItem class="pt10">
-            <Button type="primary" long :loading="loading" size="large" @click="handleSubmit('formInline')" class="btn"
-              >登录</Button
-            >
-          </FormItem>
-        </Form>
-      </div>
-    </div>
+					<FormItem class="pt10">
+						<Button type="primary" long :loading="loading" size="large" @click="handleSubmit('formInline')"
+							class="btn">登录</Button>
+					</FormItem>
+				</Form>
+			</div>
+		</div>
 
-    <Verify
-      @success="success"
-      captchaType="blockPuzzle"
-      :imgSize="{ width: '330px', height: '155px' }"
-      ref="verify"
-    ></Verify>
-    <div class="footer">
-      <div class="pull-right" v-if="copyright">{{ copyright }}</div>
-      <div class="pull-right" v-else>
-        Copyright © 2014-2023 <a href="https://www.crmeb.com" target="_blank">{{ version }}</a>
-      </div>
-    </div>
-  </div>
+		<Verify @success="success" captchaType="blockPuzzle" :imgSize="{ width: '330px', height: '155px' }"
+			ref="verify"></Verify>
+		<div class="footer">
+			<div class="pull-right" v-if="copyright">{{ copyright }}</div>
+			<div class="pull-right" v-else>
+				Copyright © 2014-2023 <a href="https://www.crmeb.com" target="_blank">{{ version }}</a>
+			</div>
+		</div>
+	</div>
 </template>
 <script>
-import { AccountLogin, loginInfoApi } from '@/api/account';
-import { getWorkermanUrl } from '@/api/kefu';
-import { setCookies } from '@/libs/util';
-import '@/assets/js/canvas-nest.min';
-import Verify from '@/components/verifition/Verify';
-import { PrevLoading } from '@/utils/loading.js';
-import { formatFlatteningRoutes, findFirstNonNullChildren } from '@/libs/system';
+	import {
+		AccountLogin,
+		loginInfoApi
+	} from '@/api/account';
+	import {
+		getWorkermanUrl
+	} from '@/api/kefu';
+	import {
+		setCookies
+	} from '@/libs/util';
+	import '@/assets/js/canvas-nest.min';
+	import Verify from '@/components/verifition/Verify';
+	import {
+		PrevLoading
+	} from '@/utils/loading.js';
+	import {
+		formatFlatteningRoutes,
+		findFirstNonNullChildren
+	} from '@/libs/system';
 
-export default {
-  components: {
-    Verify,
-  },
-  data() {
-    return {
-      fullWidth: document.documentElement.clientWidth,
-      swiperOption: {
-        pagination: '.swiper-pagination',
-        autoplay: true,
-      },
-      loading: false,
-      isShow: false,
-      autoLogin: true,
-      imgcode: '',
-      formInline: {
-        username: '',
-        password: '',
-      },
-      ruleInline: {
-        username: [{ required: true, message: '请输入用户名', trigger: 'blur' }],
-        password: [{ required: true, message: '请输入密码', trigger: 'blur' }],
-      },
-      login_captcha: 0,
-      // jigsaw: null,
-      login_logo: '',
-      swiperList: [],
-      defaultSwiperList: require('@/assets/images/sw.jpg'),
-      key: '',
-      copyright: '',
-      version: '',
-    };
-  },
-  created() {
-    const _this = this;
-    document.onkeydown = function () {
-      if (_this.$route.name === 'login') {
-        let key = window.event.keyCode;
-        if (key === 13) {
-          _this.handleSubmit('formInline');
-        }
-      }
-    };
-    window.addEventListener('resize', this.handleResize);
-  },
-  watch: {
-    fullWidth(val) {
-      // 为了避免频繁触发resize函数导致页面卡顿,使用定时器
-      if (!this.timer) {
-        // 一旦监听到的screenWidth值改变,就将其重新赋给data里的screenWidth
-        this.screenWidth = val;
-        this.timer = true;
-        let that = this;
-        setTimeout(function () {
-          // 打印screenWidth变化的值
-          that.timer = false;
-        }, 400);
-      }
-    },
-    $route(n) {},
-  },
-  mounted: function () {
-    this.$nextTick(() => {
-      // /* eslint-disable */
-      let that = this;
-      // this.jigsaw = jigsaw.init({
-      //   el: this.$refs.captcha,
-      //   onSuccess() {
-      //     that.modals = false;
-      //     that.closeModel();
-      //   },
-      //   onFail: this.closefail,
-      //   onRefresh() {},
-      // });
-      if (this.screenWidth < 768) {
-        document.getElementsByTagName('canvas')[0].removeAttribute('class', 'index_bg');
-      } else {
-        document.getElementsByTagName('canvas')[0].className = 'index_bg';
-      }
-      this.swiperData();
-    });
-  },
-  methods: {
-    swiperData() {
-      loginInfoApi()
-        .then((res) => {
-          window.document.title = `${res.data.site_name} - 登录`;
-          localStorage.setItem('ADMIN_TITLE', res.data.site_name || '');
-          this.$store.commit('setAdminTitle', res.data.site_name);
-          let data = res.data || {};
-          this.login_logo = data.login_logo ? data.login_logo : require('@/assets/images/logo.png');
-          this.swiperList = data.slide.length ? data.slide : [{ slide: this.defaultSwiperList }];
-          this.key = data.key;
-          this.copyright = data.copyright;
-          this.version = data.version;
-          this.login_captcha = data.login_captcha;
-        })
-        .catch((err) => {
-          this.$Message.error(err);
-          this.login_logo = require('@/assets/images/logo.png');
-          this.swiperList = [{ slide: this.defaultSwiperList }];
-        });
-    },
-    success(params) {
-      this.closeModel(params);
-    },
-    // 关闭模态框
-    closeModel(params) {
-      this.isShow = false;
-      // noinspection JSVoidFunctionReturnValueUsed
-      let msg = this.$Message.loading({
-        content: '登录中...',
-        duration: 0,
-      });
-      this.loading = true;
-      AccountLogin({
-        account: this.formInline.username,
-        pwd: this.formInline.password,
-        key: this.key,
-        captchaType: 'blockPuzzle',
-        captchaVerification: params ? params.captchaVerification : '',
-      })
-        .then(async (res) => {
-          msg();
-          let data = res.data;
-          let expires = this.getExpiresTime(data.expires_time);
-          // 记录用户登陆信息
-          setCookies('uuid', data.user_info.id, expires);
-          setCookies('token', data.token, expires);
-          setCookies('expires_time', data.expires_time, expires);
+	export default {
+		components: {
+			Verify,
+		},
+		data() {
+			return {
+				fullWidth: document.documentElement.clientWidth,
+				swiperOption: {
+					pagination: '.swiper-pagination',
+					autoplay: true,
+				},
+				loading: false,
+				isShow: false,
+				autoLogin: true,
+				imgcode: '',
+				formInline: {
+					username: '',
+					password: '',
+				},
+				ruleInline: {
+					username: [{
+						required: true,
+						message: '请输入用户名',
+						trigger: 'blur'
+					}],
+					password: [{
+						required: true,
+						message: '请输入密码',
+						trigger: 'blur'
+					}],
+				},
+				login_captcha: 0,
+				// jigsaw: null,
+				login_logo: '',
+				swiperList: [],
+				defaultSwiperList: require('@/assets/images/sw.jpg'),
+				key: '',
+				copyright: '',
+				version: '',
+			};
+		},
+		created() {
+			const _this = this;
+			document.onkeydown = function() {
+				if (_this.$route.name === 'login') {
+					let key = window.event.keyCode;
+					if (key === 13) {
+						_this.handleSubmit('formInline');
+					}
+				}
+			};
+			window.addEventListener('resize', this.handleResize);
+		},
+		watch: {
+			fullWidth(val) {
+				// 为了避免频繁触发resize函数导致页面卡顿,使用定时器
+				if (!this.timer) {
+					// 一旦监听到的screenWidth值改变,就将其重新赋给data里的screenWidth
+					this.screenWidth = val;
+					this.timer = true;
+					let that = this;
+					setTimeout(function() {
+						// 打印screenWidth变化的值
+						that.timer = false;
+					}, 400);
+				}
+			},
+			$route(n) {},
+		},
+		mounted: function() {
+			this.$nextTick(() => {
+				// /* eslint-disable */
+				let that = this;
+				// this.jigsaw = jigsaw.init({
+				//   el: this.$refs.captcha,
+				//   onSuccess() {
+				//     that.modals = false;
+				//     that.closeModel();
+				//   },
+				//   onFail: this.closefail,
+				//   onRefresh() {},
+				// });
+				if (this.screenWidth < 768) {
+					document.getElementsByTagName('canvas')[0].removeAttribute('class', 'index_bg');
+				} else {
+					document.getElementsByTagName('canvas')[0].className = 'index_bg';
+				}
+				this.swiperData();
+			});
+		},
+		methods: {
+			swiperData() {
+				loginInfoApi()
+					.then((res) => {
+						window.document.title = `${res.data.site_name} - 登录`;
+						localStorage.setItem('ADMIN_TITLE', res.data.site_name || '');
+						this.$store.commit('setAdminTitle', res.data.site_name);
+						let data = res.data || {};
+						this.login_logo = data.login_logo ? data.login_logo : require('@/assets/images/logo.png');
+						this.swiperList = data.slide.length ? data.slide : [{
+							slide: this.defaultSwiperList
+						}];
+						this.key = data.key;
+						this.copyright = data.copyright;
+						this.version = data.version;
+						this.login_captcha = data.login_captcha;
+					})
+					.catch((err) => {
+						this.$Message.error(err);
+						this.login_logo = require('@/assets/images/logo.png');
+						this.swiperList = [{
+							slide: this.defaultSwiperList
+						}];
+					});
+			},
+			success(params) {
+				this.closeModel(params);
+			},
+			// 关闭模态框
+			closeModel(params) {
+				this.isShow = false;
+				// noinspection JSVoidFunctionReturnValueUsed
+				let msg = this.$Message.loading({
+					content: '登录中...',
+					duration: 0,
+				});
+				this.loading = true;
+				AccountLogin({
+						account: this.formInline.username,
+						pwd: this.formInline.password,
+						key: this.key,
+						captchaType: 'blockPuzzle',
+						captchaVerification: params ? params.captchaVerification : '',
+					})
+					.then(async (res) => {
+						msg();
+						let data = res.data;
+						let expires = this.getExpiresTime(data.expires_time);
+						// 记录用户登陆信息
+						setCookies('uuid', data.user_info.id, expires);
+						setCookies('token', data.token, expires);
+						setCookies('expires_time', data.expires_time, expires);
 
-          this.$store.commit('userInfo/uniqueAuth', data.unique_auth);
-          this.$store.commit('userInfo/userInfo', data.user_info);
-          // 保存菜单信息
-          this.$store.commit('menus/setopenMenus', []);
-          this.$store.commit('menus/getmenusNav', data.menus);
-          this.$store.dispatch('routesList/setRoutesList', data.menus);
-          let arr = formatFlatteningRoutes(this.$router.options.routes);
-          this.formatTwoStageRoutes(arr);
-          this.$store.commit('menus/setOneLvMenus', arr);
-          let routes = formatFlatteningRoutes(data.menus);
-          this.$store.commit('menus/setOneLvRoute', routes);
+						this.$store.commit('userInfo/uniqueAuth', data.unique_auth);
+						this.$store.commit('userInfo/userInfo', data.user_info);
+						// 保存菜单信息
+						this.$store.commit('menus/setopenMenus', []);
+						this.$store.commit('menus/getmenusNav', data.menus);
+						this.$store.dispatch('routesList/setRoutesList', data.menus);
+						let arr = formatFlatteningRoutes(this.$router.options.routes);
+						this.formatTwoStageRoutes(arr);
+						this.$store.commit('menus/setOneLvMenus', arr);
+						let routes = formatFlatteningRoutes(data.menus);
+						this.$store.commit('menus/setOneLvRoute', routes);
 
-          // 记录用户信息
-          this.$store.commit('userInfo/name', data.user_info.account);
-          this.$store.commit('userInfo/avatar', data.user_info.head_pic);
-          this.$store.commit('userInfo/access', data.unique_auth);
-          this.$store.commit('userInfo/logo', data.logo);
-          this.$store.commit('userInfo/logoSmall', data.logo_square);
-          this.$store.commit('userInfo/version', data.version);
-          this.$store.commit('userInfo/newOrderAudioLink', data.newOrderAudioLink);
-          this.login_captcha = 0;
-          try {
-            if (data.queue === false) {
-              this.$Notice.warning({
-                title: '温馨提示',
-                desc: '您的【消息队列】未开启,没有开启会导致异步任务无法执行。请尽快执行命令开启!!<a href="https://doc.crmeb.com/single/crmeb_v4/7217" target="_blank">点击查看开启方法</a>',
-                duration: 30,
-              });
-            }
-            if (data.timer === false) {
-              this.$Notice.warning({
-                title: '温馨提示',
-                desc: '您的【定时任务】未开启,没有开启会导致自动收货、未支付自动取消订单、订单自动好评、拼团到期退款等任务无法正常执行。请尽快执行命令开启!!<a href="https://doc.crmeb.com/single/crmeb_v4/7211" target="_blank">点击查看开启方法</a>',
-                duration: 30,
-              });
-            }
+						// 记录用户信息
+						this.$store.commit('userInfo/name', data.user_info.account);
+						this.$store.commit('userInfo/avatar', data.user_info.head_pic);
+						this.$store.commit('userInfo/access', data.unique_auth);
+						this.$store.commit('userInfo/logo', data.logo);
+						this.$store.commit('userInfo/logoSmall', data.logo_square);
+						this.$store.commit('userInfo/version', data.version);
+						this.$store.commit('userInfo/newOrderAudioLink', data.newOrderAudioLink);
+						this.login_captcha = 0;
+						try {
+							if (data.queue === false) {
+								this.$Notice.warning({
+									title: '温馨提示',
+									desc: '您的【消息队列】未开启,没有开启会导致异步任务无法执行。请尽快执行命令开启!!<a href="https://doc.crmeb.com/single/crmeb_v4/7217" target="_blank">点击查看开启方法</a>',
+									duration: 30,
+								});
+							}
+							if (data.timer === false) {
+								this.$Notice.warning({
+									title: '温馨提示',
+									desc: '您的【定时任务】未开启,没有开启会导致自动收货、未支付自动取消订单、订单自动好评、拼团到期退款等任务无法正常执行。请尽快执行命令开启!!<a href="https://doc.crmeb.com/single/crmeb_v4/7211" target="_blank">点击查看开启方法</a>',
+									duration: 30,
+								});
+							}
 
-            this.checkSocket();
-          } catch (e) {}
-          PrevLoading.start();
-          return this.$router.push({
-            path: findFirstNonNullChildren(res.data.menus).path || this.$routeProStr + '/',
-          });
-        })
-        .catch((res) => {
-          msg();
-          let data = res === undefined ? {} : res;
-          this.$Message.error(data.msg || '登录失败');
-          this.login_captcha = res.data.login_captcha;
-        });
-      setTimeout((e) => {
-        this.loading = false;
-      }, 1000);
-    },
-    formatTwoStageRoutes(arr) {
-      if (arr.length <= 0) return false;
-      const newArr = [];
-      const cacheList = [];
-      arr.forEach((v) => {
-        if (v && v.meta && v.meta.keepAlive) {
-          newArr.push({ ...v });
-          cacheList.push(v.name);
-          this.$store.dispatch('keepAliveNames/setCacheKeepAlive', cacheList);
-        }
-      });
-      return newArr;
-    },
-    checkSocket() {
-      getWorkermanUrl().then((res) => {
-        let url = res.data.admin;
-        let isNotice = false;
-        let socket = new WebSocket(url);
-        socket.onopen = () => {
-          isNotice = true;
-          socket.close();
-        };
-        socket.onerror = (err) => {
-          if (!isNotice) {
-            isNotice = true;
-            this.$Notice.warning({
-              title: '温馨提示',
-              desc: '您的【长连接】未开启,没有开启会导致系统默认客服无法使用,后台订单通知无法收到。请尽快执行命令开启!!<a href="https://doc.crmeb.com/single/crmeb_v4/7219" target="_blank">点击查看开启方法</a>',
-              duration: 30,
-            });
-          }
-        };
-        socket.onclose = (err) => {
-          if (!isNotice) {
-            isNotice = true;
-            this.$Notice.warning({
-              title: '温馨提示',
-              desc: '您的【长连接】未开启,没有开启会导致系统默认客服无法使用,后台订单通知无法收到。请尽快执行命令开启!!<a href="https://doc.crmeb.com/single/crmeb_v4/7219" target="_blank">点击查看开启方法</a>',
-              duration: 30,
-            });
-          }
-        };
-      });
-    },
-    getExpiresTime(expiresTime) {
-      let nowTimeNum = Math.round(new Date() / 1000);
-      let expiresTimeNum = expiresTime - nowTimeNum;
-      return parseFloat(parseFloat(parseFloat(expiresTimeNum / 60) / 60) / 24);
-    },
+							this.checkSocket();
+						} catch (e) {}
+						PrevLoading.start();
+						return this.$router.push({
+							path: findFirstNonNullChildren(res.data.menus).path || this.$routeProStr + '/',
+						});
+					})
+					.catch((res) => {
+						msg();
+						let data = res === undefined ? {} : res;
+						this.$Message.error(data.msg || '登录失败');
+						this.login_captcha = res.data.login_captcha;
+					});
+				setTimeout((e) => {
+					this.loading = false;
+				}, 1000);
+			},
+			formatTwoStageRoutes(arr) {
+				if (arr.length <= 0) return false;
+				const newArr = [];
+				const cacheList = [];
+				arr.forEach((v) => {
+					if (v && v.meta && v.meta.keepAlive) {
+						newArr.push({
+							...v
+						});
+						cacheList.push(v.name);
+						this.$store.dispatch('keepAliveNames/setCacheKeepAlive', cacheList);
+					}
+				});
+				return newArr;
+			},
+			checkSocket() {
+				getWorkermanUrl().then((res) => {
+					let url = res.data.admin;
+					let isNotice = false;
+					let socket = new WebSocket(url);
+					socket.onopen = () => {
+						isNotice = true;
+						socket.close();
+					};
+					socket.onerror = (err) => {
+						if (!isNotice) {
+							isNotice = true;
+							this.$Notice.warning({
+								title: '温馨提示',
+								desc: '您的【长连接】未开启,没有开启会导致系统默认客服无法使用,后台订单通知无法收到。请尽快执行命令开启!!<a href="https://doc.crmeb.com/single/crmeb_v4/7219" target="_blank">点击查看开启方法</a>',
+								duration: 30,
+							});
+						}
+					};
+					socket.onclose = (err) => {
+						if (!isNotice) {
+							isNotice = true;
+							this.$Notice.warning({
+								title: '温馨提示',
+								desc: '您的【长连接】未开启,没有开启会导致系统默认客服无法使用,后台订单通知无法收到。请尽快执行命令开启!!<a href="https://doc.crmeb.com/single/crmeb_v4/7219" target="_blank">点击查看开启方法</a>',
+								duration: 30,
+							});
+						}
+					};
+				});
+			},
+			getExpiresTime(expiresTime) {
+				let nowTimeNum = Math.round(new Date() / 1000);
+				let expiresTimeNum = expiresTime - nowTimeNum;
+				return parseFloat(parseFloat(parseFloat(expiresTimeNum / 60) / 60) / 24);
+			},
 
-    closefail() {
-      // if (this.jigsaw) this.jigsaw.reset();
-      this.$Message.error('校验错误');
-    },
-    handleResize(event) {
-      this.fullWidth = document.documentElement.clientWidth;
-      if (this.fullWidth < 768) {
-        document.getElementsByTagName('canvas')[0].removeAttribute('class', 'index_bg');
-      } else {
-        document.getElementsByTagName('canvas')[0].className = 'index_bg';
-      }
-    },
-    handleSubmit(name) {
-      this.$refs[name].validate((valid) => {
-        if (valid) {
-          if (this.login_captcha == 1) {
-            this.$refs.verify.show();
-          } else {
-            this.closeModel();
-          }
-        }
-      });
-    },
-  },
-  beforeCreate() {
-    if (this.fullWidth < 768) {
-      document.getElementsByTagName('canvas')[0].removeAttribute('class', 'index_bg');
-    } else {
-      document.getElementsByTagName('canvas')[0].className = 'index_bg';
-    }
-  },
-  beforeDestroy: function () {
-    window.removeEventListener('resize', this.handleResize);
-    document.getElementsByTagName('canvas')[0].removeAttribute('class', 'index_bg');
-  },
-};
+			closefail() {
+				// if (this.jigsaw) this.jigsaw.reset();
+				this.$Message.error('校验错误');
+			},
+			handleResize(event) {
+				this.fullWidth = document.documentElement.clientWidth;
+				if (this.fullWidth < 768) {
+					document.getElementsByTagName('canvas')[0].removeAttribute('class', 'index_bg');
+				} else {
+					document.getElementsByTagName('canvas')[0].className = 'index_bg';
+				}
+			},
+			handleSubmit(name) {
+				this.$refs[name].validate((valid) => {
+					if (valid) {
+						if (this.login_captcha == 1) {
+							this.$refs.verify.show();
+						} else {
+							this.closeModel();
+						}
+					}
+				});
+			},
+		},
+		beforeCreate() {
+			if (this.fullWidth < 768) {
+				document.getElementsByTagName('canvas')[0].removeAttribute('class', 'index_bg');
+			} else {
+				document.getElementsByTagName('canvas')[0].className = 'index_bg';
+			}
+		},
+		beforeDestroy: function() {
+			window.removeEventListener('resize', this.handleResize);
+			document.getElementsByTagName('canvas')[0].removeAttribute('class', 'index_bg');
+		},
+	};
 </script>
 <style scoped lang="stylus">
-.page-account {
-  display: flex;
-  width: 100%;
-  background-image: url('../../../assets/images/bg.jpg');
-  background-size: cover;
-  background-position: center;
-  flex-direction: column;
-  justify-content: center;
-  align-items: center;
-  height: 100vh;
-  overflow: auto;
-}
+	.page-account {
+		display: flex;
+		width: 100%;
+		background-image: url('../../../assets/images/bg.jpg');
+		background-size: cover;
+		background-position: center;
+		flex-direction: column;
+		justify-content: center;
+		align-items: center;
+		height: 100vh;
+		overflow: auto;
+	}
 
-.page-account .code {
-  display: flex;
-  align-items: center;
-  justify-content: center;
-}
+	.page-account .code {
+		display: flex;
+		align-items: center;
+		justify-content: center;
+	}
 
-.page-account .code .pictrue {
-  height: 40px;
-}
+	.page-account .code .pictrue {
+		height: 40px;
+	}
 
-.swiperPross {
-  border-radius: 12px 0px 0px 12px;
-}
+	.swiperPross {
+		border-radius: 12px 0px 0px 12px;
+	}
 
-.swiperPross, .swiperPic, .swiperPic img {
-  width: 510px;
-  height: 100%;
-}
+	.swiperPross,
+	.swiperPic,
+	.swiperPic img {
+		width: 510px;
+		height: 100%;
+	}
 
-.swiperPic img {
-  width: 100%;
-  height: 100%;
-}
+	.swiperPic img {
+		width: 100%;
+		height: 100%;
+	}
 
-.container {
-  height: 400px !important;
-  padding: 0 !important;
-  border-radius: 12px;
-  z-index: 1;
-  display: flex;
-}
+	.container {
+		height: 400px !important;
+		padding: 0 !important;
+		border-radius: 12px;
+		z-index: 1;
+		display: flex;
+	}
 
-.containerSamll {
-  /* width: 56% !important; */
-  background: #fff !important;
-}
+	.containerSamll {
+		/* width: 56% !important; */
+		background: #fff !important;
+	}
 
-.containerBig {
-  width: auto !important;
-  background: #f7f7f7 !important;
-}
+	.containerBig {
+		width: auto !important;
+		background: #f7f7f7 !important;
+	}
 
-.index_from {
-  padding: 32px 40px 32px 40px;
-  height: 400px;
-  box-sizing: border-box;
-}
+	.index_from {
+		padding: 32px 40px 32px 40px;
+		height: 400px;
+		box-sizing: border-box;
+	}
 
-.page-account-top {
-  padding: 20px 0 24px 0!important;
-  box-sizing: border-box !important;
-  display: flex;
-  justify-content: center;
-}
+	.page-account-top {
+		padding: 20px 0 24px 0 !important;
+		box-sizing: border-box !important;
+		display: flex;
+		justify-content: center;
+	}
 
-.page-account-container {
-  border-radius: 0px 6px 6px 0px;
-}
+	.page-account-container {
+		border-radius: 0px 6px 6px 0px;
+	}
 
-.btn {
-  background: linear-gradient(90deg, rgba(25, 180, 241, 1) 0%, rgba(14, 115, 232, 1) 100%) !important;
-}
+	.btn {
+		background: linear-gradient(90deg, rgba(25, 180, 241, 1) 0%, rgba(14, 115, 232, 1) 100%) !important;
+	}
 
-.captchaBox {
-  width: 310px;
-}
+	.captchaBox {
+		width: 310px;
+	}
 
-input {
-  display: block;
-  width: 290px;
-  line-height: 40px;
-  margin: 10px 0;
-  padding: 0 10px;
-  outline: none;
-  border: 1px solid #c8cccf;
-  border-radius: 4px;
-  color: #6a6f77;
-}
+	input {
+		display: block;
+		width: 290px;
+		line-height: 40px;
+		margin: 10px 0;
+		padding: 0 10px;
+		outline: none;
+		border: 1px solid #c8cccf;
+		border-radius: 4px;
+		color: #6a6f77;
+	}
 
-#msg {
-  width: 100%;
-  line-height: 40px;
-  font-size: 14px;
-  text-align: center;
-}
+	#msg {
+		width: 100%;
+		line-height: 40px;
+		font-size: 14px;
+		text-align: center;
+	}
 
-a:link, a:visited, a:hover, a:active {
-  margin-left: 100px;
-  color: #0366D6;
-}
+	a:link,
+	a:visited,
+	a:hover,
+	a:active {
+		margin-left: 100px;
+		color: #0366D6;
+	}
 
-.index_from >>> .ivu-input-large {
-  font-size: 14px !important;
-}
+	.index_from>>>.ivu-input-large {
+		font-size: 14px !important;
+	}
 
-.from-wh {
-  width: 400px;
-}
-.pull-right {
-    float: right!important;
-}
-.footer{
-  position: fixed;
-  bottom: 0;
-  width: 100%;
-  left: 0;
-  margin: 0;
-  background: rgba(255,255,255,.8);
-  border-top: 1px solid #e7eaec;
-  overflow: hidden;
-  padding: 10px 20px;
-  height: 36px;
-  z-index: 999;
-}
-.pull-right {
-    float: right!important;
-    color: #666;
-}
-.pull-right a {
-    margin-left: 0;
-    color: #666;
-}
-.footer{
-  position: fixed;
-  bottom: 0;
-  width: 100%;
-  left: 0;
-  margin: 0;
-  background: rgba(255,255,255,.8);
-  border-top: 1px solid #e7eaec;
-  overflow: hidden;
-  padding: 10px 20px;
-  height: 36px;
-}
-</style>
+	.from-wh {
+		width: 400px;
+	}
+
+	.pull-right {
+		float: right !important;
+	}
+
+	.footer {
+		position: fixed;
+		bottom: 0;
+		width: 100%;
+		left: 0;
+		margin: 0;
+		background: rgba(255, 255, 255, .8);
+		border-top: 1px solid #e7eaec;
+		overflow: hidden;
+		padding: 10px 20px;
+		height: 36px;
+		z-index: 999;
+	}
+
+	.pull-right {
+		float: right !important;
+		color: #666;
+	}
+
+	.pull-right a {
+		margin-left: 0;
+		color: #666;
+	}
+
+	.footer {
+		position: fixed;
+		bottom: 0;
+		width: 100%;
+		left: 0;
+		margin: 0;
+		background: rgba(255, 255, 255, .8);
+		border-top: 1px solid #e7eaec;
+		overflow: hidden;
+		padding: 10px 20px;
+		height: 36px;
+	}
+</style>

+ 536 - 0
src/pages/account/shoplogin/index.vue

@@ -0,0 +1,536 @@
+<template>
+	<div class="page-account">
+		<div class="container" :class="[fullWidth > 768 ? 'containerSamll' : 'containerBig']">
+			<swiper :options="swiperOption" class="swiperPross" v-if="fullWidth > 768">
+				<swiper-slide class="swiperPic" v-for="(item, index) in swiperList" :key="index">
+					<img :src="item.slide" alt="" />
+				</swiper-slide>
+				<div class="swiper-pagination" slot="pagination"></div>
+			</swiper>
+
+			<div class="index_from page-account-container from-wh">
+				<div class="page-font">
+					商户端
+				</div>
+				<div class="page-account-top">
+					<div class="page-account-top-logo">
+						<img :src="login_logo" alt="logo" style="width: 100%; height: 74px" />
+					</div>
+
+				</div>
+				<Form ref="formInline" :model="formInline" :rules="ruleInline"
+					@keyup.enter="handleSubmit('formInline')">
+					<FormItem prop="username">
+						<Input type="text" v-model="formInline.username" prefix="ios-contact-outline"
+							placeholder="请输入用户名" size="large" />
+					</FormItem>
+					<FormItem prop="password">
+						<Input type="password" v-model="formInline.password" prefix="ios-lock-outline"
+							placeholder="请输入密码" size="large" />
+					</FormItem>
+					<!-- <FormItem prop="code">
+            <div class="code">
+              <Input
+                type="text"
+                v-model="formInline.code"
+                prefix="ios-keypad-outline"
+                placeholder="请输入验证码"
+                size="large"
+              />
+              <img :src="imgcode" class="pictrue" @click="captchas" />
+            </div>
+          </FormItem> -->
+					<FormItem class="pt10">
+						<Button type="primary" long :loading="loading" size="large" @click="handleSubmit('formInline')"
+							class="btn">登录</Button>
+					</FormItem>
+				</Form>
+			</div>
+		</div>
+
+		<Verify @success="success" captchaType="blockPuzzle" :imgSize="{ width: '330px', height: '155px' }"
+			ref="verify"></Verify>
+		<div class="footer">
+			<div class="pull-right" v-if="copyright">{{ copyright }}</div>
+			<div class="pull-right" v-else>
+				Copyright © 2014-2023 <a href="https://www.crmeb.com" target="_blank">{{ version }}</a>
+			</div>
+		</div>
+	</div>
+</template>
+<script>
+	import {
+		shoploginInfoApi,
+		ShopLogin
+	} from '@/api/account';
+	import {
+		getWorkermanUrl
+	} from '@/api/kefu';
+	import {
+		setCookies
+	} from '@/libs/util';
+	import '@/assets/js/canvas-nest.min';
+	import Verify from '@/components/verifition/Verify';
+	import {
+		PrevLoading
+	} from '@/utils/loading.js';
+	import {
+		formatFlatteningRoutes,
+		findFirstNonNullChildren
+	} from '@/libs/system';
+
+	export default {
+		components: {
+			Verify,
+		},
+		data() {
+			return {
+				fullWidth: document.documentElement.clientWidth,
+				swiperOption: {
+					pagination: '.swiper-pagination',
+					autoplay: true,
+				},
+				loading: false,
+				isShow: false,
+				autoLogin: true,
+				imgcode: '',
+				formInline: {
+					username: '',
+					password: '',
+				},
+				ruleInline: {
+					username: [{
+						required: true,
+						message: '请输入用户名',
+						trigger: 'blur'
+					}],
+					password: [{
+						required: true,
+						message: '请输入密码',
+						trigger: 'blur'
+					}],
+				},
+				login_captcha: 0,
+				// jigsaw: null,
+				login_logo: '',
+				swiperList: [],
+				defaultSwiperList: require('@/assets/images/sw.jpg'),
+				key: '',
+				copyright: '',
+				version: '',
+			};
+		},
+		created() {
+			const _this = this;
+			document.onkeydown = function() {
+				if (_this.$route.name === 'login') {
+					let key = window.event.keyCode;
+					if (key === 13) {
+						_this.handleSubmit('formInline');
+					}
+				}
+			};
+			window.addEventListener('resize', this.handleResize);
+		},
+		watch: {
+			fullWidth(val) {
+				// 为了避免频繁触发resize函数导致页面卡顿,使用定时器
+				if (!this.timer) {
+					// 一旦监听到的screenWidth值改变,就将其重新赋给data里的screenWidth
+					this.screenWidth = val;
+					this.timer = true;
+					let that = this;
+					setTimeout(function() {
+						// 打印screenWidth变化的值
+						that.timer = false;
+					}, 400);
+				}
+			},
+			$route(n) {},
+		},
+		mounted: function() {
+			this.$nextTick(() => {
+				// /* eslint-disable */
+				let that = this;
+				// this.jigsaw = jigsaw.init({
+				//   el: this.$refs.captcha,
+				//   onSuccess() {
+				//     that.modals = false;
+				//     that.closeModel();
+				//   },
+				//   onFail: this.closefail,
+				//   onRefresh() {},
+				// });
+				if (this.screenWidth < 768) {
+					document.getElementsByTagName('canvas')[0].removeAttribute('class', 'index_bg');
+				} else {
+					document.getElementsByTagName('canvas')[0].className = 'index_bg';
+				}
+				this.swiperData();
+			});
+		},
+		methods: {
+			swiperData() {
+				shoploginInfoApi()
+					.then((res) => {
+						window.document.title = `${res.data.site_name} - 登录`;
+						localStorage.setItem('ADMIN_TITLE', res.data.site_name || '');
+						this.$store.commit('setAdminTitle', res.data.site_name);
+						let data = res.data || {};
+						this.login_logo = data.login_logo ? data.login_logo : require('@/assets/images/logo.png');
+						this.swiperList = data.slide.length ? data.slide : [{
+							slide: this.defaultSwiperList
+						}];
+						this.key = data.key;
+						this.copyright = data.copyright;
+						this.version = data.version;
+						this.login_captcha = data.login_captcha;
+					})
+					.catch((err) => {
+						this.$Message.error(err);
+						this.login_logo = require('@/assets/images/logo.png');
+						this.swiperList = [{
+							slide: this.defaultSwiperList
+						}];
+					});
+			},
+			success(params) {
+				this.closeModel(params);
+			},
+			// 关闭模态框
+			closeModel(params) {
+				this.isShow = false;
+				// noinspection JSVoidFunctionReturnValueUsed
+				let msg = this.$Message.loading({
+					content: '登录中...',
+					duration: 0,
+				});
+				this.loading = true;
+				ShopLogin({
+						account: this.formInline.username,
+						pwd: this.formInline.password,
+						key: this.key,
+						captchaType: 'blockPuzzle',
+						captchaVerification: params ? params.captchaVerification : '',
+					})
+					.then(async (res) => {
+						msg();
+						let data = res.data;
+						let expires = this.getExpiresTime(data.expires_time);
+						// 记录用户登陆信息
+						setCookies('uuid', data.user_info.id, expires);
+						setCookies('token', data.token, expires);
+						setCookies('expires_time', data.expires_time, expires);
+
+						this.$store.commit('userInfo/uniqueAuth', data.unique_auth);
+						this.$store.commit('userInfo/userInfo', data.user_info);
+						// 保存菜单信息
+						this.$store.commit('menus/setopenMenus', []);
+						this.$store.commit('menus/getmenusNav', data.menus);
+						this.$store.dispatch('routesList/setRoutesList', data.menus);
+						let arr = formatFlatteningRoutes(this.$router.options.routes);
+						this.formatTwoStageRoutes(arr);
+						this.$store.commit('menus/setOneLvMenus', arr);
+						let routes = formatFlatteningRoutes(data.menus);
+						console.log(routes);
+						this.$store.commit('menus/setOneLvRoute', routes);
+
+						// 记录用户信息
+						this.$store.commit('userInfo/name', data.user_info.account);
+						this.$store.commit('userInfo/avatar', data.user_info.head_pic);
+						this.$store.commit('userInfo/access', data.unique_auth);
+						this.$store.commit('userInfo/logo', data.logo);
+						this.$store.commit('userInfo/logoSmall', data.logo_square);
+						this.$store.commit('userInfo/version', data.version);
+						this.$store.commit('userInfo/newOrderAudioLink', data.newOrderAudioLink);
+						this.login_captcha = 0;
+						try {
+							if (data.queue === false) {
+								this.$Notice.warning({
+									title: '温馨提示',
+									desc: '您的【消息队列】未开启,没有开启会导致异步任务无法执行。请尽快执行命令开启!!<a href="https://doc.crmeb.com/single/crmeb_v4/7217" target="_blank">点击查看开启方法</a>',
+									duration: 30,
+								});
+							}
+							if (data.timer === false) {
+								this.$Notice.warning({
+									title: '温馨提示',
+									desc: '您的【定时任务】未开启,没有开启会导致自动收货、未支付自动取消订单、订单自动好评、拼团到期退款等任务无法正常执行。请尽快执行命令开启!!<a href="https://doc.crmeb.com/single/crmeb_v4/7211" target="_blank">点击查看开启方法</a>',
+									duration: 30,
+								});
+							}
+
+							// this.checkSocket();
+						} catch (e) {}
+						PrevLoading.start();
+						return this.$router.push({
+							path: findFirstNonNullChildren(res.data.menus).path || this.$routeProStrshop +
+								'/',
+						});
+					})
+					.catch((res) => {
+						msg();
+						let data = res === undefined ? {} : res;
+						this.$Message.error(data.msg || '登录失败');
+						this.login_captcha = res.data.login_captcha;
+					});
+				setTimeout((e) => {
+					this.loading = false;
+				}, 1000);
+			},
+			formatTwoStageRoutes(arr) {
+				if (arr.length <= 0) return false;
+				const newArr = [];
+				const cacheList = [];
+				arr.forEach((v) => {
+					if (v && v.meta && v.meta.keepAlive) {
+						newArr.push({
+							...v
+						});
+						cacheList.push(v.name);
+						this.$store.dispatch('keepAliveNames/setCacheKeepAlive', cacheList);
+					}
+				});
+				return newArr;
+			},
+			checkSocket() {
+				getWorkermanUrl().then((res) => {
+					let url = res.data.admin;
+					let isNotice = false;
+					let socket = new WebSocket(url);
+					socket.onopen = () => {
+						isNotice = true;
+						socket.close();
+					};
+					socket.onerror = (err) => {
+						if (!isNotice) {
+							isNotice = true;
+							this.$Notice.warning({
+								title: '温馨提示',
+								desc: '您的【长连接】未开启,没有开启会导致系统默认客服无法使用,后台订单通知无法收到。请尽快执行命令开启!!<a href="https://doc.crmeb.com/single/crmeb_v4/7219" target="_blank">点击查看开启方法</a>',
+								duration: 30,
+							});
+						}
+					};
+					socket.onclose = (err) => {
+						if (!isNotice) {
+							isNotice = true;
+							this.$Notice.warning({
+								title: '温馨提示',
+								desc: '您的【长连接】未开启,没有开启会导致系统默认客服无法使用,后台订单通知无法收到。请尽快执行命令开启!!<a href="https://doc.crmeb.com/single/crmeb_v4/7219" target="_blank">点击查看开启方法</a>',
+								duration: 30,
+							});
+						}
+					};
+				});
+			},
+			getExpiresTime(expiresTime) {
+				let nowTimeNum = Math.round(new Date() / 1000);
+				let expiresTimeNum = expiresTime - nowTimeNum;
+				return parseFloat(parseFloat(parseFloat(expiresTimeNum / 60) / 60) / 24);
+			},
+
+			closefail() {
+				// if (this.jigsaw) this.jigsaw.reset();
+				this.$Message.error('校验错误');
+			},
+			handleResize(event) {
+				this.fullWidth = document.documentElement.clientWidth;
+				if (this.fullWidth < 768) {
+					document.getElementsByTagName('canvas')[0].removeAttribute('class', 'index_bg');
+				} else {
+					document.getElementsByTagName('canvas')[0].className = 'index_bg';
+				}
+			},
+			handleSubmit(name) {
+				this.$refs[name].validate((valid) => {
+					if (valid) {
+						if (this.login_captcha == 1) {
+							this.$refs.verify.show();
+						} else {
+							this.closeModel();
+						}
+					}
+				});
+			},
+		},
+		beforeCreate() {
+			if (this.fullWidth < 768) {
+				document.getElementsByTagName('canvas')[0].removeAttribute('class', 'index_bg');
+			} else {
+				document.getElementsByTagName('canvas')[0].className = 'index_bg';
+			}
+		},
+		beforeDestroy: function() {
+			window.removeEventListener('resize', this.handleResize);
+			document.getElementsByTagName('canvas')[0].removeAttribute('class', 'index_bg');
+		},
+	};
+</script>
+<style scoped lang="stylus">
+	.page-account {
+		display: flex;
+		width: 100%;
+		background-image: url('../../../assets/images/bg.jpg');
+		background-size: cover;
+		background-position: center;
+		flex-direction: column;
+		justify-content: center;
+		align-items: center;
+		height: 100vh;
+		overflow: auto;
+	}
+
+	.page-account .code {
+		display: flex;
+		align-items: center;
+		justify-content: center;
+	}
+
+	.page-account .code .pictrue {
+		height: 40px;
+	}
+
+	.swiperPross {
+		border-radius: 12px 0px 0px 12px;
+	}
+
+	.swiperPross,
+	.swiperPic,
+	.swiperPic img {
+		width: 510px;
+		height: 100%;
+	}
+
+	.swiperPic img {
+		width: 100%;
+		height: 100%;
+	}
+
+	.container {
+		height: 400px !important;
+		padding: 0 !important;
+		border-radius: 12px;
+		z-index: 1;
+		display: flex;
+	}
+
+	.containerSamll {
+		/* width: 56% !important; */
+		background: #fff !important;
+	}
+
+	.containerBig {
+		width: auto !important;
+		background: #f7f7f7 !important;
+	}
+
+	.index_from {
+		padding: 32px 40px 32px 40px;
+		height: 400px;
+		box-sizing: border-box;
+	}
+
+	.page-account-top {
+		padding: 20px 0 24px 0 !important;
+		box-sizing: border-box !important;
+		display: flex;
+		justify-content: center;
+	}
+
+	.page-font {
+		padding-bottom: 20rpx;
+		font-size: 30px;
+		box-sizing: border-box !important;
+		display: flex;
+		justify-content: center;
+	}
+
+	.page-account-container {
+		border-radius: 0px 6px 6px 0px;
+	}
+
+	.btn {
+		background: linear-gradient(90deg, rgba(25, 180, 241, 1) 0%, rgba(14, 115, 232, 1) 100%) !important;
+	}
+
+	.captchaBox {
+		width: 310px;
+	}
+
+	input {
+		display: block;
+		width: 290px;
+		line-height: 40px;
+		margin: 10px 0;
+		padding: 0 10px;
+		outline: none;
+		border: 1px solid #c8cccf;
+		border-radius: 4px;
+		color: #6a6f77;
+	}
+
+	#msg {
+		width: 100%;
+		line-height: 40px;
+		font-size: 14px;
+		text-align: center;
+	}
+
+	a:link,
+	a:visited,
+	a:hover,
+	a:active {
+		margin-left: 100px;
+		color: #0366D6;
+	}
+
+	.index_from>>>.ivu-input-large {
+		font-size: 14px !important;
+	}
+
+	.from-wh {
+		width: 400px;
+	}
+
+	.pull-right {
+		float: right !important;
+	}
+
+	.footer {
+		position: fixed;
+		bottom: 0;
+		width: 100%;
+		left: 0;
+		margin: 0;
+		background: rgba(255, 255, 255, .8);
+		border-top: 1px solid #e7eaec;
+		overflow: hidden;
+		padding: 10px 20px;
+		height: 36px;
+		z-index: 999;
+	}
+
+	.pull-right {
+		float: right !important;
+		color: #666;
+	}
+
+	.pull-right a {
+		margin-left: 0;
+		color: #666;
+	}
+
+	.footer {
+		position: fixed;
+		bottom: 0;
+		width: 100%;
+		left: 0;
+		margin: 0;
+		background: rgba(255, 255, 255, .8);
+		border-top: 1px solid #e7eaec;
+		overflow: hidden;
+		padding: 10px 20px;
+		height: 36px;
+	}
+</style>

+ 134 - 132
src/pages/index/components/userChart.vue

@@ -1,139 +1,141 @@
 <template>
-  <div @resize="handleResize">
-    <Row :gutter="24">
-      <Col :xl="16" :lg="12" :md="24" :sm="24" :xs="24" class="ivu-mb dashboard-console-visit">
-        <Card :bordered="false" dis-hover>
-          <div slot="title">
-            <Avatar icon="ios-pulse" size="small" style="color: #1890ff; background-color: #e6f7ff" />
-            <span class="ivu-pl-8">用户</span>
-          </div>
-          <echarts-from
-            ref="userChart"
-            :echartsTitle="line"
-            :infoList="infoList"
-            :series="series"
-            v-if="infoList && series.length !== 0"
-          ></echarts-from>
-        </Card>
-      </Col>
-      <Col :xl="8" :lg="12" :md="24" :sm="24" :xs="24">
-        <Card :bordered="false" dis-hover class="dashboard-console-visit">
-          <div slot="title">
-            <Avatar icon="ios-analytics" size="small" style="color: #1890ff; background-color: #e6f7ff" />
-            <span class="ivu-pl-8">购买用户统计</span>
-          </div>
-          <echarts-from ref="visitChart" :infoList="infoList" :echartsTitle="circle"></echarts-from>
-        </Card>
-      </Col>
-    </Row>
-  </div>
+	<div @resize="handleResize">
+		<Row :gutter="24">
+			<Col :xl="16" :lg="12" :md="24" :sm="24" :xs="24" class="ivu-mb dashboard-console-visit">
+			<Card :bordered="false" dis-hover>
+				<div slot="title">
+					<Avatar icon="ios-pulse" size="small" style="color: #1890ff; background-color: #e6f7ff" />
+					<span class="ivu-pl-8">用户</span>
+				</div>
+				<echarts-from ref="userChart" :echartsTitle="line" :infoList="infoList" :series="series"
+					v-if="infoList && series.length !== 0"></echarts-from>
+			</Card>
+			</Col>
+			<Col :xl="8" :lg="12" :md="24" :sm="24" :xs="24">
+			<Card :bordered="false" dis-hover class="dashboard-console-visit">
+				<div slot="title">
+					<Avatar icon="ios-analytics" size="small" style="color: #1890ff; background-color: #e6f7ff" />
+					<span class="ivu-pl-8">购买用户统计</span>
+				</div>
+				<echarts-from ref="visitChart" :infoList="infoList" :echartsTitle="circle"></echarts-from>
+			</Card>
+			</Col>
+		</Row>
+	</div>
 </template>
 
 <script>
-import { userApi, rankApi } from '@/api/index';
-import echartsFrom from '@/components/echarts/index';
-export default {
-  name: 'user-chart',
-  components: { echartsFrom },
-  data() {
-    return {
-      line: 'line',
-      circle: 'circle',
-      infoList: {},
-      series: [],
-      xData: [],
-      y1Data: [],
-      y2Data: [],
-      lists: [],
-      bing_data: [],
-      bing_xdata: [],
-    };
-  },
-  methods: {
-    // 统计
-    getStatistics() {
-      userApi()
-        .then(async (res) => {
-          this.infoList = res.data;
-          this.series = [
-            {
-              data: res.data.series,
-              name: '人数(人)',
-              type: 'line',
-              tooltip: true,
-              smooth: true,
-              symbol: 'none',
-              areaStyle: {
-                normal: {
-                  opacity: 0.2,
-                },
-              },
-            },
-          ];
-          this.bing_data = res.bing_data;
-          this.bing_xdata = res.bing_xdata;
-        })
-        .catch((res) => {
-          this.$Message.error(res.msg);
-        });
-    },
-    getRank() {
-      rankApi()
-        .then(async (res) => {
-          let data = res.data;
-          this.lists = data.list;
-        })
-        .catch((res) => {
-          this.$Message.error(res.msg);
-        });
-    },
-    // 监听页面宽度变化,刷新表格
-    handleResize() {
-      if (this.infoList && this.series.length !== 0) this.$refs.userChart.handleResize();
-      if (this.infoList) this.$refs.visitChart.handleResize();
-    },
-  },
-  mounted() {
-    this.getStatistics();
-    this.getRank();
-  },
-  beforeDestroy() {
-    if (this.visitChart) {
-      this.visitChart.dispose();
-      this.visitChart = null;
-    }
-  },
-};
+	import {
+		userApi,
+		rankApi
+	} from '@/api/index';
+	import echartsFrom from '@/components/echarts/index';
+	export default {
+		name: 'user-chart',
+		components: {
+			echartsFrom
+		},
+		data() {
+			return {
+				line: 'line',
+				circle: 'circle',
+				infoList: {},
+				series: [],
+				xData: [],
+				y1Data: [],
+				y2Data: [],
+				lists: [],
+				bing_data: [],
+				bing_xdata: [],
+			};
+		},
+		methods: {
+			// 统计
+			getStatistics() {
+				userApi()
+					.then(async (res) => {
+						this.infoList = res.data;
+						this.series = [{
+							data: res.data.series,
+							name: '人数(人)',
+							type: 'line',
+							tooltip: true,
+							smooth: true,
+							symbol: 'none',
+							areaStyle: {
+								normal: {
+									opacity: 0.2,
+								},
+							},
+						}, ];
+						this.bing_data = res.bing_data;
+						this.bing_xdata = res.bing_xdata;
+					})
+					.catch((res) => {
+						this.$Message.error(res.msg);
+					});
+			},
+			getRank() {
+				rankApi()
+					.then(async (res) => {
+						let data = res.data;
+						this.lists = data.list;
+					})
+					.catch((res) => {
+						this.$Message.error(res.msg);
+					});
+			},
+			// 监听页面宽度变化,刷新表格
+			handleResize() {
+				if (this.infoList && this.series.length !== 0) this.$refs.userChart.handleResize();
+				if (this.infoList) this.$refs.visitChart.handleResize();
+			},
+		},
+		mounted() {
+			this.getStatistics();
+			// this.getRank();
+		},
+		beforeDestroy() {
+			if (this.visitChart) {
+				this.visitChart.dispose();
+				this.visitChart = null;
+			}
+		},
+	};
 </script>
 
 <style scoped lang="less">
-.dashboard-console-visit {
-  ul {
-    li {
-      list-style-type: none;
-      margin-top: 12px;
-    }
-  }
-}
-.trees-coadd {
-  width: 100%;
-  height: 100%;
-  .scollhide {
-    width: 100%;
-    height: 100%;
-    overflow-x: hidden;
-    overflow-y: scroll;
-  }
-}
-.scollhide::-webkit-scrollbar {
-  display: none;
-}
-.names {
-  display: inline-block;
-  text-overflow: ellipsis;
-  overflow: hidden;
-  white-space: nowrap;
-  width: 84%;
-  margin-bottom: -7px;
-}
-</style>
+	.dashboard-console-visit {
+		ul {
+			li {
+				list-style-type: none;
+				margin-top: 12px;
+			}
+		}
+	}
+
+	.trees-coadd {
+		width: 100%;
+		height: 100%;
+
+		.scollhide {
+			width: 100%;
+			height: 100%;
+			overflow-x: hidden;
+			overflow-y: scroll;
+		}
+	}
+
+	.scollhide::-webkit-scrollbar {
+		display: none;
+	}
+
+	.names {
+		display: inline-block;
+		text-overflow: ellipsis;
+		overflow: hidden;
+		white-space: nowrap;
+		width: 84%;
+		margin-bottom: -7px;
+	}
+</style>

File diff suppressed because it is too large
+ 573 - 775
src/pages/product/productAdd/index.vue


+ 860 - 916
src/pages/product/productList/index.vue

@@ -1,953 +1,897 @@
 <template>
-  <div class="article-manager">
-    <Card :bordered="false" dis-hover class="ivu-mt">
-      <Tabs class="mb20" v-model="artFrom.type" @on-click="onClickTab">
-        <TabPane
-          :label="item.name + '(' + item.count + ')'"
-          :name="item.type.toString()"
-          v-for="(item, index) in headeNum"
-          :key="index"
-        />
-      </Tabs>
-      <Form ref="artFrom" :model="artFrom" :label-width="75" label-position="right" @submit.native.prevent>
-        <Row type="flex" :gutter="24">
-          <Col v-bind="grid">
-            <FormItem label="商品分类:" label-for="pid">
-              <!-- <Select v-model="artFrom.cate_id" placeholder="请选择商品分类" clearable @on-change="userSearchs">
+	<div class="article-manager">
+		<Card :bordered="false" dis-hover class="ivu-mt">
+			<Tabs class="mb20" v-model="artFrom.type" @on-click="onClickTab">
+				<TabPane :label="item.name + '(' + item.count + ')'" :name="item.type.toString()"
+					v-for="(item, index) in headeNum" :key="index" />
+			</Tabs>
+			<Form ref="artFrom" :model="artFrom" :label-width="75" label-position="right" @submit.native.prevent>
+				<Row type="flex" :gutter="24">
+					<Col v-bind="grid">
+					<FormItem label="商品分类:" label-for="pid">
+						<!-- <Select v-model="artFrom.cate_id" placeholder="请选择商品分类" clearable @on-change="userSearchs">
                 <Option v-for="item in treeSelect" :value="item.id" :key="item.id">{{
                   item.html + item.cate_name
                 }}</Option>
               </Select> -->
-              <el-cascader
-                v-model="artFrom.cate_id"
-                size="small"
-                :options="treeSelect"
-                :props="{ emitPath: false }"
-                clearable
-              ></el-cascader>
-            </FormItem>
-          </Col>
-          <Col v-bind="grid">
-            <FormItem label="商品搜索:" label-for="store_name">
-              <Input
-                search
-                enter-button
-                placeholder="请输入商品名称/关键字/ID"
-                v-model="artFrom.store_name"
-                @on-search="userSearchs"
-              />
-            </FormItem>
-          </Col>
-        </Row>
-      </Form>
-      <div class="Button">
-        <router-link v-auth="['product-product-save']" :to="$routeProStr + '/product/add_product'"
-          ><Button type="primary" class="bnt mr15" icon="md-add">添加商品</Button></router-link
-        >
-        <Button v-auth="['product-crawl-save']" type="success" class="bnt mr15" @click="onCopy">商品采集</Button>
-        <Dropdown class="bnt mr15" @on-click="batchSelect" :transfer="true">
-          <Button type="info">
-            批量修改
-            <Icon type="ios-arrow-down"></Icon>
-          </Button>
-          <DropdownMenu slot="list">
-            <DropdownItem :name="1">商品分类</DropdownItem>
-            <DropdownItem :name="2">物流设置</DropdownItem>
-            <DropdownItem :name="3">购买送积分</DropdownItem>
-            <DropdownItem :name="4">购买送优惠券</DropdownItem>
-            <DropdownItem :name="5">关联用户标签</DropdownItem>
-            <DropdownItem :name="6">活动推荐</DropdownItem>
-          </DropdownMenu>
-        </Dropdown>
-        <Button
-          v-auth="['product-product-product_show']"
-          class="bnt mr15"
-          type="info"
-          @click="onDismount"
-          v-show="artFrom.type === '1'"
-          >批量下架</Button
-        >
-        <Button
-          v-auth="['product-product-product_show']"
-          class="bnt mr15"
-          @click="onShelves"
-          v-show="artFrom.type === '2'"
-          >批量上架</Button
-        >
-        <Button v-auth="['export-storeProduct']" class="export" icon="ios-share-outline" @click="exports">导出</Button>
-      </div>
-      <Table
-        ref="table"
-        :columns="artFrom.type !== '1' && artFrom.type !== '2' ? columns2 : columns"
-        :data="tableList"
-        class="ivu-mt mt25"
-        :loading="loading"
-        highlight-row
-        @on-select="handleSelectRow"
-        @on-select-cancel="handleCancelRow"
-        @on-select-all="handleSelectAll"
-        @on-select-all-cancel="handleSelectAll"
-        no-data-text="暂无数据"
-        no-filtered-data-text="暂无筛选结果"
-      >
-        <template slot-scope="{ row }" slot="id">
-          {{ row.id }}
-        </template>
-        <template slot-scope="{ row }" slot="image">
-          <div class="tabBox_img" v-viewer>
-            <img v-lazy="row.image" />
-          </div>
-        </template>
-        <template slot-scope="{ row, index }" slot="state">
-          <i-switch
-            v-model="row.is_show"
-            :value="row.is_show"
-            :true-value="1"
-            :false-value="0"
-            @on-change="changeSwitch(row)"
-            size="large"
-          >
-            <span slot="open">上架</span>
-            <span slot="close">下架</span>
-          </i-switch>
-        </template>
-        <template slot-scope="{ row, index }" slot="action">
-          <a @click="look(row)">查看</a>
-          <Divider type="vertical" />
-          <a @click="edit(row)">编辑</a>
-          <Divider type="vertical" />
-          <router-link :to="{ path: $routeProStr + '/product/product_reply/' + row.id }"><a>查看评论</a></router-link>
-          <Divider type="vertical" />
-          <a @click="del(row, '恢复商品', index)" v-if="artFrom.type === '6'">恢复商品</a>
-          <a @click="del(row, '移入回收站', index)" v-else>移到回收站</a>
-        </template>
-      </Table>
-      <div class="acea-row row-right page">
-        <Page
-          :total="total"
-          :current="artFrom.page"
-          show-elevator
-          show-total
-          @on-change="pageChange"
-          :page-size="artFrom.limit"
-        />
-      </div>
-      <attribute :attrTemplate="attrTemplate" v-on:changeTemplate="changeTemplate"></attribute>
-    </Card>
-    <!-- 生成淘宝京东表单-->
-    <Modal
-      v-model="modals"
-      class="Box"
-      scrollable
-      footer-hide
-      closable
-      title="复制淘宝、天猫、京东、苏宁、1688"
-      :mask-closable="false"
-      width="1200"
-      height="500"
-    >
-      <tao-bao ref="taobaos" v-if="modals" @on-close="onClose"></tao-bao>
-    </Modal>
-    <Modal
-      v-model="batchModal"
-      class="batch-box"
-      scrollable
-      :closable="false"
-      title="批量设置"
-      :mask-closable="false"
-      width="1000"
-      @on-ok="batchSub"
-      @on-cancel="clearBatchData"
-    >
-      <Form
-        class="batchFormData"
-        ref="batchFormData"
-        :rules="ruleBatch"
-        :model="batchFormData"
-        :label-width="120"
-        label-position="right"
-        @submit.native.prevent
-      >
-        <Row :gutter="24" type="flex">
-          <Col span="24" v-if="batchType == 1">
-            <Divider orientation="left">基础设置</Divider>
-            <FormItem label="商品分类:" prop="cate_id">
-              <!-- <Select v-model="batchFormData.cate_id" placeholder="请选择商品分类" multiple class="perW20">
+						<el-cascader v-model="artFrom.cate_id" size="small" :options="treeSelect"
+							:props="{ emitPath: false }" clearable></el-cascader>
+					</FormItem>
+					</Col>
+					<Col v-bind="grid">
+					<FormItem label="商品搜索:" label-for="store_name">
+						<Input search enter-button placeholder="请输入商品名称/关键字/ID" v-model="artFrom.store_name"
+							@on-search="userSearchs" />
+					</FormItem>
+					</Col>
+				</Row>
+			</Form>
+			<div class="Button">
+				<router-link v-auth="['product-product-save']" :to="$routeProStr + '/product/add_product'"><Button
+						type="primary" class="bnt mr15" icon="md-add">添加商品</Button></router-link>
+				<Button v-auth="['product-crawl-save']" type="success" class="bnt mr15" @click="onCopy">商品采集</Button>
+				<Dropdown class="bnt mr15" @on-click="batchSelect" :transfer="true">
+					<Button type="info">
+						批量修改
+						<Icon type="ios-arrow-down"></Icon>
+					</Button>
+					<DropdownMenu slot="list">
+						<DropdownItem :name="1">商品分类</DropdownItem>
+						<DropdownItem :name="2">物流设置</DropdownItem>
+						<DropdownItem :name="3">购买送积分</DropdownItem>
+						<DropdownItem :name="4">购买送优惠券</DropdownItem>
+						<DropdownItem :name="5">关联用户标签</DropdownItem>
+						<DropdownItem :name="6">活动推荐</DropdownItem>
+					</DropdownMenu>
+				</Dropdown>
+				<Button v-auth="['product-product-product_show']" class="bnt mr15" type="info" @click="onDismount"
+					v-show="artFrom.type === '1'">批量下架</Button>
+				<Button v-auth="['product-product-product_show']" class="bnt mr15" @click="onShelves"
+					v-show="artFrom.type === '2'">批量上架</Button>
+				<Button v-auth="['export-storeProduct']" class="export" icon="ios-share-outline"
+					@click="exports">导出</Button>
+			</div>
+			<Table ref="table" :columns="artFrom.type !== '1' && artFrom.type !== '2' ? columns2 : columns"
+				:data="tableList" class="ivu-mt mt25" :loading="loading" highlight-row @on-select="handleSelectRow"
+				@on-select-cancel="handleCancelRow" @on-select-all="handleSelectAll"
+				@on-select-all-cancel="handleSelectAll" no-data-text="暂无数据" no-filtered-data-text="暂无筛选结果">
+				<template slot-scope="{ row }" slot="id">
+					{{ row.id }}
+				</template>
+				<template slot-scope="{ row }" slot="image">
+					<div class="tabBox_img" v-viewer>
+						<img v-lazy="row.image" />
+					</div>
+				</template>
+				<template slot-scope="{ row, index }" slot="state">
+					<i-switch v-model="row.is_show" :value="row.is_show" :true-value="1" :false-value="0"
+						@on-change="changeSwitch(row)" size="large">
+						<span slot="open">上架</span>
+						<span slot="close">下架</span>
+					</i-switch>
+				</template>
+				<template slot-scope="{ row, index }" slot="action">
+					<a @click="look(row)">查看</a>
+					<Divider type="vertical" />
+					<a @click="edit(row)">编辑</a>
+					<Divider type="vertical" />
+					<router-link
+						:to="{ path: $routeProStr + '/product/product_reply/' + row.id }"><a>查看评论</a></router-link>
+					<Divider type="vertical" />
+					<a @click="del(row, '恢复商品', index)" v-if="artFrom.type === '6'">恢复商品</a>
+					<a @click="del(row, '移入回收站', index)" v-else>移到回收站</a>
+				</template>
+			</Table>
+			<div class="acea-row row-right page">
+				<Page :total="total" :current="artFrom.page" show-elevator show-total @on-change="pageChange"
+					:page-size="artFrom.limit" />
+			</div>
+			<attribute :attrTemplate="attrTemplate" v-on:changeTemplate="changeTemplate"></attribute>
+		</Card>
+		<!-- 生成淘宝京东表单-->
+		<Modal v-model="modals" class="Box" scrollable footer-hide closable title="复制淘宝、天猫、京东、苏宁、1688"
+			:mask-closable="false" width="1200" height="500">
+			<tao-bao ref="taobaos" v-if="modals" @on-close="onClose"></tao-bao>
+		</Modal>
+		<Modal v-model="batchModal" class="batch-box" scrollable :closable="false" title="批量设置" :mask-closable="false"
+			width="1000" @on-ok="batchSub" @on-cancel="clearBatchData">
+			<Form class="batchFormData" ref="batchFormData" :rules="ruleBatch" :model="batchFormData" :label-width="120"
+				label-position="right" @submit.native.prevent>
+				<Row :gutter="24" type="flex">
+					<Col span="24" v-if="batchType == 1">
+					<Divider orientation="left">基础设置</Divider>
+					<FormItem label="商品分类:" prop="cate_id">
+						<!-- <Select v-model="batchFormData.cate_id" placeholder="请选择商品分类" multiple class="perW20">
                 <Option v-for="item in treeSelect" :disabled="item.pid === 0" :value="item.id" :key="item.id">{{
                   item.html + item.cate_name
                 }}</Option>
               </Select> -->
-              <el-cascader
-                v-model="batchFormData.cate_id"
-                size="small"
-                :options="treeSelect"
-                :props="{ emitPath: false }"
-                clearable
-              ></el-cascader>
-            </FormItem>
-          </Col>
-          <Col span="24" v-if="batchType == 2">
-            <Divider orientation="left">物流设置</Divider>
-            <FormItem label="物流方式:" prop="logistics">
-              <CheckboxGroup v-model="batchFormData.logistics" @on-change="logisticsBtn">
-                <Checkbox label="1">快递</Checkbox>
+						<el-cascader v-model="batchFormData.cate_id" size="small" :options="treeSelect"
+							:props="{ emitPath: false }" clearable></el-cascader>
+					</FormItem>
+					</Col>
+					<Col span="24" v-if="batchType == 2">
+					<Divider orientation="left">物流设置</Divider>
+					<FormItem label="物流方式:" prop="logistics">
+						<CheckboxGroup v-model="batchFormData.logistics" @on-change="logisticsBtn">
+							<Checkbox label="1">快递</Checkbox>
 
-                <Checkbox label="2">到店核销</Checkbox>
-              </CheckboxGroup>
-            </FormItem>
-            <FormItem label="运费设置:">
-              <RadioGroup v-model="batchFormData.freight">
-                <!-- <Radio :label="1">包邮</Radio> -->
-                <Radio :label="2">固定邮费</Radio>
-                <Radio :label="3">运费模板</Radio>
-              </RadioGroup>
-            </FormItem>
-            <FormItem label="" v-if="batchFormData.freight == 2">
-              <div class="acea-row">
-                <InputNumber :min="0" v-model="batchFormData.postage" placeholder="请输入金额" class="perW20 maxW" />
-              </div>
-            </FormItem>
-            <FormItem label="" v-if="batchFormData.freight == 3" prop="temp_id">
-              <div class="acea-row">
-                <Select v-model="batchFormData.temp_id" clearable placeholder="请选择运费模板" class="perW20 maxW">
-                  <Option v-for="(item, index) in templateList" :value="item.id" :key="index">{{ item.name }}</Option>
-                </Select>
-              </div>
-            </FormItem>
-          </Col>
-          <Col span="24" v-if="[3, 4, 5, 6].includes(batchType)">
-            <Divider orientation="left" v-if="[3, 4, 5, 6].includes(batchType)">营销设置</Divider>
-            <FormItem label="赠送积分:" prop="give_integral" v-if="batchType == 3">
-              <InputNumber v-model="batchFormData.give_integral" :min="0" :max="999999" placeholder="请输入积分" />
-            </FormItem>
-            <FormItem label="赠送优惠券:" v-if="batchType == 4">
-              <div v-if="couponName.length" class="mb20">
-                <Tag closable v-for="(item, index) in couponName" :key="index" @on-close="handleClose(item)">{{
+							<Checkbox label="2">到店核销</Checkbox>
+						</CheckboxGroup>
+					</FormItem>
+					<FormItem label="运费设置:">
+						<RadioGroup v-model="batchFormData.freight">
+							<!-- <Radio :label="1">包邮</Radio> -->
+							<Radio :label="2">固定邮费</Radio>
+							<Radio :label="3">运费模板</Radio>
+						</RadioGroup>
+					</FormItem>
+					<FormItem label="" v-if="batchFormData.freight == 2">
+						<div class="acea-row">
+							<InputNumber :min="0" v-model="batchFormData.postage" placeholder="请输入金额"
+								class="perW20 maxW" />
+						</div>
+					</FormItem>
+					<FormItem label="" v-if="batchFormData.freight == 3" prop="temp_id">
+						<div class="acea-row">
+							<Select v-model="batchFormData.temp_id" clearable placeholder="请选择运费模板" class="perW20 maxW">
+								<Option v-for="(item, index) in templateList" :value="item.id" :key="index">
+									{{ item.name }}</Option>
+							</Select>
+						</div>
+					</FormItem>
+					</Col>
+					<Col span="24" v-if="[3, 4, 5, 6].includes(batchType)">
+					<Divider orientation="left" v-if="[3, 4, 5, 6].includes(batchType)">营销设置</Divider>
+					<FormItem label="赠送积分:" prop="give_integral" v-if="batchType == 3">
+						<InputNumber v-model="batchFormData.give_integral" :min="0" :max="999999" placeholder="请输入积分" />
+					</FormItem>
+					<FormItem label="赠送优惠券:" v-if="batchType == 4">
+						<div v-if="couponName.length" class="mb20">
+							<Tag closable v-for="(item, index) in couponName" :key="index"
+								@on-close="handleClose(item)">{{
                   item.title
                 }}</Tag>
-              </div>
-              <Button type="primary" @click="addCoupon">添加优惠券</Button>
-            </FormItem>
-            <FormItem label="关联用户标签:" prop="label_id" v-if="batchType == 5">
-              <div style="display: flex">
-                <div class="labelInput acea-row row-between-wrapper" @click="openLabel">
-                  <div style="width: 90%">
-                    <div v-if="dataLabel.length">
-                      <Tag closable v-for="(item, index) in dataLabel" @on-close="closeLabel(item)" :key="index">{{
+						</div>
+						<Button type="primary" @click="addCoupon">添加优惠券</Button>
+					</FormItem>
+					<FormItem label="关联用户标签:" prop="label_id" v-if="batchType == 5">
+						<div style="display: flex">
+							<div class="labelInput acea-row row-between-wrapper" @click="openLabel">
+								<div style="width: 90%">
+									<div v-if="dataLabel.length">
+										<Tag closable v-for="(item, index) in dataLabel" @on-close="closeLabel(item)"
+											:key="index">{{
                         item.label_name
                       }}</Tag>
-                    </div>
-                    <span class="span" v-else>选择用户关联标签</span>
-                  </div>
-                  <div class="iconfont iconxiayi"></div>
-                </div>
-              </div>
-            </FormItem>
-            <FormItem label="商品推荐:" v-if="batchType == 6">
-              <CheckboxGroup v-model="batchFormData.recommend">
-                <Checkbox label="is_hot">热卖单品</Checkbox>
-                <Checkbox label="is_benefit">促销单品</Checkbox>
-                <Checkbox label="is_best">精品推荐</Checkbox>
-                <Checkbox label="is_new">首发新品</Checkbox>
-                <Checkbox label="is_good">优品推荐</Checkbox>
-              </CheckboxGroup>
-            </FormItem>
-          </Col>
-        </Row>
-      </Form>
-    </Modal>
-    <!-- 用户标签 -->
-    <Modal
-      v-model="labelShow"
-      scrollable
-      title="请选择用户标签"
-      :closable="false"
-      width="500"
-      :footer-hide="true"
-      :mask-closable="false"
-    >
-      <userLabel ref="userLabel" @activeData="activeData" @close="labelClose"></userLabel>
-    </Modal>
-    <!-- 商品弹窗 -->
-    <div v-if="isProductBox">
-      <div class="bg" @click="isProductBox = false"></div>
-      <goodsDetail :goodsId="goodsId"></goodsDetail>
-    </div>
-    <coupon-list ref="couponTemplates" @nameId="nameId" :couponids="batchFormData.coupon_ids"></coupon-list>
-  </div>
+									</div>
+									<span class="span" v-else>选择用户关联标签</span>
+								</div>
+								<div class="iconfont iconxiayi"></div>
+							</div>
+						</div>
+					</FormItem>
+					<FormItem label="商品推荐:" v-if="batchType == 6">
+						<CheckboxGroup v-model="batchFormData.recommend">
+							<Checkbox label="is_hot">热卖单品</Checkbox>
+							<Checkbox label="is_benefit">促销单品</Checkbox>
+							<Checkbox label="is_best">精品推荐</Checkbox>
+							<Checkbox label="is_new">首发新品</Checkbox>
+							<Checkbox label="is_good">优品推荐</Checkbox>
+						</CheckboxGroup>
+					</FormItem>
+					</Col>
+				</Row>
+			</Form>
+		</Modal>
+		<!-- 用户标签 -->
+		<Modal v-model="labelShow" scrollable title="请选择用户标签" :closable="false" width="500" :footer-hide="true"
+			:mask-closable="false">
+			<userLabel ref="userLabel" @activeData="activeData" @close="labelClose"></userLabel>
+		</Modal>
+		<!-- 商品弹窗 -->
+		<div v-if="isProductBox">
+			<div class="bg" @click="isProductBox = false"></div>
+			<goodsDetail :goodsId="goodsId"></goodsDetail>
+		</div>
+		<coupon-list ref="couponTemplates" @nameId="nameId" :couponids="batchFormData.coupon_ids"></coupon-list>
+	</div>
 </template>
 
 <script>
-import expandRow from './tableExpand.vue';
-import attribute from './attribute';
-import toExcel from '../../../utils/Excel.js';
-import { mapState } from 'vuex';
-import taoBao from './taoBao';
-import goodsDetail from './components/goodsDetail.vue';
-import couponList from '@/components/couponList';
-import { exportProductList } from '@/api/export';
+	import expandRow from './tableExpand.vue';
+	import attribute from './attribute';
+	import toExcel from '../../../utils/Excel.js';
+	import {
+		mapState
+	} from 'vuex';
+	import taoBao from './taoBao';
+	import goodsDetail from './components/goodsDetail.vue';
+	import couponList from '@/components/couponList';
+	import {
+		exportProductList
+	} from '@/api/export';
 
-import {
-  getGoodHeade,
-  getGoods,
-  PostgoodsIsShow,
-  cascaderListApi, // 分类列表
-  productShowApi,
-  productUnshowApi,
-  storeProductApi,
-  batchSetting,
-  productGetTemplateApi,
-} from '@/api/product';
-import userLabel from '@/components/labelList';
+	import {
+		getGoodHeade,
+		getGoods,
+		PostgoodsIsShow,
+		cascaderListApi, // 分类列表
+		productShowApi,
+		productUnshowApi,
+		storeProductApi,
+		batchSetting,
+		productGetTemplateApi,
+	} from '@/api/product';
+	import userLabel from '@/components/labelList';
 
-export default {
-  name: 'product_productList',
-  components: { expandRow, attribute, taoBao, goodsDetail, userLabel, couponList },
-  computed: {
-    ...mapState('userLevel', ['categoryId']),
-  },
-  data() {
-    return {
-      template: false,
-      modals: false,
-      batchModal: false,
-      labelShow: false,
-      batchType: 1, // 批量设置类型
-      batchFormData: {
-        cate_id: [],
-        logistics: [],
-        freight: 2,
-        postage: 0,
-        temp_id: null,
-        give_integral: 0,
-        label_id: [],
-        coupon_ids: [],
-        recommend: [],
-      },
-      ruleBatch: {},
-      couponName: [], // 优惠券
-      dataLabel: [], // 标签
-      templateList: [], // 运费模版
-      grid: {
-        xl: 6,
-        lg: 8,
-        md: 12,
-        sm: 24,
-        xs: 24,
-      },
-      artFrom: {
-        page: 1,
-        limit: 15,
-        cate_id: '',
-        type: '1',
-        store_name: '',
-      },
-      list: [],
-      tableList: [],
-      headeNum: [],
-      treeSelect: [],
-      loading: false,
-      columns: [
-        {
-          type: 'expand',
-          width: 50,
-          render: (h, params) => {
-            return h(expandRow, {
-              props: {
-                row: params.row,
-              },
-            });
-          },
-        },
-        {
-          type: 'selection',
-          width: 60,
-          align: 'center',
-        },
-        {
-          title: '商品ID',
-          key: 'id',
-          width: 80,
-        },
-        {
-          title: '商品图',
-          slot: 'image',
-          minWidth: 80,
-        },
-        {
-          title: '商品名称',
-          key: 'store_name',
-          minWidth: 250,
-        },
-        {
-          title: '商品类型',
-          key: 'product_type',
-          minWidth: 100,
-        },
-        {
-          title: '商品售价',
-          key: 'price',
-          minWidth: 90,
-        },
-        {
-          title: '销量',
-          key: 'sales',
-          minWidth: 90,
-        },
-        {
-          title: '库存',
-          key: 'stock',
-          minWidth: 80,
-        },
-        {
-          title: '排序',
-          key: 'sort',
-          minWidth: 70,
-        },
-        {
-          title: '状态',
-          slot: 'state',
-          width: 100,
-          filters: [
-            {
-              label: '上架',
-              value: 1,
-            },
-            {
-              label: '下架',
-              value: 0,
-            },
-          ],
-          filterMethod(value, row) {
-            return row.is_show === value;
-          },
-          filterMultiple: false,
-        },
-        {
-          title: '操作',
-          slot: 'action',
-          fixed: 'right',
-          minWidth: 220,
-        },
-      ],
-      data: [],
-      total: 0,
-      attrTemplate: false,
-      selectedIds: new Set(), //选中合并项的id
-      ids: [],
-      goodsId: '',
-      isProductBox: false,
-      treeSelect: [],
-    };
-  },
-  watch: {
-    $route() {
-      if (this.$route.fullPath === this.$routeProStr + '/product/product_list?type=5') {
-        this.getPath();
-      }
-    },
-  },
-  created() {},
-  activated() {
-    this.goodHeade();
-    this.goodsCategory();
-    if (this.$route.fullPath === this.$routeProStr + '/product/product_list?type=5') {
-      this.getPath();
-    } else {
-      this.getDataList();
-    }
-  },
-  methods: {
-    batchSub() {
-      let data = this.batchFormData;
-      data.ids = this.ids;
-      data.type = this.batchType;
-      let activeIds = [];
-      this.dataLabel.forEach((item) => {
-        activeIds.push(item.id);
-      });
-      data.label_id = activeIds;
-      batchSetting(data)
-        .then((res) => {
-          this.$Message.success(res.msg);
-          this.getDataList();
-          this.clearBatchData(false);
-          this.ids = [];
-          this.clearAll(false);
-        })
-        .catch((err) => {
-          this.$Message.error(err.msg);
-        });
-    },
-    clearBatchData(status) {
-      if (!status) {
-        this.batchFormData = {
-          cate_id: [],
-          logistics: [],
-          freight: 0,
-          postage: null,
-          temp_id: null,
-          give_integral: null,
-          label_id: [],
-          coupon_ids: [],
-          recommend: [],
-        };
-        this.dataLabel = [];
-      }
-    },
-    // 批量设置商品
-    batchSelect(type) {
-      if (!this.ids.length) {
-        this.$Message.warning('请选择要修改的商品');
-      } else {
-        this.batchType = type;
-        this.batchModal = true;
-        this.productGetTemplate();
-      }
-    },
-    activeData(dataLabel) {
-      this.labelShow = false;
-      this.dataLabel = dataLabel;
-    },
-    nameId(id, names) {
-      this.batchFormData.coupon_ids = id;
-      this.couponName = this.unique(names);
-    },
-    handleClose(name) {
-      let index = this.couponName.indexOf(name);
-      this.couponName.splice(index, 1);
-      this.formValidate.coupon_ids.splice(index, 1);
-    },
-    //对象数组去重;
-    unique(arr) {
-      const res = new Map();
-      return arr.filter((arr) => !res.has(arr.id) && res.set(arr.id, 1));
-    },
-    // 获取运费模板;
-    productGetTemplate() {
-      productGetTemplateApi().then((res) => {
-        this.templateList = res.data;
-      });
-    },
-    // 标签弹窗关闭
-    labelClose() {
-      this.labelShow = false;
-    },
-    look(row) {
-      this.goodsId = row.id;
-      this.isProductBox = true;
-    },
-    // 物流方式
-    logisticsBtn(e) {
-      this.batchFormData.logistics = e;
-    },
-    // 关联用户标签
-    openLabel(row) {
-      this.labelShow = true;
-      this.$refs.userLabel.userLabel(JSON.parse(JSON.stringify(this.dataLabel)));
-    },
-    closeLabel(label) {
-      let index = this.dataLabel.indexOf(this.dataLabel.filter((d) => d.id == label.id)[0]);
-      this.dataLabel.splice(index, 1);
-    },
-    // 添加优惠券
-    addCoupon() {
-      this.$refs.couponTemplates.isTemplate = true;
-      this.$refs.couponTemplates.tableList();
-    },
-    getPath() {
-      this.columns2 = [...this.columns];
-      if (name !== '1' && name !== '2') {
-        this.columns2.shift({
-          type: 'selection',
-          width: 60,
-          align: 'center',
-        });
-      }
-      this.artFrom.page = 1;
-      this.artFrom.type = this.$route.query.type.toString();
-      this.getDataList();
-    },
-    // 导出
-    async exports() {
-      let [th, filekey, data, fileName] = [[], [], [], ''];
-      let excelData = JSON.parse(JSON.stringify(this.artFrom));
-      excelData.page = 1;
-      excelData.limit = 50;
-      excelData.ids = this.ids;
-      for (let i = 0; i < excelData.page + 1; i++) {
-        let lebData = await this.getExcelData(excelData);
-        if (!fileName) fileName = lebData.filename;
-        if (!filekey.length) {
-          filekey = lebData.fileKey;
-        }
-        if (!th.length) th = lebData.header;
-        if (lebData.export.length) {
-          data = data.concat(lebData.export);
-          excelData.page++;
-        } else {
-          this.$exportExcel(th, filekey, fileName, data);
-          return;
-        }
-      }
-    },
-    getExcelData(excelData) {
-      return new Promise((resolve, reject) => {
-        exportProductList(excelData).then((res) => {
-          resolve(res.data);
-        });
-      });
-    },
-    changeTemplate(e) {
-      // this.template = e;
-    },
-    freight() {
-      this.$refs.template.isTemplate = true;
-    },
-    // 批量上架
-    onShelves() {
-      if (this.ids.length === 0) {
-        this.$Message.warning('请选择要上架的商品');
-      } else {
-        let data = {
-          ids: this.ids,
-        };
-        productShowApi(data)
-          .then((res) => {
-            this.$Message.success(res.msg);
-            this.goodHeade();
-            this.getDataList();
-          })
-          .catch((res) => {
-            this.$Message.error(res.msg);
-          });
-      }
-    },
-    // 批量下架
-    onDismount() {
-      if (this.ids.length === 0) {
-        this.$Message.warning('请选择要下架的商品');
-      } else {
-        let data = {
-          ids: this.ids,
-        };
-        productUnshowApi(data)
-          .then((res) => {
-            this.$Message.success(res.msg);
-            this.artFrom.page = 1;
-            this.goodHeade();
-            this.getDataList();
-          })
-          .catch((res) => {
-            this.$Message.error(res.msg);
-          });
-      }
-    },
+	export default {
+		name: 'product_productList',
+		components: {
+			expandRow,
+			attribute,
+			taoBao,
+			goodsDetail,
+			userLabel,
+			couponList
+		},
+		computed: {
+			...mapState('userLevel', ['categoryId']),
+		},
+		data() {
+			return {
+				template: false,
+				modals: false,
+				batchModal: false,
+				labelShow: false,
+				batchType: 1, // 批量设置类型
+				batchFormData: {
+					cate_id: [],
+					logistics: [],
+					freight: 2,
+					postage: 0,
+					temp_id: null,
+					give_integral: 0,
+					label_id: [],
+					coupon_ids: [],
+					recommend: [],
+				},
+				ruleBatch: {},
+				couponName: [], // 优惠券
+				dataLabel: [], // 标签
+				templateList: [], // 运费模版
+				grid: {
+					xl: 6,
+					lg: 8,
+					md: 12,
+					sm: 24,
+					xs: 24,
+				},
+				artFrom: {
+					page: 1,
+					limit: 15,
+					cate_id: '',
+					type: '1',
+					store_name: '',
+				},
+				list: [],
+				tableList: [],
+				headeNum: [],
+				treeSelect: [],
+				loading: false,
+				columns: [{
+						type: 'expand',
+						width: 50,
+						render: (h, params) => {
+							return h(expandRow, {
+								props: {
+									row: params.row,
+								},
+							});
+						},
+					},
+					{
+						type: 'selection',
+						width: 60,
+						align: 'center',
+					},
+					{
+						title: '商品ID',
+						key: 'id',
+						width: 80,
+					},
+					{
+						title: '商品图',
+						slot: 'image',
+						minWidth: 80,
+					},
+					{
+						title: '商品名称',
+						key: 'store_name',
+						minWidth: 250,
+					},
+					{
+						title: '商品类型',
+						key: 'product_type',
+						minWidth: 100,
+					},
+					{
+						title: '商品售价',
+						key: 'price',
+						minWidth: 90,
+					},
+					{
+						title: '销量',
+						key: 'sales',
+						minWidth: 90,
+					},
+					{
+						title: '库存',
+						key: 'stock',
+						minWidth: 80,
+					},
+					{
+						title: '排序',
+						key: 'sort',
+						minWidth: 70,
+					},
+					{
+						title: '状态',
+						slot: 'state',
+						width: 100,
+						filters: [{
+								label: '上架',
+								value: 1,
+							},
+							{
+								label: '下架',
+								value: 0,
+							},
+						],
+						filterMethod(value, row) {
+							return row.is_show === value;
+						},
+						filterMultiple: false,
+					},
+					{
+						title: '操作',
+						slot: 'action',
+						fixed: 'right',
+						minWidth: 220,
+					},
+				],
+				data: [],
+				total: 0,
+				attrTemplate: false,
+				selectedIds: new Set(), //选中合并项的id
+				ids: [],
+				goodsId: '',
+				isProductBox: false,
+				treeSelect: [],
+			};
+		},
+		watch: {
+			$route() {
+				if (this.$route.fullPath === this.$routeProStr + '/product/product_list?type=5') {
+					this.getPath();
+				}
+			},
+		},
+		created() {},
+		activated() {
+			this.goodHeade();
+			this.goodsCategory();
+			if (this.$route.fullPath === this.$routeProStr + '/product/product_list?type=5') {
+				this.getPath();
+			} else {
+				this.getDataList();
+			}
+		},
+		methods: {
+			batchSub() {
+				let data = this.batchFormData;
+				data.ids = this.ids;
+				data.type = this.batchType;
+				let activeIds = [];
+				this.dataLabel.forEach((item) => {
+					activeIds.push(item.id);
+				});
+				data.label_id = activeIds;
+				batchSetting(data)
+					.then((res) => {
+						this.$Message.success(res.msg);
+						this.getDataList();
+						this.clearBatchData(false);
+						this.ids = [];
+						this.clearAll(false);
+					})
+					.catch((err) => {
+						this.$Message.error(err.msg);
+					});
+			},
+			clearBatchData(status) {
+				if (!status) {
+					this.batchFormData = {
+						cate_id: [],
+						logistics: [],
+						freight: 0,
+						postage: null,
+						temp_id: null,
+						give_integral: null,
+						label_id: [],
+						coupon_ids: [],
+						recommend: [],
+					};
+					this.dataLabel = [];
+				}
+			},
+			// 批量设置商品
+			batchSelect(type) {
+				if (!this.ids.length) {
+					this.$Message.warning('请选择要修改的商品');
+				} else {
+					this.batchType = type;
+					this.batchModal = true;
+					this.productGetTemplate();
+				}
+			},
+			activeData(dataLabel) {
+				this.labelShow = false;
+				this.dataLabel = dataLabel;
+			},
+			nameId(id, names) {
+				this.batchFormData.coupon_ids = id;
+				this.couponName = this.unique(names);
+			},
+			handleClose(name) {
+				let index = this.couponName.indexOf(name);
+				this.couponName.splice(index, 1);
+				this.formValidate.coupon_ids.splice(index, 1);
+			},
+			//对象数组去重;
+			unique(arr) {
+				const res = new Map();
+				return arr.filter((arr) => !res.has(arr.id) && res.set(arr.id, 1));
+			},
+			// 获取运费模板;
+			productGetTemplate() {
+				productGetTemplateApi().then((res) => {
+					this.templateList = res.data;
+				});
+			},
+			// 标签弹窗关闭
+			labelClose() {
+				this.labelShow = false;
+			},
+			look(row) {
+				this.goodsId = row.id;
+				this.isProductBox = true;
+			},
+			// 物流方式
+			logisticsBtn(e) {
+				this.batchFormData.logistics = e;
+			},
+			// 关联用户标签
+			openLabel(row) {
+				this.labelShow = true;
+				this.$refs.userLabel.userLabel(JSON.parse(JSON.stringify(this.dataLabel)));
+			},
+			closeLabel(label) {
+				let index = this.dataLabel.indexOf(this.dataLabel.filter((d) => d.id == label.id)[0]);
+				this.dataLabel.splice(index, 1);
+			},
+			// 添加优惠券
+			addCoupon() {
+				this.$refs.couponTemplates.isTemplate = true;
+				this.$refs.couponTemplates.tableList();
+			},
+			getPath() {
+				this.columns2 = [...this.columns];
+				if (name !== '1' && name !== '2') {
+					this.columns2.shift({
+						type: 'selection',
+						width: 60,
+						align: 'center',
+					});
+				}
+				this.artFrom.page = 1;
+				this.artFrom.type = this.$route.query.type.toString();
+				this.getDataList();
+			},
+			// 导出
+			async exports() {
+				let [th, filekey, data, fileName] = [
+					[],
+					[],
+					[], ''
+				];
+				let excelData = JSON.parse(JSON.stringify(this.artFrom));
+				excelData.page = 1;
+				excelData.limit = 50;
+				excelData.ids = this.ids;
+				for (let i = 0; i < excelData.page + 1; i++) {
+					let lebData = await this.getExcelData(excelData);
+					if (!fileName) fileName = lebData.filename;
+					if (!filekey.length) {
+						filekey = lebData.fileKey;
+					}
+					if (!th.length) th = lebData.header;
+					if (lebData.export.length) {
+						data = data.concat(lebData.export);
+						excelData.page++;
+					} else {
+						this.$exportExcel(th, filekey, fileName, data);
+						return;
+					}
+				}
+			},
+			getExcelData(excelData) {
+				return new Promise((resolve, reject) => {
+					exportProductList(excelData).then((res) => {
+						resolve(res.data);
+					});
+				});
+			},
+			changeTemplate(e) {
+				// this.template = e;
+			},
+			freight() {
+				this.$refs.template.isTemplate = true;
+			},
+			// 批量上架
+			onShelves() {
+				if (this.ids.length === 0) {
+					this.$Message.warning('请选择要上架的商品');
+				} else {
+					let data = {
+						ids: this.ids,
+					};
+					productShowApi(data)
+						.then((res) => {
+							this.$Message.success(res.msg);
+							this.goodHeade();
+							this.getDataList();
+						})
+						.catch((res) => {
+							this.$Message.error(res.msg);
+						});
+				}
+			},
+			// 批量下架
+			onDismount() {
+				if (this.ids.length === 0) {
+					this.$Message.warning('请选择要下架的商品');
+				} else {
+					let data = {
+						ids: this.ids,
+					};
+					productUnshowApi(data)
+						.then((res) => {
+							this.$Message.success(res.msg);
+							this.artFrom.page = 1;
+							this.goodHeade();
+							this.getDataList();
+						})
+						.catch((res) => {
+							this.$Message.error(res.msg);
+						});
+				}
+			},
 
-    // 全选
-    // onSelectTab (selection) {
-    //     let data = []
-    //     selection.map((item) => {
-    //         data.push(item.id)
-    //     })
-    //     this.ids = data
-    // },
-    //全选和取消全选时触发
-    handleSelectAll(selection) {
-      if (selection.length === 0) {
-        //获取table的数据;
-        let data = this.$refs.table.data;
-        data.forEach((item) => {
-          if (this.selectedIds.has(item.id)) {
-            this.selectedIds.delete(item.id);
-          }
-        });
-      } else {
-        selection.forEach((item) => {
-          this.selectedIds.add(item.id);
-        });
-      }
-      this.$nextTick(() => {
-        //确保dom加载完毕
-        this.setChecked();
-      });
-    },
-    //  选中某一行
-    handleSelectRow(selection, row) {
-      this.selectedIds.add(row.id);
-      this.$nextTick(() => {
-        //确保dom加载完毕
-        this.setChecked();
-      });
-    },
-    clearAll(status) {
-      this.$refs.table.selectAll(status);
-    },
-    //  取消某一行
-    handleCancelRow(selection, row) {
-      this.selectedIds.delete(row.id);
-      this.$nextTick(() => {
-        //确保dom加载完毕
-        this.setChecked();
-      });
-    },
-    setChecked() {
-      //将new Set()转化为数组
-      this.ids = [...this.selectedIds];
-      // 找到绑定的table的ref对应的dom,找到table的objData对象,objData保存的是当前页的数据
-      let objData = this.$refs.table.objData;
-      for (let index in objData) {
-        if (this.selectedIds.has(objData[index].id)) {
-          objData[index]._isChecked = true;
-        }
-      }
-    },
-    // 添加淘宝商品成功
-    onClose() {
-      this.modals = false;
-    },
-    // 复制淘宝
-    onCopy() {
-      this.$router.push({
-        path: this.$routeProStr + '/product/add_product',
-        query: { type: -1 },
-      });
-      // this.modals = true
-    },
-    // tab选择
-    onClickTab(name) {
-      this.artFrom.type = name;
-      this.columns2 = [...this.columns];
-      if (name !== '1' && name !== '2') {
-        this.columns2.shift({
-          type: 'selection',
-          width: 60,
-          align: 'center',
-        });
-      }
-      this.artFrom.page = 1;
-      this.selectedIds.clear();
-      this.getDataList();
-    },
-    // 下拉树
-    handleCheckChange(data) {
-      let value = '';
-      let title = '';
-      this.list = [];
-      this.artFrom.cate_id = 0;
-      data.forEach((item, index) => {
-        value += `${item.id},`;
-        title += `${item.title},`;
-      });
-      value = value.substring(0, value.length - 1);
-      title = title.substring(0, title.length - 1);
-      this.list.push({
-        value,
-        title,
-      });
-      this.artFrom.cate_id = value;
-      this.getDataList();
-    },
-    // 获取商品表单头数量
-    goodHeade() {
-      getGoodHeade()
-        .then((res) => {
-          this.headeNum = res.data.list;
-        })
-        .catch((res) => {
-          this.$Message.error(res.msg);
-        });
-    },
-    // 商品分类;
-    goodsCategory() {
-      cascaderListApi(1)
-        .then((res) => {
-          this.treeSelect = res.data;
-        })
-        .catch((res) => {
-          this.$Message.error(res.msg);
-        });
-    },
-    // 商品列表;
-    getDataList() {
-      this.loading = true;
-      this.artFrom.cate_id = this.artFrom.cate_id || '';
-      getGoods(this.artFrom)
-        .then((res) => {
-          let data = res.data;
-          this.tableList = data.list;
-          this.total = res.data.count;
-          this.$nextTick(() => {
-            //确保dom加载完毕
-            this.setChecked();
-          });
-          this.loading = false;
-        })
-        .catch((res) => {
-          this.loading = false;
-          this.$Message.error(res.msg);
-        });
-    },
-    pageChange(status) {
-      this.artFrom.page = status;
-      this.getDataList();
-    },
-    // 表格搜索
-    userSearchs() {
-      this.artFrom.page = 1;
-      this.getDataList();
-    },
-    // 上下架
-    changeSwitch(row) {
-      PostgoodsIsShow(row.id, row.is_show)
-        .then((res) => {
-          this.$Message.success(res.msg);
-          this.goodHeade();
-          this.getDataList();
-        })
-        .catch((res) => {
-          row.is_show = !row.is_show ? 1 : 0;
-          this.$Message.error(res.msg);
-        });
-    },
-    // 数据导出;
-    exportData: function () {
-      let th = ['商品名称', '商品简介', '商品分类', '价格', '库存', '销量', '收藏人数'];
-      let filterVal = ['store_name', 'store_info', 'cate_name', 'price', 'stock', 'sales', 'collect'];
-      this.where.page = 'nopage';
-      getGoods(this.where).then((res) => {
-        let data = res.data.map((v) => filterVal.map((k) => v[k]));
-        let fileTime = Date.parse(new Date());
-        let [fileName, fileType, sheetName] = ['商户数据_' + fileTime, 'xlsx', '商户数据'];
-        toExcel({ th, data, fileName, fileType, sheetName });
-      });
-    },
-    // 属性弹出;
-    attrTap() {
-      this.attrTemplate = true;
-    },
-    changeTemplate(msg) {
-      this.attrTemplate = msg;
-    },
-    // 编辑
-    edit(row) {
-      this.$router.push({ path: this.$routeProStr + '/product/add_product/' + row.id });
-    },
-    // 确认
-    del(row, tit, num) {
-      let delfromData = {
-        title: tit,
-        num: num,
-        url: `product/product/${row.id}`,
-        method: 'DELETE',
-        ids: '',
-        un: 1,
-      };
-      this.$modalSure(delfromData)
-        .then((res) => {
-          this.$Message.success(res.msg);
-          this.tableList.splice(num, 1);
-          this.goodHeade();
-        })
-        .catch((res) => {
-          this.$Message.error(res.msg);
-        });
-    },
-    // 删除成功
-    // submitModel () {
-    //     this.tableList.splice(this.delfromData.num, 1);
-    //     this.goodHeade();
-    // }
-  },
-};
+			// 全选
+			// onSelectTab (selection) {
+			//     let data = []
+			//     selection.map((item) => {
+			//         data.push(item.id)
+			//     })
+			//     this.ids = data
+			// },
+			//全选和取消全选时触发
+			handleSelectAll(selection) {
+				if (selection.length === 0) {
+					//获取table的数据;
+					let data = this.$refs.table.data;
+					data.forEach((item) => {
+						if (this.selectedIds.has(item.id)) {
+							this.selectedIds.delete(item.id);
+						}
+					});
+				} else {
+					selection.forEach((item) => {
+						this.selectedIds.add(item.id);
+					});
+				}
+				this.$nextTick(() => {
+					//确保dom加载完毕
+					this.setChecked();
+				});
+			},
+			//  选中某一行
+			handleSelectRow(selection, row) {
+				this.selectedIds.add(row.id);
+				this.$nextTick(() => {
+					//确保dom加载完毕
+					this.setChecked();
+				});
+			},
+			clearAll(status) {
+				this.$refs.table.selectAll(status);
+			},
+			//  取消某一行
+			handleCancelRow(selection, row) {
+				this.selectedIds.delete(row.id);
+				this.$nextTick(() => {
+					//确保dom加载完毕
+					this.setChecked();
+				});
+			},
+			setChecked() {
+				//将new Set()转化为数组
+				this.ids = [...this.selectedIds];
+				// 找到绑定的table的ref对应的dom,找到table的objData对象,objData保存的是当前页的数据
+				let objData = this.$refs.table.objData;
+				for (let index in objData) {
+					if (this.selectedIds.has(objData[index].id)) {
+						objData[index]._isChecked = true;
+					}
+				}
+			},
+			// 添加淘宝商品成功
+			onClose() {
+				this.modals = false;
+			},
+			// 复制淘宝
+			onCopy() {
+				this.$router.push({
+					path: this.$routeProStr + '/product/add_product',
+					query: {
+						type: -1
+					},
+				});
+				// this.modals = true
+			},
+			// tab选择
+			onClickTab(name) {
+				this.artFrom.type = name;
+				this.columns2 = [...this.columns];
+				if (name !== '1' && name !== '2') {
+					this.columns2.shift({
+						type: 'selection',
+						width: 60,
+						align: 'center',
+					});
+				}
+				this.artFrom.page = 1;
+				this.selectedIds.clear();
+				this.getDataList();
+			},
+			// 下拉树
+			handleCheckChange(data) {
+				let value = '';
+				let title = '';
+				this.list = [];
+				this.artFrom.cate_id = 0;
+				data.forEach((item, index) => {
+					value += `${item.id},`;
+					title += `${item.title},`;
+				});
+				value = value.substring(0, value.length - 1);
+				title = title.substring(0, title.length - 1);
+				this.list.push({
+					value,
+					title,
+				});
+				this.artFrom.cate_id = value;
+				this.getDataList();
+			},
+			// 获取商品表单头数量
+			goodHeade() {
+				getGoodHeade()
+					.then((res) => {
+						this.headeNum = res.data.list;
+					})
+					.catch((res) => {
+						this.$Message.error(res.msg);
+					});
+			},
+			// 商品分类;
+			goodsCategory() {
+				cascaderListApi(1)
+					.then((res) => {
+						this.treeSelect = res.data;
+					})
+					.catch((res) => {
+						this.$Message.error(res.msg);
+					});
+			},
+			// 商品列表;
+			getDataList() {
+				this.loading = true;
+				this.artFrom.cate_id = this.artFrom.cate_id || '';
+				getGoods(this.artFrom)
+					.then((res) => {
+						let data = res.data;
+						this.tableList = data.list;
+						this.total = res.data.count;
+						this.$nextTick(() => {
+							//确保dom加载完毕
+							this.setChecked();
+						});
+						this.loading = false;
+					})
+					.catch((res) => {
+						this.loading = false;
+						this.$Message.error(res.msg);
+					});
+			},
+			pageChange(status) {
+				this.artFrom.page = status;
+				this.getDataList();
+			},
+			// 表格搜索
+			userSearchs() {
+				this.artFrom.page = 1;
+				this.getDataList();
+			},
+			// 上下架
+			changeSwitch(row) {
+				PostgoodsIsShow(row.id, row.is_show)
+					.then((res) => {
+						this.$Message.success(res.msg);
+						this.goodHeade();
+						this.getDataList();
+					})
+					.catch((res) => {
+						row.is_show = !row.is_show ? 1 : 0;
+						this.$Message.error(res.msg);
+					});
+			},
+			// 数据导出;
+			exportData: function() {
+				let th = ['商品名称', '商品简介', '商品分类', '价格', '库存', '销量', '收藏人数'];
+				let filterVal = ['store_name', 'store_info', 'cate_name', 'price', 'stock', 'sales', 'collect'];
+				this.where.page = 'nopage';
+				getGoods(this.where).then((res) => {
+					let data = res.data.map((v) => filterVal.map((k) => v[k]));
+					let fileTime = Date.parse(new Date());
+					let [fileName, fileType, sheetName] = ['商户数据_' + fileTime, 'xlsx', '商户数据'];
+					toExcel({
+						th,
+						data,
+						fileName,
+						fileType,
+						sheetName
+					});
+				});
+			},
+			// 属性弹出;
+			attrTap() {
+				this.attrTemplate = true;
+			},
+			changeTemplate(msg) {
+				this.attrTemplate = msg;
+			},
+			// 编辑
+			edit(row) {
+				this.$router.push({
+					path: this.$routeProStr + '/product/add_product/' + row.id
+				});
+			},
+			// 确认
+			del(row, tit, num) {
+				let delfromData = {
+					title: tit,
+					num: num,
+					url: `product/product/${row.id}`,
+					method: 'DELETE',
+					ids: '',
+					un: 1,
+				};
+				this.$modalSure(delfromData)
+					.then((res) => {
+						this.$Message.success(res.msg);
+						this.tableList.splice(num, 1);
+						this.goodHeade();
+					})
+					.catch((res) => {
+						this.$Message.error(res.msg);
+					});
+			},
+			// 删除成功
+			// submitModel () {
+			//     this.tableList.splice(this.delfromData.num, 1);
+			//     this.goodHeade();
+			// }
+		},
+	};
 </script>
 <style scoped lang="stylus">
-/deep/.ivu-modal-mask {
-  z-index: 999 !important;
-}
+	/deep/.ivu-modal-mask {
+		z-index: 999 !important;
+	}
 
-/deep/.ivu-modal-wrap {
-  z-index: 999 !important;
-}
+	/deep/.ivu-modal-wrap {
+		z-index: 999 !important;
+	}
 
-.Box {
-  >>> .ivu-modal-body {
-    height: 700px;
-    overflow: auto;
-  }
-}
+	.Box {
+		>>>.ivu-modal-body {
+			height: 700px;
+			overflow: auto;
+		}
+	}
 
-.batch-box {
-  >>> .ivu-modal-body {
-    overflow: auto;
-    min-height: 350px;
-  }
-}
+	.batch-box {
+		>>>.ivu-modal-body {
+			overflow: auto;
+			min-height: 350px;
+		}
+	}
 
-.tabBox_img {
-  width: 36px;
-  height: 36px;
-  border-radius: 4px;
-  cursor: pointer;
+	.tabBox_img {
+		width: 36px;
+		height: 36px;
+		border-radius: 4px;
+		cursor: pointer;
 
-  img {
-    width: 100%;
-    height: 100%;
-  }
-}
+		img {
+			width: 100%;
+			height: 100%;
+		}
+	}
 
-.bg {
-  position: fixed;
-  left: 0;
-  top: 0;
-  width: 100%;
-  height: 100%;
-  background: rgba(0, 0, 0, 0.5);
-  z-index: 11;
-}
+	.bg {
+		position: fixed;
+		left: 0;
+		top: 0;
+		width: 100%;
+		height: 100%;
+		background: rgba(0, 0, 0, 0.5);
+		z-index: 11;
+	}
 
-/deep/.happy-scroll-content {
-  width: 100%;
+	/deep/.happy-scroll-content {
+		width: 100%;
 
-  .demo-spin-icon-load {
-    animation: ani-demo-spin 1s linear infinite;
-  }
+		.demo-spin-icon-load {
+			animation: ani-demo-spin 1s linear infinite;
+		}
 
-  @keyframes ani-demo-spin {
-    from {
-      transform: rotate(0deg);
-    }
+		@keyframes ani-demo-spin {
+			from {
+				transform: rotate(0deg);
+			}
 
-    50% {
-      transform: rotate(180deg);
-    }
+			50% {
+				transform: rotate(180deg);
+			}
 
-    to {
-      transform: rotate(360deg);
-    }
-  }
+			to {
+				transform: rotate(360deg);
+			}
+		}
 
-  .demo-spin-col {
-    height: 100px;
-    position: relative;
-    border: 1px solid #eee;
-  }
-}
+		.demo-spin-col {
+			height: 100px;
+			position: relative;
+			border: 1px solid #eee;
+		}
+	}
 
-.labelInput {
-  border: 1px solid #dcdee2;
-  width: 20%;
-  padding: 0 5px;
-  border-radius: 5px;
-  min-height: 30px;
-  cursor: pointer;
+	.labelInput {
+		border: 1px solid #dcdee2;
+		width: 20%;
+		padding: 0 5px;
+		border-radius: 5px;
+		min-height: 30px;
+		cursor: pointer;
 
-  .span {
-    color: #c5c8ce;
-  }
+		.span {
+			color: #c5c8ce;
+		}
 
-  .iconxiayi {
-    font-size: 12px;
-  }
-}
-</style>
+		.iconxiayi {
+			font-size: 12px;
+		}
+	}
+</style>

+ 376 - 400
src/pages/setting/systemRole/index.vue

@@ -1,406 +1,382 @@
 <template>
-  <div>
-    <Card :bordered="false" dis-hover class="ivu-mt">
-      <Form
-        ref="formValidate"
-        :model="formValidate"
-        :label-width="labelWidth"
-        :label-position="labelPosition"
-        @submit.native.prevent
-      >
-        <Row type="flex" :gutter="24">
-          <Col v-bind="grid">
-            <FormItem label="状态:" label-for="status">
-              <Select v-model="formValidate.status" placeholder="请选择" @on-change="userSearchs" clearable>
-                <Option value="1">显示</Option>
-                <Option value="0">不显示</Option>
-              </Select>
-            </FormItem>
-          </Col>
-          <Col v-bind="grid">
-            <FormItem label="身份昵称:" label-for="role_name">
-              <Input
-                search
-                enter-button
-                placeholder="请输入身份昵称"
-                v-model="formValidate.role_name"
-                @on-search="userSearchs"
-              />
-            </FormItem>
-          </Col>
-        </Row>
-        <Row type="flex">
-          <Col v-bind="grid">
-            <Button v-auth="['setting-system_role-add']" type="primary" icon="md-add" @click="add('添加')"
-              >添加身份</Button
-            >
-          </Col>
-        </Row>
-      </Form>
-      <Table
-        :columns="columns1"
-        :data="tableList"
-        ref="table"
-        class="mt25"
-        :loading="loading"
-        highlight-row
-        no-userFrom-text="暂无数据"
-        no-filtered-userFrom-text="暂无筛选结果"
-      >
-        <template slot-scope="{ row, index }" slot="is_shows">
-          <i-switch
-            v-model="row.status"
-            :value="row.status"
-            :true-value="1"
-            :false-value="0"
-            @on-change="onchangeIsShow(row)"
-            size="large"
-          >
-            <span slot="open">显示</span>
-            <span slot="close">隐藏</span>
-          </i-switch>
-        </template>
-        <template slot-scope="{ row, index }" slot="action">
-          <a @click="edit(row, '编辑')">编辑</a>
-          <Divider type="vertical" />
-          <a @click="del(row, '删除', index)">删除</a>
-        </template>
-      </Table>
-      <div class="acea-row row-right page">
-        <Page
-          :total="total"
-          :current="formValidate.page"
-          show-elevator
-          show-total
-          @on-change="pageChange"
-          :page-size="formValidate.limit"
-        />
-      </div>
-    </Card>
-    <!-- 新增编辑-->
-    <Modal
-      v-model="modals"
-      @on-cancel="onCancel"
-      scrollable
-      footer-hide
-      closable
-      :title="`${modelTit}身份`"
-      :mask-closable="false"
-      width="600"
-    >
-      <Form
-        ref="formInline"
-        :model="formInline"
-        :rules="ruleValidate"
-        :label-width="100"
-        :label-position="labelPosition2"
-        @submit.native.prevent
-      >
-        <FormItem label="身份名称:" label-for="role_name" prop="role_name">
-          <Input placeholder="请输入身份昵称" v-model="formInline.role_name" />
-        </FormItem>
-        <FormItem label="是否开启:" prop="status">
-          <RadioGroup v-model="formInline.status">
-            <Radio :label="1">开启</Radio>
-            <Radio :label="0">关闭</Radio>
-          </RadioGroup>
-        </FormItem>
-        <FormItem label="权限:">
-          <div class="trees-coadd">
-            <div class="scollhide">
-              <div class="iconlist">
-                <Tree :data="menusList" show-checkbox ref="tree"></Tree>
-              </div>
-            </div>
-          </div>
-        </FormItem>
-        <Spin size="large" fix v-if="spinShow"></Spin>
-        <Button type="primary" size="large" long @click="handleSubmit('formInline')">提交</Button>
-      </Form>
-    </Modal>
-  </div>
+	<div>
+		<Card :bordered="false" dis-hover class="ivu-mt">
+			<Form ref="formValidate" :model="formValidate" :label-width="labelWidth" :label-position="labelPosition"
+				@submit.native.prevent>
+				<Row type="flex" :gutter="24">
+					<Col v-bind="grid">
+					<FormItem label="状态:" label-for="status">
+						<Select v-model="formValidate.status" placeholder="请选择" @on-change="userSearchs" clearable>
+							<Option value="1">显示</Option>
+							<Option value="0">不显示</Option>
+						</Select>
+					</FormItem>
+					</Col>
+					<Col v-bind="grid">
+					<FormItem label="身份昵称:" label-for="role_name">
+						<Input search enter-button placeholder="请输入身份昵称" v-model="formValidate.role_name"
+							@on-search="userSearchs" />
+					</FormItem>
+					</Col>
+				</Row>
+				<Row type="flex">
+					<Col v-bind="grid">
+					<Button v-auth="['setting-system_role-add']" type="primary" icon="md-add"
+						@click="add('添加')">添加身份</Button>
+					</Col>
+				</Row>
+			</Form>
+			<Table :columns="columns1" :data="tableList" ref="table" class="mt25" :loading="loading" highlight-row
+				no-userFrom-text="暂无数据" no-filtered-userFrom-text="暂无筛选结果">
+				<template slot-scope="{ row, index }" slot="is_shows">
+					<i-switch v-model="row.status" :value="row.status" :true-value="1" :false-value="0"
+						@on-change="onchangeIsShow(row)" size="large">
+						<span slot="open">显示</span>
+						<span slot="close">隐藏</span>
+					</i-switch>
+				</template>
+				<template slot-scope="{ row, index }" slot="action">
+					<a @click="edit(row, '编辑')">编辑</a>
+					<Divider type="vertical" />
+					<a @click="del(row, '删除', index)">删除</a>
+				</template>
+			</Table>
+			<div class="acea-row row-right page">
+				<Page :total="total" :current="formValidate.page" show-elevator show-total @on-change="pageChange"
+					:page-size="formValidate.limit" />
+			</div>
+		</Card>
+		<!-- 新增编辑-->
+		<Modal v-model="modals" @on-cancel="onCancel" scrollable footer-hide closable :title="`${modelTit}身份`"
+			:mask-closable="false" width="600">
+			<Form ref="formInline" :model="formInline" :rules="ruleValidate" :label-width="100"
+				:label-position="labelPosition2" @submit.native.prevent>
+				<FormItem label="身份名称:" label-for="role_name" prop="role_name">
+					<Input placeholder="请输入身份昵称" v-model="formInline.role_name" />
+				</FormItem>
+				<FormItem label="是否开启:" prop="status">
+					<RadioGroup v-model="formInline.status">
+						<Radio :label="1">开启</Radio>
+						<Radio :label="0">关闭</Radio>
+					</RadioGroup>
+				</FormItem>
+				<FormItem label="权限:">
+					<div class="trees-coadd">
+						<div class="scollhide">
+							<div class="iconlist">
+								<Tree :data="menusList" show-checkbox ref="tree"></Tree>
+							</div>
+						</div>
+					</div>
+				</FormItem>
+				<Spin size="large" fix v-if="spinShow"></Spin>
+				<Button type="primary" size="large" long @click="handleSubmit('formInline')">提交</Button>
+			</Form>
+		</Modal>
+	</div>
 </template>
 <script>
-import { mapState } from 'vuex';
-import { roleListApi, roleSetStatusApi, menusListApi, roleCreatApi, roleInfoApi } from '@/api/setting';
-export default {
-  name: 'systemrRole',
-  data() {
-    return {
-      spinShow: false,
-      modals: false,
-      total: 0,
-      grid: {
-        xl: 7,
-        lg: 7,
-        md: 12,
-        sm: 24,
-        xs: 24,
-      },
-      loading: false,
-      formValidate: {
-        status: '',
-        role_name: '',
-        page: 1,
-        limit: 20,
-      },
-      columns1: [
-        {
-          title: 'ID',
-          key: 'id',
-          width: 80,
-        },
-        {
-          title: '身份昵称',
-          key: 'role_name',
-          minWidth: 120,
-        },
-        {
-          title: '权限',
-          key: 'rules',
-          tooltip: true,
-          width: 1000,
-        },
-        {
-          title: '状态',
-          slot: 'is_shows',
-          minWidth: 120,
-        },
-        {
-          title: '操作',
-          slot: 'action',
-          fixed: 'right',
-          minWidth: 120,
-        },
-      ],
-      tableList: [],
-      formInline: {
-        role_name: '',
-        status: 0,
-        checked_menus: [],
-        id: 0,
-      },
-      menusList: [],
-      modelTit: '',
-      ruleValidate: {
-        role_name: [{ required: true, message: '请输入身份昵称', trigger: 'blur' }],
-        status: [{ required: true, type: 'number', message: '请选择是否开启', trigger: 'change' }],
-        // checked_menus: [
-        //     { required: true, validator: validateStatus, trigger: 'change' }
-        // ]
-      },
-    };
-  },
-  computed: {
-    ...mapState('media', ['isMobile']),
-    labelWidth() {
-      return this.isMobile ? undefined : 75;
-    },
-    labelPosition() {
-      return this.isMobile ? 'top' : 'left';
-    },
-    labelPosition2() {
-      return this.isMobile ? 'top' : 'right';
-    },
-  },
-  created() {
-    this.getList();
-  },
-  methods: {
-    // 添加
-    add(name) {
-      this.formInline.id = 0;
-      this.modelTit = name;
-      this.modals = true;
-      this.getmenusList();
-    },
-    // 删除
-    del(row, tit, num) {
-      let delfromData = {
-        title: tit,
-        num: num,
-        url: `setting/role/${row.id}`,
-        method: 'DELETE',
-        ids: '',
-      };
-      this.$modalSure(delfromData)
-        .then((res) => {
-          this.$Message.success(res.msg);
-          this.tableList.splice(num, 1);
-        })
-        .catch((res) => {
-          this.$Message.error(res.msg);
-        });
-    },
-    // 修改是否显示
-    onchangeIsShow(row) {
-      let data = {
-        id: row.id,
-        status: row.status,
-      };
-      roleSetStatusApi(data)
-        .then(async (res) => {
-          this.$Message.success(res.msg);
-        })
-        .catch((res) => {
-          this.$Message.error(res.msg);
-        });
-    },
-    // 列表
-    getList() {
-      this.loading = true;
-      this.formValidate.status = this.formValidate.status || '';
-      roleListApi(this.formValidate)
-        .then(async (res) => {
-          let data = res.data;
-          this.tableList = data.list;
-          this.total = res.data.count;
-          this.loading = false;
-        })
-        .catch((res) => {
-          this.loading = false;
-          this.$Message.error(res.msg);
-        });
-    },
-    pageChange(index) {
-      this.formValidate.page = index;
-      this.getList();
-    },
-    // 表格搜索
-    userSearchs() {
-      this.formValidate.page = 1;
-      this.getList();
-    },
-    // 编辑
-    edit(row, name) {
-      this.modelTit = name;
-      this.formInline.id = row.id;
-      this.modals = true;
-      this.rows = row;
-      this.getIofo(row);
-    },
-    // 菜单列表
-    getmenusList() {
-      this.spinShow = true;
-      menusListApi()
-        .then(async (res) => {
-          let data = res.data;
-          this.menusList = data.menus;
-          this.menusList.map((item, index) => {
-            if (item.title === '主页') {
-              // item.checked = true;
-              // item.disableCheckbox = true;
-              if (item.children.length) {
-                item.children.map((v) => {
-                  // v.checked = true;
-                  // v.disableCheckbox = true;
-                });
-              }
-            }
-            item.expand = false;
-          });
-          this.spinShow = false;
-        })
-        .catch((res) => {
-          this.spinShow = false;
-          this.$Message.error(res.msg);
-        });
-    },
-    // 详情
-    getIofo(row) {
-      this.spinShow = true;
-      roleInfoApi(row.id)
-        .then(async (res) => {
-          let data = res.data;
-          this.formInline = data.role || this.formInline;
-          this.formInline.checked_menus = this.formInline.rules;
-          this.tidyRes(data.menus);
-          this.spinShow = false;
-        })
-        .catch((res) => {
-          this.spinShow = false;
-          this.$Message.error(res.msg);
-        });
-    },
-    tidyRes(menus) {
-      let data = [];
-      menus.map((menu) => {
-        if (menu.title === '主页') {
-          menu.checked = true;
-          menu.disableCheckbox = true;
-          if (menu.children.length) {
-            menu.children.map((v) => {
-              v.checked = true;
-              v.disableCheckbox = true;
-            });
-          }
-          data.push(menu);
-        } else {
-          data.push(this.initMenu(menu));
-        }
-      });
-      this.$set(this, 'menusList', data);
-    },
-    initMenu(menu) {
-      let data = {},
-        checkMenus = ',' + this.formInline.checked_menus + ',';
-      data.title = menu.title;
-      data.id = menu.id;
-      if (menu.children && menu.children.length > 0) {
-        data.children = [];
-        menu.children.map((child) => {
-          data.children.push(this.initMenu(child));
-        });
-      } else {
-        data.checked = checkMenus.indexOf(String(',' + data.id + ',')) !== -1;
-        data.expand = !data.checked;
-      }
-      return data;
-    },
-    // 提交
-    handleSubmit(name) {
-      this.$refs[name].validate((valid) => {
-        if (valid) {
-          this.formInline.checked_menus = [];
-          this.$refs.tree.getCheckedAndIndeterminateNodes().map((node) => {
-            this.formInline.checked_menus.push(node.id);
-          });
-          if (this.formInline.checked_menus.length === 0) return this.$Message.warning('请至少选择一个权限');
-          roleCreatApi(this.formInline)
-            .then(async (res) => {
-              this.$Message.success(res.msg);
-              this.modals = false;
-              this.getList();
-              this.$refs[name].resetFields();
-              this.formInline.checked_menus = [];
-            })
-            .catch((res) => {
-              this.$Message.error(res.msg);
-            });
-        } else {
-          return false;
-        }
-      });
-    },
-    onCancel() {
-      this.$refs['formInline'].resetFields();
-      this.formInline.checked_menus = [];
-    },
-  },
-};
+	import {
+		mapState
+	} from 'vuex';
+	import {
+		roleListApi,
+		roleSetStatusApi,
+		menusListApi,
+		roleCreatApi,
+		roleInfoApi
+	} from '@/api/setting';
+	export default {
+		name: 'systemrRole',
+		data() {
+			return {
+				spinShow: false,
+				modals: false,
+				total: 0,
+				grid: {
+					xl: 7,
+					lg: 7,
+					md: 12,
+					sm: 24,
+					xs: 24,
+				},
+				loading: false,
+				formValidate: {
+					status: '',
+					role_name: '',
+					page: 1,
+					limit: 20,
+				},
+				columns1: [{
+						title: 'ID',
+						key: 'id',
+						width: 80,
+					},
+					{
+						title: '身份昵称',
+						key: 'role_name',
+						minWidth: 120,
+					},
+					{
+						title: '权限',
+						key: 'rules',
+						tooltip: true,
+						width: 1000,
+					},
+					{
+						title: '状态',
+						slot: 'is_shows',
+						minWidth: 120,
+					},
+					{
+						title: '操作',
+						slot: 'action',
+						fixed: 'right',
+						minWidth: 120,
+					},
+				],
+				tableList: [],
+				formInline: {
+					role_name: '',
+					status: 0,
+					checked_menus: [],
+					id: 0,
+				},
+				menusList: [],
+				modelTit: '',
+				ruleValidate: {
+					role_name: [{
+						required: true,
+						message: '请输入身份昵称',
+						trigger: 'blur'
+					}],
+					status: [{
+						required: true,
+						type: 'number',
+						message: '请选择是否开启',
+						trigger: 'change'
+					}],
+					// checked_menus: [
+					//     { required: true, validator: validateStatus, trigger: 'change' }
+					// ]
+				},
+			};
+		},
+		computed: {
+			...mapState('media', ['isMobile']),
+			labelWidth() {
+				return this.isMobile ? undefined : 75;
+			},
+			labelPosition() {
+				return this.isMobile ? 'top' : 'left';
+			},
+			labelPosition2() {
+				return this.isMobile ? 'top' : 'right';
+			},
+		},
+		created() {
+			this.getList();
+		},
+		methods: {
+			// 添加
+			add(name) {
+				this.formInline.id = 0;
+				this.modelTit = name;
+				this.modals = true;
+				this.getmenusList();
+			},
+			// 删除
+			del(row, tit, num) {
+				let delfromData = {
+					title: tit,
+					num: num,
+					url: `setting/role/${row.id}`,
+					method: 'DELETE',
+					ids: '',
+				};
+				this.$modalSure(delfromData)
+					.then((res) => {
+						this.$Message.success(res.msg);
+						this.tableList.splice(num, 1);
+					})
+					.catch((res) => {
+						this.$Message.error(res.msg);
+					});
+			},
+			// 修改是否显示
+			onchangeIsShow(row) {
+				let data = {
+					id: row.id,
+					status: row.status,
+				};
+				roleSetStatusApi(data)
+					.then(async (res) => {
+						this.$Message.success(res.msg);
+					})
+					.catch((res) => {
+						this.$Message.error(res.msg);
+					});
+			},
+			// 列表
+			getList() {
+				this.loading = true;
+				this.formValidate.status = this.formValidate.status || '';
+				roleListApi(this.formValidate)
+					.then(async (res) => {
+						let data = res.data;
+						this.tableList = data.list;
+						this.total = res.data.count;
+						this.loading = false;
+					})
+					.catch((res) => {
+						this.loading = false;
+						this.$Message.error(res.msg);
+					});
+			},
+			pageChange(index) {
+				this.formValidate.page = index;
+				this.getList();
+			},
+			// 表格搜索
+			userSearchs() {
+				this.formValidate.page = 1;
+				this.getList();
+			},
+			// 编辑
+			edit(row, name) {
+				this.modelTit = name;
+				this.formInline.id = row.id;
+				this.modals = true;
+				this.rows = row;
+				this.getIofo(row);
+			},
+			// 菜单列表
+			getmenusList() {
+				this.spinShow = true;
+				menusListApi()
+					.then(async (res) => {
+						let data = res.data;
+						this.menusList = data.menus;
+						this.menusList.map((item, index) => {
+							if (item.title === '主页') {
+								// item.checked = true;
+								// item.disableCheckbox = true;
+								if (item.children.length) {
+									item.children.map((v) => {
+										// v.checked = true;
+										// v.disableCheckbox = true;
+									});
+								}
+							}
+							item.expand = false;
+						});
+						this.spinShow = false;
+					})
+					.catch((res) => {
+						this.spinShow = false;
+						this.$Message.error(res.msg);
+					});
+			},
+			// 详情
+			getIofo(row) {
+				this.spinShow = true;
+				roleInfoApi(row.id)
+					.then(async (res) => {
+						let data = res.data;
+						this.formInline = data.role || this.formInline;
+						this.formInline.checked_menus = this.formInline.rules;
+						this.tidyRes(data.menus);
+						this.spinShow = false;
+					})
+					.catch((res) => {
+						this.spinShow = false;
+						this.$Message.error(res.msg);
+					});
+			},
+			tidyRes(menus) {
+				let data = [];
+				menus.map((menu) => {
+					if (menu.title === '主页') {
+						menu.checked = true;
+						menu.disableCheckbox = true;
+						if (menu.children.length) {
+							menu.children.map((v) => {
+								v.checked = true;
+								v.disableCheckbox = true;
+							});
+						}
+						data.push(menu);
+					} else {
+						data.push(this.initMenu(menu));
+					}
+				});
+				console.log(data, 'info');
+				this.$set(this, 'menusList', data);
+			},
+			initMenu(menu) {
+				let data = {},
+					checkMenus = ',' + this.formInline.checked_menus + ',';
+				data.title = menu.title;
+				data.id = menu.id;
+				if (menu.children && menu.children.length > 0) {
+					data.children = [];
+					menu.children.map((child) => {
+						data.children.push(this.initMenu(child));
+					});
+				} else {
+					data.checked = checkMenus.indexOf(String(',' + data.id + ',')) !== -1;
+					data.expand = !data.checked;
+				}
+				return data;
+			},
+			// 提交
+			handleSubmit(name) {
+				this.$refs[name].validate((valid) => {
+					if (valid) {
+						this.formInline.checked_menus = [];
+						this.$refs.tree.getCheckedAndIndeterminateNodes().map((node) => {
+							this.formInline.checked_menus.push(node.id);
+						});
+						if (this.formInline.checked_menus.length === 0) return this.$Message.warning('请至少选择一个权限');
+						roleCreatApi(this.formInline)
+							.then(async (res) => {
+								this.$Message.success(res.msg);
+								this.modals = false;
+								this.getList();
+								this.$refs[name].resetFields();
+								this.formInline.checked_menus = [];
+							})
+							.catch((res) => {
+								this.$Message.error(res.msg);
+							});
+					} else {
+						return false;
+					}
+				});
+			},
+			onCancel() {
+				this.$refs['formInline'].resetFields();
+				this.formInline.checked_menus = [];
+			},
+		},
+	};
 </script>
 
 <style scoped lang="stylus">
-.trees-coadd
-    width: 100%;
-    height: 385px;
-    .scollhide
-        width: 100%;
-        height: 100%;
-        overflow-x: hidden;
-        overflow-y: scroll;
-       // margin-left: 18px;
-.scollhide::-webkit-scrollbar {
-    display: none;
-}
-</style>
+	.trees-coadd {
+		width: 100%;
+		height: 385px;
+	}
+
+	.scollhide {
+		width: 100%;
+		height: 100%;
+		overflow-x: hidden;
+		overflow-y: scroll;
+	}
+
+	// margin-left: 18px;
+	.scollhide::-webkit-scrollbar {
+		display: none;
+	}
+</style>

+ 381 - 0
src/pages/shop/apply.vue

@@ -0,0 +1,381 @@
+<template>
+	<div>
+		<Card :bordered="false" dis-hover class="ivu-mb-16">
+			<Form ref="formValidate" :model="formValidate" :label-width="labelWidth" :label-position="labelPosition"
+				class="tabform" @submit.native.prevent>
+				<Row :gutter="24" type="flex">
+					<Col span="24">
+					<FormItem label="时间选择:">
+						<RadioGroup v-model="formValidate.data" type="button"
+							@on-change="selectChange(formValidate.data)" class="mr">
+							<Radio :label="item.val" v-for="(item, i) in fromList.fromTxt" :key="i">{{ item.text }}
+							</Radio>
+						</RadioGroup>
+						<DatePicker :editable="false" @on-change="onchangeTime" :value="timeVal" format="yyyy/MM/dd"
+							type="daterange" placement="bottom-end" placeholder="请选择时间" style="width: 200px">
+						</DatePicker>
+					</FormItem>
+					</Col>
+					<Col span="24">
+					<FormItem label="搜索:">
+						<div class="acea-row row-middle">
+							<Input search enter-button @on-search="selChange" placeholder="商户名称/客户名称/手机号"
+								element-id="name" v-model="formValidate.nireid" style="width: 30%" />
+						</div>
+					</FormItem>
+					</Col>
+				</Row>
+			</Form>
+		</Card>
+		<Card :bordered="false" dis-hover>
+			<Table ref="table" :columns="columns" :data="tabList" class="ivu-mt" :loading="loading" no-data-text="暂无数据"
+				no-filtered-data-text="暂无筛选结果">
+				<template slot-scope="{ row, index }" slot="image">
+					<div class="tabBox_img" v-viewer>
+						<img v-lazy="row.image" />
+					</div>
+				</template>
+				<template slot-scope="{ row, index }" slot="status">
+					<div class="status" v-if="row.status === 0">
+						<div class="statusVal">申请中</div>
+						<div>
+							<Button type="error" icon="md-close" size="small" class="item"
+								@click="invalid(row)">驳回</Button>
+							<Button type="info" icon="md-checkmark" size="small" class="item"
+								@click="adopt(row, '审核通过', index)">通过</Button>
+						</div>
+					</div>
+					<div class="statusVal" v-if="row.status === 1">审核通过</div>
+					<div class="statusVal" v-if="row.status === 2 &&row.fail_msg">审核未通过<br /> 未通过原因:{{ row.fail_msg }}
+					</div>
+					<div class="statusVal" v-if="row.status === 2 &&!row.fail_msg">审核未通过
+					</div>
+				</template>
+				<template slot-scope="{ row }" slot="createModalFrame">
+					<a href="javascript:void(0);" @click="edit(row)">编辑</a>
+				</template>
+			</Table>
+			<div class="acea-row row-right page">
+				<Page :total="total" :current="formValidate.page" show-elevator show-total @on-change="pageChange"
+					:page-size="formValidate.limit" />
+			</div>
+		</Card>
+
+		<!-- 编辑表单-->
+		<edit-from ref="edits" :FromData="FromData" @submitFail="submitFail"></edit-from>
+		<!-- 拒绝通过-->
+		<Modal v-model="modals" scrollable closable title="未通过原因" :mask-closable="false">
+			<Input v-model="fail_msg.message" type="textarea" :rows="4" placeholder="请输入未通过原因" />
+			<div slot="footer">
+				<Button type="primary" size="large" long :loading="modal_loading" @click="oks">确定</Button>
+			</div>
+		</Modal>
+	</div>
+</template>
+<script>
+	import searchFrom from '@/components/publicSearchFrom';
+	import {
+		mapState
+	} from 'vuex';
+	import {
+		intentionList,
+		adopt,
+		refuse
+	} from '@/api/shop';
+	import {
+		formatDate
+	} from '@/utils/validate';
+	import editFrom from '@/components/from/from';
+	export default {
+		name: 'shopApply',
+		components: {
+			searchFrom,
+			editFrom
+		},
+		filters: {
+			formatDate(time) {
+				if (time !== 0) {
+					let date = new Date(time * 1000);
+					return formatDate(date, 'yyyy-MM-dd hh:mm');
+				}
+			},
+		},
+		data() {
+			return {
+				images: ['1.jpg', '2.jpg'],
+				modal_loading: false,
+				fail_msg: {
+					message: '输入信息不完整或有误!',
+				},
+				modals: false,
+				total: 0,
+				loading: false,
+				columns: [{
+						title: 'ID',
+						key: 'mer_intention_id',
+						width: 80,
+					},
+					{
+						title: '商户名称',
+						key: 'mer_name',
+						minWidth: 180,
+					},
+					{
+						title: '商户分类',
+						key: 'merchant_category_name',
+						minWidth: 90,
+					},
+					{
+						title: '商户类型',
+						key: 'mer_type_name',
+						minWidth: 150,
+					},
+					{
+						title: '商户姓名',
+						key: 'name',
+						minWidth: 150,
+					},
+					{
+						title: '联系方式',
+						key: 'phone',
+						minWidth: 150,
+					},
+					{
+						title: '申请时间',
+						key: 'add_time',
+						minWidth: 100,
+					},
+					// {
+					// 	title: '资质图片',
+					// 	slot: 'add_time',
+					// 	minWidth: 100,
+					// },
+					{
+						title: '审核状态',
+						slot: 'status',
+						minWidth: 180,
+					},
+					// {
+					// 	title: '操作',
+					// 	slot: 'createModalFrame',
+					// 	fixed: 'right',
+					// 	width: 100,
+					// },
+				],
+				tabList: [],
+				fromList: {
+					title: '选择时间',
+					custom: true,
+					fromTxt: [{
+							text: '全部',
+							val: ''
+						},
+						{
+							text: '今天',
+							val: 'today'
+						},
+						{
+							text: '昨天',
+							val: 'yesterday'
+						},
+						{
+							text: '本周',
+							val: 'week'
+						},
+						{
+							text: '本月',
+							val: 'month'
+						},
+						{
+							text: '本季度',
+							val: 'quarter'
+						},
+						{
+							text: '本年',
+							val: 'year'
+						},
+					],
+				},
+				formValidate: {
+					status: '',
+					nireid: '',
+					data: '',
+					page: 1,
+					limit: 20,
+				},
+				timeVal: [],
+				FromData: null,
+				extractId: 0,
+			};
+		},
+		watch: {
+			$route() {
+				if (this.$route.fullPath === this.$routeProStr + '/finance/user_extract/index?status=0') {
+					this.getPath();
+				}
+			},
+		},
+		computed: {
+			...mapState('media', ['isMobile']),
+			labelWidth() {
+				return this.isMobile ? undefined : 80;
+			},
+			labelPosition() {
+				return this.isMobile ? 'top' : 'left';
+			},
+		},
+		mounted() {
+			if (this.$route.fullPath === this.$routeProStr + '/finance/user_extract/index?status=0') {
+				this.getPath();
+			} else {
+				this.getList();
+			}
+		},
+		methods: {
+			getPath() {
+				this.formValidate.page = 1;
+				this.formValidate.status = parseInt(this.$route.query.status);
+				this.getList();
+			},
+			// 无效
+			invalid(row) {
+				this.extractId = row.mer_intention_id;
+				this.modals = true;
+			},
+			// 确定
+			oks() {
+				this.modal_loading = true;
+				console.log(this.fail_msg.message);
+				refuse({
+						fail_msg: this.fail_msg.message
+					}, this.extractId)
+					.then(async (res) => {
+						this.$Message.success(res.msg);
+						this.modal_loading = false;
+						this.modals = false;
+						this.getList();
+					})
+					.catch((res) => {
+						this.$Message.error(res.msg);
+					});
+			},
+			// 通过
+			adopt(row, tit, num) {
+				let delfromData = {
+					title: tit,
+					num: num,
+					url: `merchant/intention/adopt/${row.mer_intention_id}`,
+					method: 'get',
+					ids: '',
+				};
+				this.$modalSure(delfromData)
+					.then((res) => {
+						this.$Message.success(res.msg);
+						this.getList();
+					})
+					.catch((res) => {
+						this.$Message.error(res.msg);
+					});
+			},
+			// 具体日期
+			onchangeTime(e) {
+				this.timeVal = e;
+				this.formValidate.data = this.timeVal.join('-');
+				this.formValidate.page = 1;
+				this.getList();
+			},
+			// 选择时间
+			selectChange(tab) {
+				this.formValidate.page = 1;
+				this.formValidate.data = tab;
+				this.timeVal = [];
+				this.getList();
+			},
+			// 选择
+			selChange() {
+				this.formValidate.page = 1;
+				this.getList();
+			},
+			// 列表
+			getList() {
+				this.loading = true;
+				console.log(this.formValidate);
+				intentionList(this.formValidate)
+					.then(async (res) => {
+						let data = res.data;
+						this.tabList = data.merchantIntention;
+						this.total = data.count;
+						this.loading = false;
+					})
+					.catch((res) => {
+						this.loading = false;
+						this.$Message.error(res.msg);
+					});
+			},
+			pageChange(index) {
+				this.formValidate.page = index;
+				this.getList();
+			},
+			// 编辑
+			edit(row) {
+				cashEditApi(row.id)
+					.then(async (res) => {
+						if (res.data.status === false) {
+							return this.$authLapse(res.data);
+						}
+						this.FromData = res.data;
+						this.$refs.edits.modals = true;
+					})
+					.catch((res) => {
+						this.$Message.error(res.msg);
+					});
+			},
+			// 编辑提交成功
+			submitFail() {
+				this.getList();
+			},
+		},
+	};
+</script>
+<style scoped lang="stylus">
+	.ivu-mt .type .item {
+		margin: 3px 0;
+	}
+
+	.tabform {
+		margin-bottom 10px;
+	}
+
+	.Refresh {
+		font-size 12px color #1890FF cursor pointer;
+	}
+
+	.ivu-form-item {
+		margin-bottom 10px;
+	}
+
+	.status>>>.item~.item {
+		margin-left 6px;
+	}
+
+	.status>>>.statusVal {
+		margin-bottom 7px;
+	}
+
+	/*.ivu-mt >>> .ivu-table-header*/
+	/*    border-top:1px dashed #ddd!important*/
+	.type {
+		padding 3px 0 box-sizing border-box;
+	}
+
+	.tabBox_img {
+		width 36px;
+		height 36px;
+		border-radius: 4px cursor pointer;
+	}
+
+	img {
+		width 100%;
+		height 100%;
+	}
+</style>

+ 198 - 0
src/pages/shop/classify.vue

@@ -0,0 +1,198 @@
+<template>
+	<div class="article-manager">
+		<Card :bordered="false" dis-hover class="ivu-mt">
+			<Form ref="artFrom" :model="artFrom" :label-width="75" label-position="right" @submit.native.prevent>
+				<Row type="flex">
+					<Col v-bind="grid">
+					<Button v-auth="['product-save-cate']" type="primary" class="bnt" icon="md-add"
+						@click="addClass">添加分类</Button>
+					</Col>
+				</Row>
+			</Form>
+			<vxe-table class="mt25" highlight-hover-row :loading="loading" header-row-class-name="false"
+				:tree-config="{ children: 'children' }" :data="tableData">
+				<vxe-table-column field="merchant_category_id" title="ID" tooltip width="80"></vxe-table-column>
+				<vxe-table-column field="category_name" tree-node title="分类名称" min-width="250"></vxe-table-column>
+				<!-- <vxe-table-column field="pic" title="分类图标" min-width="100">
+					<template v-slot="{ row }">
+						<div class="tabBox_img" v-viewer v-if="row.pic">
+							<img v-lazy="row.pic" />
+						</div>
+					</template>
+				</vxe-table-column> -->
+				<!-- <vxe-table-column field="is_show" title="状态" min-width="120">
+					<template v-slot="{ row }">
+						<i-switch v-model="row.is_show" :value="row.is_show" :true-value="1" :false-value="0"
+							@on-change="onchangeIsShow(row)" size="large">
+							<span slot="open">显示</span>
+							<span slot="close">隐藏</span>
+						</i-switch>
+					</template>
+				</vxe-table-column> -->
+				<vxe-table-column field="date" title="操作" width="250" fixed="right" align="center">
+					<template v-slot="{ row, index }">
+						<a @click="edit(row)">编辑</a>
+						<Divider type="vertical" />
+						<a @click="del(row, '删除商户分类', index)">删除</a>
+					</template>
+				</vxe-table-column>
+			</vxe-table>
+			<!--            <div class="acea-row row-right page">-->
+			<!--                <Page :total="total" :current="artFrom.page" show-elevator show-total @on-change="pageChange"-->
+			<!--                      :page-size="artFrom.limit"/>-->
+			<!--            </div>-->
+		</Card>
+		<!-- 添加 编辑表单-->
+		<edit-from ref="edits" :FromData="FromData" @submitFail="userSearchs"></edit-from>
+	</div>
+</template>
+
+<script>
+	import {
+		mapState
+	} from 'vuex';
+	import {
+		lst,
+		addcreate,
+		getedit,
+		editcategory,
+		deletecategory,
+		getCreate
+	} from '@/api/shop';
+	import editFrom from '../../components/from/from';
+	export default {
+		name: 'shop_shopClassify',
+		components: {
+			editFrom,
+		},
+		data() {
+			return {
+				treeSelect: [],
+				FromData: null,
+				grid: {
+					xl: 7,
+					lg: 7,
+					md: 12,
+					sm: 24,
+					xs: 24,
+				},
+				loading: false,
+				artFrom: {
+					page: 1,
+					limit: 15,
+				},
+				total: 0,
+				tableData: [],
+			};
+		},
+		computed: {
+			...mapState('admin/userLevel', ['categoryId']),
+		},
+		mounted() {
+			this.getList();
+		},
+		methods: {
+			// 列表
+			getList() {
+				this.loading = true;
+				lst(this.artFrom)
+					.then(async (res) => {
+						this.tableData = res.data
+						console.log(this.tableData, 'info');
+						this.loading = false;
+					})
+					.catch((res) => {
+						this.loading = false;
+						this.$Message.error(res.msg);
+					});
+			},
+			pageChange(index) {
+				this.artFrom.page = index;
+				this.getList();
+			},
+			// 添加
+			addClass() {
+				this.$modalForm(getCreate()).then(() => this.getList());
+			},
+			// 编辑
+			edit(row) {
+				console.log(row, 'info');
+				this.$modalForm(getedit({}, row.merchant_category_id)).then(() => this.getList());
+			},
+			// 修改状态
+			onchangeIsShow(row) {
+				let data = {
+					id: row.id,
+					is_show: row.is_show,
+				};
+				setShowApi(data)
+					.then(async (res) => {
+						this.$Message.success(res.msg);
+					})
+					.catch((res) => {
+						this.$Message.error(res.msg);
+					});
+			},
+			// 下拉树
+			handleCheckChange(data) {
+				let value = '';
+				let title = '';
+				this.list = [];
+				this.artFrom.pid = 0;
+				data.forEach((item, index) => {
+					value += `${item.id},`;
+					title += `${item.title},`;
+				});
+				value = value.substring(0, value.length - 1);
+				title = title.substring(0, title.length - 1);
+				this.list.push({
+					value,
+					title,
+				});
+				this.artFrom.pid = value;
+				this.getList();
+			},
+			// 删除
+			del(row, tit, num) {
+				let delfromData = {
+					title: tit,
+					num: num,
+					url: `merchant/category/delete/${row.merchant_category_id}`,
+					method: 'get',
+					ids: '',
+				};
+				this.$modalSure(delfromData)
+					.then((res) => {
+						this.$Message.success(res.msg);
+						this.getList();
+					})
+					.catch((res) => {
+						this.$Message.error(res.msg);
+					});
+			},
+			// 表格搜索
+			userSearchs() {
+				this.artFrom.page = 1;
+				this.getList();
+			},
+		},
+	};
+</script>
+<style scoped lang="stylus">
+	.treeSel>>>.ivu-select-dropdown-list {
+		padding: 0 10px !important;
+		box-sizing: border-box;
+	}
+
+	.tabBox_img {
+		width: 36px;
+		height: 36px;
+		border-radius: 4px;
+		cursor: pointer;
+
+		img {
+			width: 100%;
+			height: 100%;
+		}
+	}
+</style>

+ 724 - 0
src/pages/shop/shop.vue

@@ -0,0 +1,724 @@
+<template>
+	<div class="article-manager">
+		<Card :bordered="false" dis-hover class="ivu-mt">
+			<Tabs class="mb20" v-model="artFrom.type" @on-click="onClickTab">
+				<TabPane :label="item.name + '(' + item.count + ')'" :name="item.type.toString()"
+					v-for="(item, index) in headeNum" :key="index" />
+			</Tabs>
+			<Form ref="artFrom" :model="artFrom" :label-width="75" label-position="right" @submit.native.prevent>
+				<Row type="flex" :gutter="24">
+					<Col v-bind="grid">
+					<FormItem label="商户分类:" label-for="merchant_category_id">
+						<!-- <Select v-model="artFrom.cate_id" placeholder="请选择商品分类" clearable @on-change="userSearchs">
+                <Option v-for="item in treeSelect" :value="item.id" :key="item.id">{{
+                  item.html + item.cate_name
+                }}</Option>
+              </Select> -->
+						<el-cascader v-model="artFrom.category_id" size="small" :options="classifySelect"
+							:props="{ emitPath: false,value:'merchant_category_id',label:'category_name' }"
+							clearable></el-cascader>
+					</FormItem>
+					</Col>
+					<Col v-bind="grid">
+					<FormItem label="商户类型:" label-for="mer_type_id">
+						<!-- <Select v-model="artFrom.cate_id" placeholder="请选择商品分类" clearable @on-change="userSearchs">
+					  <Option v-for="item in treeSelect" :value="item.id" :key="item.id">{{
+					    item.html + item.cate_name
+					  }}</Option>
+					</Select> -->
+						<el-cascader v-model="artFrom.type_id" size="small" :options="typeSelect"
+							:props="{ emitPath: false ,value:'mer_type_id',label:'type_name'}" clearable></el-cascader>
+					</FormItem>
+					</Col>
+					<Col v-bind="grid">
+					<FormItem label="商品搜索:" label-for="store_name">
+						<Input search enter-button placeholder="请输入商品名称/关键字/ID" v-model="artFrom.store_name"
+							@on-search="userSearchs" />
+					</FormItem>
+					</Col>
+				</Row>
+			</Form>
+			<div class="Button">
+				<Button type="primary" @click="add('添加')" class="bnt mr15" icon="md-add">添加商户</Button>
+			</div>
+			<Table ref="table" :columns="artFrom.type !== '1' && artFrom.type !== '2' ? columns2 : columns"
+				:data="tableList" class="ivu-mt mt25" :loading="loading" highlight-row no-data-text="暂无数据"
+				no-filtered-data-text="暂无筛选结果">
+				<template slot-scope="{ row }" slot="image">
+					<div class="tabBox_img" v-viewer>
+						<img v-lazy="row.image" />
+					</div>
+				</template>
+				<template slot-scope="{ row, index }" slot="state">
+					<i-switch v-model="row.status" :value="row.status" :true-value="1" :false-value="0"
+						@on-change="changeSwitch(row)" size="large">
+						<span slot="open">开启</span>
+						<span slot="close">禁用</span>
+					</i-switch>
+				</template>
+				<template slot-scope="{ row, index }" slot="product_state">
+					<i-switch v-model="row.mer_state" :value="row.mer_state" :true-value="1" :false-value="0"
+						@on-change="changeProSwitch(row)" size="large">
+						<span slot="open">开启</span>
+						<span slot="close">禁用</span>
+					</i-switch>
+				</template>
+				<template slot-scope="{ row, index }" slot="action">
+					<a @click="onLogo(row)">登录</a>
+					<Divider type="vertical" />
+					<a @click="edit(row)">编辑</a>
+					<Divider type="vertical" />
+					<a @click="openPwd(row)">修改密码</a>
+				</template>
+			</Table>
+			<div class="acea-row row-right page">
+				<Page :total="total" :current="artFrom.page" show-elevator show-total @on-change="pageChange"
+					:page-size="artFrom.limit" />
+			</div>
+		</Card>
+		<!-- 新增编辑-->
+		<Modal v-model="modals" @on-cancel="onCancel" scrollable footer-hide closable :title="`${modelTit}商户`"
+			:mask-closable="false" width="700">
+			<Form ref="formInline" :model="formInline" :rules="ruleValidate" :label-width="150"
+				:label-position="labelPosition2" @submit.native.prevent>
+				<FormItem label="商户名称:" label-for="mer_name" prop="mer_name">
+					<Input placeholder="请输入商户名称" v-model="formInline.mer_name" />
+				</FormItem>
+				<FormItem label="商户分类:" label-for="category_id" prop="category_id">
+					<el-cascader v-model="formInline.category_id" size="small" :options="classifySelect"
+						:props="{ emitPath: false,value:'merchant_category_id',label:'category_name' }"
+						clearable></el-cascader>
+				</FormItem>
+				<FormItem label="商户类型:" label-for="type_id" prop="type_id">
+					<el-cascader v-model="formInline.type_id" size="small" :options="typeSelect"
+						:props="{ emitPath: false ,value:'mer_type_id',label:'type_name'}" clearable></el-cascader>
+				</FormItem>
+				<FormItem label="商户负责人名称:" label-for="real_name" prop="real_name">
+					<Input placeholder="请输入商户负责人名称" v-model="formInline.real_name" />
+				</FormItem>
+				<FormItem label="商户负责人手机号:" label-for="real_name" prop="real_name">
+					<Input placeholder="请输入商户负责人手机号" v-model="formInline.mer_phone" />
+				</FormItem>
+				<FormItem label="商户账号:" label-for="account" prop="account">
+					<Input placeholder="请输入商户账号" v-model="formInline.account" />
+				</FormItem>
+				<FormItem label="商户密码:" label-for="pwd" prop="pwd">
+					<Input type="password" placeholder="请输入商户密码" v-model="formInline.pwd" />
+				</FormItem>
+				<FormItem label="商户地址:" label-for="mer_address" prop="mer_address">
+					<Input placeholder="请输入商户地址" v-model="formInline.mer_address" />
+				</FormItem>
+				<FormItem label="商户关键字:" label-for="mer_keyword" prop="mer_keyword">
+					<Input placeholder="请输入商户关键字" v-model="formInline.mer_keyword" />
+				</FormItem>
+
+				<Button type="primary" size="large" long @click="handleSubmit('formInline')">提交</Button>
+
+			</Form>
+		</Modal>
+		<!-- 修改密码 -->
+		<Modal v-model="pwd" @on-cancel="onCancel" scrollable footer-hide closable title="修改密码" :mask-closable="false"
+			width="700">
+			<Form ref="pwdinfo" :model="pwdinfo" :rules="rulepwd" :label-width="150" :label-position="labelPosition2"
+				@submit.native.prevent>
+				<FormItem label="密码:" label-for="pwd" prop="pwd">
+					<Input type="password" placeholder="请输入密码" v-model="pwdinfo.pwd" />
+				</FormItem>
+				<FormItem label="确认密码:" label-for="pwd_two" prop="pwd_two">
+					<Input type="password" placeholder="请再次输入密码" v-model="pwdinfo.pwd_two" />
+				</FormItem>
+
+				<Button type="primary" size="large" long @click="changePassword('pwdinfo')">提交</Button>
+			</Form>
+		</Modal>
+	</div>
+</template>
+
+<script>
+	import toExcel from '../../utils/Excel.js';
+	import {
+		mapState
+	} from 'vuex';
+	import {
+		exportProductList
+	} from '@/api/export';
+
+	import {
+		merchentlist,
+		getmerchent,
+		addadmin,
+		updataadmin,
+		changepwd,
+		lst,
+		typeList,
+		forbidden,
+		openMerchant,
+		merchantLoginApi
+	} from '@/api/shop';
+	import {
+		setCookies
+	} from '@/libs/util';
+	import SettingMer from "@/libs/settingMer";
+	export default {
+		name: 'shop_list',
+		computed: {
+			...mapState('userLevel', ['categoryId']),
+			labelPosition2() {
+				return this.isMobile ? 'top' : 'right';
+			},
+		},
+		data() {
+			return {
+				template: false,
+				grid: {
+					xl: 6,
+					lg: 8,
+					md: 12,
+					sm: 24,
+					xs: 24,
+				},
+				artFrom: {
+					page: 1,
+					limit: 10,
+					type_id: '',
+					category_id: '',
+					type: '1',
+				},
+				list: [],
+				tableList: [],
+				headeNum: [],
+				classifySelect: [],
+				typeSelect: [],
+				loading: false,
+				columns: [{
+						title: '商户ID',
+						key: 'mer_id',
+						width: 80,
+					},
+					{
+						title: '商户头像',
+						slot: 'image',
+						minWidth: 80,
+					},
+					{
+						title: '商户名称',
+						key: 'mer_name',
+						minWidth: 100,
+					},
+					{
+						title: '商户类型',
+						key: 'type_name',
+						minWidth: 100,
+					},
+					{
+						title: '商户分类',
+						key: 'category_name',
+						minWidth: 100,
+					},
+					{
+						title: '商家姓名',
+						key: 'real_name',
+						minWidth: 100,
+					},
+					{
+						title: '商家手机号',
+						key: 'mer_phone',
+						minWidth: 150,
+					},
+					{
+						title: '商户简介',
+						key: 'mer_info',
+						minWidth: 150,
+					},
+					{
+						title: '状态',
+						slot: 'state',
+						width: 100,
+						filters: [{
+								label: '开启',
+								value: 1,
+							},
+							{
+								label: '禁用',
+								value: 0,
+							},
+						],
+					},
+					{
+						title: '商户商品',
+						slot: 'product_state',
+						width: 100,
+						filters: [{
+								label: '显示',
+								value: 1,
+							},
+							{
+								label: '关闭',
+								value: 0,
+							},
+						],
+					},
+					{
+						title: '操作',
+						slot: 'action',
+						fixed: 'right',
+						minWidth: 220,
+					},
+				],
+				data: [],
+				total: 0,
+				attrTemplate: false,
+				ids: [],
+				goodsId: '',
+				isProductBox: false,
+				treeSelect: [],
+				modals: false,
+				pwd: false,
+				modelTit: '',
+				formInline: {
+					mer_name: '',
+					category_id: '',
+					type_id: '',
+					real_name: '',
+					account: '',
+					pwd: '',
+					mer_phone: '',
+					mer_address: '',
+					mer_keyword: ''
+				},
+				pwdinfo: {
+					pwd: '',
+					pwd_two: ''
+				},
+				rulepwd: {
+					pwd: [{
+						required: true,
+						message: '请输入密码',
+						trigger: 'blur'
+					}],
+					pwd_two: [{
+						required: true,
+						message: '请再次输入密码',
+						trigger: 'blur'
+					}],
+				},
+				ruleValidate: {
+					mer_name: [{
+						required: true,
+						message: '请输入商户名称',
+						trigger: 'blur'
+					}],
+					// category_id: [{
+					// 	required: true,
+					// 	message: '请选择商户分类',
+					// 	trigger: 'blur'
+					// }],
+					// type_id: [{
+					// 	required: true,
+					// 	message: '请选择商户类型',
+					// 	trigger: 'blur'
+					// }],
+					real_name: [{
+						required: true,
+						message: '请输入商户负责人名称',
+						trigger: 'blur'
+					}],
+					account: [{
+						required: true,
+						message: '请输入商户账号',
+						trigger: 'blur'
+					}],
+					pwd: [{
+						required: true,
+						message: '请输入商户密码',
+						trigger: 'blur'
+					}],
+					mer_phone: [{
+						required: true,
+						message: '请输入联系人手机号',
+						trigger: 'blur'
+					}],
+					mer_address: [{
+						required: true,
+						message: '请输入商户地址',
+						trigger: 'blur'
+					}],
+					mer_keyword: [{
+						required: true,
+						message: '请输入商户关键字',
+						trigger: 'blur'
+					}],
+				},
+			};
+		},
+		watch: {
+			$route() {
+				if (this.$route.fullPath === this.$routeProStr + '/product/product_list?type=5') {
+					this.getPath();
+				}
+			},
+		},
+		created() {
+			this.gettype();
+			this.getclassify();
+			this.getDataList();
+		},
+		activated() {
+			this.goodHeade();
+			// this.goodsCategory();
+			if (this.$route.fullPath === this.$routeProStr + '/product/product_list?type=5') {
+				this.getPath();
+			} else {
+				this.getDataList();
+			}
+		},
+		methods: {
+			onLogo(row) {
+				merchantLoginApi({}, row.mer_id)
+					.then(res => {
+						let data = res.data;
+						let expires = this.getExpiresTime(data.expires_time);
+						// 记录用户登陆信息
+						setCookies('uuid', data.user_info.id, expires);
+						setCookies('token', data.token, expires);
+						setCookies('expires_time', data.expires_time, expires);
+
+						this.$store.commit('userInfo/uniqueAuth', data.unique_auth);
+						this.$store.commit('userInfo/userInfo', data.user_info);
+						// 保存菜单信息
+						this.$store.commit('menus/setopenMenus', []);
+						this.$store.commit('menus/getmenusNav', data.menus);
+						this.$store.dispatch('routesList/setRoutesList', data.menus);
+						let arr = formatFlatteningRoutes(this.$router.options.routes);
+						this.formatTwoStageRoutes(arr);
+						this.$store.commit('menus/setOneLvMenus', arr);
+						let routes = formatFlatteningRoutes(data.menus);
+						console.log(routes);
+						this.$store.commit('menus/setOneLvRoute', routes);
+
+						// 记录用户信息
+						this.$store.commit('userInfo/name', data.user_info.account);
+						this.$store.commit('userInfo/avatar', data.user_info.head_pic);
+						this.$store.commit('userInfo/access', data.unique_auth);
+						this.$store.commit('userInfo/logo', data.logo);
+						this.$store.commit('userInfo/logoSmall', data.logo_square);
+						this.$store.commit('userInfo/version', data.version);
+						this.$store.commit('userInfo/newOrderAudioLink', data.newOrderAudioLink);
+						this.login_captcha = 0;
+					})
+					.catch(res => {
+						this.$message.error(res.message);
+					});
+			},
+			getExpiresTime(expiresTime) {
+				let nowTimeNum = Math.round(new Date() / 1000);
+				let expiresTimeNum = expiresTime - nowTimeNum;
+				return parseFloat(parseFloat(parseFloat(expiresTimeNum / 60) / 60) / 24);
+			},
+			//对象数组去重;
+			unique(arr) {
+				const res = new Map();
+				return arr.filter((arr) => !res.has(arr.id) && res.set(arr.id, 1));
+			},
+			getPath() {
+				this.columns2 = [...this.columns];
+				if (name !== '1' && name !== '2') {
+					this.columns2.shift({
+						type: 'selection',
+						width: 60,
+						align: 'center',
+					});
+				}
+				this.artFrom.page = 1;
+				this.artFrom.type = this.$route.query.type.toString();
+				this.getDataList();
+			},
+			freight() {
+				this.$refs.template.isTemplate = true;
+			},
+			clearAll(status) {
+				this.$refs.table.selectAll(status);
+			},
+			setChecked() {
+				//将new Set()转化为数组
+				this.ids = [...this.selectedIds];
+				// 找到绑定的table的ref对应的dom,找到table的objData对象,objData保存的是当前页的数据
+				let objData = this.$refs.table.objData;
+				for (let index in objData) {
+					if (this.selectedIds.has(objData[index].id)) {
+						objData[index]._isChecked = true;
+					}
+				}
+			},
+			// tab选择
+			onClickTab(name) {
+				this.artFrom.type = name;
+				this.columns2 = [...this.columns];
+				if (name !== '1' && name !== '2') {
+					this.columns2.shift({
+						type: 'selection',
+						width: 60,
+						align: 'center',
+					});
+				}
+				this.artFrom.page = 1;
+				this.selectedIds.clear();
+				this.getDataList();
+			},
+			// 获取商品表单头数量
+			goodHeade() {
+				getGoodHeade()
+					.then((res) => {
+						this.headeNum = res.data.list;
+					})
+					.catch((res) => {
+						this.$Message.error(res.msg);
+					});
+			},
+			// 商品分类;
+			gettype() {
+				console.log('进入');
+				typeList()
+					.then((res) => {
+						this.typeSelect = res.data;
+					})
+					.catch((res) => {
+						this.$Message.error(res.msg);
+					});
+			},
+			// 商品分类;
+			getclassify() {
+				console.log('进入');
+				lst()
+					.then((res) => {
+						this.classifySelect = res.data;
+					})
+					.catch((res) => {
+						this.$Message.error(res.msg);
+					});
+			},
+			// 商户列表
+			getDataList() {
+				this.loading = true;
+				this.artFrom.type_id = this.artFrom.type_id || '';
+				this.artFrom.category_id = this.artFrom.category_id || '';
+				merchentlist(this.artFrom)
+					.then((res) => {
+						let data = res.data;
+						this.tableList = data.list;
+						this.total = data.count;
+						// this.$nextTick(() => {
+						// 	//确保dom加载完毕
+						// 	this.setChecked();
+						// });
+						this.loading = false;
+					})
+					.catch((res) => {
+						this.loading = false;
+						this.$Message.error(res.msg);
+					});
+			},
+			pageChange(status) {
+				this.artFrom.page = status;
+				this.getDataList();
+			},
+			// 表格搜索
+			userSearchs() {
+				this.artFrom.page = 1;
+				this.getDataList();
+			},
+			// 商户开启关闭
+			changeSwitch(row) {
+				forbidden({
+						mer_id: row.mer_id,
+						status: row.status
+					})
+					.then((res) => {
+						this.$Message.success(res.msg);
+					})
+					.catch((res) => {
+						row.is_show = !row.is_show ? 1 : 0;
+						this.$Message.error(res.msg);
+					});
+			},
+			// 商户商品开启关闭
+			changeProSwitch(row) {
+				openMerchant({
+						mer_id: row.mer_id,
+						mer_state: row.mer_state
+					})
+					.then((res) => {
+						this.$Message.success(res.msg);
+					})
+					.catch((res) => {
+						row.is_show = !row.is_show ? 1 : 0;
+						this.$Message.error(res.msg);
+					});
+			},
+			// 编辑
+			edit(row) {
+				this.$modalForm(getmerchent({}, row.mer_id)).then(() => this.getDataList());
+			},
+			// 添加
+			add(name) {
+				this.modelTit = name;
+				this.modals = true;
+			},
+			handleSubmit(name) {
+				console.log(this.formInline, '123456');
+				this.$refs[name].validate((valid) => {
+					if (valid) {
+						if (this.formInline.category_id == '') return this.$Message.warning('请选择商户分类');
+						if (this.formInline.type_id == '') return this.$Message.warning('请选择商户类型');
+						addadmin(this.formInline)
+							.then(async (res) => {
+								this.$Message.success(res.msg);
+								this.modals = false;
+								this.getDataList();
+								this.$refs[name].resetFields();
+							})
+							.catch((res) => {
+								this.$Message.error(res.msg);
+							});
+					} else {
+						return false;
+					}
+				});
+			},
+			onCancel() {
+				this.$refs['formInline'].resetFields();
+			},
+			// 确认
+			del(row, tit, num) {
+				let delfromData = {
+					title: tit,
+					num: num,
+					url: `product/product/${row.id}`,
+					method: 'DELETE',
+					ids: '',
+					un: 1,
+				};
+				this.$modalSure(delfromData)
+					.then((res) => {
+						this.$Message.success(res.msg);
+						this.tableList.splice(num, 1);
+						this.goodHeade();
+					})
+					.catch((res) => {
+						this.$Message.error(res.msg);
+					});
+			},
+			openPwd(row) {
+				this.goodsId = row.mer_id
+				this.pwd = true
+			},
+			changePassword(name) {
+				this.$refs[name].validate((valid) => {
+					if (valid) {
+						changepwd(this.pwdinfo, this.goodsId)
+							.then(async (res) => {
+								this.$Message.success(res.msg);
+								this.pwd = false;
+								this.$refs[name].resetFields();
+							})
+							.catch((res) => {
+								this.$Message.error(res.msg);
+							});
+					} else {
+						return false;
+					}
+				});
+			}
+		},
+	};
+</script>
+<style scoped lang="stylus">
+	/deep/.ivu-modal-mask {
+		z-index: 999 !important;
+	}
+
+	/deep/.ivu-modal-wrap {
+		z-index: 999 !important;
+	}
+
+	.Box {
+		>>>.ivu-modal-body {
+			height: 700px;
+			overflow: auto;
+		}
+	}
+
+	.batch-box {
+		>>>.ivu-modal-body {
+			overflow: auto;
+			min-height: 350px;
+		}
+	}
+
+	.tabBox_img {
+		width: 36px;
+		height: 36px;
+		border-radius: 4px;
+		cursor: pointer;
+
+		img {
+			width: 100%;
+			height: 100%;
+		}
+	}
+
+	.bg {
+		position: fixed;
+		left: 0;
+		top: 0;
+		width: 100%;
+		height: 100%;
+		background: rgba(0, 0, 0, 0.5);
+		z-index: 11;
+	}
+
+	/deep/.happy-scroll-content {
+		width: 100%;
+
+		.demo-spin-icon-load {
+			animation: ani-demo-spin 1s linear infinite;
+		}
+
+		@keyframes ani-demo-spin {
+			from {
+				transform: rotate(0deg);
+			}
+
+			50% {
+				transform: rotate(180deg);
+			}
+
+			to {
+				transform: rotate(360deg);
+			}
+		}
+
+		.demo-spin-col {
+			height: 100px;
+			position: relative;
+			border: 1px solid #eee;
+		}
+	}
+
+	.labelInput {
+		border: 1px solid #dcdee2;
+		width: 20%;
+		padding: 0 5px;
+		border-radius: 5px;
+		min-height: 30px;
+		cursor: pointer;
+
+		.span {
+			color: #c5c8ce;
+		}
+
+		.iconxiayi {
+			font-size: 12px;
+		}
+	}
+</style>

+ 385 - 0
src/pages/shop/type.vue

@@ -0,0 +1,385 @@
+<template>
+	<div>
+		<Card :bordered="false" dis-hover class="ivu-mt">
+			<Form ref="formValidate" :model="formValidate" :label-width="labelWidth" :label-position="labelPosition"
+				@submit.native.prevent>
+				<Row type="flex">
+					<Col v-bind="grid">
+					<Button v-auth="['setting-system_role-add']" type="primary" icon="md-add"
+						@click="add('添加')">添加商户类型</Button>
+					</Col>
+				</Row>
+			</Form>
+			<Table :columns="columns1" :data="tableList" ref="table" class="mt25" :loading="loading" highlight-row
+				no-userFrom-text="暂无数据" no-filtered-userFrom-text="暂无筛选结果">
+				<template slot-scope="{ row, index }" slot="is_shows">
+					<i-switch v-model="row.status" :value="row.status" :true-value="1" :false-value="0"
+						@on-change="onchangeIsShow(row)" size="large">
+						<span slot="open">显示</span>
+						<span slot="close">隐藏</span>
+					</i-switch>
+				</template>
+				<template slot-scope="{ row, index }" slot="action">
+					<a @click="edit(row, '编辑')">编辑</a>
+					<Divider type="vertical" />
+					<a @click="del(row, '删除', index)">删除</a>
+				</template>
+			</Table>
+			<!-- <div class="acea-row row-right page">
+				<Page :total="total" :current="formValidate.page" show-elevator show-total @on-change="pageChange"
+					:page-size="formValidate.limit" />
+			</div> -->
+		</Card>
+		<!-- 新增编辑-->
+		<Modal v-model="modals" @on-cancel="onCancel" scrollable footer-hide closable :title="`${modelTit}商户类型`"
+			:mask-closable="false" width="600">
+			<Form ref="formInline" :model="formInline" :rules="ruleValidate" :label-width="120"
+				:label-position="labelPosition2" @submit.native.prevent>
+				<FormItem label="商户分类名称:" label-for="type_name" prop="type_name">
+					<Input placeholder="请输入商户分类名称" v-model="formInline.type_name" />
+				</FormItem>
+				<FormItem label="商户分类简介:" label-for="description" prop="description">
+					<Input placeholder="请输入商户分类简介" v-model="formInline.description" />
+				</FormItem>
+				<FormItem label="权限:">
+					<div class="trees-coadd">
+						<div class="scollhide">
+							<div class="iconlist">
+								<Tree :data="menusList" show-checkbox ref="tree"></Tree>
+							</div>
+						</div>
+					</div>
+				</FormItem>
+				<Spin size="large" fix v-if="spinShow"></Spin>
+				<Button type="primary" size="large" long @click="handleSubmit('formInline')">提交</Button>
+			</Form>
+		</Modal>
+	</div>
+</template>
+<script>
+	import {
+		mapState
+	} from 'vuex';
+	import {
+		getRole,
+		deleteType,
+		updataType,
+		getType,
+		addType,
+		typeList
+	} from '@/api/shop';
+	export default {
+		name: 'shopType',
+		data() {
+			return {
+				spinShow: false,
+				modals: false,
+				total: 0,
+				grid: {
+					xl: 7,
+					lg: 7,
+					md: 12,
+					sm: 24,
+					xs: 24,
+				},
+				loading: false,
+				formValidate: {
+					status: '',
+					role_name: '',
+					page: 1,
+					limit: 20,
+				},
+				columns1: [{
+						title: 'ID',
+						key: 'mer_type_id',
+						width: 50,
+					},
+					{
+						title: '商户类型名称',
+						key: 'type_name',
+						minWidth: 150,
+					},
+					{
+						title: '创建时间',
+						key: 'create_time',
+						minWidth: 200,
+					},
+					{
+						title: '商户类型简介',
+						key: 'description',
+						width: 1000,
+					},
+					{
+						title: '操作',
+						slot: 'action',
+						fixed: 'right',
+						minWidth: 120,
+					},
+				],
+				tableList: [],
+				formInline: {
+					role_name: '',
+					status: 0,
+					checked_menus: [],
+					id: 0,
+				},
+				menusList: [],
+				modelTit: '',
+				ruleValidate: {
+					role_name: [{
+						required: true,
+						message: '请输入身份昵称',
+						trigger: 'blur'
+					}],
+					status: [{
+						required: true,
+						type: 'number',
+						message: '请选择是否开启',
+						trigger: 'change'
+					}],
+					// checked_menus: [
+					//     { required: true, validator: validateStatus, trigger: 'change' }
+					// ]
+				},
+			};
+		},
+		computed: {
+			...mapState('media', ['isMobile']),
+			labelWidth() {
+				return this.isMobile ? undefined : 75;
+			},
+			labelPosition() {
+				return this.isMobile ? 'top' : 'left';
+			},
+			labelPosition2() {
+				return this.isMobile ? 'top' : 'right';
+			},
+		},
+		created() {
+			this.getList();
+		},
+		methods: {
+			// 添加
+			add(name) {
+				this.formInline.id = 0;
+				this.modelTit = name;
+				this.modals = true;
+				this.getmenusList();
+			},
+			// 删除
+			del(row, tit, num) {
+				let delfromData = {
+					title: tit,
+					num: num,
+					url: `merchant/type/delete/${row.mer_type_id}`,
+					method: 'get',
+					ids: '',
+				};
+				this.$modalSure(delfromData)
+					.then((res) => {
+						this.$Message.success(res.msg);
+						this.tableList.splice(num, 1);
+					})
+					.catch((res) => {
+						this.$Message.error(res.msg);
+					});
+			},
+			// 修改是否显示
+			onchangeIsShow(row) {
+				let data = {
+					id: row.id,
+					status: row.status,
+				};
+				roleSetStatusApi(data)
+					.then(async (res) => {
+						this.$Message.success(res.msg);
+					})
+					.catch((res) => {
+						this.$Message.error(res.msg);
+					});
+			},
+			// 列表
+			getList() {
+				this.loading = true;
+				this.formValidate.status = this.formValidate.status || '';
+				typeList(this.formValidate)
+					.then(async (res) => {
+						let data = res.data;
+						this.tableList = data;
+						this.total = res.data.count;
+						this.loading = false;
+					})
+					.catch((res) => {
+						this.loading = false;
+						this.$Message.error(res.msg);
+					});
+			},
+			pageChange(index) {
+				this.formValidate.page = index;
+				this.getList();
+			},
+			// 表格搜索
+			userSearchs() {
+				this.formValidate.page = 1;
+				this.getList();
+			},
+			// 编辑
+			edit(row, name) {
+				this.modelTit = name;
+				this.formInline.id = row.id;
+				this.modals = true;
+				this.rows = row;
+				this.getIofo(row);
+			},
+			// 菜单列表
+			getmenusList() {
+				this.spinShow = true;
+				getRole()
+					.then(async (res) => {
+						let data = res.data;
+						this.menusList = data.menus;
+						this.menusList.map((item, index) => {
+							if (item.title === '主页') {
+								// item.checked = true;
+								// item.disableCheckbox = true;
+								if (item.children.length) {
+									item.children.map((v) => {
+										// v.checked = true;
+										// v.disableCheckbox = true;
+									});
+								}
+							}
+							item.expand = false;
+						});
+						this.spinShow = false;
+					})
+					.catch((res) => {
+						this.spinShow = false;
+						this.$Message.error(res.msg);
+					});
+			},
+			// 详情
+			getIofo(row) {
+				this.spinShow = true;
+				getType({}, row.mer_type_id)
+					.then(async (res) => {
+						let data = res.data;
+						console.log(data, 'info');
+						this.formInline = data.merchantType || this.formInline;
+						this.formInline.checked_menus = this.formInline.rules;
+						this.tidyRes(data.menus);
+						this.spinShow = false;
+					})
+					.catch((res) => {
+						this.spinShow = false;
+						this.$Message.error(res.msg);
+					});
+			},
+			tidyRes(menus) {
+				let data = [];
+				menus.map((menu) => {
+					if (menu.title === '主页') {
+						menu.checked = true;
+						menu.disableCheckbox = true;
+						if (menu.children.length) {
+							menu.children.map((v) => {
+								v.checked = true;
+								v.disableCheckbox = true;
+							});
+						}
+						data.push(menu);
+					} else {
+						data.push(this.initMenu(menu));
+					}
+				});
+				// console.log(data, ruleslist);
+				this.$set(this, 'menusList', data);
+			},
+			initMenu(menu) {
+				let data = {},
+					checkMenus = ',' + this.formInline.checked_menus + ',';
+				console.log(checkMenus, 'info');
+				data.title = menu.title;
+				data.id = menu.id;
+				if (menu.children && menu.children.length > 0) {
+					data.children = [];
+					menu.children.map((child) => {
+						data.children.push(this.initMenu(child));
+					});
+				} else {
+					data.checked = checkMenus.indexOf(String(',' + data.id + ',')) !== -1;
+					data.expand = !data.checked;
+				}
+				return data;
+			},
+			// 提交
+			handleSubmit(name) {
+				this.$refs[name].validate((valid) => {
+					console.log(valid);
+					if (valid) {
+						this.formInline.rules = '';
+						this.$refs.tree.getCheckedAndIndeterminateNodes().map((node) => {
+							if (this.formInline.rules != '') {
+								this.formInline.rules = this.formInline.rules + ',' + node.id;
+							} else {
+								this.formInline.rules = node.id + ''
+							}
+						});
+						console.log(this.formInline, '1111');
+						if (this.formInline.rules == '') return this.$Message.warning('请至少选择一个权限');
+						if (this.modelTit == '添加') {
+							addType(this.formInline)
+								.then(async (res) => {
+									this.$Message.success(res.msg);
+									this.modals = false;
+									this.getList();
+									this.$refs[name].resetFields();
+									this.formInline.rules = '';
+								})
+								.catch((res) => {
+									this.$Message.error(res.msg);
+								});
+						} else {
+							updataType(this.formInline, this.rows.mer_type_id)
+								.then(async (res) => {
+									this.$Message.success(res.msg);
+									this.modals = false;
+									this.getList();
+									this.$refs[name].resetFields();
+									this.formInline.rules = '';
+								})
+								.catch((res) => {
+									this.$Message.error(res.msg);
+								});
+						}
+					} else {
+						return false;
+					}
+				});
+			},
+			onCancel() {
+				this.$refs['formInline'].resetFields();
+				this.formInline.checked_menus = [];
+			},
+		},
+	};
+</script>
+
+<style scoped lang="stylus">
+	.trees-coadd {
+		width: 100%;
+		height: 385px;
+	}
+
+	.scollhide {
+		width: 100%;
+		height: 100%;
+		overflow-x: hidden;
+		overflow-y: scroll;
+	}
+
+	// margin-left: 18px;
+	.scollhide::-webkit-scrollbar {
+		display: none;
+	}
+</style>

+ 286 - 0
src/pages/shop_product/list_wait.vue

@@ -0,0 +1,286 @@
+<template>
+  <div class="article-manager">
+    <div class="i-layout-page-header">
+      <PageHeader
+        title="商品管理"
+        hidden-breadcrumb
+        :tab-list="tabList"
+        :tab-active-key="tabActiveKey"
+        @on-tab-change="handleChangeTab"
+      >
+      </PageHeader>
+    </div>
+    <Card :bordered="false" dis-hover class="ivu-mt">
+      <div class="acea-row row-middle">
+        <span>商品分类:</span>
+        <TreeSelect v-model="value" :data="treeSelect" style="width: 160px" />
+        <div class="ivu-search acea-row row-middle">
+          <div>商品搜索:</div>
+          <div class="ivu-mt ivu-mb" style="max-width: 200px">
+            <Input search size="default" enter-button placeholder="请输入" />
+          </div>
+          <Button class="export" @click="exportData">导出</Button>
+        </div>
+      </div>
+      <div class="Button">
+        <Button type="primary" class="bnt">批量上架</Button>
+      </div>
+      <Table
+        ref="table"
+        :columns="columns"
+        :data="data"
+        class="ivu-mt"
+        :loading="loading"
+        no-data-text="暂无数据"
+        no-filtered-data-text="暂无筛选结果"
+      >
+        <template slot-scope="{ row }" slot="id">
+          {{ row.id }}
+        </template>
+        <template slot-scope="{ row }" slot="image">
+          <img v-lazy="row.image" />
+        </template>
+        <template slot-scope="{ row }" slot="name">
+          {{ row.name }}
+        </template>
+        <template slot-scope="{ row }" slot="sales">
+          {{ row.sales }}
+        </template>
+        <template slot-scope="{ row }" slot="voidSales">
+          {{ row.voidSales }}
+        </template>
+        <template slot-scope="{ row }" slot="stock">
+          {{ row.stock }}
+        </template>
+        <template slot-scope="{ row }" slot="collects">
+          {{ row.collects }}
+        </template>
+        <template slot-scope="{ row }" slot="sort">
+          {{ row.sort }}
+        </template>
+        <template slot-scope="{ row }" slot="state">
+          <Switch size="large" v-model="row.is_show ? true : false" @on-change="change">
+            <span slot="open">上架</span>
+            <span slot="close">下架</span>
+          </Switch>
+        </template>
+        <template slot-scope="{ row, index }" slot="action">
+          <a>编辑</a>
+          <Divider type="vertical" />
+          <template>
+            <Dropdown>
+              <a href="javascript:void(0)">
+                更多
+                <Icon type="ios-arrow-down"></Icon>
+              </a>
+            </Dropdown>
+          </template>
+        </template>
+      </Table>
+      <div class="acea-row row-right page">
+        <Page :total="total" show-elevator />
+      </div>
+    </Card>
+  </div>
+</template>
+<style scoped lang="less">
+img {
+  height: 36px;
+  display: block;
+}
+
+.ivu-mt .ivu-search {
+  margin-left: 16px;
+}
+
+.ivu-mt .export {
+  margin-left: 6px;
+}
+
+.ivu-mt .Button .bnt {
+  margin-right: 6px;
+}
+</style>
+<script>
+import expandRow from './tableExpand.vue';
+
+export default {
+  name: 'product_list_wait',
+  components: { expandRow },
+  data() {
+    return {
+      tabActiveKey: 'list_wait',
+      loading: false,
+      cityList: [
+        {
+          value: '跌幅很大功夫大湖股份',
+          label: '跌幅很大功夫大湖股份',
+        },
+        {
+          value: 'London',
+          label: 'London',
+        },
+      ],
+      model11: '',
+      model12: '',
+      columns: [
+        {
+          type: 'selection',
+          width: 60,
+          align: 'center',
+        },
+        {
+          type: 'expand',
+          width: 50,
+          render: (h, params) => {
+            return h(expandRow, {
+              props: {
+                row: params.row,
+              },
+            });
+          },
+        },
+        {
+          title: '商品ID',
+          slot: 'id',
+          width: 100,
+        },
+        {
+          title: '商品图',
+          slot: 'image',
+          minWidth: 80,
+        },
+        {
+          title: '商品名称',
+          slot: 'name',
+          minWidth: 250,
+        },
+        {
+          title: '销量',
+          slot: 'sales',
+          sortable: true,
+          minWidth: 90,
+        },
+        {
+          title: '虚拟销量',
+          slot: 'voidSales',
+          minWidth: 100,
+        },
+        {
+          title: '库存',
+          slot: 'stock',
+          minWidth: 80,
+        },
+        {
+          title: '收藏',
+          slot: 'collects',
+          minWidth: 70,
+        },
+        {
+          title: '排序',
+          slot: 'sort',
+          minWidth: 70,
+        },
+        {
+          title: '状态',
+          key: 'state',
+          slot: 'state',
+          width: 100,
+          filters: [
+            {
+              label: '上架',
+              value: 1,
+            },
+            {
+              label: '下架',
+              value: 0,
+            },
+          ],
+          filterMethod(value, row) {
+            return row.is_show === value;
+          },
+          filterMultiple: false,
+        },
+        {
+          title: '操作',
+          slot: 'action',
+          fixed: 'right',
+          minWidth: 150,
+        },
+      ],
+      data: [],
+      total: 0,
+    };
+  },
+  mounted() {
+    this.getData();
+  },
+  methods: {
+    getData() {
+      this.loading = true;
+      setTimeout(() => {
+        let data = [
+          {
+            id: '1120',
+            image: 'https://dev-file.iviewui.com/PKCycgm3DWJOca5I2uAEqneuLFQAcKa7/middle',
+            name: 'CRMEB商城系统V3.0将在8月与大家见面',
+            sales: '357万',
+            voidSales: '400万',
+            stock: '3570',
+            collects: '26',
+            sort: '2',
+            is_show: 1,
+            job: 'Data engineer',
+            interest: 'badminton',
+            birthday: '1991-05-14',
+            book: 'Steve Jobs',
+            movie: 'The Prestige',
+          },
+          {
+            id: '2',
+            image: 'https://dev-file.iviewui.com/KUa7CaC6m7vRtDCfY0SAXlp7dw9OvBrf/middle',
+            name: 'CRMEB商城系统V3.0将在8月与大家见面',
+            sales: '357万',
+            voidSales: '400万',
+            stock: '3570',
+            collects: '26',
+            sort: '2',
+            is_show: 0,
+            job: 'Data engineer',
+            interest: 'badminton',
+            birthday: '1991-05-14',
+            book: 'Steve Jobs',
+            movie: 'The Prestige',
+          },
+          {
+            id: '666',
+            image: 'https://dev-file.iviewui.com/OYZqqiP1bbwN22Ai2HnwvSagxuSNchdD/middle',
+            name: 'CRMEB商城系统V3.0将在8月与大家见面',
+            sales: '357万',
+            voidSales: '400万',
+            stock: '3570',
+            collects: '26',
+            sort: '2',
+            is_show: 1,
+            job: 'Data engineer',
+            interest: 'badminton',
+            birthday: '1991-05-14',
+            book: 'Steve Jobs',
+            movie: 'The Prestige',
+          },
+        ];
+        this.loading = false;
+        this.data = data;
+        this.total = data.length;
+      }, 1000);
+    },
+    change(status) {},
+    // 数据导出;
+    exportData: function () {
+      this.$refs.table.exportCsv({
+        filename: '商品列表',
+      });
+    },
+  },
+};
+</script>

+ 3111 - 0
src/pages/shop_product/productAdd/index.vue

@@ -0,0 +1,3111 @@
+<template>
+	<div class="" id="shopp-manager">
+		<div class="i-layout-page-header header-title">
+			<div class="fl_header">
+				<router-link :to="{ path: $routeProStrshop + '/product/product_list' }"><Button icon="ios-arrow-back"
+						size="small" type="text">返回</Button></router-link>
+				<Divider type="vertical" />
+				<span class="ivu-page-header-title mr20" style="padding: 0"
+					v-text="$route.params.id ? '编辑商品' : '添加商品'"></span>
+			</div>
+		</div>
+		<Card :bordered="false" dis-hover class="ivu-mt">
+			<Tabs v-model="currentTab" @on-click="onhangeTab">
+				<TabPane v-for="(item, index) in headTab" :key="index" :label="item.tit" :name="item.name"></TabPane>
+			</Tabs>
+			<Form class="formValidate mt20" ref="formValidate" :rules="ruleValidate" :model="formValidate"
+				:label-width="labelWidth" :label-position="labelPosition" @submit.native.prevent>
+				<!-- 基础信息-->
+				<Row :gutter="24" type="flex" v-show="currentTab === '1'">
+					<Col span="24">
+					<FormItem label="商品类型:" props="is_virtual">
+						<div class="virtual"
+							:class="formValidate.virtual_type == item.id ? 'virtual_boder' : 'virtual_boder2'"
+							v-for="(item, index) in virtual" :key="index" @click="virtualbtn(item.id, 2)">
+							<div class="virtual_top">{{ item.tit }}</div>
+							<div class="virtual_bottom">({{ item.tit2 }})</div>
+							<div v-if="formValidate.virtual_type == item.id" class="virtual_san"></div>
+							<div v-if="formValidate.virtual_type == item.id" class="virtual_dui">✓</div>
+						</div>
+					</FormItem>
+					</Col>
+					<Col span="24">
+					<FormItem label="商品分类:" prop="cate_id">
+						<!-- {{ formValidate.cate_id }}
+              <Select v-model="formValidate.cate_id" placeholder="请选择商品分类" multiple class="perW30">
+                <Option v-for="item in treeSelect" :disabled="item.pid === 0" :value="item.id" :key="item.id">{{
+                  item.html + item.cate_name
+                }}</Option>
+              </Select>
+              {{ formValidate.cate_id }} -->
+						<el-cascader class="perW30" v-model="formValidate.cate_id" size="small" :options="treeSelect"
+							:props="{ multiple: true, emitPath: false }" clearable></el-cascader>
+						<!-- <span class="addfont" @click="addCate">新增分类</span> -->
+					</FormItem>
+					</Col>
+					<Col span="24">
+					<FormItem label="商品名称:" prop="store_name">
+						<Input class="perW30" v-model.trim="formValidate.store_name" placeholder="请输入商品名称" />
+					</FormItem>
+					</Col>
+
+					<Col span="24">
+					<FormItem label="单位:" prop="unit_name">
+						<Input class="perW30" v-model="formValidate.unit_name" placeholder="请输入单位" />
+					</FormItem>
+					</Col>
+					<Col span="24">
+					<FormItem label="商品轮播图:" prop="slider_image">
+						<div class="acea-row">
+							<div class="pictrue" v-for="(item, index) in formValidate.slider_image" :key="index"
+								draggable="true" @dragstart="handleDragStart($event, item)"
+								@dragover.prevent="handleDragOver($event, item)"
+								@dragenter="handleDragEnter($event, item)" @dragend="handleDragEnd($event, item)">
+								<img v-lazy="item" />
+								<Button shape="circle" icon="md-close" @click.native="handleRemove(index)"
+									class="btndel"></Button>
+							</div>
+							<div v-if="formValidate.slider_image.length < 10" class="upLoad acea-row row-center-wrapper"
+								@click="modalPicTap('duo')">
+								<Icon type="ios-camera-outline" size="26" />
+							</div>
+							<Input v-model="formValidate.slider_image[0]" style="display: none"></Input>
+						</div>
+
+						<div class="titTip">建议尺寸:800*800,可拖拽改变图片顺序,默认首张图为主图,最多上传10张</div>
+
+						<!-- <div class="tips">(最多10张<br />750*750)</div> -->
+					</FormItem>
+					</Col>
+					<Col span="24">
+					<FormItem label="添加视频:">
+						<i-switch v-model="formValidate.video_open" size="large">
+							<span slot="open">开启</span>
+							<span slot="close">关闭</span>
+						</i-switch>
+					</FormItem>
+					</Col>
+					<Col span="24" v-if="formValidate.video_open">
+					<FormItem label="视频类型:">
+						<RadioGroup v-model="seletVideo" @on-change="changeVideo">
+							<Radio :label="0" class="radio">本地视频</Radio>
+							<Radio :label="1">视频链接</Radio>
+						</RadioGroup>
+					</FormItem>
+					</Col>
+					<Col span="24" v-if="formValidate.video_open" id="selectvideo">
+					<FormItem label="" prop="video_link">
+						<Input v-if="seletVideo == 1 && !formValidate.video_link" class="perW30" v-model="videoLink"
+							placeholder="请输入视频链接" />
+						<input type="file" ref="refid" @change="zh_uploadFile_change" style="display: none" />
+						<div v-if="seletVideo == 0 && (upload_type !== '1' || videoLink) && !formValidate.video_link"
+							class="ml10 videbox" @click="zh_uploadFile">
+							+
+						</div>
+						<Button v-if="seletVideo == 1 && (upload_type !== '1' || videoLink) && !formValidate.video_link"
+							type="primary" icon="ios-cloud-upload-outline" class="ml10"
+							@click="zh_uploadFile">确认添加</Button>
+						<Upload v-if="upload_type === '1' && !videoLink" :show-upload-list="false" :action="fileUrl2"
+							:before-upload="videoSaveToUrl" :data="uploadData" :headers="header" :multiple="true"
+							style="display: inline-block">
+							<div v-if="seletVideo === 0 && !formValidate.video_link" class="videbox">+</div>
+						</Upload>
+						<div class="iview-video-style" v-if="formValidate.video_link">
+							<video style="width: 100%; height: 100% !important; border-radius: 10px"
+								:src="formValidate.video_link" controls="controls">
+								您的浏览器不支持 video 标签。
+							</video>
+							<div class="mark"></div>
+							<Icon type="ios-trash-outline" class="iconv" @click="delVideo" />
+						</div>
+						<Progress class="progress" :percent="progress" :stroke-width="5"
+							v-if="upload.videoIng || videoIng" />
+						<div class="titTip">建议时长:9~30秒,视频宽高比16:9</div>
+					</FormItem>
+					</Col>
+					<Col v-bind="grid">
+					<FormItem label="商品状态:">
+						<RadioGroup v-model="formValidate.is_show">
+							<Radio :label="1" class="radio">上架</Radio>
+							<Radio :label="0">下架</Radio>
+						</RadioGroup>
+					</FormItem>
+					</Col>
+
+					<!-- <Col span="24">
+                        <FormItem label="商品标签:" prop="label_id">
+                            <Select v-model="formValidate.label_id" multiple v-width="'50%'">
+                                <Option v-for="item in dataLabel" :value="item.id" :key="item.id">{{ item.label_name }}</Option>
+                            </Select>
+                        </FormItem>
+                    </Col> -->
+				</Row>
+				<!-- 规格库存-->
+				<Row :gutter="24" type="flex" v-show="currentTab === '2'">
+					<Col span="24">
+					<FormItem label="商品规格:" props="spec_type">
+						<RadioGroup v-model="formValidate.spec_type" @on-change="changeSpec">
+							<Radio :label="0" class="radio">单规格</Radio>
+							<Radio :label="1">多规格</Radio>
+						</RadioGroup>
+					</FormItem>
+					</Col>
+					<!-- 多规格添加-->
+					<Col span="24" v-if="formValidate.spec_type === 1" class="noForm">
+					<Col span="24">
+					<FormItem label="选择规格:" prop="">
+						<div class="acea-row row-middle">
+							<Select v-model="formValidate.selectRule" class="perW30">
+								<Option v-for="(item, index) in ruleList" :value="item.rule_name" :key="index">{{
+                      item.rule_name
+                    }}</Option>
+							</Select>
+							<Button type="primary" class="mr20" @click="confirm">确认</Button>
+							<Button @click="addRule">添加规格模板</Button>
+						</div>
+					</FormItem>
+					</Col>
+					<Col span="24">
+					<FormItem v-if="attrs.length !== 0">
+						<draggable class="dragArea list-group" :list="attrs" group="peoples" handle=".move-icon"
+							:move="checkMove" @end="end">
+							<div v-for="(item, index) in attrs" :key="index" class="acea-row row-middle mb10">
+								<div class="move-icon">
+									<span class="iconfont icondrag2"></span>
+								</div>
+								<div style="width: 90%" :class="moveIndex === index ? 'borderStyle' : ''">
+									<div class="acea-row row-middle">
+										<span class="mr5">{{ item.value }}</span>
+										<Icon type="ios-close-circle" size="14" class="curs"
+											@click="handleRemoveRole(index)" />
+									</div>
+									<div class="rulesBox">
+										<draggable :list="item.detail" handle=".drag">
+											<Tag type="dot" closable color="primary" v-for="(j, indexn) in item.detail"
+												:key="indexn" :name="j" class="mr20 drag"
+												@on-close="handleRemove2(item.detail, indexn)">{{ j }}</Tag>
+										</draggable>
+										<Input search enter-button="添加" placeholder="请输入属性名称"
+											v-model="item.detail.attrsVal"
+											@on-search="createAttr(item.detail.attrsVal, index)" style="width: 150px" />
+									</div>
+								</div>
+							</div>
+						</draggable>
+						<!-- <div  v-for="(item, index) in attrs" :key="index">
+                                    <div class="acea-row row-middle"><span class="mr5">{{item.value}}</span><Icon type="ios-close-circle" size="14" class="curs" @click="handleRemoveRole(index)"/></div>
+                                    <div class="rulesBox">
+                                        <Tag type="dot" closable color="primary" v-for="(j, indexn) in item.detail" :key="indexn" :name="j" class="mr20" @on-close="handleRemove2(item.detail,indexn)">{{j}}</Tag>
+                                        <Input search enter-button="添加" placeholder="请输入属性名称" v-model="item.detail.attrsVal" @on-search="createAttr(item.detail.attrsVal,index)" style="width: 150px"/>
+                                    </div>
+                                </div> -->
+					</FormItem>
+					</Col>
+					<Col span="24" v-if="createBnt">
+					<FormItem>
+						<Button type="primary" icon="md-add" @click="addBtn" class="mr15">添加新规格</Button>
+						<Button type="success" @click="generate(1)">立即生成</Button>
+					</FormItem>
+					</Col>
+					<Col span="24" v-if="showIput">
+					<Col :xl="6" :lg="9" :md="10" :sm="24" :xs="24">
+					<FormItem label="规格:">
+						<Input placeholder="请输入规格" v-model="formDynamic.attrsName" />
+					</FormItem>
+					</Col>
+					<Col :xl="6" :lg="9" :md="10" :sm="24" :xs="24">
+					<FormItem label="规格值:">
+						<Input v-model="formDynamic.attrsVal" placeholder="请输入规格值" />
+					</FormItem>
+					</Col>
+					<Col :xl="6" :lg="5" :md="10" :sm="24" :xs="24">
+					<FormItem>
+						<Button type="primary" class="mr15" @click="createAttrName">确定</Button>
+						<Button @click="offAttrName">取消</Button>
+					</FormItem>
+					</Col>
+					</Col>
+					<!-- 多规格设置-->
+					<Col :xl="24" :lg="24" :md="24" :sm="24" :xs="24"
+						v-if="manyFormValidate.length && formValidate.header.length !== 0 && attrs.length !== 0">
+					<!-- 批量设置-->
+
+					<Col span="24" v-if="[0, 3].includes(formValidate.virtual_type)">
+					<FormItem label="批量设置:" class="labeltop">
+						<Table :data="oneFormBatch" :columns="formValidate.is_virtual ? columns3 : columns2" border>
+							<template slot-scope="{ row, index }" slot="pic">
+								<div class="acea-row row-middle row-center-wrapper"
+									@click="modalPicTap('dan', 'duopi', index)">
+									<div class="pictrue pictrueTab" v-if="oneFormBatch[0].pic">
+										<img v-lazy="oneFormBatch[0].pic" />
+									</div>
+									<div class="upLoad pictrueTab acea-row row-center-wrapper" v-else>
+										<Icon type="ios-camera-outline" size="21" class="iconfont" />
+									</div>
+								</div>
+							</template>
+							<template slot-scope="{ row, index }" slot="price">
+								<InputNumber v-model="oneFormBatch[0].price" :min="0" :max="99999999" class="priceBox">
+								</InputNumber>
+							</template>
+							<template slot-scope="{ row, index }" slot="cost">
+								<InputNumber v-model="oneFormBatch[0].cost" :min="0" :max="99999999" class="priceBox">
+								</InputNumber>
+							</template>
+							<template slot-scope="{ row, index }" slot="ot_price">
+								<InputNumber v-model="oneFormBatch[0].ot_price" :min="0" class="priceBox"></InputNumber>
+							</template>
+							<template slot-scope="{ row, index }" slot="stock">
+								<InputNumber v-model="oneFormBatch[0].stock" :disabled="formValidate.virtual_type == 1"
+									:min="0" :max="99999999" class="priceBox"></InputNumber>
+							</template>
+							<template slot-scope="{ row, index }" slot="fictitious">
+								<Button v-if="!row.coupon_id && formValidate.virtual_type == 2"
+									@click="addGoodsCoupon(index, 'oneFormBatch')">添加优惠券</Button>
+								<span class="see" v-else-if="row.coupon_id && formValidate.virtual_type == 2"
+									@click="see(row, 'manyFormValidate', index)">{{ row.coupon_name }}</span>
+								<Button v-else-if="!row.virtual_list.length && formValidate.virtual_type == 1"
+									@click="addVirtual(index, 'oneFormBatch')">添加卡密</Button>
+								<span class="see" v-else-if="row.virtual_list.length && formValidate.virtual_type == 1"
+									@click="see(row, 'oneFormBatch', index)">已设置</span>
+							</template>
+							<template slot-scope="{ row, index }" slot="bar_code">
+								<Input v-model="oneFormBatch[0].bar_code"></Input>
+							</template>
+							<template slot-scope="{ row, index }" slot="weight">
+								<InputNumber v-model="oneFormBatch[0].weight" :step="0.1" :min="0" :max="99999999"
+									class="priceBox"></InputNumber>
+							</template>
+							<template slot-scope="{ row, index }" slot="volume">
+								<InputNumber v-model="oneFormBatch[0].volume" :step="0.1" :min="0" :max="99999999"
+									class="priceBox"></InputNumber>
+							</template>
+							<template slot-scope="{ row, index }" slot="action">
+								<a @click="batchAdd">批量添加</a>
+								<Divider type="vertical" />
+								<a @click="batchDel">清空</a>
+							</template>
+						</Table>
+					</FormItem>
+					</Col>
+					<!-- 多规格表格-->
+					<Col span="24">
+					<FormItem label="商品属性:" class="labeltop">
+						<Table :data="manyFormValidate" :columns="formValidate.header" border>
+							<template slot-scope="{ row, index }" slot="pic">
+								<div class="acea-row row-middle row-center-wrapper"
+									@click="modalPicTap('dan', 'duoTable', index)">
+									<div class="pictrue pictrueTab" v-if="manyFormValidate[index].pic">
+										<img v-lazy="manyFormValidate[index].pic" />
+									</div>
+									<div class="upLoad pictrueTab acea-row row-center-wrapper" v-else>
+										<Icon type="ios-camera-outline" size="21" class="iconfont" />
+									</div>
+								</div>
+							</template>
+							<template slot-scope="{ row, index }" slot="price">
+								<InputNumber v-model="manyFormValidate[index].price" :min="0" :max="99999999"
+									class="priceBox"></InputNumber>
+							</template>
+							<template slot-scope="{ row, index }" slot="cost">
+								<InputNumber v-model="manyFormValidate[index].cost" :min="0" :max="99999999"
+									class="priceBox"></InputNumber>
+							</template>
+							<template slot-scope="{ row, index }" slot="ot_price">
+								<InputNumber v-model="manyFormValidate[index].ot_price" :min="0" :max="99999999"
+									class="priceBox"></InputNumber>
+							</template>
+							<template slot-scope="{ row, index }" slot="stock">
+								<InputNumber v-model="manyFormValidate[index].stock"
+									:disabled="formValidate.virtual_type == 1" :min="0" :max="99999999" :precision="0"
+									class="priceBox"></InputNumber>
+							</template>
+							<template slot-scope="{ row, index }" slot="bar_code">
+								<Input v-model="manyFormValidate[index].bar_code"></Input>
+							</template>
+							<template slot-scope="{ row, index }" slot="weight">
+								<InputNumber v-model="manyFormValidate[index].weight" :min="0" :max="99999999"
+									class="priceBox"></InputNumber>
+							</template>
+							<template slot-scope="{ row, index }" slot="volume">
+								<InputNumber v-model="manyFormValidate[index].volume" :min="0" :max="99999999"
+									class="priceBox"></InputNumber>
+							</template>
+							<template slot-scope="{ row, index }" slot="fictitious">
+								<Button v-if="!row.coupon_id && formValidate.virtual_type == 2"
+									@click="addGoodsCoupon(index, 'manyFormValidate')">添加优惠券</Button>
+								<span class="see" v-else-if="row.coupon_id && formValidate.virtual_type == 2"
+									@click="see(row, 'manyFormValidate', index)">{{ row.coupon_name }}</span>
+								<Button v-else-if="!row.virtual_list && !row.stock && formValidate.virtual_type == 1"
+									@click="addVirtual(index, 'manyFormValidate')">添加卡密</Button>
+								<span class="see"
+									v-else-if="(row.virtual_list.length || row.stock) && formValidate.virtual_type == 1"
+									@click="see(row, 'manyFormValidate', index)">已设置</span>
+							</template>
+							<template slot-scope="{ row, index }" slot="action">
+								<a @click="delAttrTable(index)">删除</a>
+							</template>
+						</Table>
+					</FormItem>
+					</Col>
+					</Col>
+					</Col>
+					<!-- 单规格表格-->
+					<div v-if="formValidate.spec_type === 0">
+						<Col span="24">
+						<FormItem label="图片:">
+							<div class="pictrueBox" @click="modalPicTap('dan', 'danTable', 0)">
+								<div class="pictrue" v-if="oneFormValidate[0].pic">
+									<img v-lazy="oneFormValidate[0].pic" />
+									<Input v-model="oneFormValidate[0].pic" style="display: none"></Input>
+								</div>
+								<div class="upLoad acea-row row-center-wrapper" v-else>
+									<Input v-model="oneFormValidate[0].pic" style="display: none"></Input>
+									<Icon type="ios-camera-outline" size="26" />
+								</div>
+							</div>
+						</FormItem>
+						</Col>
+						<Col span="24">
+						<FormItem label="售价:">
+							<InputNumber v-model="oneFormValidate[0].price" :min="0" :precision="2" :max="99999999"
+								class="perW20" :active-change="false"></InputNumber>
+						</FormItem>
+						</Col>
+						<Col span="24">
+						<FormItem label="成本价:">
+							<InputNumber v-model="oneFormValidate[0].cost" :min="0" :max="99999999" :precision="2"
+								:active-change="false" class="perW20"></InputNumber>
+						</FormItem>
+						</Col>
+						<Col span="24">
+						<FormItem label="原价:">
+							<InputNumber v-model="oneFormValidate[0].ot_price" :min="0" :max="99999999" :precision="2"
+								:active-change="false" class="perW20"></InputNumber>
+						</FormItem>
+						</Col>
+						<Col span="24">
+						<FormItem label="库存:">
+							<InputNumber v-model="oneFormValidate[0].stock" :min="0" :max="99999999"
+								:disabled="formValidate.virtual_type == 1" :precision="0" class="perW20"></InputNumber>
+						</FormItem>
+						</Col>
+						<Col span="24">
+						<FormItem label="商品编号:">
+							<Input v-model.trim="oneFormValidate[0].bar_code" class="perW20"></Input>
+						</FormItem>
+						</Col>
+						<Col span="24" v-if="formValidate.virtual_type == 0">
+						<FormItem label="重量(KG):">
+							<InputNumber v-model="oneFormValidate[0].weight" :min="0" :max="99999999" class="perW20">
+							</InputNumber>
+						</FormItem>
+						</Col>
+						<Col span="24">
+						<FormItem label="体积(m³):" v-if="formValidate.virtual_type == 0">
+							<InputNumber v-model="oneFormValidate[0].volume" :min="0" :max="99999999" class="perW20">
+							</InputNumber>
+						</FormItem>
+						</Col>
+
+						<Col span="24">
+						<FormItem label="虚拟商品:" v-if="formValidate.virtual_type == 1 || formValidate.virtual_type == 2">
+							<Button v-if="!oneFormValidate[0].coupon_id && formValidate.virtual_type == 2"
+								@click="addGoodsCoupon(0, 'oneFormValidate')">添加优惠券</Button>
+							<span class="see" v-else-if="oneFormValidate[0].coupon_id && formValidate.virtual_type == 2"
+								@click="see(oneFormValidate[0], 'oneFormValidate', 0)">{{ oneFormValidate[0].coupon_name }}</span>
+							<Button v-if="
+                    !oneFormValidate[0].virtual_list.length &&
+                    !oneFormValidate[0].stock &&
+                    formValidate.virtual_type == 1
+                  " @click="addVirtual(0, 'oneFormValidate')">添加卡密</Button>
+							<span class="see" v-else-if="
+                    (oneFormValidate[0].virtual_list.length || oneFormValidate[0].stock > 0) &&
+                    formValidate.virtual_type == 1
+                  " @click="see(oneFormValidate[0], 'oneFormValidate', 0)">已设置</span>
+						</FormItem>
+						</Col>
+					</div>
+				</Row>
+				<!-- 商品详情-->
+				<Row v-show="currentTab === '3'">
+					<Col span="16">
+					<FormItem label="商品详情:">
+						<WangEditor style="width: 100%" :content="contents" @editorContent="getEditorContent">
+						</WangEditor>
+					</FormItem>
+					</Col>
+					<Col span="6" style="width: 33%">
+					<div class="ifam">
+						<div class="content" v-html="content"></div>
+					</div>
+					</Col>
+				</Row>
+
+				<!-- 物流设置-->
+				<Row v-show="headTab.length === 6 ? currentTab === '4' : false">
+					<Col span="24">
+					<FormItem label="物流方式:" prop="logistics">
+						<CheckboxGroup v-model="formValidate.logistics" @on-change="logisticsBtn">
+							<Checkbox label="1">快递</Checkbox>
+
+							<Checkbox label="2">到店核销</Checkbox>
+						</CheckboxGroup>
+					</FormItem>
+					</Col>
+					<Col span="24">
+					<FormItem label="运费设置:">
+						<RadioGroup v-model="formValidate.freight">
+							<!-- <Radio :label="1">包邮</Radio> -->
+							<Radio :label="2">固定邮费</Radio>
+							<Radio :label="3">运费模板</Radio>
+						</RadioGroup>
+					</FormItem>
+					</Col>
+					<Col span="24" v-if="formValidate.freight != 3 && formValidate.freight != 1">
+					<FormItem label="" :prop="formValidate.freight != 1 ? 'freight' : ''">
+						<div class="acea-row">
+							<InputNumber :min="0" v-model="formValidate.postage" placeholder="请输入金额"
+								class="perW30 maxW" />
+						</div>
+					</FormItem>
+					</Col>
+					<Col span="24" v-if="formValidate.freight == 3">
+					<FormItem label="" prop="temp_id">
+						<div class="acea-row">
+							<Select v-model="formValidate.temp_id" clearable placeholder="请选择运费模板" class="perW30 maxW">
+								<Option v-for="(item, index) in templateList" :value="item.id" :key="index">
+									{{ item.name }}
+								</Option>
+							</Select>
+							<span class="addfont" @click="addTemp">新增运费模板</span>
+						</div>
+					</FormItem>
+					</Col>
+				</Row>
+				<!-- 营销设置-->
+				<Row :gutter="24" type="flex" v-show="headTab.length === 6 ? currentTab === '5' : currentTab === '4'">
+					<Col span="24">
+					<FormItem label="已售数量:">
+						<InputNumber :min="0" :max="999999" v-model="formValidate.ficti" placeholder="请输入虚拟销量" />
+					</FormItem>
+					</Col>
+					<Col span="24">
+					<FormItem label="排序:">
+						<InputNumber :min="0" :max="999999" v-model="formValidate.sort" placeholder="请输入排序" />
+					</FormItem>
+					</Col>
+					<Col span="24">
+					<div class="line"></div>
+					</Col>
+
+					<Col span="24">
+					<FormItem label="购买送积分:" prop="give_integral">
+						<InputNumber v-model="formValidate.give_integral" :min="0" :max="999999" placeholder="请输入积分" />
+					</FormItem>
+					</Col>
+					<Col v-bind="grid3">
+					<FormItem label="购买送优惠券:">
+						<div v-if="couponName.length" class="mb20">
+							<Tag closable v-for="(item, index) in couponName" :key="index"
+								@on-close="handleClose(item)">{{
+                  item.title
+                }}</Tag>
+						</div>
+						<Button type="primary" @click="addCoupon">添加优惠券</Button>
+					</FormItem>
+					</Col>
+					<Col span="24">
+					<FormItem label="关联用户标签:" prop="label_id">
+						<div style="display: flex">
+							<div class="labelInput acea-row row-between-wrapper" @click="openLabel">
+								<div style="width: 90%">
+									<div v-if="dataLabel.length">
+										<Tag closable v-for="(item, index) in dataLabel" @on-close="closeLabel(item)"
+											:key="index">{{
+                        item.label_name
+                      }}</Tag>
+									</div>
+									<span class="span" v-else>选择用户关联标签</span>
+								</div>
+								<div class="iconfont iconxiayi"></div>
+							</div>
+							<span class="addfont" @click="addLabel">新增标签</span>
+						</div>
+					</FormItem>
+					</Col>
+					<Col span="24">
+					<div class="line"></div>
+					</Col>
+					<Col span="24">
+					<FormItem label="付费会员专属:">
+						<i-switch v-model="formValidate.vip_product" size="large">
+							<span slot="open">开启</span>
+							<span slot="close">关闭</span>
+						</i-switch>
+						<div class="titTip">开启后仅付费会员可以看见并购买此商品</div>
+					</FormItem>
+					</Col>
+					<Col span="24">
+					<FormItem label="单独设置:">
+						<CheckboxGroup v-model="formValidate.is_sub" @on-change="checkAllGroupChange">
+							<Checkbox :label="1">佣金设置(数字即返佣金额)</Checkbox>
+							<Checkbox :label="0">付费会员价</Checkbox>
+						</CheckboxGroup>
+						<!-- <RadioGroup v-model="formValidate.is_sub">
+                                <Radio :label="1" class="radio">佣金设置</Radio>
+                                <Radio :label="0">会员价</Radio>
+                            </RadioGroup> -->
+					</FormItem>
+					</Col>
+					<Col span="24" v-if="formValidate.is_sub.length">
+					<!--单规格返佣-->
+					<FormItem label="商品属性:" v-if="formValidate.spec_type === 0">
+						<Table :data="oneFormValidate" :columns="columnsInstall" border>
+							<template slot-scope="{ row, index }" slot="pic">
+								<div class="pictrue pictrueTab">
+									<img v-lazy="oneFormValidate[0].pic" />
+								</div>
+							</template>
+							<template slot-scope="{ row, index }" slot="price">{{ oneFormValidate[0].price }}</template>
+							<template slot-scope="{ row, index }" slot="cost">{{ oneFormValidate[0].cost }}</template>
+							<template slot-scope="{ row, index }"
+								slot="ot_price">{{ oneFormValidate[0].ot_price }}</template>
+							<template slot-scope="{ row, index }" slot="stock">{{ oneFormValidate[0].stock }}</template>
+							<template slot-scope="{ row, index }"
+								slot="bar_code">{{ oneFormValidate[0].bar_code }}</template>
+							<template slot-scope="{ row, index }"
+								slot="weight">{{ oneFormValidate[0].weight }}</template>
+							<template slot-scope="{ row, index }" slot="fictitious">
+								<Button v-if="!row.coupon_id && formValidate.virtual_type == 2"
+									@click="addGoodsCoupon(index, 'oneFormValidate')">添加优惠券</Button>
+								<span class="see" v-else-if="row.coupon_id && formValidate.virtual_type == 2"
+									@click="see(row, 'manyFormValidate', index)">{{ row.coupon_name }}</span>
+								<Button
+									v-else-if="!row.virtual_list.length && !row.stock && formValidate.virtual_type == 1"
+									@click="addVirtual(index, 'oneFormValidate')">添加卡密</Button>
+								<span class="see"
+									v-else-if="(row.virtual_list.length || row.stock) && formValidate.virtual_type == 1"
+									@click="see(row, 'oneFormValidate', index)">已设置</span>
+							</template>
+							<template slot-scope="{ row, index }"
+								slot="volume">{{ oneFormValidate[0].volume }}</template>
+							<template slot-scope="{ row, index }" slot="brokerage">
+								<InputNumber v-model="oneFormValidate[0].brokerage" :min="0" :max="999999"
+									class="priceBox"></InputNumber>
+							</template>
+							<template slot-scope="{ row }" slot="brokerage_two">
+								<InputNumber v-model="oneFormValidate[0].brokerage_two" :min="0" :max="999999"
+									class="priceBox"></InputNumber>
+							</template>
+							<template slot-scope="{ row }" slot="vip_price">
+								<InputNumber v-model="oneFormValidate[0].vip_price" :min="0" :max="999999"
+									class="priceBox"></InputNumber>
+							</template>
+						</Table>
+						<!-- <Table v-else :data="oneFormValidate" :columns="columnsInsta8" border>
+                                <template slot-scope="{ row, index }" slot="pic">
+                                    <div class="pictrue pictrueTab"><img v-lazy="oneFormValidate[0].pic"></div>
+                                </template>
+                                <template slot-scope="{ row, index }" slot="price">{{oneFormValidate[0].price}}</template>
+                                <template slot-scope="{ row, index }" slot="cost">{{oneFormValidate[0].cost}}</template>
+                                <template slot-scope="{ row, index }" slot="ot_price">{{oneFormValidate[0].ot_price}}</template>
+                                <template slot-scope="{ row, index }" slot="vip_price">
+                                    <InputNumber  v-model="oneFormValidate[0].vip_price" :min="0" :precision="0" class="priceBox"></InputNumber>
+                                </template>
+                            </Table> -->
+					</FormItem>
+					<!--多规格返佣-->
+					<FormItem label="批量设置:" v-if="formValidate.spec_type === 1">
+						<span v-if="formValidate.is_sub.indexOf(1) > -1">
+							一级返佣:<InputNumber placeholder="请输入一级返佣" :min="0" :max="9999999" class="columnsBox perW30"
+								v-model="manyBrokerage"></InputNumber>
+							二级返佣:<InputNumber placeholder="请输入二级返佣" :min="0" :max="99999999" class="columnsBox perW30"
+								v-model="manyBrokerageTwo"></InputNumber>
+						</span>
+						<span v-if="formValidate.is_sub.indexOf(0) > -1">
+							会员价:<InputNumber placeholder="请输入会员价" :min="0" :max="99999999" class="columnsBox perW30"
+								v-model="manyVipPrice"></InputNumber>
+						</span>
+						<Button type="primary" @click="brokerageSetUp">批量设置</Button>
+						<!-- <template v-if="formValidate.is_sub">
+                                <InputNumber v-width="'20%'" placeholder="请输入一级返佣" :min="0" class="columnsBox" v-model="manyBrokerage"></InputNumber>
+                                <InputNumber v-width="'20%'" placeholder="请输入二级返佣" :min="0" class="columnsBox" v-model="manyBrokerageTwo"></InputNumber>
+                                <Button type="primary" @click="brokerageSetUp">批量设置</Button>
+                            </template>
+                            <template v-else>
+                                <InputNumber v-width="'20%'" placeholder="请输入会员价" :min="0" class="columnsBox" v-model="manyVipPrice"></InputNumber>
+                                <Button type="primary" @click="vipPriceSetUp">批量设置</Button>
+                            </template> -->
+					</FormItem>
+					<FormItem label="商品属性:" v-if="formValidate.spec_type === 1 && manyFormValidate.length">
+						<Table v-if="formValidate.is_sub" :data="manyFormValidate" :columns="columnsInstal2" border>
+							<template slot-scope="{ row, index }" slot="pic">
+								<div class="pictrue pictrueTab">
+									<img v-lazy="manyFormValidate[index].pic" />
+								</div>
+							</template>
+							<template slot-scope="{ row, index }"
+								slot="price">{{ manyFormValidate[index].price }}</template>
+							<template slot-scope="{ row, index }"
+								slot="cost">{{ manyFormValidate[index].cost }}</template>
+							<template slot-scope="{ row, index }"
+								slot="ot_price">{{ manyFormValidate[index].ot_price }}</template>
+							<template slot-scope="{ row, index }"
+								slot="stock">{{ manyFormValidate[index].stock }}</template>
+							<template slot-scope="{ row, index }"
+								slot="bar_code">{{ manyFormValidate[index].bar_code }}</template>
+							<template slot-scope="{ row, index }"
+								slot="weight">{{ manyFormValidate[index].weight }}</template>
+							<template slot-scope="{ row, index }" slot="fictitious">
+								<Button v-if="!row.coupon_id && formValidate.virtual_type == 2"
+									@click="addGoodsCoupon(index, 'manyFormValidate')">添加优惠券</Button>
+								<span class="see" v-else-if="row.coupon_id && formValidate.virtual_type == 2"
+									@click="see(row, 'manyFormValidate', index)">{{ row.coupon_name }}</span>
+								<Button
+									v-else-if="!row.virtual_list.length && !row.stock && formValidate.virtual_type == 1"
+									@click="addVirtual(index, 'manyFormValidate')">添加卡密</Button>
+								<span class="see"
+									v-else-if="(row.virtual_list.length || row.stock) && formValidate.virtual_type == 1"
+									@click="see(row, 'manyFormValidate', index)">已设置</span>
+							</template>
+							<template slot-scope="{ row, index }"
+								slot="volume">{{ manyFormValidate[index].volume }}</template>
+							<template slot-scope="{ row, index }" slot="brokerage">
+								<InputNumber v-model="manyFormValidate[index].brokerage" :min="0" :max="99999999"
+									class="priceBox"></InputNumber>
+							</template>
+							<template slot-scope="{ row, index }" slot="brokerage_two">
+								<InputNumber v-model="manyFormValidate[index].brokerage_two" :min="0" :max="99999999"
+									class="priceBox"></InputNumber>
+							</template>
+							<template slot-scope="{ row, index }" slot="vip_price">
+								<InputNumber v-model="manyFormValidate[index].vip_price" :min="0" :max="99999999"
+									class="priceBox"></InputNumber>
+							</template>
+						</Table>
+						<!-- <Table v-else :data="manyFormValidate" :columns="columnsInsta9" border>
+                                <template slot-scope="{ row, index }" slot="pic">
+                                    <div class="pictrue pictrueTab"><img v-lazy="manyFormValidate[index].pic"></div>
+                                </template>
+                                <template slot-scope="{ row, index }" slot="price">{{manyFormValidate[index].price}}</template>
+                                <template slot-scope="{ row, index }" slot="cost">{{manyFormValidate[index].cost}}</template>
+                                <template slot-scope="{ row, index }" slot="ot_price">{{manyFormValidate[index].ot_price}}</template>
+                                <template slot-scope="{ row, index }" slot="vip_price">
+                                    <InputNumber  v-model="manyFormValidate[index].vip_price" :min="0" class="priceBox"></InputNumber>
+                                </template>
+                            </Table> -->
+					</FormItem>
+					</Col>
+					<Col span="24">
+					<div class="line"></div>
+					</Col>
+					<Col span="24">
+					<FormItem label="是否限购:">
+						<i-switch v-model="formValidate.is_limit" size="large">
+							<span slot="open">开启</span>
+							<span slot="close">关闭</span>
+						</i-switch>
+					</FormItem>
+					</Col>
+					<Col span="24">
+					<FormItem label="限购类型:" v-if="formValidate.is_limit">
+						<RadioGroup v-model="formValidate.limit_type">
+							<Radio :label="1">单次限购</Radio>
+							<Radio :label="2">永久限购</Radio>
+						</RadioGroup>
+						<div class="titTip">单次限购是限制每次下单最多购买的数量,永久限购是限制一个用户总共可以购买的数量</div>
+					</FormItem>
+					</Col>
+					<Col span="24" v-if="formValidate.is_limit">
+					<FormItem label="限购数量:" prop="limit_num">
+						<div class="acea-row row-middle">
+							<span class="mr10"></span>
+							<InputNumber placeholder="请输入限购数量" :precision="0" :min="1"
+								v-model="formValidate.limit_num" />
+							<span class="ml10"> 件 </span>
+						</div>
+					</FormItem>
+					</Col>
+					<Col span="24" v-if="formValidate.virtual_type == 0 || formValidate.virtual_type == 3">
+					<FormItem label="预售商品:">
+						<i-switch v-model="formValidate.presale" size="large">
+							<span slot="open">开启</span>
+							<span slot="close">关闭</span>
+						</i-switch>
+					</FormItem>
+					</Col>
+					<Col span="24" v-if="formValidate.presale">
+					<FormItem label="预售活动时间:" prop="presale_time">
+						<div class="acea-row row-middle">
+							<DatePicker :editable="false" type="datetimerange" format="yyyy-MM-dd HH:mm"
+								placeholder="请选择活动时间" @on-change="onchangeTime" :value="formValidate.presale_time"
+								v-model="formValidate.presale_time"></DatePicker>
+						</div>
+						<div class="titTip">设置活动开启结束时间,用户可以在设置时间内发起参与预售</div>
+					</FormItem>
+					</Col>
+					<Col span="24" v-if="formValidate.presale">
+					<FormItem label="发货时间:" prop="presale_day">
+						<div class="acea-row row-middle">
+							<span class="mr10">预售活动结束后</span>
+							<InputNumber placeholder="请输入发货时间" :precision="0" :min="1"
+								v-model="formValidate.presale_day" />
+							<span class="ml10"> 天之内 </span>
+							<div class="ml10 grey"></div>
+						</div>
+					</FormItem>
+					</Col>
+
+					<Col span="24">
+					<FormItem label="商品推荐:">
+						<CheckboxGroup v-model="formValidate.recommend">
+							<Checkbox label="is_hot">热卖单品</Checkbox>
+							<Checkbox label="is_benefit">促销单品</Checkbox>
+							<Checkbox label="is_best">精品推荐</Checkbox>
+							<Checkbox label="is_new">首发新品</Checkbox>
+							<Checkbox label="is_good">优品推荐</Checkbox>
+						</CheckboxGroup>
+					</FormItem>
+					</Col>
+					<!-- <Col v-bind="grid">
+            <FormItem label="热卖单品:">
+              <RadioGroup v-model="formValidate.is_hot">
+                <Radio :label="1" class="radio">开启</Radio>
+                <Radio :label="0">关闭</Radio>
+              </RadioGroup>
+            </FormItem>
+          </Col>
+          <Col v-bind="grid">
+            <FormItem label="促销单品:">
+              <RadioGroup v-model="formValidate.is_benefit">
+                <Radio :label="1" class="radio">开启</Radio>
+                <Radio :label="0">关闭</Radio>
+              </RadioGroup>
+            </FormItem>
+          </Col>
+          <Col v-bind="grid">
+            <FormItem label="精品推荐:">
+              <RadioGroup v-model="formValidate.is_best">
+                <Radio :label="1" class="radio">开启</Radio>
+                <Radio :label="0">关闭</Radio>
+              </RadioGroup>
+            </FormItem>
+          </Col>
+          <Col v-bind="grid">
+            <FormItem label="首发新品:">
+              <RadioGroup v-model="formValidate.is_new">
+                <Radio :label="1" class="radio">开启</Radio>
+                <Radio :label="0">关闭</Radio>
+              </RadioGroup>
+            </FormItem>
+          </Col>
+          <Col v-bind="grid">
+            <FormItem label="优品推荐:">
+              <RadioGroup v-model="formValidate.is_good">
+                <Radio :label="1" class="radio">开启</Radio>
+                <Radio :label="0">关闭</Radio>
+              </RadioGroup>
+            </FormItem>
+          </Col> -->
+					<Col v-bind="grid3">
+					<FormItem label="活动优先级:">
+						<div class="color-list acea-row row-middle">
+							<div class="color-item" :class="activity[color]" v-for="color in formValidate.activity"
+								v-dragging="{
+                    item: color,
+                    list: formValidate.activity,
+                    group: 'color',
+                  }" :key="color">
+								{{ color }}
+							</div>
+						</div>
+						<div class="titTip">可拖动按钮调整活动的优先展示顺序</div>
+					</FormItem>
+					</Col>
+					<Col v-bind="grid3">
+					<FormItem label="选择优品推荐商品:">
+						<div class="picBox">
+							<div class="pictrue" v-for="(item, index) in formValidate.recommend_list" :key="index">
+								<img v-lazy="item.image" />
+								<Button shape="circle" icon="md-close" @click.native="handleRemoveRecommend(index)"
+									class="btndel"></Button>
+							</div>
+							<div class="upLoad acea-row row-center-wrapper" @click="changeGoods">
+								<Icon type="ios-add" size="26" class="iconfonts" />
+							</div>
+						</div>
+					</FormItem>
+					</Col>
+				</Row>
+				<!-- 其他设置-->
+				<Row type="flex" justify="space-between"
+					v-show="headTab.length === 6 ? currentTab === '6' : currentTab === '5'">
+					<Col span="24">
+					<FormItem label="商品关键字:">
+						<Input class="perW30" v-model.trim="formValidate.keyword" placeholder="请输入商品关键字" />
+					</FormItem>
+					</Col>
+					<Col span="24">
+					<FormItem label="商品简介:">
+						<Input class="perW30" v-model.trim="formValidate.store_info" type="textarea" :rows="3"
+							placeholder="请输入商品简介" />
+					</FormItem>
+					</Col>
+					<Col span="24">
+					<FormItem label="商品口令:">
+						<Input v-model.trim="formValidate.command_word" placeholder="请输入商品口令" type="textarea" :rows="3"
+							class="perW30" />
+					</FormItem>
+					</Col>
+
+					<Col span="24">
+					<FormItem label="商品推荐图:">
+						<div class="pictrueBox" @click="modalPicTap('dan', 'recommend_image')">
+							<div class="pictrue" v-if="formValidate.recommend_image">
+								<img v-lazy="formValidate.recommend_image" />
+								<Input v-model.trim="formValidate.recommend_image" style="display: none"></Input>
+							</div>
+							<div class="upLoad acea-row row-center-wrapper" v-else>
+								<Input v-model.trim="formValidate.recommend_image" style="display: none"></Input>
+								<Icon type="ios-camera-outline" size="26" />
+							</div>
+							<div class="titTip">建议比例:5:2</div>
+						</div>
+					</FormItem>
+					</Col>
+					<Col span="24">
+					<FormItem label="自定义留言:">
+						<i-switch v-model="customBtn" @on-change="customMessBtn" size="large">
+							<span slot="open">开启</span>
+							<span slot="close">关闭</span>
+						</i-switch>
+						<div class="addCustom_content" v-if="customBtn">
+							<div v-for="(item, index) in formValidate.custom_form" type="flex" :key="index"
+								class="custom_box">
+								<Input v-model.trim="item.title" :placeholder="'留言标题' + (index + 1)"
+									style="width: 150px; margin-right: 10px" :maxlength="10" />
+								<Select v-model="item.label" style="width: 200px; margin-left: 6px; margin-right: 10px">
+									<Option v-for="items in CustomList" :value="items.value" :key="items.value">{{
+                      items.label
+                    }}</Option>
+								</Select>
+								<Checkbox v-model="item.status">必填</Checkbox>
+								<div class="addfont" @click="delcustom(index)">删除</div>
+							</div>
+						</div>
+						<div class="addCustomBox" v-show="customBtn">
+							<div class="btn" @click="addcustom">+ 添加表单</div>
+							<div class="titTip">用户下单时需填写的信息,最多可设置10条</div>
+						</div>
+					</FormItem>
+					</Col>
+				</Row>
+				<FormItem>
+					<Button v-if="currentTab !== '1'" @click="upTab">上一步</Button>
+					<Button type="primary" class="submission"
+						v-if="currentTab !== '6' && formValidate.virtual_type == 0" @click="downTab">下一步</Button>
+					<Button type="primary" class="submission"
+						v-if="currentTab !== '5' && formValidate.virtual_type != 0" @click="downTab">下一步</Button>
+					<Button type="primary" :disabled="openSubimit" class="submission"
+						@click="handleSubmit('formValidate')"
+						v-if="($route.params.id || currentTab === '6') && formValidate.virtual_type == 0">保存</Button>
+					<Button type="primary" :disabled="openSubimit" class="submission"
+						@click="handleSubmit('formValidate')"
+						v-if="($route.params.id || currentTab === '5') && formValidate.virtual_type != 0">保存</Button>
+				</FormItem>
+				<Spin size="large" fix v-if="spinShow"></Spin>
+			</Form>
+			<Modal v-model="modalPic" width="1024px" scrollable footer-hide closable title="上传商品图"
+				:mask-closable="false" :z-index="1">
+				<uploadPictures :isChoice="isChoice" @getPic="getPic" @getPicD="getPicD" :gridBtn="gridBtn"
+					:gridPic="gridPic" v-if="modalPic"></uploadPictures>
+			</Modal>
+			<Modal v-model="addVirtualModel" width="700px" closable title="添加卡密" :mask-closable="false" :z-index="1"
+				footer-hide @on-visible-change="initVirtualData">
+				<div class="trip"></div>
+				<div class="type-radio">
+					<Form :label-width="80">
+						<FormItem label="卡密类型:">
+							<RadioGroup v-model="disk_type" size="large">
+								<Radio :label="1">固定卡密</Radio>
+								<Radio :label="2">一次性卡密</Radio>
+							</RadioGroup>
+							<div v-if="disk_type == 1">
+								<div class="stock-disk">
+									<Input v-model="disk_info" size="large" type="textarea" :rows="4"
+										placeholder="填写卡密信息" />
+								</div>
+								<div class="stock-input">
+									<!-- <Input type="number" v-model="stock" size="large" :min='0' placeholder="填写库存数量">
+                    <span slot="append">件</span>
+                  </Input> -->
+									<InputNumber :max="100000" :min="1" :step="1" :precision="0" v-model="stock" />
+									<span class="pl10">件</span>
+								</div>
+							</div>
+							<div class="scroll-virtual" v-if="disk_type == 2">
+								<div class="virtual-data mb10" v-for="(item, index) in virtualList" :key="index">
+									<span class="mr10 virtual-title">卡号{{ index + 1 }}:</span>
+									<Input class="mr10" type="text" v-model.trim="item.key" style="width: 150px"
+										placeholder="请输入卡号(非必填)"></Input>
+									<span class="mr10 virtual-title">卡密{{ index + 1 }}:</span>
+									<Input class="mr10" type="text" v-model.trim="item.value" style="width: 150px"
+										placeholder="请输入卡密"></Input>
+									<span class="deteal-btn" @click="removeVirtual(index)">删除</span>
+								</div>
+							</div>
+							<div class="add-more" v-if="disk_type == 2">
+								<Button type="primary" @click="handleAdd" icon="md-add">新增</Button>
+								<Upload class="ml10" :action="cardUrl" :data="uploadData" :headers="header"
+									:on-success="upFile">
+									<Button icon="ios-cloud-upload-outline">导入卡密</Button>
+								</Upload>
+							</div>
+						</FormItem>
+					</Form>
+				</div>
+				<div class="footer">
+					<div class="clear" @click="closeVirtual">取消</div>
+					<div class="submit" @click="upVirtual">确认</div>
+				</div>
+			</Modal>
+		</Card>
+		<freightTemplate :template="template" v-on:changeTemplate="changeTemplate" ref="templates"></freightTemplate>
+		<add-attr ref="addattr" @getList="userSearchs"></add-attr>
+		<coupon-list ref="couponTemplates" @nameId="nameId" :couponids="formValidate.coupon_ids" :updateIds="updateIds"
+			:updateName="updateName"></coupon-list>
+		<coupon-list ref="goodsCoupon" many="one" :luckDraw="true" @getCouponId="goodsCouponId"></coupon-list>
+		<!-- 生成淘宝京东表单-->
+		<Modal v-model="modals" @on-cancel="cancel" class="Box" scrollable footer-hide closable
+			title="复制淘宝、天猫、京东、苏宁、1688" :mask-closable="false" width="800" height="500">
+			<tao-bao ref="taobaos" v-if="modals" @on-close="onClose"></tao-bao>
+		</Modal>
+		<Modal v-model="goods_modals" title="商品列表" footerHide class="paymentFooter" scrollable width="900">
+			<goods-list v-if="goods_modals" ref="goodslist" :ischeckbox="true"
+				@getProductId="getProductId"></goods-list>
+		</Modal>
+		<!-- 用户标签 -->
+		<Modal v-model="labelShow" scrollable title="请选择用户标签" :closable="false" width="500" :footer-hide="true"
+			:mask-closable="false">
+			<userLabel ref="userLabel" @activeData="activeData" @close="labelClose"></userLabel>
+		</Modal>
+	</div>
+</template>
+
+<script>
+	import userLabel from '@/components/labelList';
+	import {
+		mapState
+	} from 'vuex';
+	import vuedraggable from 'vuedraggable';
+	import uploadPictures from '@/components/uploadPictures2';
+	import freightTemplate from '@/components/freightTemplate2';
+	import couponList from '@/components/couponList';
+	import addAttr from '../productAttr/addAttr';
+	import goodsList from '@/components/goodsList/index';
+	import taoBao from './taoBao';
+	import WangEditor from '@/components/wangEditor/index.vue';
+	import {
+		userLabelAddApi
+	} from '@/api/user';
+	import {
+		productInfoApi,
+		cascaderListApi,
+		productAddApi,
+		generateAttrApi,
+		productGetRuleApi,
+		productGetTemplateApi,
+		productGetTempKeysApi,
+		checkActivityApi,
+		productCache,
+		cacheDelete,
+		uploadType,
+		importCard,
+		productCreateApi,
+	} from '@/api/shop_product';
+	import Setting from '@/setting';
+	import {
+		getCookies
+	} from '@/libs/util';
+	import {
+		uploadByPieces
+	} from '@/utils/uploads'; //引入uploadByPieces方法
+
+	export default {
+		name: 'product_productAdd',
+		components: {
+			// VueUeditorWrap,
+			uploadPictures,
+			freightTemplate,
+			addAttr,
+			couponList,
+			taoBao,
+			draggable: vuedraggable,
+			goodsList,
+			WangEditor,
+			userLabel,
+		},
+		data() {
+			return {
+				labelShow: false,
+				dataLabel: [],
+				headTab: [{
+						tit: '基础信息',
+						name: '1'
+					},
+					{
+						tit: '规格库存',
+						name: '2'
+					},
+					{
+						tit: '商品详情',
+						name: '3'
+					},
+					{
+						tit: '物流设置',
+						name: '4'
+					},
+					{
+						tit: '营销设置',
+						name: '5'
+					},
+					{
+						tit: '其他设置',
+						name: '6'
+					},
+				],
+				virtual: [{
+						tit: '普通商品',
+						id: 0,
+						tit2: '物流发货'
+					},
+					{
+						tit: '卡密/网盘',
+						id: 1,
+						tit2: '自动发货'
+					},
+					{
+						tit: '优惠券',
+						id: 2,
+						tit2: '自动发货'
+					},
+					{
+						tit: '虚拟商品',
+						id: 3,
+						tit2: '虚拟发货'
+					},
+				],
+				seletVideo: 0, //选择视频类型
+				customBtn: false, //自定义留言开关
+				content: '',
+				contents: '',
+				fileUrl: Setting.apiBaseURL + '/mer/file/upload',
+				fileUrl2: Setting.apiBaseURL + '/mer/file/video_upload',
+				cardUrl: Setting.apiBaseURL + '/mer/file/upload/1',
+				upload_type: '', //视频上传类型 1 本地上传 2 3 4 OSS上传
+				uploadData: {}, // 上传参数
+				header: {},
+
+				type: 0,
+				modals: false,
+				goods_modals: false,
+				spinShow: false,
+				openSubimit: false,
+				virtualData: '',
+				virtualList: [{
+					key: '',
+					value: '',
+				}, ],
+				grid2: {
+					xl: 10,
+					lg: 12,
+					md: 12,
+					sm: 24,
+					xs: 24,
+				},
+				grid3: {
+					xl: 18,
+					lg: 18,
+					md: 20,
+					sm: 24,
+					xs: 24,
+				},
+				// 批量设置表格data
+				oneFormBatch: [{
+					pic: '',
+					price: 0,
+					cost: 0,
+					ot_price: 0,
+					stock: 0,
+					bar_code: '',
+					weight: 0,
+					volume: 0,
+				}, ],
+				// 规格数据
+				formDynamic: {
+					attrsName: '',
+					attrsVal: '',
+				},
+				disk_type: 1, //卡密类型
+				tabIndex: 0,
+				tabName: '',
+				formDynamicNameData: [],
+				isBtn: false,
+				columns2: [{
+						title: '图片',
+						slot: 'pic',
+						align: 'center',
+						minWidth: 80,
+					},
+					{
+						title: '售价',
+						slot: 'price',
+						align: 'center',
+						minWidth: 95,
+					},
+					{
+						title: '成本价',
+						slot: 'cost',
+						align: 'center',
+						minWidth: 95,
+					},
+					{
+						title: '原价',
+						slot: 'ot_price',
+						align: 'center',
+						minWidth: 95,
+					},
+					{
+						title: '库存',
+						slot: 'stock',
+						align: 'center',
+						minWidth: 95,
+					},
+					{
+						title: '商品编号',
+						slot: 'bar_code',
+						align: 'center',
+						minWidth: 120,
+					},
+					{
+						title: '重量(KG)',
+						slot: 'weight',
+						align: 'center',
+						minWidth: 95,
+					},
+					{
+						title: '体积(m³)',
+						slot: 'volume',
+						align: 'center',
+						minWidth: 95,
+					},
+					{
+						title: '操作',
+						slot: 'action',
+						fixed: 'right',
+						align: 'center',
+						minWidth: 140,
+					},
+				],
+				columns3: [{
+						title: '图片',
+						slot: 'pic',
+						align: 'center',
+						minWidth: 80,
+					},
+					{
+						title: '售价',
+						slot: 'price',
+						align: 'center',
+						minWidth: 95,
+					},
+					{
+						title: '成本价',
+						slot: 'cost',
+						align: 'center',
+						minWidth: 95,
+					},
+					{
+						title: '原价',
+						slot: 'ot_price',
+						align: 'center',
+						minWidth: 95,
+					},
+					{
+						title: '库存',
+						slot: 'stock',
+						align: 'center',
+						minWidth: 95,
+					},
+					{
+						title: '商品编号',
+						slot: 'bar_code',
+						align: 'center',
+						minWidth: 120,
+					},
+					{
+						title: '虚拟商品',
+						slot: 'fictitious',
+						align: 'center',
+						minWidth: 95,
+					},
+					{
+						title: '操作',
+						slot: 'action',
+						fixed: 'right',
+						align: 'center',
+						minWidth: 140,
+					},
+				],
+				columns: [],
+				columnsInstall: [],
+				columnsInstal2: [],
+				gridPic: {
+					xl: 6,
+					lg: 8,
+					md: 12,
+					sm: 12,
+					xs: 12,
+				},
+				gridBtn: {
+					xl: 4,
+					lg: 8,
+					md: 8,
+					sm: 8,
+					xs: 8,
+				},
+				//自定义留言下拉选择
+				CustomList: [{
+						value: 'text',
+						label: '文本框',
+					},
+					{
+						value: 'number',
+						label: '数字',
+					},
+					{
+						value: 'email',
+						label: '邮件',
+					},
+					{
+						value: 'data',
+						label: '日期',
+					},
+					{
+						value: 'time',
+						label: '时间',
+					},
+					{
+						value: 'id',
+						label: '身份证',
+					},
+					{
+						value: 'phone',
+						label: '手机号',
+					},
+					{
+						value: 'img',
+						label: '图片',
+					},
+				],
+				customess: {
+					content: [],
+				}, //自定义留言内容
+
+				formValidate: {
+					disk_info: '', //卡密类型
+					logistics: ['1'], //选择物流方式
+					freight: 2, //运费设置
+					postage: 0, //设置运费金额
+					recommend: [], //商品推荐
+					presale_day: 1, //预售发货时间-结束
+					presale: false, //预售商品开关
+					is_limit: false,
+					limit_type: 0,
+					limit_num: 0,
+					video_open: false, //视频按钮是否显示
+					vip_product: false, //付费会员专属开关
+					custom_form: [], //自定义留言
+					store_name: '',
+					cate_id: [],
+					label_id: [],
+					keyword: '',
+					unit_name: '',
+					store_info: '',
+					image: '',
+					recommend_image: '',
+					slider_image: [],
+					description: '',
+					ficti: 0,
+					give_integral: 0,
+					sort: 0,
+					is_show: 1,
+					is_hot: 0,
+					is_benefit: 0,
+					is_best: 0,
+					is_new: 0,
+					is_good: 0,
+					is_postage: 0,
+					is_sub: [],
+					recommend_list: [],
+					virtual_type: 0,
+					// is_sub: 0,
+					id: 0,
+					spec_type: 0,
+					is_virtual: 0,
+					video_link: '',
+					// postage: 0,
+					temp_id: '',
+					attrs: [],
+					items: [{
+						pic: '',
+						price: 0,
+						cost: 0,
+						ot_price: 0,
+						stock: 0,
+						bar_code: '',
+					}, ],
+					activity: ['默认', '秒杀', '砍价', '拼团'],
+					couponName: [],
+					header: [],
+					selectRule: '',
+					coupon_ids: [],
+					command_word: '',
+				},
+				ruleList: [],
+				templateList: [],
+				createBnt: true,
+				showIput: false,
+				manyFormValidate: [],
+				// 单规格表格data
+				oneFormValidate: [{
+					pic: '',
+					price: 0,
+					cost: 0,
+					ot_price: 0,
+					stock: 0,
+					bar_code: '',
+					weight: 0,
+					volume: 0,
+					brokerage: 0,
+					brokerage_two: 0,
+					vip_price: 0,
+					virtual_list: [],
+					coupon_id: 0,
+				}, ],
+				images: [],
+				imagesTable: '',
+				currentTab: '1',
+				isChoice: '',
+				grid: {
+					xl: 8,
+					lg: 8,
+					md: 12,
+					sm: 24,
+					xs: 24,
+				},
+				loading: false,
+				modalPic: false,
+				addVirtualModel: false,
+				template: false,
+				uploadList: [],
+				treeSelect: [],
+				picTit: '',
+				tableIndex: 0,
+				ruleValidate: {
+					store_name: [{
+						required: true,
+						message: '请输入商品名称',
+						trigger: 'blur'
+					}],
+					cate_id: [{
+						required: true,
+						message: '请选择商品分类',
+						trigger: 'change',
+						type: 'array',
+						min: '1',
+					}, ],
+					unit_name: [{
+						required: true,
+						message: '请输入单位',
+						trigger: 'blur'
+					}],
+					// image: [{ required: true, message: "请上传商品图", trigger: "change" }],
+					slider_image: [{
+						required: true,
+						message: '请上传商品轮播图',
+						type: 'array',
+						trigger: 'change',
+					}, ],
+					spec_type: [{
+						required: true,
+						message: '请选择商品规格',
+						trigger: 'change'
+					}],
+					is_virtual: [{
+						required: true,
+						message: '请选择商品类型',
+						trigger: 'change'
+					}],
+					selectRule: [{
+						required: true,
+						message: '请选择商品规格属性',
+						trigger: 'change'
+					}],
+					temp_id: [{
+						required: true,
+						message: '请选择运费模板',
+						trigger: 'change',
+						type: 'number',
+					}, ],
+					presale_time: [{
+						required: true,
+						type: 'array',
+						message: '请选择活动时间',
+						trigger: 'change',
+					}, ],
+					logistics: [{
+							required: true,
+							type: 'array',
+							min: 1,
+							message: '请选择物流方式',
+							trigger: 'change',
+						},
+						{
+							type: 'array',
+							max: 2,
+							message: '请选择物流方式',
+							trigger: 'change',
+						},
+					],
+					give_integral: [{
+						type: 'integer',
+						message: '请输入整数'
+					}],
+				},
+				manyBrokerage: 0,
+				manyBrokerageTwo: 0,
+				manyVipPrice: 0,
+				upload: {
+					videoIng: false, // 是否显示进度条;
+				},
+				videoIng: false, // 是否显示进度条;
+				progress: 0, // 进度条默认0
+				stock: 0,
+				disk_info: '',
+				videoLink: '',
+				attrs: [],
+				activity: {
+					默认: 'red',
+					秒杀: 'blue',
+					砍价: 'green',
+					拼团: 'yellow'
+				},
+				couponName: [],
+				updateIds: [],
+				updateName: [],
+				couponIds: '',
+				couponNames: [],
+				rakeBack: [{
+						title: '一级返佣',
+						slot: 'brokerage',
+						align: 'center',
+						width: 95,
+					},
+					{
+						title: '二级返佣',
+						slot: 'brokerage_two',
+						align: 'center',
+						width: 95,
+					},
+				],
+				member: [{
+					title: '会员价',
+					slot: 'vip_price',
+					align: 'center',
+					width: 95,
+				}, ],
+				columnsInstalM: [],
+				moveIndex: '',
+				// aa: [],
+				// openSubimit: false
+			};
+		},
+		computed: {
+			...mapState('media', ['isMobile']),
+			labelWidth() {
+				return this.isMobile ? undefined : 120;
+			},
+			labelPosition() {
+				return this.isMobile ? 'top' : 'right';
+			},
+			labelBottom() {
+				return this.isMobile ? undefined : 15;
+			},
+		},
+		beforeRouteUpdate(to, from, next) {
+			this.bus.$emit('onTagsViewRefreshRouterView', this.$route.path);
+			next();
+		},
+		created() {
+			this.columns = this.columns2.slice(0, 8);
+			this.getToken();
+			console.log(this.fileUrl2, '123')
+			// this.columnsInstall = this.columns2.slice(0, 4).concat(this.columnsInstall);
+			// this.columnsInsta8 = this.columns2.slice(0, 4).concat(this.columnsInsta8);
+		},
+		mounted() {
+			if (this.$route.params.id !== '0' && this.$route.params.id) {
+				this.getInfo();
+			} else if (this.$route.params.id === '0') {
+				productCache()
+					.then((res) => {
+						let data = res.data.info;
+						if (!Array.isArray(data)) {
+							let cate_id = data.cate_id.map(Number);
+							let label_id = data.label_id.map(Number);
+							this.attrs = data.items || [];
+							let ids = [];
+							// let names = [];
+							if (data.coupons) {
+								data.coupons.map((item) => {
+									ids.push(item.id);
+									// names.push(item.title);
+								});
+								this.couponName = data.coupons;
+							}
+
+							this.formValidate = data;
+							// this.couponName = data.coupons;
+							// that.couponName = names;
+							this.dataLabel = data.label_id;
+							this.formValidate.coupon_ids = ids;
+							this.updateIds = ids;
+							this.updateName = data.coupons;
+							this.formValidate.cate_id = cate_id;
+							// this.formValidate.label_id = label_id;
+							this.oneFormValidate = data.attrs;
+							this.formValidate.logistics = data.logistics || ['1'];
+							this.formValidate.header = [];
+							this.generate(0);
+							this.manyFormValidate = data.attrs;
+							this.spec_type = data.spec_type;
+							this.formValidate.is_virtual = data.is_virtual;
+							this.formValidate.custom_form = data.custom_form || [];
+							if (this.formValidate.custom_form.length != 0) {
+								this.customBtn = true;
+							}
+							this.virtualbtn(data.virtual_type, 1);
+							if (data.spec_type === 0) {
+								this.manyFormValidate = [];
+							} else {
+								this.createBnt = true;
+								this.oneFormValidate = [{
+									pic: data.image,
+									price: 0,
+									cost: 0,
+									ot_price: 0,
+									stock: 0,
+									bar_code: '',
+									weight: 0,
+									volume: 0,
+									brokerage: 0,
+									brokerage_two: 0,
+									vip_price: 0,
+									virtual_list: [],
+									coupon_id: 0,
+								}, ];
+							}
+							this.spinShow = false;
+						}
+					})
+					.catch((err) => {
+						this.$Message.error(err.msg);
+					});
+			}
+			if (this.$route.query.type) {
+				this.modals = true;
+				this.type = this.$route.query.type;
+			} else {
+				this.type = 0;
+			}
+			this.goodsCategory();
+			this.productGetRule();
+			this.productGetTemplate();
+			// this.userLabel();
+			this.uploadType();
+		},
+		methods: {
+			// 分片上传
+			videoSaveToUrl(file) {
+				uploadByPieces({
+					file: file, // 视频实体
+					pieceSize: 3, // 分片大小
+					success: (data) => {
+						this.formValidate.video_link = data.file_path;
+						this.progress = 100;
+					},
+					error: (e) => {
+						this.$Message.error(e.msg);
+					},
+					uploading: (chunk, allChunk) => {
+						this.videoIng = true;
+						let st = Math.floor((chunk / allChunk) * 100);
+						this.progress = st;
+					},
+				});
+				return false;
+			},
+			// 类型选择/填入内容判断
+			virtualbtn(index, type) {
+				if (type != 1) {
+					this.formValidate.is_sub = [];
+					let id = this.$route.params.id;
+					if (id) {
+						checkActivityApi(id)
+							.then((res) => {})
+							.catch((res) => {
+								this.formValidate.spec_type = this.spec_type;
+								this.$Message.error(res.msg);
+							});
+					} else {
+						if (this.formValidate.spec_type == 1) {
+							this.generate(1);
+						}
+					}
+				}
+				switch (index) {
+					case 0:
+						this.formValidate.virtual_type = 0;
+						this.formValidate.is_virtual = 0;
+						this.headTab = [{
+								tit: '基础信息',
+								name: '1'
+							},
+							{
+								tit: '规格库存',
+								name: '2'
+							},
+							{
+								tit: '商品详情',
+								name: '3'
+							},
+							{
+								tit: '物流设置',
+								name: '4'
+							},
+							{
+								tit: '营销设置',
+								name: '5'
+							},
+							{
+								tit: '其他设置',
+								name: '6'
+							},
+						];
+						break;
+					case 1:
+						this.formValidate.virtual_type = 1;
+						this.formValidate.postage = 0;
+						this.formValidate.is_virtual = 1;
+						this.headTab = [{
+								tit: '基础信息',
+								name: '1'
+							},
+							{
+								tit: '规格库存',
+								name: '2'
+							},
+							{
+								tit: '商品详情',
+								name: '3'
+							},
+							// { tit: "物流设置", name: "4" },
+							{
+								tit: '营销设置',
+								name: '4'
+							},
+							{
+								tit: '其他设置',
+								name: '5'
+							},
+						];
+						break;
+					case 2:
+						this.formValidate.virtual_type = 2;
+						this.formValidate.is_virtual = 1;
+						this.headTab = [{
+								tit: '基础信息',
+								name: '1'
+							},
+							{
+								tit: '规格库存',
+								name: '2'
+							},
+							{
+								tit: '商品详情',
+								name: '3'
+							},
+							// { tit: "物流设置", name: "4" },
+							{
+								tit: '营销设置',
+								name: '4'
+							},
+							{
+								tit: '其他设置',
+								name: '5'
+							},
+						];
+						break;
+					case 3:
+						this.formValidate.virtual_type = 3;
+						this.formValidate.is_virtual = 1;
+						this.headTab = [{
+								tit: '基础信息',
+								name: '1'
+							},
+							{
+								tit: '规格库存',
+								name: '2'
+							},
+							{
+								tit: '商品详情',
+								name: '3'
+							},
+							// { tit: "物流设置", name: "4" },
+							{
+								tit: '营销设置',
+								name: '4'
+							},
+							{
+								tit: '其他设置',
+								name: '5'
+							},
+						];
+						break;
+				}
+			},
+			// 新增分类
+			addCate() {
+				this.$modalForm(productCreateApi()).then(() => this.goodsCategory());
+			},
+			// 物流方式选择
+			logisticsBtn(e) {
+				this.formValidate.logistics = e;
+			},
+			// 新增标签
+			addLabel() {
+				this.$modalForm(userLabelAddApi(0)).then(() => this.userLabel());
+			},
+			// 自定义留言 开启关闭
+			customMessBtn(e) {
+				if (!e) {
+					this.formValidate.custom_form = [];
+				}
+			},
+			// 自定义留言 新增表单
+			addcustom() {
+				if (this.formValidate.custom_form.length > 9) {
+					this.$Message.warning('最多添加10条');
+				} else {
+					this.formValidate.custom_form.push({
+						title: '',
+						label: 'text',
+						value: '',
+						status: false,
+					});
+				}
+			},
+			// 删除
+			delcustom(index) {
+				this.formValidate.custom_form.splice(index, 1);
+			},
+			// 预售具体日期
+			onchangeTime(e) {
+				this.formValidate.presale_time = e;
+			},
+			// 商品详情
+			getEditorContent(data) {
+				this.content = data;
+			},
+			cancel() {
+				this.$router.push({
+					path: this.$routeProStrshop + '/product/product_list'
+				});
+			},
+			// 上传头部token
+			getToken() {
+				this.header['Authori-zation'] = 'Bearer ' + getCookies('token');
+			},
+			// 导入卡密
+			upFile(res) {
+				importCard({
+					file: res.data.src
+				}).then((res) => {
+					this.virtualList = this.virtualList.concat(res.data);
+				});
+			},
+			//获取视频上传类型
+			uploadType() {
+				uploadType().then((res) => {
+					this.upload_type = res.data.upload_type;
+				});
+			},
+			// 初始化数据展示
+			infoData(data) {
+				let cate_id = data.cate_id.map(Number);
+				let label_id = data.label_id.map(Number);
+				this.attrs = data.items || [];
+				let ids = [];
+				data.coupons.map((item) => {
+					ids.push(item.id);
+				});
+				this.formValidate = data;
+				this.seletVideo = data.seletVideo;
+				this.contents = data.description;
+				this.couponName = data.coupons;
+				this.formValidate.coupon_ids = ids;
+				this.updateIds = ids;
+				this.dataLabel = data.label_id;
+				this.updateName = data.coupons;
+				this.virtualbtn(data.virtual_type, 1);
+				this.formValidate.logistics = data.logistics || ['1'];
+				this.formValidate.custom_form = data.custom_form || [];
+				if (this.formValidate.custom_form.length != 0) {
+					this.customBtn = true;
+				}
+				this.formValidate.cate_id = cate_id;
+				if (data.attr) {
+					this.oneFormValidate = [data.attr];
+				}
+				this.formValidate.header = [];
+				this.generate(0);
+				// this.manyFormValidate = data.attrs;
+				this.$set(this, 'manyFormValidate', data.attrs);
+				this.spec_type = data.spec_type;
+				this.formValidate.is_virtual = data.is_virtual;
+				if (data.spec_type === 0) {
+					this.manyFormValidate = [];
+				} else {
+					this.createBnt = true;
+					this.oneFormValidate = [{
+						pic: '',
+						price: 0,
+						cost: 0,
+						ot_price: 0,
+						stock: 0,
+						bar_code: '',
+						weight: 0,
+						volume: 0,
+						brokerage: 0,
+						brokerage_two: 0,
+						vip_price: 0,
+						virtual_list: [],
+						coupon_id: 0,
+					}, ];
+				}
+			},
+			//关闭淘宝弹窗并生成数据;
+			onClose(data) {
+				this.modals = false;
+				this.infoData(data);
+			},
+
+			checkMove(evt) {
+				this.moveIndex = evt.draggedContext.index;
+			},
+			end() {
+				this.moveIndex = '';
+				this.generate(1);
+			},
+			// 单独设置会员设置
+			checkAllGroupChange(data) {
+				this.checkAllGroup(data);
+			},
+			checkAllGroup(data) {
+				if (this.formValidate.spec_type === 0) {
+					if (data.indexOf(0) > -1) {
+						this.columnsInstall = this.columns2.slice(0, 4).concat(this.member);
+					} else if (data.indexOf(1) > -1) {
+						this.columnsInstall = this.columns2.slice(0, 4).concat(this.rakeBack);
+					} else {
+						this.columnsInstall = this.columns2.slice(0, 4);
+					}
+					if (data.length === 2) {
+						this.columnsInstall = this.columns2.slice(0, 4).concat(this.rakeBack).concat(this.member);
+					}
+				} else {
+					if (data.indexOf(0) > -1) {
+						this.columnsInstal2 = this.columnsInstalM.slice(0, 4).concat(this.member);
+					} else if (data.indexOf(1) > -1) {
+						this.columnsInstal2 = this.columnsInstalM.slice(0, 4).concat(this.rakeBack);
+					} else {
+						this.columnsInstal2 = this.columnsInstalM.slice(0, 4);
+					}
+					if (data.length === 2) {
+						this.columnsInstal2 = this.columnsInstalM.slice(0, 4).concat(this.rakeBack).concat(this.member);
+					}
+				}
+			},
+			// 添加优惠券
+			addCoupon() {
+				this.$refs.couponTemplates.isTemplate = true;
+				this.$refs.couponTemplates.tableList();
+			},
+			// 规格中优惠券查看
+			see(data, name, index) {
+				this.tabName = name;
+				this.tabIndex = index;
+
+				if (this.formValidate.virtual_type === 1) {
+					if (data.disk_info != '') {
+						this.disk_type = 1;
+						this.disk_info = data.disk_info;
+						this.stock = data.stock;
+					} else if (data.virtual_list.length) {
+						this.disk_type = 2;
+						this.virtualList = data.virtual_list;
+					}
+					this.addVirtualModel = true;
+				} else {
+					this.$refs.goodsCoupon.isTemplate = true;
+					this.$refs.goodsCoupon.tableList(3);
+				}
+			},
+			// 添加优惠券
+			addGoodsCoupon(index, name) {
+				this.tabIndex = index;
+				this.tabName = name;
+				this.$refs.goodsCoupon.isTemplate = true;
+				this.$refs.goodsCoupon.tableList(3);
+			},
+			addVirtual(index, name) {
+				this.tabIndex = index;
+				this.tabName = name;
+				this.addVirtualModel = true;
+			},
+			// 提交卡密信息
+			upVirtual() {
+				if (this.disk_type == 2) {
+					for (let i = 0; i < this.virtualList.length; i++) {
+						const element = this.virtualList[i];
+						if (!element.value) {
+							this.$Message.error('请输入所有卡密');
+							return;
+						}
+					}
+					this.$set(this[this.tabName][this.tabIndex], 'virtual_list', this.virtualList);
+					this.$set(this[this.tabName][this.tabIndex], 'stock', this.virtualList.length);
+					this.virtualList = [{
+						key: '',
+						value: '',
+					}, ];
+					this.$set(this[this.tabName][this.tabIndex], 'disk_info', '');
+				} else {
+					if (!this.disk_info.length) {
+						return this.$Message.error('请填写卡密信息');
+					}
+					if (!this.stock) {
+						return this.$Message.error('请填写库存数量');
+					}
+					this.$set(this[this.tabName][this.tabIndex], 'stock', Number(this.stock));
+					this.$set(this[this.tabName][this.tabIndex], 'stock', Number(this.stock));
+					this.$set(this[this.tabName][this.tabIndex], 'disk_info', this.disk_info);
+					this.$set(this[this.tabName][this.tabIndex], 'virtual_list', []);
+				}
+				this.addVirtualModel = false;
+				this.closeVirtual();
+			},
+			//  初始化卡密数据信息
+			closeVirtual() {
+				this.addVirtualModel = false;
+				this.virtualList = [{
+					key: '',
+					value: '',
+				}, ];
+				this.disk_info = '';
+				this.stock = 0;
+			},
+			//对象数组去重;
+			unique(arr) {
+				const res = new Map();
+				return arr.filter((arr) => !res.has(arr.id) && res.set(arr.id, 1));
+			},
+			// 获取优惠券id数据
+			nameId(id, names) {
+				this.formValidate.coupon_ids = id;
+				this.couponName = this.unique(names);
+			},
+			// 获取优惠券信息
+			goodsCouponId(data) {
+				// this[this.tabName][this.tabIndex].coupon_id = data.id;
+				// this[this.tabName][this.tabIndex].coupon_name = data.title;
+				this.$set(this[this.tabName][this.tabIndex], 'coupon_id', data.id);
+				this.$set(this[this.tabName][this.tabIndex], 'coupon_name', data.title);
+				this.$refs.goodsCoupon.isTemplate = false;
+			},
+			handleClose(name) {
+				let index = this.couponName.indexOf(name);
+				this.couponName.splice(index, 1);
+				let couponIds = this.formValidate.coupon_ids;
+				couponIds.splice(index, 1);
+				this.updateIds = couponIds;
+				this.updateName = this.couponName;
+			},
+			// 运费模板
+			getList() {
+				this.productGetTemplate();
+			},
+			// 添加运费模板
+			addTemp() {
+				this.$refs.templates.isTemplate = true;
+			},
+			// 删除视频;
+			delVideo() {
+				let that = this;
+				that.$set(that.formValidate, 'video_link', '');
+				that.$set(that, 'progress', 0);
+				that.videoIng = false;
+				that.upload.videoIng = false;
+			},
+			zh_uploadFile() {
+				if (this.seletVideo == 1) {
+					this.formValidate.video_link = this.videoLink;
+				} else {
+					this.$refs.refid.click();
+				}
+			},
+			// 上传视频
+			zh_uploadFile_change(evfile) {
+				let that = this;
+				let suffix = evfile.target.files[0].name.substr(evfile.target.files[0].name.indexOf('.'));
+				if (suffix.indexOf('.mp4') === -1) {
+					return that.$Message.error('只能上传MP4文件');
+				}
+				productGetTempKeysApi()
+					.then((res) => {
+						that.$videoCloud
+							.videoUpload({
+								type: res.data.type,
+								evfile: evfile,
+								res: res,
+								uploading(status, progress) {
+									that.upload.videoIng = status;
+									if (res.status == 200) {
+										that.progress = 100;
+									}
+								},
+							})
+							.then((res) => {
+								that.formValidate.video_link = res.url;
+								that.$Message.success('视频上传成功');
+								that.upload.videoIng = false;
+							})
+							.catch((res) => {
+								that.$Message.error(res);
+							});
+					})
+					.catch((res) => {
+						that.$Message.error(res.msg);
+					});
+			},
+			// 上一页;
+			upTab() {
+				this.currentTab = (Number(this.currentTab) - 1).toString();
+			},
+			// 下一页;
+			downTab() {
+				this.currentTab = (Number(this.currentTab) + 1).toString();
+			},
+			// 属性弹窗回调函数;
+			userSearchs() {
+				this.productGetRule();
+			},
+			// 添加规则;
+			addRule() {
+				this.$refs.addattr.modal = true;
+			},
+			// 批量设置分佣;
+			brokerageSetUp() {
+				let that = this;
+				if (that.formValidate.is_sub.indexOf(1) > -1) {
+					if (that.manyBrokerage <= 0 || that.manyBrokerageTwo <= 0) {
+						return that.$Message.error('请填写返佣金额后进行批量添加');
+					}
+				} else if (that.formValidate.is_sub.indexOf(0) > -1) {
+					if (that.manyVipPrice <= 0) {
+						return that.$Message.error('请填写会员价后进行批量添加');
+					}
+				}
+				if (this.formValidate.is_sub.length === 2) {
+					if (that.manyBrokerage <= 0 || that.manyBrokerageTwo <= 0 || that.manyVipPrice <= 0) {
+						return that.$Message.error('请填写完金额后进行批量添加');
+					}
+				}
+				for (let val of that.manyFormValidate) {
+					this.$set(val, 'brokerage', that.manyBrokerage);
+					this.$set(val, 'brokerage_two', that.manyBrokerageTwo);
+					this.$set(val, 'vip_price', that.manyVipPrice);
+				}
+			},
+			// 批量设置会员价
+			vipPriceSetUp() {
+				let that = this;
+				if (that.manyVipPrice <= 0) {
+					return that.$Message.error('请填写会员价在进行批量添加');
+				} else {
+					for (let val of that.manyFormValidate) {
+						this.$set(val, 'vip_price', that.manyVipPrice);
+					}
+				}
+			},
+			// 新增卡密
+			handleAdd() {
+				this.virtualList.push({
+					key: '',
+					value: '',
+				});
+			},
+			// 初始化卡密信息
+			initVirtualData(status) {
+				if (!status) {
+					this.virtualList = [{
+						key: '',
+						value: '',
+					}, ];
+				}
+			},
+			removeVirtual(index) {
+				this.virtualList.splice(index, 1);
+			},
+			// 清空批量规格信息
+			batchDel() {
+				this.oneFormBatch = [{
+					pic: '',
+					price: 0,
+					cost: 0,
+					ot_price: 0,
+					stock: 0,
+					bar_code: '',
+					weight: 0,
+					volume: 0,
+				}, ];
+			},
+			confirm() {
+				let that = this;
+				that.createBnt = true;
+				if (that.formValidate.selectRule.trim().length <= 0) {
+					return that.$Message.error('请选择属性');
+				}
+				that.ruleList.forEach(function(item, index) {
+					if (item.rule_name === that.formValidate.selectRule) {
+						that.attrs = item.rule_value;
+					}
+				});
+			},
+			// 获取商品属性模板;
+			productGetRule() {
+				productGetRuleApi().then((res) => {
+					this.ruleList = res.data;
+				});
+			},
+			// 获取运费模板;
+			productGetTemplate() {
+				productGetTemplateApi().then((res) => {
+					this.templateList = res.data;
+				});
+			},
+			// 删除表格中的属性
+			delAttrTable(index) {
+				let id = this.$route.params.id;
+				if (id) {
+					checkActivityApi(id)
+						.then((res) => {
+							this.manyFormValidate.splice(index, 1);
+							this.$Message.success(res.msg);
+						})
+						.catch((res) => {
+							this.$Message.error(res.msg);
+						});
+				} else {
+					this.manyFormValidate.splice(index, 1);
+				}
+			},
+			// 批量添加
+			batchAdd() {
+				for (let val of this.manyFormValidate) {
+					if (this.oneFormBatch[0].pic) {
+						this.$set(val, 'pic', this.oneFormBatch[0].pic);
+					}
+					if (this.oneFormBatch[0].price > 0) {
+						this.$set(val, 'price', this.oneFormBatch[0].price);
+					}
+					if (this.oneFormBatch[0].cost > 0) {
+						this.$set(val, 'cost', this.oneFormBatch[0].cost);
+					}
+					if (this.oneFormBatch[0].ot_price > 0) {
+						this.$set(val, 'ot_price', this.oneFormBatch[0].ot_price);
+					}
+					if (this.oneFormBatch[0].stock > 0) {
+						this.$set(val, 'stock', this.oneFormBatch[0].stock);
+					}
+					if (this.oneFormBatch[0].bar_code !== '') {
+						this.$set(val, 'bar_code', this.oneFormBatch[0].bar_code);
+					}
+					if (this.oneFormBatch[0].weight > 0) {
+						this.$set(val, 'weight', this.oneFormBatch[0].weight);
+					}
+					if (this.oneFormBatch[0].volume > 0) {
+						this.$set(val, 'volume', this.oneFormBatch[0].volume);
+					}
+				}
+			},
+			// 添加按钮
+			addBtn() {
+				this.clearAttr();
+				this.createBnt = false;
+				this.showIput = true;
+			},
+			// 立即生成
+			generate(type) {
+				generateAttrApi({
+							attrs: this.attrs,
+							is_virtual: [1, 2].includes(this.formValidate.virtual_type) ? 1 : 0,
+							virtual_type: this.formValidate.virtual_type,
+						},
+						this.formValidate.id,
+						type,
+					)
+					.then((res) => {
+						let info = res.data.info,
+							header1 = JSON.parse(JSON.stringify(info.header));
+						if (this.$route.params.id !== '0' && (this.$route.query.type != -1 || type)) {
+							this.manyFormValidate = info.value;
+						}
+						let header = info.header;
+						if ([1, 2].includes(this.formValidate.virtual_type)) {
+							this.columnsInstalM = header;
+							this.formValidate.header = header;
+						} else {
+							this.formValidate.header = header1;
+							this.columnsInstalM = info.header;
+						}
+						this.checkAllGroup(this.formValidate.is_sub);
+						if (!this.$route.params.id && this.formValidate.spec_type === 1) {
+							this.manyFormValidate.map((item) => {
+								item.pic = this.formValidate.image;
+							});
+							this.oneFormBatch[0].pic = this.formValidate.image;
+						} else if (this.$route.params.id) {
+							this.manyFormValidate.map((item) => {
+								if (!item.pic) {
+									item.pic = this.formValidate.image;
+								}
+							});
+							this.oneFormBatch[0].pic = this.formValidate.image;
+						}
+					})
+					.catch((res) => {
+						this.$Message.error(res.msg);
+					});
+			},
+			// 取消
+			offAttrName() {
+				this.showIput = false;
+				this.createBnt = true;
+			},
+			clearAttr() {
+				this.formDynamic.attrsName = '';
+				this.formDynamic.attrsVal = '';
+			},
+			// 删除规格
+			handleRemoveRole(index) {
+				this.attrs.splice(index, 1);
+				this.manyFormValidate.splice(index, 1);
+			},
+			// 删除属性
+			handleRemove2(item, index) {
+				item.splice(index, 1);
+			},
+			// 添加规则名称
+			createAttrName() {
+				if (this.formDynamic.attrsName && this.formDynamic.attrsVal) {
+					let data = {
+						value: this.formDynamic.attrsName,
+						detail: [this.formDynamic.attrsVal],
+					};
+					this.attrs.push(data);
+					var hash = {};
+					this.attrs = this.attrs.reduce(function(item, next) {
+						/* eslint-disable */
+						hash[next.value] ? '' : (hash[next.value] = true && item.push(next));
+						return item;
+					}, []);
+					this.clearAttr();
+					this.showIput = false;
+					this.createBnt = true;
+				} else {
+					this.$Message.warning('请添加完整的规格!');
+				}
+			},
+			// 添加属性
+			createAttr(num, idx) {
+				if (num) {
+					this.attrs[idx].detail.push(num);
+					var hash = {};
+					this.attrs[idx].detail = this.attrs[idx].detail.reduce(function(item, next) {
+						/* eslint-disable */
+						hash[next] ? '' : (hash[next] = true && item.push(next));
+						return item;
+					}, []);
+				} else {
+					this.$Message.warning('请添加属性');
+				}
+			},
+			// 商品分类;
+			goodsCategory() {
+				cascaderListApi(1)
+					.then((res) => {
+						this.treeSelect = res.data;
+					})
+					.catch((res) => {
+						this.$Message.error(res.msg);
+					});
+			},
+			//视视上传类型
+			changeVideo(e) {
+				this.formValidate.video_link = '';
+				this.videoLink = '';
+			},
+			// 改变规格
+			changeSpec() {
+				this.formValidate.is_sub = [];
+				let id = this.$route.params.id;
+				if (id) {
+					checkActivityApi(id)
+						.then((res) => {})
+						.catch((res) => {
+							this.formValidate.spec_type = this.spec_type;
+							this.$Message.error(res.msg);
+						});
+				}
+			},
+			// 详情
+			getInfo() {
+				let that = this;
+				that.spinShow = true;
+				productInfoApi(that.$route.params.id)
+					.then(async (res) => {
+						let data = res.data.productInfo;
+						this.infoData(data);
+						this.spinShow = false;
+					})
+					.catch((res) => {
+						this.spinShow = false;
+						this.$Message.error(res.msg);
+					});
+			},
+			// tab切换
+			onhangeTab(name) {
+				this.currentTab = name;
+			},
+			handleRemove(i) {
+				this.images.splice(i, 1);
+				this.formValidate.slider_image.splice(i, 1);
+				this.oneFormValidate[0].pic = this.formValidate.slider_image[0];
+			},
+			// 关闭图片上传模态框
+			changeCancel(msg) {
+				this.modalPic = false;
+			},
+			// 点击商品图
+			modalPicTap(tit, picTit, index) {
+				this.modalPic = true;
+				this.isChoice = tit === 'dan' ? '单选' : '多选';
+				this.picTit = picTit;
+				this.tableIndex = index;
+			},
+			// 获取单张图片信息
+			getPic(pc) {
+				switch (this.picTit) {
+					case 'danFrom':
+						this.formValidate.image = pc.att_dir;
+						if (!this.$route.params.id) {
+							if (this.formValidate.spec_type === 0) {
+								this.oneFormValidate[0].pic = pc.att_dir;
+							} else {
+								this.manyFormValidate.map((item) => {
+									item.pic = pc.att_dir;
+								});
+								this.oneFormBatch[0].pic = pc.att_dir;
+							}
+						}
+						break;
+					case 'danTable':
+						this.oneFormValidate[this.tableIndex].pic = pc.att_dir;
+						break;
+					case 'duopi':
+						this.oneFormBatch[this.tableIndex].pic = pc.att_dir;
+						break;
+					case 'recommend_image':
+						this.formValidate.recommend_image = pc.att_dir;
+						break;
+					default:
+						this.manyFormValidate[this.tableIndex].pic = pc.att_dir;
+				}
+				this.modalPic = false;
+			},
+			// 获取多张图信息
+			getPicD(pc) {
+				this.images = pc;
+				this.images.map((item) => {
+					this.formValidate.slider_image.push(item.att_dir);
+					this.formValidate.slider_image = this.formValidate.slider_image.splice(0, 10);
+				});
+				this.oneFormValidate[0].pic = this.formValidate.slider_image[0];
+				this.modalPic = false;
+			},
+			// 提交
+			handleSubmit(name) {
+				this.$refs[name].validate((valid) => {
+					if (valid) {
+						this.formValidate.type = this.type;
+						if (this.formValidate.spec_type === 0) {
+							this.formValidate.attrs = this.oneFormValidate;
+							this.formValidate.header = [];
+							this.formValidate.items = [];
+							this.formValidate.is_copy = 0;
+						} else {
+							this.formValidate.items = this.attrs;
+							this.formValidate.attrs = this.manyFormValidate;
+							this.formValidate.is_copy = 1;
+						}
+						if (this.formValidate.spec_type === 1 && this.manyFormValidate.length === 0) {
+							return this.$Message.warning('商品信息-请点击生成多规格');
+							// return this.$Message.warning('请点击生成规格!');
+						}
+						let item = this.formValidate.attrs;
+						for (let i = 0; i < item.length; i++) {
+							if (item[i].stock > 1000000) {
+								return this.$Message.error('规格库存-库存超出系统范围(1000000)');
+							}
+						}
+						if (this.formValidate.is_sub[0] === 1) {
+							for (let i = 0; i < item.length; i++) {
+								if (item[i].brokerage === null || item[i].brokerage_two === null) {
+									return this.$Message.error('营销设置- 一二级返佣不能为空');
+								}
+							}
+						} else {
+							for (let i = 0; i < item.length; i++) {
+								if (item[i].vip_price === null) {
+									return this.$Message.error('营销设置-会员价不能为空');
+								}
+							}
+						}
+						if (this.formValidate.is_sub.length === 2) {
+							for (let i = 0; i < item.length; i++) {
+								if (item[i].brokerage === null || item[i].brokerage_two === null || item[i]
+									.vip_price === null) {
+									return this.$Message.error('营销设置- 一二级返佣和会员价不能为空');
+								}
+							}
+						}
+						if (this.formValidate.freight == 3 && !this.formValidate.temp_id) {
+							return this.$Message.warning('商品信息-运费模板不能为空');
+						}
+						let activeIds = [];
+						this.dataLabel.forEach((item) => {
+							activeIds.push(item.id);
+						});
+						this.formValidate.label_id = activeIds;
+						this.openSubimit = true;
+						this.formValidate.description = this.formatRichText(this.content);
+						productAddApi(this.formValidate)
+							.then(async (res) => {
+								this.openSubimit = false;
+								this.$Message.success(res.msg);
+								if (this.$route.params.id === '0') {
+									cacheDelete().catch((err) => {
+										this.$Message.error(err.msg);
+									});
+								}
+								setTimeout(() => {
+									this.openSubimit = false;
+									this.$router.push({
+										path: this.$routeProStrshop +
+											'/product/product_list'
+									});
+								}, 500);
+							})
+							.catch((res) => {
+								setTimeout((e) => {
+									this.openSubimit = false;
+								}, 1000);
+								this.$Message.error(res.msg);
+							});
+					} else {
+						if (!this.formValidate.store_name) {
+							return this.$Message.warning('商品信息-商品名称不能为空');
+						} else if (!this.formValidate.cate_id.length) {
+							return this.$Message.warning('商品信息-商品分类不能为空');
+						} else if (!this.formValidate.unit_name) {
+							return this.$Message.warning('商品信息-商品单位不能为空');
+						} else if (!this.formValidate.slider_image.length) {
+							return this.$Message.warning('商品信息-商品轮播图不能为空');
+						} else if (!this.formValidate.logistics.length && !this.formValidate.virtual_type) {
+							return this.$Message.warning('物流设置-至少选择一种物流方式');
+						} else if (!this.formValidate.temp_id && this.formValidate.freight == 3) {
+							return this.$Message.warning('商品信息-运费模板不能为空');
+						}
+					}
+				});
+			},
+			changeTemplate(msg) {
+				this.template = msg;
+			},
+			// 表单验证
+			validate(prop, status, error) {
+				if (status === false) {
+					this.$Message.warning(error);
+				}
+			},
+			// 移动
+			handleDragStart(e, item) {
+				this.dragging = item;
+			},
+			handleDragEnd(e, item) {
+				this.dragging = null;
+			},
+			handleDragOver(e) {
+				e.dataTransfer.dropEffect = 'move';
+			},
+			handleDragEnter(e, item) {
+				e.dataTransfer.effectAllowed = 'move';
+				if (item === this.dragging) {
+					return;
+				}
+				const newItems = [...this.formValidate.slider_image];
+				const src = newItems.indexOf(this.dragging);
+				const dst = newItems.indexOf(item);
+				newItems.splice(dst, 0, ...newItems.splice(src, 1));
+				this.formValidate.slider_image = newItems;
+			},
+			// 过滤详情内容
+			formatRichText(html) {
+				let newContent = html.replace(/<img[^>]*>/gi, function(match, capture) {
+					match = match.replace(/style="[^"]+"/gi, '').replace(/style='[^']+'/gi, '');
+					match = match.replace(/width="[^"]+"/gi, '').replace(/width='[^']+'/gi, '');
+					match = match.replace(/height="[^"]+"/gi, '').replace(/height='[^']+'/gi, '');
+					return match;
+				});
+				newContent = newContent.replace(/style="[^"]+"/gi, function(match, capture) {
+					match = match.replace(/width:[^;]+;/gi, 'max-width:100%;').replace(/width:[^;]+;/gi,
+						'max-width:100%;');
+					return match;
+				});
+				newContent = newContent.replace(/<br[^>]*\/>/gi, '');
+				newContent = newContent.replace(
+					/\<img/gi,
+					'<img style="max-width:100%;height:auto;display:block;margin-top:0;margin-bottom:0;"',
+				);
+				return newContent;
+			},
+			// 商品id
+			getProductId(row) {
+				this.goods_modals = false;
+				let arr = this.formValidate.recommend_list.concat(row);
+				this.formValidate.recommend_list = this.uniques(arr);
+			},
+			// 选择推荐商品
+			changeGoods() {
+				this.goods_modals = true;
+				this.$refs.goodslist.getList();
+				this.$refs.goodslist.goodsCategory();
+			},
+			// 选择用户标签
+			activeData(dataLabel) {
+				this.labelShow = false;
+				this.dataLabel = dataLabel;
+			},
+			// 标签弹窗关闭
+			labelClose() {
+				this.labelShow = false;
+			},
+			// 删除用户标签
+			closeLabel(label) {
+				let index = this.dataLabel.indexOf(this.dataLabel.filter((d) => d.id == label.id)[0]);
+				this.dataLabel.splice(index, 1);
+			},
+			// 打开选择用户标签
+			openLabel(row) {
+				this.labelShow = true;
+				this.$refs.userLabel.userLabel(JSON.parse(JSON.stringify(this.dataLabel)));
+			},
+			uniques(songs) {
+				let result = {};
+				let finalResult = [];
+				for (let i = 0; i < songs.length; i++) {
+					result[songs[i].product_id] = songs[i];
+				}
+				for (let item in result) {
+					finalResult.push(result[item]);
+				}
+				return finalResult;
+			},
+			handleRemoveRecommend(i) {
+				this.formValidate.recommend_list.splice(i, 1);
+			},
+		},
+	};
+</script>
+<style scoped lang="stylus">
+	.list-group {
+		margin-left: -8px;
+	}
+
+	.borderStyle {
+		border: 1px solid #ccc;
+		padding: 8px;
+		border-radius: 4px;
+	}
+
+	.drag {
+		cursor: move;
+	}
+
+	.move-icon {
+		width: 30px;
+		cursor: move;
+		margin-right: 10px;
+	}
+
+	.move-icon .icondrag2 {
+		font-size: 26px;
+		color: #d8d8d8;
+	}
+
+	.maxW /deep/.ivu-select-dropdown {
+		max-width: 600px;
+	}
+
+	#shopp-manager .ivu-table-wrapper {
+		border-left: 1px solid #dcdee2;
+		border-top: 1px solid #dcdee2;
+	}
+
+	.noLeft {
+		>>>.ivu-form-item-content {
+			margin-left: 0 !important;
+		}
+	}
+
+	#shopp-manager .ivu-form-item {
+		position: relative;
+	}
+
+	#shopp-manager .ivu-form-item .tips {
+		position: absolute;
+		color: #999;
+		top: 29px;
+		left: -77px;
+		font-size: 12px;
+	}
+
+	.iview-video-style {
+		width: 40%;
+		height: 180px;
+		border-radius: 10px;
+		background-color: #707070;
+		margin-top: 10px;
+		position: relative;
+		overflow: hidden;
+	}
+
+	.iview-video-style .iconv {
+		color: #fff;
+		line-height: 180px;
+		width: 50px;
+		height: 50px;
+		display: inherit;
+		font-size: 26px;
+		position: absolute;
+		top: -74px;
+		left: 50%;
+		margin-left: -25px;
+	}
+
+	.iview-video-style .mark {
+		position: absolute;
+		width: 100%;
+		height: 30px;
+		top: 0;
+		background-color: rgba(0, 0, 0, 0.5);
+		text-align: center;
+	}
+
+	.submission {
+		margin-left: 10px;
+	}
+
+	.color-list .tip {
+		color: #c9c9c9;
+	}
+
+	.color-list .color-item {
+		height: 30px;
+		line-height: 30px;
+		padding: 0 10px;
+		color: #fff;
+		margin-right: 10px;
+	}
+
+	.color-list .color-item.blue {
+		background-color: #1E9FFF;
+	}
+
+	.color-list .color-item.yellow {
+		background-color: rgb(254, 185, 0);
+	}
+
+	.color-list .color-item.green {
+		background-color: #009688;
+	}
+
+	.color-list .color-item.red {
+		background-color: #ed4014;
+	}
+
+	.columnsBox {
+		margin-right: 10px;
+	}
+
+	.priceBox {
+		width: 100%;
+	}
+
+	.rulesBox {
+		display: flex;
+		flex-wrap: wrap;
+	}
+
+	.pictrueBox {
+		display: inline-block;
+	}
+
+	.pictrueTab {
+		width: 40px !important;
+		height: 40px !important;
+	}
+
+	.pictrue {
+		width: 60px;
+		height: 60px;
+		border: 1px dotted rgba(0, 0, 0, 0.1);
+		margin-right: 15px;
+		display: inline-block;
+		position: relative;
+		cursor: pointer;
+
+		img {
+			width: 100%;
+			height: 100%;
+		}
+
+		.btndel {
+			position: absolute;
+			z-index: 1;
+			width: 20px !important;
+			height: 20px !important;
+			left: 46px;
+			top: -4px;
+		}
+	}
+
+	.upLoad {
+		width: 58px;
+		height: 58px;
+		line-height: 58px;
+		border: 1px dotted rgba(0, 0, 0, 0.1);
+		border-radius: 4px;
+		background: rgba(0, 0, 0, 0.02);
+		cursor: pointer;
+	}
+
+	.curs {
+		cursor: pointer;
+	}
+
+	.inpWith {
+		width: 60%;
+	}
+
+	.labeltop {
+		>>>.ivu-form-item-label {
+			float: none !important;
+			display: inline-block !important;
+			margin-left: 120px !important;
+			width: auto !important;
+		}
+	}
+
+	.video-icon {
+		background-image: url('https://cdn.oss.9gt.net/prov1.1/1/icons.png'); // cdn.oss.9gt.net/prov1.1/1/icons.png);
+		background-color: #fff;
+		background-position: -9999px;
+		background-repeat: no-repeat;
+	}
+
+	.see {
+		color: #2d8cf0;
+		cursor: pointer;
+	}
+
+	.trip {
+		color: #bbb;
+		margin-bottom: 10px;
+	}
+
+	.virtual-data {
+		display: flex;
+		align-items: center;
+	}
+
+	.add-more {
+		margin-top: 20px;
+		display: flex;
+	}
+
+	.virtual-title {
+		width: 50px;
+	}
+
+	.scroll-virtual {
+		max-height: 400px;
+		overflow-y: auto;
+		margin-top: 10px;
+	}
+
+	.footer {
+		width: 100%;
+		display: flex;
+		align-items: center;
+		justify-content: center;
+		margin-top: 30px;
+
+		.clear,
+		.submit {
+			padding: 10px 20px;
+			border-radius: 5px;
+			color: #fff;
+			cursor: pointer;
+		}
+
+		.clear {
+			background-color: #ccc;
+			margin-right: 20px;
+		}
+
+		.submit {
+			background-color: #2d8cf0;
+		}
+	}
+
+	.picBox {
+		display: flex;
+	}
+
+	.btndel {
+		position: absolute;
+		z-index: 9;
+		width: 20px !important;
+		height: 20px !important;
+		left: 46px;
+		top: -4px;
+	}
+
+	.ifam {
+		width: 344px;
+		height: 644px;
+		background: url('../../../assets/images/phonebg.png') no-repeat center top;
+		background-size: 344px 644px;
+		padding: 40px 20px;
+		padding-top: 50px;
+		margin: 0 auto;
+
+		.content {
+			height: 560px;
+			overflow: hidden;
+			scrollbar-width: none;
+			/* firefox */
+			-ms-overflow-style: none;
+			/* IE 10+ */
+			overflow-x: hidden;
+			overflow-y: auto;
+		}
+
+		.content::-webkit-scrollbar {
+			display: none;
+			/* Chrome Safari */
+		}
+	}
+</style>
+<style scoped lang="stylus">
+	/deep/.ivu-date-picker {
+		width: 300px;
+	}
+
+	.virtual_boder {
+		border: 1px solid #1890FF;
+	}
+
+	.virtual_boder2 {
+		border: 1px solid #E7E7E7;
+	}
+
+	.virtual_san {
+		position: absolute;
+		bottom: 0;
+		right: 0;
+		width: 0;
+		height: 0;
+		border-bottom: 26px solid #1890FF;
+		border-left: 26px solid transparent;
+	}
+
+	.virtual_dui {
+		position: absolute;
+		bottom: -2px;
+		right: 2px;
+		color: #FFFFFF;
+		font-family: system-ui;
+	}
+
+	.virtual {
+		width: 120px;
+		height: 60px;
+		background: #FFFFFF;
+		border-radius: 3px;
+		// border: 1px solid #E7E7E7;
+		float: left;
+		text-align: center;
+		padding-top: 8px;
+		position: relative;
+		cursor: pointer;
+		line-height: 23px;
+
+		.virtual_top {
+			font-size: 14px;
+			font-weight: 600;
+			color: rgba(0, 0, 0, 0.85);
+		}
+
+		.virtual_bottom {
+			font-size: 12px;
+			font-weight: 400;
+			color: #999999;
+		}
+	}
+
+	.virtual:nth-child(2n) {
+		margin: 0 12px;
+	}
+
+	.addfont {
+		display: inline-block;
+		font-size: 13px;
+		font-weight: 400;
+		color: #1890FF;
+		margin-left: 14px;
+		cursor: pointer;
+	}
+
+	.titTip {
+		display: inline-bolck;
+		font-size: 12px;
+		line-height: 24px;
+		font-weight: 400;
+		color: #999999;
+	}
+
+	.videbox {
+		width: 60px;
+		height: 60px;
+		background: rgba(0, 0, 0, 0.02);
+		border-radius: 4px;
+		border: 1px dashed #DDDDDD;
+		line-height: 50px;
+		text-align: center;
+		color: #898989;
+		font-size: 30px;
+		font-weight: 400;
+		cursor: pointer;
+	}
+
+	.addCustom_content {
+		margin-top: 20px;
+
+		.custom_box {
+			margin-bottom: 10px;
+		}
+	}
+
+	.addCustomBox {
+		margin-top: 12px;
+		font-size: 13px;
+		font-weight: 400;
+		color: #1890FF;
+
+		.btn {
+			cursor: pointer;
+			width: max-content;
+		}
+	}
+
+	.type-radio {
+		margin-buttom: 10px;
+	}
+
+	.deteal-btn {
+		color: #5179ea;
+	}
+
+	.stock-disk {
+		margin: 10px 0;
+	}
+
+	.line {
+		border-bottom: 1px dashed #eee;
+		margin-bottom: 20px;
+	}
+
+	.labelInput {
+		border: 1px solid #dcdee2;
+		width: 20%;
+		padding: 0 5px;
+		border-radius: 5px;
+		min-height: 30px;
+		cursor: pointer;
+
+		.span {
+			color: #c5c8ce;
+		}
+
+		.iconxiayi {
+			font-size: 12px;
+		}
+	}
+
+	#shopp-manager /deep/.ivu-form-item-content {
+		line-height: 33px !important;
+	}
+
+	#selectvideo /deep/.ivu-form-item-content {
+		line-height: 0px !important;
+	}
+
+	.progress {
+		margin-top: 10px;
+	}
+</style>

+ 132 - 0
src/pages/shop_product/productAdd/taoBao.vue

@@ -0,0 +1,132 @@
+<template>
+	<div class="Box">
+		<!-- <Card>
+      <div>
+        生成的商品默认是没有上架的,请手动上架商品!
+        <a href="http://help.crmeb.net/crmeb-v4/1863579" v-if="copyConfig.copy_type == 2" target="_blank"
+          >如何配置密钥</a
+        >
+        <span v-else
+          >您当前剩余{{ copyConfig.copy_num }}条采集次数,<span class="add" @click="mealPay('copy')"
+            >增加采集次数</span
+          ></span
+        >
+      </div>
+      <div>商品采集设置:设置 > 系统设置 > 第三方接口设置 > 采集商品配置</div>
+    </Card> -->
+		<Form class="formValidate mt20" ref="formValidate" :label-width="120" label-position="right"
+			@submit.native.prevent>
+			<Row :gutter="24" type="flex">
+				<Col span="18">
+				<FormItem label="链接地址:">
+					<Input search enter-button="确定" v-model="soure_link" placeholder="请输入链接地址" class="numPut"
+						@on-search="add" />
+				</FormItem>
+				</Col>
+			</Row>
+		</Form>
+		<Spin size="large" fix v-if="spinShow"></Spin>
+	</div>
+</template>
+
+<script>
+	import {
+		crawlFromApi,
+		copyConfigApi
+	} from '@/api/shop_product';
+
+	export default {
+		name: 'taoBao',
+		data() {
+			return {
+				soure_link: '',
+				spinShow: false,
+				grid: {
+					xl: 8,
+					lg: 8,
+					md: 12,
+					sm: 24,
+					xs: 24,
+				},
+				grid2: {
+					xl: 12,
+					lg: 12,
+					md: 12,
+					sm: 24,
+					xs: 24,
+				},
+				copyConfig: {
+					copy_type: 2,
+					copy_num: 0,
+				},
+				artFrom: {
+					type: 'taobao',
+					url: '',
+				},
+			};
+		},
+		computed: {},
+		created() {},
+		mounted() {
+			this.getCopyConfig();
+		},
+		methods: {
+			mealPay(val) {
+				this.$router.push({
+					path: this.$routeProStr + '/setting/sms/sms_pay/index',
+					query: {
+						type: val
+					}
+				});
+			},
+			getCopyConfig() {
+				copyConfigApi().then((res) => {
+					this.copyConfig.copy_type = res.data.copy_type;
+					this.copyConfig.copy_num = res.data.copy_num;
+				});
+			},
+			// 生成表单
+			add() {
+				if (this.soure_link) {
+					var reg = /(http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?/;
+					if (!reg.test(this.soure_link)) {
+						return this.$Message.warning('请输入以http开头的地址!');
+					}
+					this.spinShow = true;
+					this.artFrom.url = this.soure_link;
+					crawlFromApi(this.artFrom)
+						.then((res) => {
+							let info = res.data.productInfo;
+							this.$emit('on-close', info);
+							this.spinShow = false;
+						})
+						.catch((res) => {
+							this.spinShow = false;
+							this.$Message.error(res.msg);
+						});
+				} else {
+					this.$Message.warning('请输入链接地址!');
+				}
+			},
+		},
+	};
+</script>
+
+<style scoped lang="stylus">
+	/deep/ .ivu-form-item-content {
+		line-height unset !important;
+	}
+
+	.Box .ivu-radio-wrapper {
+		margin-right: 25px;
+	}
+
+	.add {
+		color: #2D8cF0;
+		cursor pointer
+	}
+
+	.Box .numPut {
+		width: 100% !important;
+	}
+</style>

+ 225 - 0
src/pages/shop_product/productAttr/addAttr.vue

@@ -0,0 +1,225 @@
+<template>
+	<Modal scrollable v-model="modal" @on-cancel="onCancel" title="商品规格" width="950">
+		<Form ref="formDynamic" :model="formDynamic" :rules="rules" class="attrFrom" :label-width="110"
+			label-position="right" @submit.native.prevent>
+			<Row :gutter="24">
+				<Col span="24">
+				<Col span="8" class="mb15">
+				<FormItem label="规格模板名称:" prop="rule_name">
+					<Input placeholder="请输入标题名称" :maxlength="20" v-model.trim="formDynamic.rule_name" />
+				</FormItem>
+				</Col>
+				</Col>
+				<Col span="23" class="noForm" v-for="(item, index) in formDynamic.spec" :key="index">
+				<FormItem>
+					<div class="acea-row row-middle">
+						<span class="mr5">{{ item.value }}</span>
+						<Icon type="ios-close-circle" @click="handleRemove(index)" />
+					</div>
+					<div class="rulesBox">
+						<Tag type="dot" class="" closable color="primary" v-for="(j, indexn) in item.detail"
+							:key="indexn" :name="j" @on-close="handleRemove2(item.detail, indexn)">{{ j }}</Tag>
+						<Input search enter-button="添加" placeholder="请输入属性名称" v-model.trim="item.detail.attrsVal"
+							@on-search="createAttr(item.detail.attrsVal, index)" style="width: 200px" />
+					</div>
+				</FormItem>
+				</Col>
+				<Col span="24" v-if="isBtn" class="mt10">
+				<Col span="8" class="mr15">
+				<FormItem label="规格名称:">
+					<Input placeholder="请输入规格" v-model="attrsName" />
+				</FormItem>
+				</Col>
+				<Col span="8" class="mr20">
+				<FormItem label="规格值:">
+					<Input v-model="attrsVal" placeholder="请输入规格值" />
+				</FormItem>
+				</Col>
+				<Col span="2">
+				<Button type="primary" @click="createAttrName">确定</Button>
+				</Col>
+				<Col span="2">
+				<Button @click="offAttrName">取消</Button>
+				</Col>
+				</Col>
+				<Spin size="large" fix v-if="spinShow"></Spin>
+			</Row>
+			<Button type="primary" icon="md-add" @click="addBtn" v-if="!isBtn" class="ml95 mt10">添加新规格</Button>
+		</Form>
+		<div slot="footer">
+			<Button type="primary" :loading="modal_loading" @click="handleSubmit('formDynamic')">确定</Button>
+		</div>
+	</Modal>
+</template>
+
+<script>
+	import {
+		mapState
+	} from 'vuex';
+	import {
+		ruleAddApi,
+		ruleInfoApi
+	} from '@/api/shop_product';
+	export default {
+		name: 'addAttr',
+		data() {
+			return {
+				spinShow: false,
+				modal_loading: false,
+				grid: {
+					xl: 3,
+					lg: 3,
+					md: 12,
+					sm: 24,
+					xs: 24,
+				},
+				modal: false,
+				index: 1,
+				rules: {
+					rule_name: [{
+						required: true,
+						message: '请输入规格名称',
+						trigger: 'blur'
+					}],
+				},
+				formDynamic: {
+					rule_name: '',
+					spec: [],
+				},
+				attrsName: '',
+				attrsVal: '',
+				formDynamicNameData: [],
+				isBtn: false,
+				formDynamicName: [],
+				results: [],
+				result: [],
+				ids: 0,
+			};
+		},
+		computed: {},
+		methods: {
+			onCancel() {
+				this.ids = 0;
+				this.clear();
+			},
+			// 添加按钮
+			addBtn() {
+				this.isBtn = true;
+			},
+			// 详情
+			getIofo(row) {
+				this.spinShow = true;
+				this.ids = row.id;
+				ruleInfoApi(row.id)
+					.then((res) => {
+						this.formDynamic = res.data.info;
+						this.spinShow = false;
+					})
+					.catch((res) => {
+						this.spinShow = false;
+						this.$Message.error(res.msg);
+					});
+			},
+			// 提交
+			handleSubmit(name) {
+				this.$refs[name].validate((valid) => {
+					if (valid) {
+						if (this.formDynamic.spec.length === 0) {
+							return this.$Message.warning('请至少添加一条商品规格!');
+						}
+						this.modal_loading = true;
+						setTimeout(() => {
+							ruleAddApi(this.formDynamic, this.ids)
+								.then((res) => {
+									this.$Message.success(res.msg);
+									setTimeout(() => {
+										this.modal = false;
+										this.modal_loading = false;
+									}, 500);
+									setTimeout(() => {
+										this.$emit('getList');
+										this.clear();
+									}, 600);
+								})
+								.catch((res) => {
+									this.modal_loading = false;
+									this.$Message.error(res.msg);
+								});
+						}, 1200);
+					} else {
+						return false;
+					}
+				});
+			},
+			clear() {
+				this.$refs['formDynamic'].resetFields();
+				this.formDynamic.spec = [];
+				this.isBtn = false;
+				this.attrsName = '';
+				this.attrsVal = '';
+				this.ids = 0;
+			},
+			// 取消
+			offAttrName() {
+				this.isBtn = false;
+			},
+			// 删除
+			handleRemove(index) {
+				this.formDynamic.spec.splice(index, 1);
+			},
+			// 删除属性
+			handleRemove2(item, index) {
+				item.splice(index, 1);
+			},
+			// 添加规则名称
+			createAttrName() {
+				if (this.attrsName && this.attrsVal) {
+					let data = {
+						value: this.attrsName,
+						detail: [this.attrsVal],
+					};
+					this.formDynamic.spec.push(data);
+					var hash = {};
+					this.formDynamic.spec = this.formDynamic.spec.reduce(function(item, next) {
+						/* eslint-disable */
+						hash[next.value] ? '' : (hash[next.value] = true && item.push(next));
+						return item;
+					}, []);
+					this.attrsName = '';
+					this.attrsVal = '';
+					this.isBtn = false;
+				} else {
+					this.$Message.warning('请添加规格名称或规格值');
+				}
+			},
+			// 添加属性
+			createAttr(num, idx) {
+				if (num) {
+					this.formDynamic.spec[idx].detail.push(num);
+					var hash = {};
+					this.formDynamic.spec[idx].detail = this.formDynamic.spec[idx].detail.reduce(function(item, next) {
+						/* eslint-disable */
+						hash[next] ? '' : (hash[next] = true && item.push(next));
+						return item;
+					}, []);
+				} else {
+					this.$Message.warning('请添加属性');
+				}
+			},
+		},
+	};
+</script>
+
+<style scoped lang="stylus">
+	.rulesBox {
+		display: flex;
+		align-items: center;
+		flex-wrap: wrap;
+	}
+
+	.attrFrom {
+		>>>.ivu-form-item {
+			margin-bottom: 0px !important;
+		}
+	}
+</style>

+ 223 - 0
src/pages/shop_product/productAttr/index.vue

@@ -0,0 +1,223 @@
+<template>
+	<div>
+		<Card :bordered="false" dis-hover class="ivu-mt">
+			<Form ref="artFrom" :model="artFrom" :label-width="80" label-position="right" class="tabform"
+				@submit.native.prevent>
+				<Row :gutter="24" type="flex" justify="end">
+					<Col span="24" class="ivu-text-left">
+					<FormItem label="规格搜索:">
+						<Input search enter-button v-model="artFrom.rule_name" placeholder="请输入规格名称" style="width: 30%"
+							@on-search="userSearchs"></Input>
+					</FormItem>
+					</Col>
+					<Col span="24">
+					<Button v-auth="['product-rule-save']" class="mr20" type="primary" icon="md-add"
+						@click="addAttr">添加商品规格</Button>
+					<Button v-auth="['product-product-rule-delete']" @click="del(null, '批量删除规格')">批量删除</Button>
+					</Col>
+				</Row>
+			</Form>
+			<Table class="mt25" ref="table" :columns="columns4" :data="tableList" :loading="loading" highlight-row
+				@on-select="handleSelectRow" @on-select-cancel="handleCancelRow" @on-select-all="handleSelectAll"
+				@on-select-all-cancel="handleSelectAll" no-data-text="暂无数据" no-filtered-data-text="暂无筛选结果">
+				<template slot-scope="{ row }" slot="attr_value">
+					<span v-for="(item, index) in row.attr_value" :key="index" v-text="item"
+						style="display: block"></span>
+				</template>
+				<template slot-scope="{ row }" slot="action">
+					<a @click="edit(row)">编辑</a>
+					<Divider type="vertical" />
+					<a @click="del(row, '删除规格')">删除</a>
+				</template>
+			</Table>
+			<div class="acea-row row-right page">
+				<Page :total="total" :current="artFrom.page" show-elevator show-total @on-change="pageChange"
+					:page-size="artFrom.limit" />
+			</div>
+		</Card>
+		<add-attr ref="addattr" @getList="userSearchs"></add-attr>
+	</div>
+</template>
+
+<script>
+	import {
+		mapState
+	} from 'vuex';
+	import addAttr from './addAttr';
+	import {
+		ruleListApi
+	} from '@/api/shop_product';
+	export default {
+		name: 'productAttr',
+		components: {
+			addAttr
+		},
+		data() {
+			return {
+				loading: false,
+				artFrom: {
+					page: 1,
+					limit: 15,
+					rule_name: '',
+				},
+				columns4: [{
+						type: 'selection',
+						width: 60,
+					},
+					{
+						title: 'ID',
+						key: 'id',
+						width: 80,
+					},
+					{
+						title: '规格名称',
+						key: 'rule_name',
+						minWidth: 150,
+					},
+					{
+						title: '商品规格',
+						key: 'attr_name',
+						minWidth: 250,
+					},
+					{
+						title: '商品属性',
+						slot: 'attr_value',
+						minWidth: 300,
+					},
+					{
+						title: '操作',
+						slot: 'action',
+						fixed: 'right',
+						minWidth: 120,
+					},
+				],
+				tableList: [],
+				total: 0,
+				selectedIds: new Set(), //选中合并项的id
+				ids: '',
+			};
+		},
+		computed: {
+			...mapState('admin/order', ['orderChartType']),
+		},
+		created() {
+			this.getDataList();
+		},
+		methods: {
+			//全选和取消全选时触发
+			handleSelectAll(selection) {
+				if (selection.length === 0) {
+					//获取table的数据;
+					let data = this.$refs.table.data;
+					data.forEach((item) => {
+						if (this.selectedIds.has(item.id)) {
+							this.selectedIds.delete(item.id);
+						}
+					});
+				} else {
+					selection.forEach((item) => {
+						this.selectedIds.add(item.id);
+					});
+				}
+				this.$nextTick(() => {
+					//确保dom加载完毕
+					this.setChecked();
+				});
+			},
+			//  选中某一行
+			handleSelectRow(selection, row) {
+				this.selectedIds.add(row.id);
+				this.$nextTick(() => {
+					//确保dom加载完毕
+					this.setChecked();
+				});
+			},
+			//  取消某一行
+			handleCancelRow(selection, row) {
+				this.selectedIds.delete(row.id);
+				this.$nextTick(() => {
+					//确保dom加载完毕
+					this.setChecked();
+				});
+			},
+			setChecked() {
+				//将new Set()转化为数组
+				this.ids = [...this.selectedIds].join(',');
+				// 找到绑定的table的ref对应的dom,找到table的objData对象,objData保存的是当前页的数据
+				let objData = this.$refs.table.objData;
+				for (let index in objData) {
+					if (this.selectedIds.has(objData[index].id)) {
+						objData[index]._isChecked = true;
+					}
+				}
+			},
+			// 删除
+			del(row, tit) {
+				let data = {};
+				if (tit === '批量删除规格') {
+					if (this.selectedIds.size === 0) return this.$Message.warning('请选择要删除的规格!');
+					data = {
+						ids: this.ids,
+					};
+				} else {
+					data = {
+						ids: row.id,
+					};
+				}
+				let delfromData = {
+					title: tit,
+					num: 0,
+					url: `product/product/rule/delete`,
+					method: 'DELETE',
+					ids: data,
+				};
+				this.$modalSure(delfromData)
+					.then((res) => {
+						this.$Message.success(res.msg);
+						this.getDataList();
+					})
+					.catch((res) => {
+						this.$Message.error(res.msg);
+					});
+			},
+			addAttr() {
+				this.$refs.addattr.modal = true;
+			},
+			// 编辑
+			edit(row) {
+				this.$refs.addattr.modal = true;
+				this.$refs.addattr.getIofo(row);
+			},
+			// 列表;
+			getDataList() {
+				this.loading = true;
+				ruleListApi(this.artFrom)
+					.then((res) => {
+						let data = res.data;
+						this.tableList = data.list;
+						this.$nextTick(() => {
+							//确保dom加载完毕
+							this.setChecked();
+						});
+						this.total = res.data.count;
+						this.loading = false;
+					})
+					.catch((res) => {
+						this.loading = false;
+						this.$Message.error(res.msg);
+					});
+			},
+			pageChange(status) {
+				this.artFrom.page = status;
+				this.getDataList();
+			},
+			// 表格搜索
+			userSearchs() {
+				this.artFrom.page = 1;
+				this.getDataList();
+			},
+		},
+	};
+</script>
+
+<style scoped></style>

+ 401 - 0
src/pages/shop_product/productClassify/index.vue

@@ -0,0 +1,401 @@
+<template>
+	<div class="article-manager">
+		<Card :bordered="false" dis-hover class="ivu-mt">
+			<Form ref="artFrom" :model="artFrom" :label-width="75" label-position="right" @submit.native.prevent>
+				<Row type="flex" :gutter="24">
+					<Col v-bind="grid">
+					<FormItem label="商品分类:" prop="pid" label-for="pid">
+						<Select v-model="artFrom.pid" placeholder="请选择商品分类" @on-change="userSearchs" clearable>
+							<Option v-for="item in treeSelect" :value="item.id" :key="item.id">{{ item.cate_name }}
+							</Option>
+						</Select>
+					</FormItem>
+					</Col>
+					<Col v-bind="grid">
+					<FormItem label="分类状态:" label-for="is_show">
+						<Select v-model="artFrom.is_show" placeholder="请选择分类状态" clearable @on-change="userSearchs">
+							<Option value="1">显示</Option>
+							<Option value="0">隐藏</Option>
+						</Select>
+					</FormItem>
+					</Col>
+					<Col v-bind="grid">
+					<FormItem label="分类名称:" label-for="status2">
+						<Input search enter-button placeholder="请输入分类名称" v-model="artFrom.cate_name"
+							@on-search="userSearchs" />
+					</FormItem>
+					</Col>
+				</Row>
+				<Row type="flex">
+					<Col v-bind="grid">
+					<Button v-auth="['product-save-cate']" type="primary" class="bnt" icon="md-add"
+						@click="addClass">添加分类</Button>
+					</Col>
+				</Row>
+			</Form>
+			<vxe-table class="mt25" highlight-hover-row :loading="loading" header-row-class-name="false"
+				:tree-config="{ children: 'children' }" :data="tableData">
+				<vxe-table-column field="id" title="ID" tooltip width="80"></vxe-table-column>
+				<vxe-table-column field="cate_name" tree-node title="分类名称" min-width="250"></vxe-table-column>
+				<vxe-table-column field="pic" title="分类图标" min-width="100">
+					<template v-slot="{ row }">
+						<div class="tabBox_img" v-viewer v-if="row.pic">
+							<img v-lazy="row.pic" />
+						</div>
+					</template>
+				</vxe-table-column>
+				<vxe-table-column field="sort" title="排序" min-width="100" tooltip="true"></vxe-table-column>
+				<vxe-table-column field="is_show" title="状态" min-width="120">
+					<template v-slot="{ row }">
+						<i-switch v-model="row.is_show" :value="row.is_show" :true-value="1" :false-value="0"
+							@on-change="onchangeIsShow(row)" size="large">
+							<span slot="open">显示</span>
+							<span slot="close">隐藏</span>
+						</i-switch>
+					</template>
+				</vxe-table-column>
+				<vxe-table-column field="date" title="操作" width="250" fixed="right" align="center">
+					<template v-slot="{ row, index }">
+						<a @click="edit(row)">编辑</a>
+						<Divider type="vertical" />
+						<a @click="del(row, '删除商品分类', index)">删除</a>
+					</template>
+				</vxe-table-column>
+			</vxe-table>
+			<!--            <div class="acea-row row-right page">-->
+			<!--                <Page :total="total" :current="artFrom.page" show-elevator show-total @on-change="pageChange"-->
+			<!--                      :page-size="artFrom.limit"/>-->
+			<!--            </div>-->
+		</Card>
+		<!-- 添加 编辑表单-->
+		<edit-from ref="edits" :FromData="FromData" @submitFail="userSearchs"></edit-from>
+		<Modal v-model="modals" @on-cancel="onCancel" scrollable footer-hide closable :title="`${modelTit}分类`"
+			:mask-closable="false" width="700">
+			<Form ref="formInline" :model="formInline" :rules="ruleValidate" :label-width="150"
+				:label-position="labelPosition2" @submit.native.prevent>
+				<FormItem label="上级分类" label-for="pid" prop="pid">
+					<el-cascader v-model="formInline.pid" size="small" :options="classtable"
+						:props="{ emitPath: false }" clearable></el-cascader>
+				</FormItem>
+				<FormItem label="分类名称:" label-for="cate_name" prop="cate_name">
+					<Input placeholder="请输入分类名称" v-model="formInline.cate_name" />
+				</FormItem>
+				<FormItem label="分类图标(180*180)" prop="pic">
+					<div class="acea-row">
+						<div class="upLoad acea-row row-center-wrapper" @click="modalPicTap('pic')">
+							<Icon v-if="!formInline.pic" type="ios-camera-outline" size="26" />
+							<img style="width: 100px;height: 100px;" v-else v-lazy="formInline.pic" />
+						</div>
+						<Input v-model="formInline.pic" style="display: none"></Input>
+					</div>
+				</FormItem>
+				<FormItem label="分类大图(468*340)" prop="big_pic">
+					<div class="acea-row">
+						<div class="upLoad acea-row row-center-wrapper" @click="modalPicTap('big_pic')">
+							<Icon v-if="!formInline.big_pic" type="ios-camera-outline" size="26" />
+							<img style="width: 100px;height: 100px;" v-else v-lazy="formInline.big_pic" />
+						</div>
+						<Input v-model="formInline.big_pic" style="display: none"></Input>
+					</div>
+				</FormItem>
+				<FormItem label="排序" label-for="sort" prop="sort">
+					<Input placeholder="" v-model="formInline.sort" type="number" />
+				</FormItem>
+
+				<Button type="primary" size="large" long @click="handleSubmit('formInline')">提交</Button>
+
+			</Form>
+		</Modal>
+		<Modal v-model="modalPic" width="1024px" scrollable footer-hide closable title="上传商品图" :mask-closable="false"
+			:z-index="1">
+			<shopuploadPictures :isChoice="isChoice" @getPic="getPic" :gridBtn="gridBtn" :gridPic="gridPic"
+				v-if="modalPic"></shopuploadPictures>
+		</Modal>
+	</div>
+</template>
+
+<script>
+	import {
+		mapState
+	} from 'vuex';
+	import shopuploadPictures from '@/components/uploadPictures2';
+	import {
+		productListApi,
+		productCreateApi,
+		productCreate,
+		productEditApi,
+		productEdit,
+		setShowApi,
+		treeListApi
+	} from '@/api/shop_product';
+	import editFrom from '../../../components/from/from';
+	export default {
+		name: 'product_productClassify',
+		components: {
+			editFrom,
+			shopuploadPictures
+		},
+		data() {
+			return {
+				treeSelect: [],
+				FromData: null,
+				modalPic: false,
+				grid: {
+					xl: 7,
+					lg: 7,
+					md: 12,
+					sm: 24,
+					xs: 24,
+				},
+				gridBtn: {
+					xl: 4,
+					lg: 8,
+					md: 8,
+					sm: 8,
+					xs: 8,
+				},
+				gridPic: {
+					xl: 6,
+					lg: 8,
+					md: 12,
+					sm: 12,
+					xs: 12,
+				},
+				modals: false,
+				loading: false,
+				artFrom: {
+					pid: 0,
+					is_show: '',
+					page: 1,
+					cate_name: '',
+					limit: 15,
+				},
+				modelTit: '',
+				isChoice: '单选',
+				id: '',
+				total: 0,
+				tableData: [],
+				formInline: {
+					big_pic: '',
+					cate_name: '',
+					is_show: '1',
+					pic: '',
+					pid: '',
+					sort: '0'
+				},
+				classtable: [],
+				ruleValidate: {
+					cate_name: [{
+						required: true,
+						message: '请填写分类名称',
+						trigger: 'blur'
+					}],
+				},
+			};
+		},
+		computed: {
+			...mapState('admin/userLevel', ['categoryId']),
+			labelPosition2() {
+				return this.isMobile ? 'top' : 'right';
+			},
+		},
+		mounted() {
+			this.goodsCategory();
+			this.getList();
+		},
+		methods: {
+			modalPicTap(picTit) {
+				this.modalPic = true;
+				this.modals = false;
+				this.picTit = picTit;
+			},
+			// 商品分类;
+			goodsCategory() {
+				treeListApi(0)
+					.then((res) => {
+						this.treeSelect = res.data;
+					})
+					.catch((res) => {
+						this.$Message.error(res.msg);
+					});
+			},
+			onCancel() {
+				this.$refs['formInline'].resetFields();
+			},
+			// 列表
+			getList() {
+				this.loading = true;
+				this.artFrom.is_show = this.artFrom.is_show || '';
+				this.artFrom.pid = this.artFrom.pid || '';
+				productListApi(this.artFrom)
+					.then(async (res) => {
+						let data = res.data;
+						this.tableData = data.list;
+						this.total = data.count;
+						this.loading = false;
+					})
+					.catch((res) => {
+						this.loading = false;
+						this.$Message.error(res.msg);
+					});
+			},
+			pageChange(index) {
+				this.artFrom.page = index;
+				this.getList();
+			},
+			// 添加
+			addClass() {
+				this.modelTit = '添加'
+				const obj = this
+				productCreateApi().then((res) => {
+					res.data.rules.forEach(e => {
+						if (e.field == 'pid') {
+							obj.classtable = e.options
+						}
+					})
+					obj.modals = true
+				})
+				// this.$modalForm(productCreateApi()).then(() => this.getList());
+			},
+			// 编辑
+			edit(row) {
+				this.modelTit = '编辑'
+				this.id = row.id
+				const obj = this
+				productEditApi(row.id).then((res) => {
+					res.data.rules.forEach(e => {
+						obj.formInline[e.field] = e.value
+						if (e.field == 'pid') {
+							obj.classtable = e.options
+						}
+					})
+					obj.modals = true
+				})
+			},
+			// 修改状态
+			onchangeIsShow(row) {
+				let data = {
+					id: row.id,
+					is_show: row.is_show,
+				};
+				setShowApi(data)
+					.then(async (res) => {
+						this.$Message.success(res.msg);
+					})
+					.catch((res) => {
+						this.$Message.error(res.msg);
+					});
+			},
+			handleSubmit(name) {
+				this.$refs[name].validate((valid) => {
+					if (valid) {
+						if (this.modelTit == '添加') {
+							productCreate(this.formInline)
+								.then(async (res) => {
+									this.$Message.success(res.msg);
+									this.modals = false;
+									this.goodsCategory();
+									this.getList();
+									this.$refs[name].resetFields();
+								})
+								.catch((res) => {
+									this.$Message.error(res.msg);
+								});
+						} else {
+							productEdit(this.formInline, this.id)
+								.then(async (res) => {
+									this.$Message.success(res.msg);
+									this.modals = false;
+									this.goodsCategory();
+									this.getList();
+									this.$refs[name].resetFields();
+								})
+								.catch((res) => {
+									this.$Message.error(res.msg);
+								});
+						}
+
+					} else {
+						return false;
+					}
+				});
+			},
+			// 下拉树
+			handleCheckChange(data) {
+				let value = '';
+				let title = '';
+				this.list = [];
+				this.artFrom.pid = 0;
+				data.forEach((item, index) => {
+					value += `${item.id},`;
+					title += `${item.title},`;
+				});
+				value = value.substring(0, value.length - 1);
+				title = title.substring(0, title.length - 1);
+				this.list.push({
+					value,
+					title,
+				});
+				this.artFrom.pid = value;
+				this.getList();
+			},
+			// 获取单张图片信息
+			getPic(pc) {
+				console.log(pc, 'info');
+				switch (this.picTit) {
+					case 'pic':
+						this.formInline.pic = pc.att_dir;
+						break;
+					case 'big_pic':
+						this.formInline.big_pic = pc.att_dir;
+						break;
+					default:
+				}
+				console.log(this.formInline, '');
+				this.modalPic = false;
+				this.modals = true;
+			},
+			// 删除
+			del(row, tit, num) {
+				let delfromData = {
+					title: tit,
+					num: num,
+					url: `mer/category/${row.id}`,
+					method: 'DELETE',
+					ids: '',
+				};
+				this.$modalSure(delfromData)
+					.then((res) => {
+						this.$Message.success(res.msg);
+						this.getList();
+					})
+					.catch((res) => {
+						this.$Message.error(res.msg);
+					});
+			},
+			// 表格搜索
+			userSearchs() {
+				this.artFrom.page = 1;
+				this.getList();
+			},
+		},
+	};
+</script>
+<style scoped lang="stylus">
+	.treeSel>>>.ivu-select-dropdown-list {
+		padding: 0 10px !important;
+		box-sizing: border-box;
+	}
+
+	.tabBox_img {
+		width: 36px;
+		height: 36px;
+		border-radius: 4px;
+		cursor: pointer;
+
+		img {
+			width: 100%;
+			height: 100%;
+		}
+	}
+</style>

+ 115 - 0
src/pages/shop_product/productList/attribute/index.vue

@@ -0,0 +1,115 @@
+<template>
+  <div>
+    <Modal v-model="val" title="商品属性" width="70%" @on-cancel="cancel">
+      <div class="Modals">
+        <Form class="form" ref="form" :label-width="70" label-position="right">
+          <Row :gutter="24" type="flex">
+            <Col :xl="24" :lg="24" :md="24" :sm="24" :xs="24">
+              <FormItem label="规格:" prop="store_name" label-for="store_name">
+                <Input
+                  placeholder="规格"
+                  style="width: 10%"
+                  class="input"
+                  :value="item"
+                  v-for="(item, index) in specs"
+                  :key="index"
+                >
+                  <Icon type="md-close" slot="suffix" />
+                </Input>
+                <Input placeholder="请输入" v-model="specsVal" style="width: 10%" class="input">
+                  <Icon type="md-add" slot="suffix" @click="confirm" />
+                </Input>
+                <!--<Button type="primary" icon="md-add" @click="confirm"></Button>-->
+              </FormItem>
+            </Col>
+            <Col :xl="24" :lg="24" :md="24" :sm="24" :xs="24">
+              <FormItem
+                :label="item.attr + ':'"
+                prop="store_name"
+                label-for="store_name"
+                v-for="(item, index) in attrList"
+                :key="index"
+              >
+                <Tag type="border" closable color="primary" v-for="(itemn, index) in item.attrVal" :key="index">{{
+                  itemn
+                }}</Tag>
+                <Input placeholder="请输入" v-model="item.inputVal" style="width: 10%" class="input">
+                  <Icon type="md-add" slot="suffix" @click="confirmAttr(index)" />
+                </Input>
+                <!--<Button type="primary" icon="md-add" @click="confirm"></Button>-->
+              </FormItem>
+            </Col>
+          </Row>
+        </Form>
+      </div>
+      <div slot="footer"></div>
+    </Modal>
+  </div>
+</template>
+
+<script>
+import { mapState } from 'vuex';
+export default {
+  name: 'attribute',
+  props: {
+    attrTemplate: {
+      type: Boolean,
+    },
+  },
+  data() {
+    return {
+      val: false,
+      specsVal: '',
+      specs: [],
+      attrVal: '',
+      attrList: [],
+    };
+  },
+  watch: {
+    attrTemplate: function (n) {
+      this.val = n;
+    },
+  },
+  computed: {},
+  methods: {
+    cancel() {
+      this.$emit('changeTemplate', false);
+    },
+    confirm() {
+      if (this.specsVal === '') {
+        this.$Message.error('请填写规格名称');
+      } else {
+        this.specs.push(this.specsVal);
+        this.attrList.push({
+          attr: this.specsVal,
+          inputVal: '',
+          attrVal: [],
+        });
+        this.specsVal = '';
+        if (this.specsVal !== '') {
+          this.attrList.forEach((item) => {
+            if (item.attrVal.length < 1) {
+              this.$Message.error('请填写规格属性');
+            }
+          });
+        }
+      }
+    },
+    confirmAttr(index) {
+      let attrList = this.attrList[index];
+      if (attrList.inputVal === '') {
+        this.$Message.error('请填写规格属性');
+      } else {
+        attrList.attrVal.push(attrList.inputVal);
+        attrList.inputVal === '';
+      }
+    },
+  },
+  mounted() {},
+};
+</script>
+
+<style scoped lang="stylus">
+.Modals >>> .input
+  margin-right 10px;
+</style>

+ 178 - 0
src/pages/shop_product/productList/components/goodsDetail.vue

@@ -0,0 +1,178 @@
+<template>
+	<div class="goods_detail">
+		<div class="goods_detail_wrapper" style="height: 640px">
+			<HappyScroll size="5" resize hide-horizontal>
+				<div style="width: 375px">
+					<div class="title-box">商品详情</div>
+					<div class="swiper-box">
+						<Carousel :autoplay="goodsInfo.productInfo.slider_image.length > 1" v-model="value2" loop
+							arrow="never">
+							<CarouselItem v-for="(item, index) in goodsInfo.productInfo.slider_image" :key="index">
+								<div class="demo-carousel"><img :src="item" alt="" /></div>
+							</CarouselItem>
+						</Carousel>
+					</div>
+					<div class="goods_info">
+						<div class="number-wrapper">
+							<div class="price"><span>¥</span>{{ goodsInfo.productInfo.price }}</div>
+							<div class="old-price" v-if="goodsInfo.productInfo.vip_price != '0.00'">
+								¥{{ goodsInfo.productInfo.vip_price }}
+							</div>
+							<div v-if="goodsInfo.productInfo.vip_price != '0.00'">
+								<img src="../../../../assets/images/goods_vip.png" />
+							</div>
+						</div>
+						<div class="name">{{ goodsInfo.productInfo.store_name }}</div>
+						<div class="msg">
+							<div class="item">原价:¥{{ goodsInfo.productInfo.ot_price }}</div>
+							<div class="item">库存:{{ goodsInfo.productInfo.stock }}{{ goodsInfo.productInfo.unit_name }}
+							</div>
+							<div class="item">
+								销量:{{ goodsInfo.productInfo.sales + goodsInfo.productInfo.ficti
+                }}{{ goodsInfo.productInfo.unit_name }}
+							</div>
+						</div>
+					</div>
+					<div class="con-box">
+						<div class="title-box">商品介绍</div>
+						<div class="content" v-html="goodsInfo.productInfo.description"></div>
+					</div>
+				</div>
+			</HappyScroll>
+		</div>
+	</div>
+</template>
+
+<script>
+	import {
+		HappyScroll
+	} from 'vue-happy-scroll';
+	import {
+		productInfoApi
+	} from '@/api/shop_product';
+	export default {
+		name: 'goods_detail',
+		props: {
+			goodsId: {
+				type: String | Number,
+				default: '',
+			},
+		},
+		components: {
+			HappyScroll,
+		},
+		data() {
+			return {
+				value2: 0,
+				goodsInfo: {},
+			};
+		},
+		mounted() {
+			this.getInfo();
+		},
+		methods: {
+			getInfo() {
+				console.log('123456');
+				productInfoApi(this.goodsId).then((res) => {
+					this.goodsInfo = res.data;
+				});
+			},
+		},
+	};
+</script>
+
+<style lang="stylus" scoped>
+	.goods_detail {
+		.goods_detail_wrapper {
+			background: url('../../../../assets/images/phonebg.png') no-repeat center top !important;
+			background-size: 375px 640px !important;
+			padding: 50px 20px;
+			z-index: 20;
+			position: fixed;
+			left: 50%;
+			top: 50%;
+			transform: translate(-50%, -50%);
+			width: 375px;
+			background: #F0F2F5;
+		}
+
+		.title-box {
+			width: 335px;
+			height: 46px;
+			line-height: 46px;
+			background: #fff;
+			text-align: center;
+			color: #333;
+			font-size: 16px;
+		}
+
+		.swiper-box {
+			height: 375px;
+
+			.demo-carousel {
+				width: 333px;
+				height: 375px;
+
+				img {
+					width: 100%;
+					height: 100%;
+					display: block;
+				}
+			}
+		}
+
+		.goods_info {
+			width: 332px;
+			padding: 15px;
+			background: #fff;
+
+			.number-wrapper {
+				display: flex;
+				align-items: center;
+
+				.price {
+					color: #FF3838;
+					font-size: 25px;
+
+					span {
+						font-size: 15px;
+					}
+				}
+
+				.old-price {
+					font-size: 15px;
+					margin-left: 10px;
+					color: #333333;
+				}
+			}
+
+			.name {
+				font-size: 16px;
+				color: #333;
+			}
+
+			.msg {
+				display: flex;
+				align-items: center;
+				justify-content: space-between;
+				margin-top: 10px;
+
+				.item {
+					color: #999999;
+					font-size: 14px;
+				}
+			}
+		}
+
+		.con-box {
+			margin-top: 10px;
+			padding-bottom: 20px;
+			background: #f0f2f5;
+			width: 335px;
+
+			.content /deep/ video {
+				width 100% !important
+			}
+		}
+	}
+</style>

+ 898 - 0
src/pages/shop_product/productList/index.vue

@@ -0,0 +1,898 @@
+<template>
+	<div class="article-manager">
+		<Card :bordered="false" dis-hover class="ivu-mt">
+			<Tabs class="mb20" v-model="artFrom.type" @on-click="onClickTab">
+				<TabPane :label="item.name + '(' + item.count + ')'" :name="item.type.toString()"
+					v-for="(item, index) in headeNum" :key="index" />
+			</Tabs>
+			<Form ref="artFrom" :model="artFrom" :label-width="75" label-position="right" @submit.native.prevent>
+				<Row type="flex" :gutter="24">
+					<Col v-bind="grid">
+					<FormItem label="商品分类:" label-for="pid">
+						<!-- <Select v-model="artFrom.cate_id" placeholder="请选择商品分类" clearable @on-change="userSearchs">
+                <Option v-for="item in treeSelect" :value="item.id" :key="item.id">{{
+                  item.html + item.cate_name
+                }}</Option>
+              </Select> -->
+						<el-cascader v-model="artFrom.cate_id" size="small" :options="treeSelect"
+							:props="{ emitPath: false }" clearable></el-cascader>
+					</FormItem>
+					</Col>
+					<Col v-bind="grid">
+					<FormItem label="商品搜索:" label-for="store_name">
+						<Input search enter-button placeholder="请输入商品名称/关键字/ID" v-model="artFrom.store_name"
+							@on-search="userSearchs" />
+					</FormItem>
+					</Col>
+				</Row>
+			</Form>
+			<div class="Button">
+				<router-link v-auth="['product-product-save']" :to="$routeProStrshop + '/product/add_product'"><Button
+						type="primary" class="bnt mr15" icon="md-add">添加商品</Button></router-link>
+				<Button v-auth="['product-crawl-save']" type="success" class="bnt mr15" @click="onCopy">商品采集</Button>
+				<Dropdown class="bnt mr15" @on-click="batchSelect" :transfer="true">
+					<Button type="info">
+						批量修改
+						<Icon type="ios-arrow-down"></Icon>
+					</Button>
+					<DropdownMenu slot="list">
+						<DropdownItem :name="1">商品分类</DropdownItem>
+						<DropdownItem :name="2">物流设置</DropdownItem>
+						<DropdownItem :name="3">购买送积分</DropdownItem>
+						<DropdownItem :name="4">购买送优惠券</DropdownItem>
+						<DropdownItem :name="5">关联用户标签</DropdownItem>
+						<DropdownItem :name="6">活动推荐</DropdownItem>
+					</DropdownMenu>
+				</Dropdown>
+				<Button v-auth="['product-product-product_show']" class="bnt mr15" type="info" @click="onDismount"
+					v-show="artFrom.type === '1'">批量下架</Button>
+				<Button v-auth="['product-product-product_show']" class="bnt mr15" @click="onShelves"
+					v-show="artFrom.type === '2'">批量上架</Button>
+				<Button v-auth="['export-storeProduct']" class="export" icon="ios-share-outline"
+					@click="exports">导出</Button>
+			</div>
+			<Table ref="table" :columns="artFrom.type !== '1' && artFrom.type !== '2' ? columns2 : columns"
+				:data="tableList" class="ivu-mt mt25" :loading="loading" highlight-row @on-select="handleSelectRow"
+				@on-select-cancel="handleCancelRow" @on-select-all="handleSelectAll"
+				@on-select-all-cancel="handleSelectAll" no-data-text="暂无数据" no-filtered-data-text="暂无筛选结果">
+				<template slot-scope="{ row }" slot="id">
+					{{ row.id }}
+				</template>
+				<template slot-scope="{ row }" slot="image">
+					<div class="tabBox_img" v-viewer>
+						<img v-lazy="row.image" />
+					</div>
+				</template>
+				<template slot-scope="{ row, index }" slot="state">
+					<i-switch v-model="row.is_show" :value="row.is_show" :true-value="1" :false-value="0"
+						@on-change="changeSwitch(row)" size="large">
+						<span slot="open">上架</span>
+						<span slot="close">下架</span>
+					</i-switch>
+				</template>
+				<template slot-scope="{ row, index }" slot="action">
+					<a @click="look(row)">查看</a>
+					<Divider type="vertical" />
+					<a @click="edit(row)">编辑</a>
+					<Divider type="vertical" />
+					<!-- <router-link
+						:to="{ path: $routeProStr + '/product/product_reply/' + row.id }"><a>查看评论</a></router-link>
+					<Divider type="vertical" /> -->
+					<a @click="del(row, '恢复商品', index)" v-if="artFrom.type === '6'">恢复商品</a>
+					<a @click="del(row, '移入回收站', index)" v-else>移到回收站</a>
+				</template>
+			</Table>
+			<div class="acea-row row-right page">
+				<Page :total="total" :current="artFrom.page" show-elevator show-total @on-change="pageChange"
+					:page-size="artFrom.limit" />
+			</div>
+			<attribute :attrTemplate="attrTemplate" v-on:changeTemplate="changeTemplate"></attribute>
+		</Card>
+		<!-- 生成淘宝京东表单-->
+		<Modal v-model="modals" class="Box" scrollable footer-hide closable title="复制淘宝、天猫、京东、苏宁、1688"
+			:mask-closable="false" width="1200" height="500">
+			<tao-bao ref="taobaos" v-if="modals" @on-close="onClose"></tao-bao>
+		</Modal>
+		<Modal v-model="batchModal" class="batch-box" scrollable :closable="false" title="批量设置" :mask-closable="false"
+			width="1000" @on-ok="batchSub" @on-cancel="clearBatchData">
+			<Form class="batchFormData" ref="batchFormData" :rules="ruleBatch" :model="batchFormData" :label-width="120"
+				label-position="right" @submit.native.prevent>
+				<Row :gutter="24" type="flex">
+					<Col span="24" v-if="batchType == 1">
+					<Divider orientation="left">基础设置</Divider>
+					<FormItem label="商品分类:" prop="cate_id">
+						<!-- <Select v-model="batchFormData.cate_id" placeholder="请选择商品分类" multiple class="perW20">
+                <Option v-for="item in treeSelect" :disabled="item.pid === 0" :value="item.id" :key="item.id">{{
+                  item.html + item.cate_name
+                }}</Option>
+              </Select> -->
+						<el-cascader v-model="batchFormData.cate_id" size="small" :options="treeSelect"
+							:props="{ emitPath: false }" clearable></el-cascader>
+					</FormItem>
+					</Col>
+					<Col span="24" v-if="batchType == 2">
+					<Divider orientation="left">物流设置</Divider>
+					<FormItem label="物流方式:" prop="logistics">
+						<CheckboxGroup v-model="batchFormData.logistics" @on-change="logisticsBtn">
+							<Checkbox label="1">快递</Checkbox>
+
+							<Checkbox label="2">到店核销</Checkbox>
+						</CheckboxGroup>
+					</FormItem>
+					<FormItem label="运费设置:">
+						<RadioGroup v-model="batchFormData.freight">
+							<!-- <Radio :label="1">包邮</Radio> -->
+							<Radio :label="2">固定邮费</Radio>
+							<Radio :label="3">运费模板</Radio>
+						</RadioGroup>
+					</FormItem>
+					<FormItem label="" v-if="batchFormData.freight == 2">
+						<div class="acea-row">
+							<InputNumber :min="0" v-model="batchFormData.postage" placeholder="请输入金额"
+								class="perW20 maxW" />
+						</div>
+					</FormItem>
+					<FormItem label="" v-if="batchFormData.freight == 3" prop="temp_id">
+						<div class="acea-row">
+							<Select v-model="batchFormData.temp_id" clearable placeholder="请选择运费模板" class="perW20 maxW">
+								<Option v-for="(item, index) in templateList" :value="item.id" :key="index">
+									{{ item.name }}
+								</Option>
+							</Select>
+						</div>
+					</FormItem>
+					</Col>
+					<Col span="24" v-if="[3, 4, 5, 6].includes(batchType)">
+					<Divider orientation="left" v-if="[3, 4, 5, 6].includes(batchType)">营销设置</Divider>
+					<FormItem label="赠送积分:" prop="give_integral" v-if="batchType == 3">
+						<InputNumber v-model="batchFormData.give_integral" :min="0" :max="999999" placeholder="请输入积分" />
+					</FormItem>
+					<FormItem label="赠送优惠券:" v-if="batchType == 4">
+						<div v-if="couponName.length" class="mb20">
+							<Tag closable v-for="(item, index) in couponName" :key="index"
+								@on-close="handleClose(item)">{{
+                  item.title
+                }}</Tag>
+						</div>
+						<Button type="primary" @click="addCoupon">添加优惠券</Button>
+					</FormItem>
+					<FormItem label="关联用户标签:" prop="label_id" v-if="batchType == 5">
+						<div style="display: flex">
+							<div class="labelInput acea-row row-between-wrapper" @click="openLabel">
+								<div style="width: 90%">
+									<div v-if="dataLabel.length">
+										<Tag closable v-for="(item, index) in dataLabel" @on-close="closeLabel(item)"
+											:key="index">{{
+                        item.label_name
+                      }}</Tag>
+									</div>
+									<span class="span" v-else>选择用户关联标签</span>
+								</div>
+								<div class="iconfont iconxiayi"></div>
+							</div>
+						</div>
+					</FormItem>
+					<FormItem label="商品推荐:" v-if="batchType == 6">
+						<CheckboxGroup v-model="batchFormData.recommend">
+							<Checkbox label="is_hot">热卖单品</Checkbox>
+							<Checkbox label="is_benefit">促销单品</Checkbox>
+							<Checkbox label="is_best">精品推荐</Checkbox>
+							<Checkbox label="is_new">首发新品</Checkbox>
+							<Checkbox label="is_good">优品推荐</Checkbox>
+						</CheckboxGroup>
+					</FormItem>
+					</Col>
+				</Row>
+			</Form>
+		</Modal>
+		<!-- 用户标签 -->
+		<Modal v-model="labelShow" scrollable title="请选择用户标签" :closable="false" width="500" :footer-hide="true"
+			:mask-closable="false">
+			<userLabel ref="userLabel" @activeData="activeData" @close="labelClose"></userLabel>
+		</Modal>
+		<!-- 商品弹窗 -->
+		<div v-if="isProductBox">
+			<div class="bg" @click="isProductBox = false"></div>
+			<goodsDetail :goodsId="goodsId"></goodsDetail>
+		</div>
+		<coupon-list ref="couponTemplates" @nameId="nameId" :couponids="batchFormData.coupon_ids"></coupon-list>
+	</div>
+</template>
+
+<script>
+	import expandRow from './tableExpand.vue';
+	import attribute from './attribute';
+	import toExcel from '../../../utils/Excel.js';
+	import {
+		mapState
+	} from 'vuex';
+	import taoBao from './taoBao';
+	import goodsDetail from './components/goodsDetail.vue';
+	import couponList from '@/components/couponList';
+	import {
+		shopexportProductList
+	} from '@/api/export';
+
+	import {
+		getGoodHeade,
+		getGoods,
+		PostgoodsIsShow,
+		cascaderListApi, // 分类列表
+		productShowApi,
+		productUnshowApi,
+		storeProductApi,
+		batchSetting,
+		productGetTemplateApi,
+	} from '@/api/shop_product';
+	import userLabel from '@/components/labelList';
+
+	export default {
+		name: 'product_productList',
+		components: {
+			expandRow,
+			attribute,
+			taoBao,
+			goodsDetail,
+			userLabel,
+			couponList
+		},
+		computed: {
+			...mapState('userLevel', ['categoryId']),
+		},
+		data() {
+			return {
+				template: false,
+				modals: false,
+				batchModal: false,
+				labelShow: false,
+				batchType: 1, // 批量设置类型
+				batchFormData: {
+					cate_id: [],
+					logistics: [],
+					freight: 2,
+					postage: 0,
+					temp_id: null,
+					give_integral: 0,
+					label_id: [],
+					coupon_ids: [],
+					recommend: [],
+				},
+				ruleBatch: {},
+				couponName: [], // 优惠券
+				dataLabel: [], // 标签
+				templateList: [], // 运费模版
+				grid: {
+					xl: 6,
+					lg: 8,
+					md: 12,
+					sm: 24,
+					xs: 24,
+				},
+				artFrom: {
+					page: 1,
+					limit: 15,
+					cate_id: '',
+					type: '1',
+					store_name: '',
+				},
+				list: [],
+				tableList: [],
+				headeNum: [],
+				treeSelect: [],
+				loading: false,
+				columns: [{
+						type: 'expand',
+						width: 50,
+						render: (h, params) => {
+							return h(expandRow, {
+								props: {
+									row: params.row,
+								},
+							});
+						},
+					},
+					{
+						type: 'selection',
+						width: 60,
+						align: 'center',
+					},
+					{
+						title: '商品ID',
+						key: 'id',
+						width: 80,
+					},
+					{
+						title: '商品图',
+						slot: 'image',
+						minWidth: 80,
+					},
+					{
+						title: '商品名称',
+						key: 'store_name',
+						minWidth: 250,
+					},
+					{
+						title: '商品类型',
+						key: 'product_type',
+						minWidth: 100,
+					},
+					{
+						title: '商品售价',
+						key: 'price',
+						minWidth: 90,
+					},
+					{
+						title: '销量',
+						key: 'sales',
+						minWidth: 90,
+					},
+					{
+						title: '库存',
+						key: 'stock',
+						minWidth: 80,
+					},
+					{
+						title: '排序',
+						key: 'sort',
+						minWidth: 70,
+					},
+					{
+						title: '状态',
+						slot: 'state',
+						width: 100,
+						filters: [{
+								label: '上架',
+								value: 1,
+							},
+							{
+								label: '下架',
+								value: 0,
+							},
+						],
+						filterMethod(value, row) {
+							return row.is_show === value;
+						},
+						filterMultiple: false,
+					},
+					{
+						title: '操作',
+						slot: 'action',
+						fixed: 'right',
+						minWidth: 220,
+					},
+				],
+				data: [],
+				total: 0,
+				attrTemplate: false,
+				selectedIds: new Set(), //选中合并项的id
+				ids: [],
+				goodsId: '',
+				isProductBox: false,
+				treeSelect: [],
+			};
+		},
+		watch: {
+			$route() {
+				if (this.$route.fullPath === this.$routeProStrshop + '/product/product_list?type=5') {
+					this.getPath();
+				}
+			},
+		},
+		created() {},
+		activated() {
+			this.goodHeade();
+			this.goodsCategory();
+			if (this.$route.fullPath === this.$routeProStrshop + '/product/product_list?type=5') {
+				this.getPath();
+			} else {
+				this.getDataList();
+			}
+		},
+		methods: {
+			batchSub() {
+				let data = this.batchFormData;
+				data.ids = this.ids;
+				data.type = this.batchType;
+				let activeIds = [];
+				this.dataLabel.forEach((item) => {
+					activeIds.push(item.id);
+				});
+				data.label_id = activeIds;
+				batchSetting(data)
+					.then((res) => {
+						this.$Message.success(res.msg);
+						this.getDataList();
+						this.clearBatchData(false);
+						this.ids = [];
+						this.clearAll(false);
+					})
+					.catch((err) => {
+						this.$Message.error(err.msg);
+					});
+			},
+			clearBatchData(status) {
+				if (!status) {
+					this.batchFormData = {
+						cate_id: [],
+						logistics: [],
+						freight: 0,
+						postage: null,
+						temp_id: null,
+						give_integral: null,
+						label_id: [],
+						coupon_ids: [],
+						recommend: [],
+					};
+					this.dataLabel = [];
+				}
+			},
+			// 批量设置商品
+			batchSelect(type) {
+				if (!this.ids.length) {
+					this.$Message.warning('请选择要修改的商品');
+				} else {
+					this.batchType = type;
+					this.batchModal = true;
+					this.productGetTemplate();
+				}
+			},
+			activeData(dataLabel) {
+				this.labelShow = false;
+				this.dataLabel = dataLabel;
+			},
+			nameId(id, names) {
+				this.batchFormData.coupon_ids = id;
+				this.couponName = this.unique(names);
+			},
+			handleClose(name) {
+				let index = this.couponName.indexOf(name);
+				this.couponName.splice(index, 1);
+				this.formValidate.coupon_ids.splice(index, 1);
+			},
+			//对象数组去重;
+			unique(arr) {
+				const res = new Map();
+				return arr.filter((arr) => !res.has(arr.id) && res.set(arr.id, 1));
+			},
+			// 获取运费模板;
+			productGetTemplate() {
+				productGetTemplateApi().then((res) => {
+					this.templateList = res.data;
+				});
+			},
+			// 标签弹窗关闭
+			labelClose() {
+				this.labelShow = false;
+			},
+			look(row) {
+				this.goodsId = row.id;
+				this.isProductBox = true;
+			},
+			// 物流方式
+			logisticsBtn(e) {
+				this.batchFormData.logistics = e;
+			},
+			// 关联用户标签
+			openLabel(row) {
+				this.labelShow = true;
+				this.$refs.userLabel.userLabel(JSON.parse(JSON.stringify(this.dataLabel)));
+			},
+			closeLabel(label) {
+				let index = this.dataLabel.indexOf(this.dataLabel.filter((d) => d.id == label.id)[0]);
+				this.dataLabel.splice(index, 1);
+			},
+			// 添加优惠券
+			addCoupon() {
+				this.$refs.couponTemplates.isTemplate = true;
+				this.$refs.couponTemplates.tableList();
+			},
+			getPath() {
+				this.columns2 = [...this.columns];
+				if (name !== '1' && name !== '2') {
+					this.columns2.shift({
+						type: 'selection',
+						width: 60,
+						align: 'center',
+					});
+				}
+				this.artFrom.page = 1;
+				this.artFrom.type = this.$route.query.type.toString();
+				this.getDataList();
+			},
+			// 导出
+			async exports() {
+				let [th, filekey, data, fileName] = [
+					[],
+					[],
+					[], ''
+				];
+				let excelData = JSON.parse(JSON.stringify(this.artFrom));
+				excelData.page = 1;
+				excelData.limit = 50;
+				excelData.ids = this.ids;
+				for (let i = 0; i < excelData.page + 1; i++) {
+					let lebData = await this.getExcelData(excelData);
+					if (!fileName) fileName = lebData.filename;
+					if (!filekey.length) {
+						filekey = lebData.fileKey;
+					}
+					if (!th.length) th = lebData.header;
+					if (lebData.export.length) {
+						data = data.concat(lebData.export);
+						excelData.page++;
+					} else {
+						this.$exportExcel(th, filekey, fileName, data);
+						return;
+					}
+				}
+			},
+			getExcelData(excelData) {
+				return new Promise((resolve, reject) => {
+					shopexportProductList(excelData).then((res) => {
+						resolve(res.data);
+					});
+				});
+			},
+			changeTemplate(e) {
+				// this.template = e;
+			},
+			freight() {
+				this.$refs.template.isTemplate = true;
+			},
+			// 批量上架
+			onShelves() {
+				if (this.ids.length === 0) {
+					this.$Message.warning('请选择要上架的商品');
+				} else {
+					let data = {
+						ids: this.ids,
+					};
+					productShowApi(data)
+						.then((res) => {
+							this.$Message.success(res.msg);
+							this.goodHeade();
+							this.getDataList();
+						})
+						.catch((res) => {
+							this.$Message.error(res.msg);
+						});
+				}
+			},
+			// 批量下架
+			onDismount() {
+				if (this.ids.length === 0) {
+					this.$Message.warning('请选择要下架的商品');
+				} else {
+					let data = {
+						ids: this.ids,
+					};
+					productUnshowApi(data)
+						.then((res) => {
+							this.$Message.success(res.msg);
+							this.artFrom.page = 1;
+							this.goodHeade();
+							this.getDataList();
+						})
+						.catch((res) => {
+							this.$Message.error(res.msg);
+						});
+				}
+			},
+
+			// 全选
+			// onSelectTab (selection) {
+			//     let data = []
+			//     selection.map((item) => {
+			//         data.push(item.id)
+			//     })
+			//     this.ids = data
+			// },
+			//全选和取消全选时触发
+			handleSelectAll(selection) {
+				if (selection.length === 0) {
+					//获取table的数据;
+					let data = this.$refs.table.data;
+					data.forEach((item) => {
+						if (this.selectedIds.has(item.id)) {
+							this.selectedIds.delete(item.id);
+						}
+					});
+				} else {
+					selection.forEach((item) => {
+						this.selectedIds.add(item.id);
+					});
+				}
+				this.$nextTick(() => {
+					//确保dom加载完毕
+					this.setChecked();
+				});
+			},
+			//  选中某一行
+			handleSelectRow(selection, row) {
+				this.selectedIds.add(row.id);
+				this.$nextTick(() => {
+					//确保dom加载完毕
+					this.setChecked();
+				});
+			},
+			clearAll(status) {
+				this.$refs.table.selectAll(status);
+			},
+			//  取消某一行
+			handleCancelRow(selection, row) {
+				this.selectedIds.delete(row.id);
+				this.$nextTick(() => {
+					//确保dom加载完毕
+					this.setChecked();
+				});
+			},
+			setChecked() {
+				//将new Set()转化为数组
+				this.ids = [...this.selectedIds];
+				// 找到绑定的table的ref对应的dom,找到table的objData对象,objData保存的是当前页的数据
+				let objData = this.$refs.table.objData;
+				for (let index in objData) {
+					if (this.selectedIds.has(objData[index].id)) {
+						objData[index]._isChecked = true;
+					}
+				}
+			},
+			// 添加淘宝商品成功
+			onClose() {
+				this.modals = false;
+			},
+			// 复制淘宝
+			onCopy() {
+				this.$router.push({
+					path: this.$routeProStrshop + '/product/add_product',
+					query: {
+						type: -1
+					},
+				});
+				// this.modals = true
+			},
+			// tab选择
+			onClickTab(name) {
+				this.artFrom.type = name;
+				this.columns2 = [...this.columns];
+				if (name !== '1' && name !== '2') {
+					this.columns2.shift({
+						type: 'selection',
+						width: 60,
+						align: 'center',
+					});
+				}
+				this.artFrom.page = 1;
+				this.selectedIds.clear();
+				this.getDataList();
+			},
+			// 下拉树
+			handleCheckChange(data) {
+				let value = '';
+				let title = '';
+				this.list = [];
+				this.artFrom.cate_id = 0;
+				data.forEach((item, index) => {
+					value += `${item.id},`;
+					title += `${item.title},`;
+				});
+				value = value.substring(0, value.length - 1);
+				title = title.substring(0, title.length - 1);
+				this.list.push({
+					value,
+					title,
+				});
+				this.artFrom.cate_id = value;
+				this.getDataList();
+			},
+			// 获取商品表单头数量
+			goodHeade() {
+				getGoodHeade()
+					.then((res) => {
+						this.headeNum = res.data.list;
+					})
+					.catch((res) => {
+						this.$Message.error(res.msg);
+					});
+			},
+			// 商品分类;
+			goodsCategory() {
+				cascaderListApi(1)
+					.then((res) => {
+						this.treeSelect = res.data;
+					})
+					.catch((res) => {
+						this.$Message.error(res.msg);
+					});
+			},
+			// 商品列表;
+			getDataList() {
+				this.loading = true;
+				this.artFrom.cate_id = this.artFrom.cate_id || '';
+				getGoods(this.artFrom)
+					.then((res) => {
+						let data = res.data;
+						this.tableList = data.list;
+						this.total = res.data.count;
+						this.$nextTick(() => {
+							//确保dom加载完毕
+							this.setChecked();
+						});
+						this.loading = false;
+					})
+					.catch((res) => {
+						this.loading = false;
+						this.$Message.error(res.msg);
+					});
+			},
+			pageChange(status) {
+				this.artFrom.page = status;
+				this.getDataList();
+			},
+			// 表格搜索
+			userSearchs() {
+				this.artFrom.page = 1;
+				this.getDataList();
+			},
+			// 上下架
+			changeSwitch(row) {
+				PostgoodsIsShow(row.id, row.is_show)
+					.then((res) => {
+						this.$Message.success(res.msg);
+						this.goodHeade();
+						this.getDataList();
+					})
+					.catch((res) => {
+						row.is_show = !row.is_show ? 1 : 0;
+						this.$Message.error(res.msg);
+					});
+			},
+			// 数据导出;
+			exportData: function() {
+				let th = ['商品名称', '商品简介', '商品分类', '价格', '库存', '销量', '收藏人数'];
+				let filterVal = ['store_name', 'store_info', 'cate_name', 'price', 'stock', 'sales', 'collect'];
+				this.where.page = 'nopage';
+				getGoods(this.where).then((res) => {
+					let data = res.data.map((v) => filterVal.map((k) => v[k]));
+					let fileTime = Date.parse(new Date());
+					let [fileName, fileType, sheetName] = ['商户数据_' + fileTime, 'xlsx', '商户数据'];
+					toExcel({
+						th,
+						data,
+						fileName,
+						fileType,
+						sheetName
+					});
+				});
+			},
+			// 属性弹出;
+			attrTap() {
+				this.attrTemplate = true;
+			},
+			changeTemplate(msg) {
+				this.attrTemplate = msg;
+			},
+			// 编辑
+			edit(row) {
+				this.$router.push({
+					path: this.$routeProStrshop + '/product/add_product/' + row.id
+				});
+			},
+			// 确认
+			del(row, tit, num) {
+				let delfromData = {
+					title: tit,
+					num: num,
+					url: `mer/product/${row.id}`,
+					method: 'DELETE',
+					ids: '',
+					un: 1,
+				};
+				this.$modalSure(delfromData)
+					.then((res) => {
+						this.$Message.success(res.msg);
+						this.tableList.splice(num, 1);
+						this.goodHeade();
+					})
+					.catch((res) => {
+						this.$Message.error(res.msg);
+					});
+			},
+			// 删除成功
+			// submitModel () {
+			//     this.tableList.splice(this.delfromData.num, 1);
+			//     this.goodHeade();
+			// }
+		},
+	};
+</script>
+<style scoped lang="stylus">
+	/deep/.ivu-modal-mask {
+		z-index: 999 !important;
+	}
+
+	/deep/.ivu-modal-wrap {
+		z-index: 999 !important;
+	}
+
+	.Box {
+		>>>.ivu-modal-body {
+			height: 700px;
+			overflow: auto;
+		}
+	}
+
+	.batch-box {
+		>>>.ivu-modal-body {
+			overflow: auto;
+			min-height: 350px;
+		}
+	}
+
+	.tabBox_img {
+		width: 36px;
+		height: 36px;
+		border-radius: 4px;
+		cursor: pointer;
+
+		img {
+			width: 100%;
+			height: 100%;
+		}
+	}
+
+	.bg {
+		position: fixed;
+		left: 0;
+		top: 0;
+		width: 100%;
+		height: 100%;
+		background: rgba(0, 0, 0, 0.5);
+		z-index: 11;
+	}
+
+	/deep/.happy-scroll-content {
+		width: 100%;
+
+		.demo-spin-icon-load {
+			animation: ani-demo-spin 1s linear infinite;
+		}
+
+		@keyframes ani-demo-spin {
+			from {
+				transform: rotate(0deg);
+			}
+
+			50% {
+				transform: rotate(180deg);
+			}
+
+			to {
+				transform: rotate(360deg);
+			}
+		}
+
+		.demo-spin-col {
+			height: 100px;
+			position: relative;
+			border: 1px solid #eee;
+		}
+	}
+
+	.labelInput {
+		border: 1px solid #dcdee2;
+		width: 20%;
+		padding: 0 5px;
+		border-radius: 5px;
+		min-height: 30px;
+		cursor: pointer;
+
+		.span {
+			color: #c5c8ce;
+		}
+
+		.iconxiayi {
+			font-size: 12px;
+		}
+	}
+</style>

+ 40 - 0
src/pages/shop_product/productList/tableExpand.vue

@@ -0,0 +1,40 @@
+<template>
+  <div>
+    <Row class="expand-row">
+      <Col span="8" class="mr20">
+        <span class="expand-key">商品分类:</span>
+        <span class="expand-value">{{ row.cate_name }}</span>
+      </Col>
+      <Col span="8">
+        <span class="expand-key">商品市场价格:</span>
+        <span class="expand-value">{{ row.ot_price }}</span>
+      </Col>
+      <Col span="8">
+        <span class="expand-key">成本价:</span>
+        <span class="expand-value">{{ row.cost }}</span>
+      </Col>
+    </Row>
+    <Row class="expand-row">
+      <Col span="8">
+        <span class="expand-key">收藏:</span>
+        <span class="expand-value">{{ row.collect }}</span>
+      </Col>
+      <Col span="8">
+        <span class="expand-key">虚拟销量:</span>
+        <span class="expand-value">{{ row.ficti }}</span>
+      </Col>
+    </Row>
+  </div>
+</template>
+<style scoped>
+.expand-row {
+  margin-bottom: 16px;
+}
+</style>
+<script>
+export default {
+  props: {
+    row: Object,
+  },
+};
+</script>

+ 759 - 0
src/pages/shop_product/productList/taoBao.vue

@@ -0,0 +1,759 @@
+<template>
+	<div class="Box">
+		<!-- <Card>
+      <div>
+        生成的商品默认是没有上架的,请手动上架商品!
+        <a href="http://help.crmeb.net/crmeb-v4/1863579" v-if="copyConfig.copy_type == 2" target="_blank"
+          >如何配置密钥</a
+        >
+        <span v-else
+          >您当前剩余{{ copyConfig.copy_num }}条采集次数,<a class="add" @click="mealPay('copy')">增加采集次数</a></span
+        >
+      </div>
+      <div>商品采集设置:设置 > 系统设置 > 第三方接口设置 > 采集商品配置</div>
+    </Card> -->
+		<Form class="formValidate mt20" ref="formValidate" :model="formValidate" :rules="ruleInline" :label-width="120"
+			label-position="right" @submit.native.prevent>
+			<Row :gutter="24" type="flex">
+				<!--<Col span="24">-->
+				<!--<FormItem label=""  label-for="">-->
+				<!--<RadioGroup v-model="artFrom.type">-->
+				<!--<Radio label="taobao">淘宝</Radio>-->
+				<!--<Radio label="tmall">天猫</Radio>-->
+				<!--<Radio label="jd">京东</Radio>-->
+				<!--<Radio label="pdd">拼多多</Radio>-->
+				<!--<Radio label="suning">苏宁</Radio>-->
+				<!--<Radio label="1688">1688</Radio>-->
+				<!--</RadioGroup>-->
+				<!--</FormItem>-->
+				<!--</Col>-->
+				<Col span="15">
+				<FormItem label="链接地址:">
+					<Input search enter-button="确定" v-model="soure_link" placeholder="请输入链接地址" class="numPut"
+						@on-search="add" />
+				</FormItem>
+				</Col>
+				<div>
+					<div v-if="isData">
+						<Col span="24" class="">
+						<FormItem label="商品名称:" prop="store_name">
+							<Input v-model="formValidate.store_name" placeholder="请输入商品名称" />
+						</FormItem>
+						</Col>
+						<Col span="24">
+						<FormItem label="商品简介:" prop="store_info" label-for="store_info">
+							<Input v-model="formValidate.store_info" type="textarea" :rows="3" placeholder="请输入商品简介" />
+						</FormItem>
+						</Col>
+						<Col span="24">
+						<FormItem label="商品分类:" prop="cate_id">
+							<!-- <Select v-model="formValidate.cate_id" multiple>
+                  <Option v-for="item in treeSelect" :disabled="item.pid === 0" :value="item.id" :key="item.id">{{
+                    item.html + item.cate_name
+                  }}</Option>
+                </Select> -->
+							<el-cascader v-model="formValidate.cate_id" size="small" :options="treeSelect"
+								:props="{ multiple: true, emitPath: false }" clearable></el-cascader>
+						</FormItem>
+						</Col>
+						<Col v-bind="grid">
+						<FormItem label="商品关键字:" prop="keyword" label-for="keyword">
+							<Input v-model="formValidate.keyword" placeholder="请输入商品关键字" />
+						</FormItem>
+						</Col>
+						<Col v-bind="grid">
+						<FormItem label="单位:" prop="unit_name" label-for="unit_name">
+							<Input v-model="formValidate.unit_name" placeholder="请输入单位" />
+						</FormItem>
+						</Col>
+						<Col v-bind="grid">
+						<FormItem label="虚拟销量:" label-for="ficti">
+							<InputNumber class="perW100" v-model="formValidate.ficti" placeholder="请输入虚拟销量" />
+						</FormItem>
+						</Col>
+						<Col v-bind="grid">
+						<FormItem label="积分:" label-for="give_integral">
+							<InputNumber class="perW100" v-model="formValidate.give_integral" placeholder="请输入积分" />
+						</FormItem>
+						</Col>
+						<Col v-bind="grid">
+						<FormItem label="运费模板:" prop="temp_id">
+							<Select v-model="formValidate.temp_id" clearable>
+								<Option v-for="(item, index) in templateList" :value="item.id" :key="index">
+									{{ item.name }}
+								</Option>
+							</Select>
+						</FormItem>
+						</Col>
+						<!--<Col v-bind="grid">-->
+						<!--<FormItem label="邮费:"  label-for="postage">-->
+						<!--<InputNumber  v-model="formValidate.postage" placeholder="请输入邮费"  />-->
+						<!--</FormItem>-->
+						<!--</Col>-->
+						<Col span="24">
+						<FormItem label="商品图:">
+							<div class="pictrueBox">
+								<div class="pictrue" v-if="formValidate.image" v-viewer>
+									<img v-lazy="formValidate.image" />
+								</div>
+							</div>
+						</FormItem>
+						</Col>
+						<Col span="24">
+						<FormItem label="商品轮播图:">
+							<div class="acea-row" v-viewer>
+								<div class="lunBox mr15" v-for="(item, index) in formValidate.slider_image" :key="index"
+									draggable="true" @dragstart="handleDragStart($event, item)"
+									@dragover.prevent="handleDragOver($event, item)"
+									@dragenter="handleDragEnter($event, item)" @dragend="handleDragEnd($event, item)">
+									<div class="pictrue"><img v-lazy="item" /></div>
+									<ButtonGroup size="small">
+										<Button @click.native="checked(item, index)">主图</Button>
+										<Button @click.native="handleRemove(index)">移除</Button>
+									</ButtonGroup>
+								</div>
+							</div>
+						</FormItem>
+						</Col>
+						<Col span="24">
+						<FormItem label="批量设置:" class="labeltop" v-if="formValidate.attrs">
+							<Col :xl="23" :lg="24" :md="24" :sm="24" :xs="24">
+							<FormItem>
+								<Table :data="oneFormBatch" :columns="columnsBatch" border>
+									<template slot-scope="{ row, index }" slot="pic">
+										<div class="acea-row row-middle row-center-wrapper"
+											@click="modalPicTap('dan', 'duopi', index)">
+											<div class="pictrue pictrueTab" v-if="oneFormBatch[0].pic">
+												<img v-lazy="oneFormBatch[0].pic" />
+											</div>
+											<div class="upLoad pictrueTab acea-row row-center-wrapper" v-else>
+												<Icon type="ios-camera-outline" size="21" class="iconfont" />
+											</div>
+										</div>
+									</template>
+									<template slot-scope="{ row, index }" slot="price">
+										<InputNumber v-model="oneFormBatch[0].price" :min="0" class="priceBox">
+										</InputNumber>
+									</template>
+									<template slot-scope="{ row, index }" slot="cost">
+										<InputNumber v-model="oneFormBatch[0].cost" :min="0" class="priceBox">
+										</InputNumber>
+									</template>
+									<template slot-scope="{ row, index }" slot="ot_price">
+										<InputNumber v-model="oneFormBatch[0].ot_price" :min="0" class="priceBox">
+										</InputNumber>
+									</template>
+									<template slot-scope="{ row, index }" slot="stock">
+										<InputNumber v-model="oneFormBatch[0].stock" :min="0" class="priceBox">
+										</InputNumber>
+									</template>
+									<template slot-scope="{ row, index }" slot="bar_code">
+										<Input v-model="oneFormBatch[0].bar_code"></Input>
+									</template>
+									<template slot-scope="{ row, index }" slot="weight">
+										<InputNumber v-model="oneFormBatch[0].weight" :min="0" class="priceBox">
+										</InputNumber>
+									</template>
+									<template slot-scope="{ row, index }" slot="volume">
+										<InputNumber v-model="oneFormBatch[0].volume" :min="0" class="priceBox">
+										</InputNumber>
+									</template>
+									<template slot-scope="{ row, index }" slot="action">
+										<a @click="batchAdd">添加</a>
+										<Divider type="vertical" />
+										<a @click="batchDel">清空</a>
+									</template>
+								</Table>
+							</FormItem>
+							</Col>
+						</FormItem>
+						</Col>
+						<Col span="24">
+						<FormItem label="商品规格:" props="spec_type" label-for="spec_type">
+							<!-- 单规格表格-->
+							<Col :xl="23" :lg="24" :md="24" :sm="24" :xs="24">
+							<FormItem>
+								<Table :data="items" :columns="columns" border>
+									<template slot-scope="{ row, index }" slot="pic">
+										<div class="acea-row row-middle row-center-wrapper"
+											@click="modalPicTap('dan', index)">
+											<div class="pictrue pictrueTab" v-if="formValidate.attrs[index].pic">
+												<img v-lazy="formValidate.attrs[index].pic" />
+											</div>
+											<div class="upLoad upLoadTab acea-row row-center-wrapper" v-else>
+												<Icon type="ios-camera-outline" size="26" class="iconfont" />
+											</div>
+										</div>
+									</template>
+									<template slot-scope="{ row, index }" slot="price">
+										<InputNumber v-model="formValidate.attrs[index].price" class="priceBox">
+										</InputNumber>
+									</template>
+									<template slot-scope="{ row, index }" slot="cost">
+										<InputNumber v-model="formValidate.attrs[index].cost" class="priceBox">
+										</InputNumber>
+									</template>
+									<template slot-scope="{ row, index }" slot="ot_price">
+										<InputNumber v-model="formValidate.attrs[index].ot_price" class="priceBox">
+										</InputNumber>
+									</template>
+									<template slot-scope="{ row, index }" slot="stock">
+										<InputNumber v-model="formValidate.attrs[index].stock" class="priceBox">
+										</InputNumber>
+									</template>
+									<template slot-scope="{ row, index }" slot="bar_code">
+										<Input v-model="formValidate.attrs[index].bar_code"></Input>
+									</template>
+									<template slot-scope="{ row, index }" slot="weight">
+										<InputNumber v-model="formValidate.attrs[index].weight" :min="0"
+											class="priceBox"></InputNumber>
+									</template>
+									<template slot-scope="{ row, index }" slot="volume">
+										<InputNumber v-model="formValidate.attrs[index].volume" :min="0"
+											class="priceBox"></InputNumber>
+									</template>
+									<template slot-scope="{ row, index }" slot="action">
+										<a @click="delAttrTable(index)">删除</a>
+									</template>
+								</Table>
+							</FormItem>
+							</Col>
+						</FormItem>
+						</Col>
+						<Col span="24">
+						<FormItem label="商品详情:">
+							<WangEditor style="width: 100%" :content="formValidate.description"
+								@editorContent="getEditorContent"></WangEditor>
+						</FormItem>
+						</Col>
+						<Col span="24">
+						<FormItem>
+							<Button type="primary" :loading="modal_loading" class="submission"
+								@click="handleSubmit('formValidate')">提交</Button>
+						</FormItem>
+						</Col>
+					</div>
+					<Spin size="large" fix v-if="spinShow"></Spin>
+				</div>
+			</Row>
+		</Form>
+		<Modal v-model="modalPic" width="950px" scrollable footer-hide closable title="上传商品图" :mask-closable="false"
+			:z-index="9999">
+			<uploadPictures :isChoice="isChoice" @getPic="getPic" :gridBtn="gridBtn" :gridPic="gridPic" v-if="modalPic">
+			</uploadPictures>
+		</Modal>
+	</div>
+</template>
+
+<script>
+	import {
+		crawlFromApi,
+		cascaderListApi,
+		crawlSaveApi,
+		productGetTemplateApi,
+		copyConfigApi
+	} from '@/api/shop_product';
+	import uploadPictures from '@/components/uploadPictures2';
+	import WangEditor from '@/components/wangEditor/index.vue';
+
+	export default {
+		name: 'taoBao',
+		data() {
+			return {
+				// 批量设置表格data
+				oneFormBatch: [{
+					pic: '',
+					price: 0,
+					cost: 0,
+					ot_price: 0,
+					stock: 0,
+					bar_code: '',
+					weight: 0,
+					volume: 0,
+				}, ],
+				columnsBatch: [{
+						title: '图片',
+						slot: 'pic',
+						align: 'center',
+						minWidth: 80,
+					},
+					{
+						title: '售价',
+						slot: 'price',
+						align: 'center',
+						minWidth: 95,
+					},
+					{
+						title: '成本价',
+						slot: 'cost',
+						align: 'center',
+						minWidth: 95,
+					},
+					{
+						title: '原价',
+						slot: 'ot_price',
+						align: 'center',
+						minWidth: 95,
+					},
+					{
+						title: '库存',
+						slot: 'stock',
+						align: 'center',
+						minWidth: 95,
+					},
+					{
+						title: '商品编号',
+						slot: 'bar_code',
+						align: 'center',
+						minWidth: 120,
+					},
+					{
+						title: '重量(KG)',
+						slot: 'weight',
+						align: 'center',
+						minWidth: 95,
+					},
+					{
+						title: '体积(m³)',
+						slot: 'volume',
+						align: 'center',
+						minWidth: 95,
+					},
+					{
+						title: '操作',
+						slot: 'action',
+						align: 'center',
+						minWidth: 140,
+					},
+				],
+				modal_loading: false,
+				images: '',
+				soure_link: '',
+				modalPic: false,
+				isChoice: '',
+				spinShow: false,
+				gridPic: {
+					xl: 6,
+					lg: 8,
+					md: 12,
+					sm: 12,
+					xs: 12,
+				},
+				gridBtn: {
+					xl: 4,
+					lg: 8,
+					md: 8,
+					sm: 8,
+					xs: 8,
+				},
+				columns: [],
+				treeSelect: [],
+				ruleInline: {
+					cate_id: [{
+						required: true,
+						message: '请选择商品分类',
+						trigger: 'change',
+						type: 'array',
+						min: '1',
+					}, ],
+					temp_id: [{
+						required: true,
+						message: '请选择运费模板',
+						trigger: 'change',
+						type: 'number',
+					}, ],
+				},
+				grid: {
+					xl: 8,
+					lg: 8,
+					md: 12,
+					sm: 24,
+					xs: 24,
+				},
+				grid2: {
+					xl: 12,
+					lg: 12,
+					md: 12,
+					sm: 24,
+					xs: 24,
+				},
+				formValidate: {
+					store_name: '',
+					cate_id: [],
+					temp_id: '',
+					keyword: '',
+					unit_name: '',
+					store_info: '',
+					image: '',
+					slider_image: [],
+					description: '',
+					ficti: 0,
+					give_integral: 0,
+					is_show: 0,
+					price: 0,
+					cost: 0,
+					ot_price: 0,
+					stock: 0,
+					soure_link: '',
+					description_images: '',
+					postage: 0,
+					attrs: [],
+					items: [],
+				},
+				items: [{
+					pic: '',
+					price: 0,
+					cost: 0,
+					ot_price: 0,
+					stock: 0,
+					bar_code: '',
+					weight: 0,
+					volume: 0,
+				}, ],
+				templateList: [],
+				copyConfig: {
+					copy_type: 2,
+					copy_num: 0,
+				},
+				isData: false,
+				artFrom: {
+					type: 'taobao',
+					url: '',
+				},
+				tableIndex: 0,
+				content: '',
+			};
+		},
+		components: {
+			WangEditor,
+			uploadPictures
+		},
+		computed: {},
+
+		created() {
+			this.goodsCategory();
+		},
+		mounted() {
+			this.productGetTemplate();
+			this.getCopyConfig();
+		},
+		methods: {
+			mealPay(val) {
+				this.$router.push({
+					path: this.$routeProStr + '/setting/sms/sms_pay/index',
+					query: {
+						type: val
+					},
+				});
+			},
+			batchDel() {
+				this.oneFormBatch = [{
+					pic: '',
+					price: 0,
+					cost: 0,
+					ot_price: 0,
+					stock: 0,
+					bar_code: '',
+					weight: 0,
+					volume: 0,
+				}, ];
+			},
+			batchAdd() {
+				let formBatch = this.oneFormBatch[0];
+				this.$set(
+					this.formValidate,
+					'attrs',
+					this.formValidate.attrs.map((item) => {
+						if (formBatch.pic) {
+							item.pic = formBatch.pic;
+						}
+						if (formBatch.price > 0) {
+							item.price = formBatch.price;
+						}
+						if (formBatch.cost > 0) {
+							item.cost = formBatch.cost;
+						}
+						if (formBatch.ot_price > 0) {
+							item.ot_price = formBatch.ot_price;
+						}
+						if (formBatch.stock > 0) {
+							item.stock = formBatch.stock;
+						}
+						if (formBatch.bar_code) {
+							item.bar_code = formBatch.bar_code;
+						}
+						if (formBatch.weight) {
+							item.weight = formBatch.weight;
+						}
+						if (formBatch.volume) {
+							item.weight = formBatch.volume;
+						}
+						return item;
+					}),
+				);
+			},
+			getEditorContent(data) {
+				this.content = data;
+			},
+			// 删除表格中的属性
+			delAttrTable(index) {
+				this.items.splice(index, 1);
+			},
+			// 获取运费模板;
+			productGetTemplate() {
+				productGetTemplateApi().then((res) => {
+					this.templateList = res.data;
+				});
+			},
+			getCopyConfig() {
+				copyConfigApi().then((res) => {
+					this.copyConfig.copy_type = res.data.copy_type;
+					this.copyConfig.copy_num = res.data.copy_num;
+				});
+			},
+			// 删除图片
+			handleRemove(i) {
+				this.formValidate.slider_image.splice(i, 1);
+			},
+			// 选择主图
+			checked(item, index) {
+				this.formValidate.image = item;
+			},
+			// 商品分类;
+			goodsCategory() {
+				cascaderListApi(1)
+					.then((res) => {
+						this.treeSelect = res.data;
+					})
+					.catch((res) => {
+						this.$Message.error(res.msg);
+					});
+			},
+			// 生成表单
+			add() {
+				if (this.soure_link) {
+					var reg = /(http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?/;
+					if (!reg.test(this.soure_link)) {
+						return this.$Message.warning('请输入以http开头的地址!');
+					}
+					this.spinShow = true;
+					this.artFrom.url = this.soure_link;
+					crawlFromApi(this.artFrom)
+						.then((res) => {
+							let info = res.data.info;
+							this.columns = info.info.header;
+							this.formValidate = info;
+							this.formValidate.soure_link = this.soure_link;
+							this.formValidate.attrs = info.info.value;
+							if (this.formValidate.image) {
+								this.oneFormBatch[0].pic = this.formValidate.image;
+							}
+							this.items = this.formValidate.attrs;
+							this.isData = true;
+							this.spinShow = false;
+						})
+						.catch((res) => {
+							this.spinShow = false;
+							this.$Message.error(res.msg);
+						});
+				} else {
+					this.$Message.warning('请输入链接地址!');
+				}
+			},
+			// 提交
+			handleSubmit(name) {
+				this.formValidate.description = this.content;
+				this.$refs[name].validate((valid) => {
+					if (valid) {
+						this.modal_loading = true;
+						// this.formValidate.attrs = [
+						//     {
+						//         pic: this.images,
+						//         price: this.formValidate.price,
+						//         cost: this.formValidate.cost,
+						//         ot_price: this.formValidate.ot_price,
+						//         stock: this.formValidate.stock,
+						//         bar_code: this.formValidate.bar_code,
+						//         weight: this.formValidate.weight,
+						//         volume: this.formValidate.volume
+						//     }
+						// ];
+						// this.formValidate.items = [];
+						crawlSaveApi(this.formValidate)
+							.then((res) => {
+								this.$Message.success('商品默认为不上架状态请手动上架商品!');
+								setTimeout(() => {
+									this.modal_loading = false;
+								}, 500);
+								setTimeout(() => {
+									this.$emit('on-close');
+								}, 600);
+							})
+							.catch((res) => {
+								this.modal_loading = false;
+								this.$Message.error(res.msg);
+							});
+					} else {
+						if (!this.formValidate.cate_id) {
+							this.$Message.warning('请填写商品分类!');
+						}
+					}
+				});
+			},
+			// 点击商品图
+			modalPicTap(tit, index) {
+				this.modalPic = true;
+				this.isChoice = tit === 'dan' ? '单选' : '多选';
+				this.tableIndex = index;
+			},
+			// 获取单张图片信息
+			getPic(pc) {
+				if (this.tableIndex === 'duopi') {
+					this.oneFormBatch[0].pic = pc.att_dir;
+				} else {
+					this.formValidate.attrs[this.tableIndex].pic = pc.att_dir;
+				}
+				this.modalPic = false;
+			},
+			handleDragStart(e, item) {
+				this.dragging = item;
+			},
+			handleDragEnd(e, item) {
+				this.dragging = null;
+			},
+			// 首先把div变成可以放置的元素,即重写dragenter/dragover
+			handleDragOver(e) {
+				// e.dataTransfer.dropEffect="move";//在dragenter中针对放置目标来设置!
+				e.dataTransfer.dropEffect = 'move';
+			},
+			handleDragEnter(e, item) {
+				// 为需要移动的元素设置dragstart事件
+				e.dataTransfer.effectAllowed = 'move';
+				if (item === this.dragging) {
+					return;
+				}
+				const newItems = [...this.formValidate.slider_image];
+				const src = newItems.indexOf(this.dragging);
+				const dst = newItems.indexOf(item);
+				newItems.splice(dst, 0, ...newItems.splice(src, 1));
+				this.formValidate.slider_image = newItems;
+			},
+			// 添加自定义弹窗
+			addCustomDialog(editorId) {
+				window.UE.registerUI(
+					'test-dialog',
+					function(editor, uiName) {
+						// 创建 dialog
+						let dialog = new window.UE.ui.Dialog({
+							iframeUrl: this.$routeProStr + '/widget.images/index.html?fodder=dialog',
+							editor: editor,
+							name: uiName,
+							title: '上传图片',
+							cssRules: 'width:960px;height:550px;padding:20px;',
+						});
+						this.dialog = dialog;
+						let btn = new window.UE.ui.Button({
+							name: 'dialog-button',
+							title: '上传图片',
+							cssRules: `background-image: url(../../../assets/images/icons.png);background-position: -726px -77px;`,
+							onclick: function() {
+								// 渲染dialog
+								dialog.render();
+								dialog.open();
+							},
+						});
+						return btn;
+					},
+					37,
+				);
+				// window.UE.registerUI('test-dialog', function (editor, uiName) {
+				//     let dialog = new window.UE.ui.Dialog({
+				//         iframeUrl: '/admin/widget.images/index.html?fodder=dialog',
+				//         editor: editor,
+				//         name: uiName,
+				//         title: '上传图片',
+				//         cssRules: 'width:960px;height:550px;padding:20px;'
+				//     })
+				//     this.dialog = dialog
+				//     var btn = new window.UE.ui.Button({
+				//         name: 'dialog-button',
+				//         title: '上传图片',
+				//         cssRules: `background-image: url(../../../assets/images/icons.png);background-position: -726px -77px;`,
+				//         onclick: function () {
+				//             dialog.render()
+				//             dialog.open()
+				//         }
+				//     })
+				//     return btn
+				// }, 37)
+			},
+		},
+	};
+</script>
+
+<style scoped lang="stylus">
+	/deep/.ivu-form-item-content {
+		line-height: unset !important;
+	}
+
+	.Box .ivu-radio-wrapper {
+		margin-right: 25px;
+	}
+
+	.Box .numPut {
+		width: 100% !important;
+	}
+
+	.add {
+		color: #2D8cF0;
+		cursor pointer
+	}
+
+	.lunBox {
+		/* width 80px */
+		display: flex;
+		flex-direction: column;
+		border: 1px solid #0bb20c;
+	}
+
+	.pictrueBox {
+		display: inline-block;
+	}
+
+	.pictrue {
+		width: 85px;
+		height: 85px;
+		border: 1px dotted rgba(0, 0, 0, 0.1);
+		display: inline-block;
+		position: relative;
+		cursor: pointer;
+
+		img {
+			width: 100%;
+			height: 100%;
+		}
+	}
+
+	.pictrueTab {
+		width: 40px !important;
+		height: 40px !important;
+	}
+
+	.upLoad {
+		width: 40px;
+		height: 40px;
+		border: 1px dotted rgba(0, 0, 0, 0.1);
+		border-radius: 4px;
+		background: rgba(0, 0, 0, 0.02);
+		cursor: pointer;
+	}
+
+	.ivu-table-wrapper {
+		border-left: 1px solid #dcdee2;
+		border-top: 1px solid #dcdee2;
+	}
+
+	.ft {
+		color: red;
+	}
+</style>

+ 396 - 0
src/pages/shop_product/productReply/index.vue

@@ -0,0 +1,396 @@
+<template>
+	<div class="article-manager">
+		<div class="i-layout-page-header header-title">
+			<div class="fl_header">
+				<router-link :to="{ path: $routeProStr + '/product/product_list' }" v-if="$route.params.id"><Button
+						icon="ios-arrow-back" size="small" class="mr20">返回</Button></router-link>
+				<span class="ivu-page-header-title mr20">商品评论管理</span>
+			</div>
+		</div>
+		<Card :bordered="false" dis-hover class="ivu-mt">
+			<Form ref="formValidate" :model="formValidate" :label-width="75" label-position="left"
+				@submit.native.prevent>
+				<Row type="flex" :gutter="24">
+					<Col span="24">
+					<FormItem label="评论时间:">
+						<RadioGroup v-model="formValidate.data" type="button"
+							@on-change="selectChange(formValidate.data)" class="mr">
+							<Radio :label="item.val" v-for="(item, i) in fromList.fromTxt" :key="i">{{ item.text }}
+							</Radio>
+						</RadioGroup>
+						<DatePicker :editable="false" @on-change="onchangeTime" :value="timeVal" format="yyyy/MM/dd"
+							type="daterange" placement="bottom-end" placeholder="请选择时间" style="width: 200px">
+						</DatePicker>
+					</FormItem>
+					</Col>
+					<Col v-bind="grid">
+					<FormItem label="评价状态:">
+						<Select v-model="formValidate.is_reply" placeholder="请选择" clearable @on-change="userSearchs">
+							<Option value="1">已回复</Option>
+							<Option value="0">未回复</Option>
+						</Select>
+					</FormItem>
+					</Col>
+					<Col v-bind="grid" v-if="!$route.params.id">
+					<FormItem label="商品信息:" label-for="store_name">
+						<Input size="default" enter-button placeholder="请输入商品ID或者商品信息" clearable
+							v-model="formValidate.store_name" />
+					</FormItem>
+					</Col>
+					<Col v-bind="grid">
+					<FormItem label="用户名称:" label-for="account">
+						<Input size="default" enter-button placeholder="请输入" clearable v-model="formValidate.account" />
+					</FormItem>
+					</Col>
+					<Col :xl="3" :lg="3" :md="12" :sm="12" :xs="24" class="search">
+					<FormItem>
+						<Button type="primary" icon="ios-search" @click="userSearchs">搜索</Button>
+					</FormItem>
+					</Col>
+				</Row>
+			</Form>
+			<!--            <div class="Button">-->
+			<!--                <Button type="primary" class="bnt" icon="md-add">添加评论</Button>-->
+			<!--            </div>-->
+			<Row type="flex">
+				<Col v-bind="grid">
+				<Button v-auth="['product-reply-save_fictitious_reply']" type="primary" icon="md-add"
+					@click="add">添加自评</Button>
+				</Col>
+			</Row>
+			<Table ref="table" :columns="columns" :data="tableList" class="ivu-mt mt25" :loading="loading"
+				@on-sort-change="sortMethod" no-data-text="暂无数据" no-filtered-data-text="暂无筛选结果">
+				<template slot-scope="{ row }" slot="info">
+					<div class="imgPic acea-row row-middle">
+						<div class="pictrue" v-viewer><img v-lazy="row.image" /></div>
+						<div class="info">{{ row.store_name }}</div>
+					</div>
+				</template>
+				<template slot-scope="{ row }" slot="content">
+					<div class="mb5 content_font">{{ row.comment }}</div>
+					<div v-viewer class="pictrue mr10" v-for="(item, index) in row.pics || []" :key="index">
+						<img v-lazy="item" :src="item" />
+					</div>
+				</template>
+				<template slot-scope="{ row, index }" slot="action">
+					<a @click="reply(row)">回复</a>
+					<Divider type="vertical" />
+					<a @click="del(row, '删除评论', index)">删除</a>
+				</template>
+			</Table>
+			<div class="acea-row row-right page">
+				<Page :total="total" :current="formValidate.page" show-elevator show-total @on-change="pageChange"
+					:page-size="formValidate.limit" />
+			</div>
+		</Card>
+		<Modal v-model="modals" scrollable title="回复内容" closable>
+			<Form ref="contents" :model="contents" :rules="ruleInline" label-position="right" @submit.native.prevent>
+				<FormItem prop="content">
+					<Input v-model="contents.content" type="textarea" :rows="4" placeholder="请输入回复内容" />
+				</FormItem>
+			</Form>
+			<div slot="footer">
+				<Button type="primary" @click="oks">确定</Button>
+				<Button @click="cancels">取消</Button>
+			</div>
+		</Modal>
+	</div>
+</template>
+
+<script>
+	import {
+		mapState
+	} from 'vuex';
+	import {
+		replyListApi,
+		setReplyApi,
+		fictitiousReply
+	} from '@/api/shop_product';
+	export default {
+		name: 'product_productEvaluate',
+		data() {
+			return {
+				modals: false,
+				grid: {
+					xl: 7,
+					lg: 10,
+					md: 12,
+					sm: 12,
+					xs: 24,
+				},
+				formValidate: {
+					is_reply: '',
+					data: '',
+					store_name: '',
+					key: '',
+					order: '',
+					account: '',
+					product_id: this.$route.params.id === undefined ? 0 : this.$route.params.id,
+					page: 1,
+					limit: 15,
+				},
+				fromList: {
+					title: '选择时间',
+					custom: true,
+					fromTxt: [{
+							text: '全部',
+							val: ''
+						},
+						{
+							text: '今天',
+							val: 'today'
+						},
+						{
+							text: '昨天',
+							val: 'yesterday'
+						},
+						{
+							text: '最近7天',
+							val: 'lately7'
+						},
+						{
+							text: '最近30天',
+							val: 'lately30'
+						},
+						{
+							text: '本月',
+							val: 'month'
+						},
+						{
+							text: '本年',
+							val: 'year'
+						},
+					],
+				},
+				value: '45',
+				tableList: [],
+				total: 0,
+				loading: false,
+				columns: [{
+						title: '评论ID',
+						key: 'id',
+						width: 80,
+					},
+					{
+						title: '商品信息',
+						slot: 'info',
+						minWidth: 230,
+					},
+					{
+						title: '用户名称',
+						key: 'nickname',
+						minWidth: 150,
+					},
+					{
+						title: '评分',
+						key: 'score',
+						sortable: true,
+						minWidth: 90,
+					},
+					{
+						title: '评价内容',
+						slot: 'content',
+						minWidth: 210,
+					},
+					{
+						title: '回复内容',
+						key: 'merchant_reply_content',
+						minWidth: 250,
+					},
+					{
+						title: '评价时间',
+						key: 'add_time',
+						sortable: true,
+						minWidth: 150,
+					},
+					{
+						title: '操作',
+						slot: 'action',
+						fixed: 'right',
+						minWidth: 150,
+					},
+				],
+				timeVal: [],
+				contents: {
+					content: '',
+				},
+				ruleInline: {
+					content: [{
+						required: true,
+						message: '请输入回复内容',
+						trigger: 'blur'
+					}],
+				},
+				rows: {},
+			};
+		},
+		computed: {},
+		created() {
+			if (this.$route.query.is_reply == 0) this.formValidate.is_reply = this.$route.query.is_reply;
+			this.getList();
+		},
+		watch: {
+			'$route.params.id'(to, from) {
+				this.formValidate.product_id = 0;
+				this.getList();
+			},
+		},
+		methods: {
+			// 添加虚拟评论;
+			add() {
+				this.$modalForm(fictitiousReply(this.formValidate.product_id)).then(() => this.getList());
+			},
+			oks() {
+				this.modals = true;
+				this.$refs['contents'].validate((valid) => {
+					if (valid) {
+						setReplyApi(this.contents, this.rows.id)
+							.then(async (res) => {
+								this.$Message.success(res.msg);
+								this.modals = false;
+								this.$refs['contents'].resetFields();
+								this.getList();
+							})
+							.catch((res) => {
+								this.$Message.error(res.msg);
+							});
+					} else {
+						return false;
+					}
+				});
+			},
+			cancels() {
+				this.modals = false;
+				this.$refs['contents'].resetFields();
+			},
+			// 删除
+			del(row, tit, num) {
+				let delfromData = {
+					title: tit,
+					num: num,
+					url: `product/reply/${row.id}`,
+					method: 'DELETE',
+					ids: '',
+				};
+				this.$modalSure(delfromData)
+					.then((res) => {
+						this.$Message.success(res.msg);
+						this.tableList.splice(num, 1);
+						this.total = this.total - 1;
+					})
+					.catch((res) => {
+						this.$Message.error(res.msg);
+					});
+			},
+			// 回复
+			reply(row) {
+				this.modals = true;
+				this.rows = row;
+			},
+			// 具体日期
+			onchangeTime(e) {
+				this.timeVal = e;
+				this.formValidate.data = this.timeVal[0] ? this.timeVal.join('-') : '';
+				this.formValidate.page = 1;
+				this.getList();
+			},
+			sortMethod(a) {
+				if (a.order === 'normal') {
+					this.formValidate.key = '';
+					this.formValidate.order = '';
+				} else {
+					this.formValidate.key = a.key;
+					this.formValidate.order = a.order;
+				}
+				this.getList();
+			},
+			// 选择时间
+			selectChange(tab) {
+				this.formValidate.data = tab;
+				this.timeVal = [];
+				this.formValidate.page = 1;
+				this.getList();
+			},
+			// 列表
+			getList() {
+				this.loading = true;
+				this.formValidate.is_reply = this.formValidate.is_reply || '';
+				this.formValidate.store_name = this.formValidate.store_name || '';
+				replyListApi(this.formValidate)
+					.then(async (res) => {
+						let data = res.data;
+						this.tableList = data.list;
+						this.total = res.data.count;
+						this.loading = false;
+					})
+					.catch((res) => {
+						this.loading = false;
+						this.$Message.error(res.msg);
+					});
+			},
+			pageChange(index) {
+				this.formValidate.page = index;
+				this.getList();
+			},
+			// 表格搜索
+			userSearchs() {
+				this.formValidate.page = 1;
+				this.getList();
+			},
+			search() {},
+		},
+	};
+</script>
+<style scoped lang="stylus">
+	.content_font {
+		color: #2b85e4;
+	}
+
+	.search {
+		>>>.ivu-form-item-content {
+			margin-left: 0 !important;
+		}
+	}
+
+	.ivu-mt .Button .bnt {
+		margin-right: 6px;
+	}
+
+	.ivu-mt .ivu-table-row {
+		font-size: 12px;
+		color: rgba(0, 0, 0, 0.65);
+	}
+
+	.ivu-mt>>>.ivu-table-cell {
+		padding: 10px 0 !important;
+	}
+
+	.pictrue {
+		width: 36px;
+		height: 36px;
+		display: inline-block;
+		cursor: pointer;
+	}
+
+	.pictrue img {
+		width: 100%;
+		height: 100%;
+		display: block;
+		object-fit: cover;
+	}
+
+	.ivu-mt .imgPic .info {
+		width: 60%;
+		margin-left: 10px;
+	}
+
+	.ivu-mt .picList .pictrue {
+		height: 36px;
+		margin: 7px 3px 0 3px;
+	}
+
+	.ivu-mt .picList .pictrue img {
+		height: 100%;
+		display: block;
+	}
+</style>

+ 70 - 0
src/pages/shop_product/tableExpand.vue

@@ -0,0 +1,70 @@
+<template>
+  <div>
+    <Row class="expand-row">
+      <Col span="6">
+        <span class="expand-key">首次访问:</span>
+        <span class="expand-value"> {{ row.add_time | formatDate }}</span>
+      </Col>
+      <Col span="6">
+        <span class="expand-key">近次访问:</span>
+        <span class="expand-value">{{ row.last_time | formatDate }}</span>
+      </Col>
+      <Col span="6">
+        <span class="expand-key">身份证号:</span>
+        <span class="expand-value">{{ row.card_id }}</span>
+      </Col>
+      <Col span="6">
+        <span class="expand-key">真实姓名:</span>
+        <span class="expand-value">{{ row.real_name }}</span>
+      </Col>
+    </Row>
+    <Row class="expand-row">
+      <Col span="6">
+        <span class="expand-key">标签:</span>
+        <span class="expand-value">{{ row.labels }}</span>
+      </Col>
+      <Col span="6">
+        <span class="expand-key">生日:</span>
+        <span class="expand-value">{{ row.birthday }}</span>
+      </Col>
+      <Col span="6">
+        <span class="expand-key">推荐人:</span>
+        <span class="expand-value">{{ row.spread_uid_nickname }}</span>
+      </Col>
+      <Col span="6">
+        <span class="expand-key">地址:</span>
+        <span class="expand-value">{{ row.addres }}</span>
+      </Col>
+    </Row>
+    <Row class="expand-row">
+      <Col span="6">
+        <span class="expand-key">备注:</span>
+        <span class="expand-value">{{ row.mark }}</span>
+      </Col>
+    </Row>
+  </div>
+</template>
+
+<script>
+import { formatDate } from '@/utils/validate';
+export default {
+  name: 'table-expand',
+  filters: {
+    formatDate(time) {
+      if (time !== 0) {
+        let date = new Date(time * 1000);
+        return formatDate(date, 'yyyy-MM-dd hh:mm');
+      }
+    },
+  },
+  props: {
+    row: Object,
+  },
+};
+</script>
+
+<style scoped>
+.expand-row {
+  margin-bottom: 16px;
+}
+</style>

+ 169 - 0
src/pages/shop_setting/agreement/index.vue

@@ -0,0 +1,169 @@
+<template>
+  <div class="agreemant">
+    <Card :bordered="false" dis-hover class="ivu-mt">
+      <div class="new_card_pd">
+        <Tabs v-model="currentTab" @on-click="changeTab">
+          <TabPane :label="item.label" :name="item.value.toString()" v-for="(item, index) in headerList" :key="index" />
+        </Tabs>
+      </div>
+    </Card>
+
+    <Row class="content">
+      <Col span="16">
+        <WangEditor style="width: 100%" :content="formValidate.content" @editorContent="getEditorContent"></WangEditor>
+      </Col>
+      <Col span="6" style="width: 33%">
+        <div class="ifam">
+          <div class="content" v-html="content"></div>
+        </div>
+      </Col>
+    </Row>
+    <!-- <Row class="mb10 content">
+      <Button class="bnt" type="primary" @click="save" :loading="loadingExist"
+        >保存</Button
+      >
+    </Row> -->
+
+    <Card
+      :bordered="false"
+      dis-hover
+      class="fixed-card"
+      :style="{ left: `${!menuCollapse ? '240px' : isMobile ? '0' : '80px'}` }"
+    >
+      <div class="acea-row row-center">
+        <Button class="bnt" type="primary" @click="save" :loading="loadingExist">保存</Button>
+      </div>
+    </Card>
+  </div>
+</template>
+
+<script>
+import { mapState } from 'vuex';
+import WangEditor from '@/components/wangEditor/index.vue';
+import { getAgreements, setAgreements } from '@/api/system';
+
+export default {
+  components: { WangEditor },
+  data() {
+    return {
+      loadingExist: false,
+      currentTab: '1',
+      headerList: [
+        { label: '付费会员协议', value: '1' },
+        { label: '代理商协议', value: '2' },
+        { label: '隐私协议', value: '3' },
+        { label: '用户协议', value: '4' },
+        { label: '注销协议', value: '5' },
+        { label: '积分协议', value: '6' },
+      ],
+      ueConfig: {
+        autoHeightEnabled: false,
+        initialFrameHeight: 500,
+        initialFrameWidth: '100%',
+        UEDITOR_HOME_URL: '/UEditor/',
+        serverUrl: '',
+      },
+      id: 0,
+      formValidate: {
+        content: '',
+      },
+      content: '',
+      spinShow: false,
+    };
+  },
+  computed: {
+    ...mapState('layout', ['menuCollapse']),
+    ...mapState('admin/layout', ['isMobile']),
+  },
+  created() {
+    this.changeTab(this.currentTab);
+  },
+  methods: {
+    save() {
+      this.formValidate.content = this.content;
+      setAgreements(this.formValidate)
+        .then(async (res) => {
+          this.$Message.success(res.msg);
+        })
+        .catch((res) => {
+          this.$Message.error(res.msg);
+        });
+    },
+    getEditorContent(content) {
+      this.content = content;
+    },
+    changeTab(data) {
+      this.formValidate.content = ' ';
+      getAgreements(data).then((res) => {
+        this.formValidate.id = res.data.id || 0;
+        this.formValidate.type = res.data.type;
+        this.formValidate.title = res.data.title;
+        this.formValidate.content = res.data.content;
+        this.content = res.data.content;
+      });
+    },
+  },
+};
+</script>
+
+<style lang="stylus" scoped>
+.agreemant {
+  background-color: #fff;
+}
+
+.content {
+  padding: 10px 16px;
+}
+
+.ifam {
+  width: 344px;
+  height: 644px;
+  background: url('../../../assets/images/ag-phone.png') no-repeat center top;
+  background-size: 344px 644px;
+  padding: 40px 20px;
+  padding-top: 50px;
+  margin: 0 auto 0 20px;
+
+  .content {
+    height: 560px;
+    overflow: hidden;
+    scrollbar-width: none; /* firefox */
+    -ms-overflow-style: none; /* IE 10+ */
+    overflow-x: hidden;
+    overflow-y: auto;
+  }
+
+  .content::-webkit-scrollbar {
+    display: none; /* Chrome Safari */
+  }
+}
+
+.new_tab {
+  >>>.ivu-tabs-nav .ivu-tabs-tab {
+    padding: 4px 16px 20px !important;
+    font-weight: 500;
+  }
+}
+
+.fixed-card {
+  position: fixed;
+  right: 0;
+  bottom: 0;
+  left: 200px;
+  z-index: 8;
+  box-shadow: 0 -1px 2px rgb(240, 240, 240);
+
+  /deep/ .ivu-card-body {
+    padding: 15px 16px 14px;
+  }
+
+  .ivu-form-item {
+    margin-bottom: 0;
+  }
+
+  /deep/ .ivu-form-item-content {
+    margin-right: 124px;
+    text-align: center;
+  }
+}
+</style>

+ 171 - 0
src/pages/shop_setting/cityDada/index.vue

@@ -0,0 +1,171 @@
+<template>
+  <div>
+    <Card :bordered="false" dis-hover class="ivu-mt">
+      <div class="acea-row row-between-wrapper mb20">
+        <Row type="flex">
+          <Col v-bind="grid">
+            <div class="button acea-row row-middle">
+              <Button class="mr20" type="primary" icon="md-add" @click="add(0)">添加省份</Button>
+              <Button type="primary" @click="cleanCache">清除缓存</Button>
+            </div>
+          </Col>
+        </Row>
+      </div>
+      <Table row-key="id" :load-data="handleLoadData" :columns="columns1" :data="cityLists">
+        <template slot-scope="{ row, index }" slot="action">
+          <a v-if="row.hasOwnProperty('children')" @click="add(row.city_id)">添加</a>
+          <Divider v-if="row.hasOwnProperty('children')" type="vertical" />
+          <a @click="edit(row.id)">编辑</a>
+          <Divider type="vertical" />
+          <a @click="del(row, '删除城市', index)">删除</a>
+        </template>
+      </Table>
+    </Card>
+  </div>
+</template>
+
+<script>
+import { mapState } from 'vuex';
+import { cityListApi, cityAddApi, cityApi, cityCleanCacheApi } from '@/api/setting';
+export default {
+  name: 'setting_dada',
+  data() {
+    return {
+      grid: {
+        xl: 7,
+        lg: 7,
+        md: 12,
+        sm: 24,
+        xs: 24,
+      },
+      loading: false,
+      columns1: [
+        {
+          title: '编号',
+          key: 'id',
+          width: 80,
+        },
+        {
+          title: '地区名称',
+          key: 'label',
+          minWidth: 300,
+          tree: true,
+        },
+        {
+          title: '上级名称',
+          key: 'parent_name',
+          minWidth: 300,
+        },
+        {
+          title: '操作',
+          slot: 'action',
+          fixed: 'right',
+          minWidth: 120,
+        },
+      ],
+      cityLists: [],
+      cityId: 0, // 城市id
+    };
+  },
+  computed: {
+    ...mapState('media', ['isMobile']),
+    labelWidth() {
+      return this.isMobile ? undefined : 75;
+    },
+    labelPosition() {
+      return this.isMobile ? 'top' : 'left';
+    },
+  },
+  created() {
+    this.getList(0);
+  },
+  methods: {
+    // 清除缓存;
+    cleanCache() {
+      cityCleanCacheApi()
+        .then((res) => {
+          this.$Message.success(res.msg);
+        })
+        .catch((res) => {
+          this.$Message.success(res.msg);
+        });
+    },
+    // 添加
+    add(cityId) {
+      this.$modalForm(cityAddApi(cityId)).then(() => this.getList(0));
+    },
+    // 添加下级;
+    lower(cityId) {
+      this.cityId = cityId;
+      this.getList(cityId);
+    },
+    // 城市列表
+    getList(parentId) {
+      let that = this;
+      that.loading = true;
+      cityListApi(parentId)
+        .then(async (res) => {
+          that.cityLists = res.data;
+          that.loading = false;
+        })
+        .catch((res) => {
+          that.loading = false;
+          that.$Message.error(res.msg);
+        });
+    },
+    // 返回
+    goBack() {
+      this.cityId = 0;
+      this.getList(0);
+    },
+    // 修改
+    edit(id) {
+      this.$modalForm(cityApi(id)).then(() => this.getList(this.cityId));
+    },
+    // 删除
+    del(row, tit, num) {
+      let delfromData = {
+        title: tit,
+        num: num,
+        url: `setting/city/del/${row.city_id}`,
+        method: 'DELETE',
+        ids: '',
+      };
+      this.$modalSure(delfromData)
+        .then((res) => {
+          this.$Message.success(res.msg);
+          this.cityLists.splice(num, 1);
+          this.getList(this.cityId);
+        })
+        .catch((res) => {
+          this.$Message.error(res.msg);
+        });
+    },
+    handleLoadData(item, callback) {
+      cityListApi(item.city_id).then((res) => {
+        callback(res.data);
+      });
+    },
+  },
+};
+</script>
+
+<style scoped lang="stylus">
+/deep/.ivu-table-cell-tree {
+  border: 0;
+  font-size: 15px;
+  background-color: unset;
+}
+
+/deep/.ivu-table-cell-tree .ivu-icon-ios-add:before {
+  content: '\F11F';
+}
+
+/deep/.ivu-table-cell-tree .ivu-icon-ios-remove:before {
+  content: '\F116';
+}
+
+.button {
+  width: 300px;
+}
+</style>

+ 241 - 0
src/pages/shop_setting/clerkList/index.vue

@@ -0,0 +1,241 @@
+<template>
+  <div>
+    <Card :bordered="false" dis-hover class="ivu-mt">
+      <Form
+        ref="artFrom"
+        :model="artFrom"
+        :label-width="labelWidth"
+        :label-position="labelPosition"
+        @submit.native.prevent
+      >
+        <Row type="flex" :gutter="24">
+          <Col v-bind="grid" class="mr">
+            <FormItem label="提货点名称:" label-for="store_name">
+              <Select v-model="artFrom.store_id" element-id="store_id" clearable @on-change="userSearchs">
+                <Option v-for="item in storeSelectList" :value="item.id" :key="item.id">{{ item.name }}</Option>
+              </Select>
+            </FormItem>
+          </Col>
+          <!--<Col v-bind="grid" class="mr">-->
+          <!--<Button type="primary" class="mr15" @click="userSearchs">搜索</Button>-->
+          <!--</Col>-->
+        </Row>
+      </Form>
+      <Row type="flex">
+        <Col v-bind="grid">
+          <Button v-auth="['merchant-store_staff-create']" type="primary" icon="md-add" @click="add">添加核销员</Button>
+        </Col>
+      </Row>
+      <Table
+        :columns="columns"
+        :data="storeLists"
+        ref="table"
+        class="mt25"
+        :loading="loading"
+        highlight-row
+        no-userFrom-text="暂无数据"
+        no-filtered-userFrom-text="暂无筛选结果"
+      >
+        <template slot-scope="{ row, index }" slot="avatar">
+          <div class="tabBox_img" v-viewer>
+            <img v-lazy="row.avatar" />
+          </div>
+        </template>
+        <template slot-scope="{ row, index }" slot="status">
+          <i-switch
+            v-model="row.status"
+            :value="row.status"
+            :true-value="1"
+            :false-value="0"
+            @on-change="onchangeIsShow(row.id, row.status)"
+            size="large"
+            >>
+            <span slot="open">显示</span>
+            <span slot="close">隐藏</span>
+          </i-switch>
+        </template>
+        <template slot-scope="{ row, index }" slot="action">
+          <a @click="edit(row.id)">编辑</a>
+          <Divider type="vertical" />
+          <a @click="del(row, '删除核销员', index)">删除</a>
+        </template>
+      </Table>
+      <div class="acea-row row-right page">
+        <Page
+          :total="total"
+          :current="artFrom.page"
+          show-elevator
+          show-total
+          @on-change="pageChange"
+          :page-size="artFrom.limit"
+        />
+      </div>
+    </Card>
+  </div>
+</template>
+
+<script>
+import { mapState } from 'vuex';
+import {
+  storeStaffApi,
+  storeStaffCreateApi,
+  merchantStoreListApi,
+  storeStaffSetShowApi,
+  storeStaffEditApi,
+} from '@/api/setting';
+export default {
+  name: 'setting_staff',
+  components: {},
+  computed: {
+    ...mapState('media', ['isMobile']),
+    ...mapState('userLevel', ['categoryId']),
+    labelWidth() {
+      return this.isMobile ? undefined : 85;
+    },
+    labelPosition() {
+      return this.isMobile ? 'top' : 'right';
+    },
+  },
+  data() {
+    return {
+      grid: {
+        xl: 10,
+        lg: 10,
+        md: 12,
+        sm: 24,
+        xs: 24,
+      },
+      artFrom: {
+        page: 1,
+        limit: 15,
+        store_id: 0,
+      },
+      loading: false,
+      columns: [
+        {
+          title: 'ID',
+          key: 'id',
+          width: 80,
+          sortable: true,
+        },
+        {
+          title: '微信名称',
+          key: 'nickname',
+          minWidth: 100,
+        },
+        {
+          title: '头像',
+          slot: 'avatar',
+          minWidth: 100,
+        },
+        {
+          title: '核销员名称',
+          key: 'staff_name',
+          minWidth: 100,
+        },
+        {
+          title: '所属提货点',
+          key: 'name',
+          minWidth: 100,
+        },
+        {
+          title: '添加时间',
+          key: 'add_time',
+          minWidth: 100,
+        },
+        {
+          title: '状态',
+          slot: 'status',
+          minWidth: 100,
+        },
+        {
+          title: '操作',
+          slot: 'action',
+          fixed: 'right',
+          minWidth: 120,
+        },
+      ],
+      storeLists: [],
+      storeSelectList: [],
+      total: 0,
+    };
+  },
+  mounted() {
+    this.getList();
+    this.storeList();
+  },
+  methods: {
+    storeList() {
+      let that = this;
+      merchantStoreListApi().then((res) => {
+        that.storeSelectList = res.data;
+      });
+    },
+    getList() {
+      let that = this;
+      that.loading = true;
+      storeStaffApi(that.artFrom)
+        .then((res) => {
+          that.loading = false;
+          that.storeLists = res.data.list;
+          that.total = res.data.count;
+        })
+        .catch((res) => {
+          this.$Message.error(res.msg);
+        });
+    },
+    // 搜索;
+    userSearchs() {
+      this.artFrom.page = 1;
+      this.getList();
+    },
+    pageChange(index) {
+      this.artFrom.page = index;
+      this.getList();
+    },
+    // 删除
+    del(row, tit, num) {
+      let delfromData = {
+        title: tit,
+        num: num,
+        url: `merchant/store_staff/del/${row.id}`,
+        method: 'DELETE',
+        ids: '',
+      };
+      this.$modalSure(delfromData)
+        .then((res) => {
+          this.$Message.success(res.msg);
+          this.storeLists.splice(num, 1);
+        })
+        .catch((res) => {
+          this.$Message.error(res.msg);
+        });
+    },
+    // 添加核销员;
+    add() {
+      this.$modalForm(storeStaffCreateApi(0)).then(() => this.getList());
+    },
+    onchangeIsShow(id, is_show) {
+      let that = this;
+      storeStaffSetShowApi(id, is_show).then((res) => {
+        that.$Message.success(res.msg);
+        that.getList();
+      });
+    },
+    edit(id) {
+      this.$modalForm(storeStaffEditApi(id)).then(() => this.getList());
+    },
+  },
+};
+</script>
+
+<style scoped lang="stylus">
+.tabBox_img
+    width 36px
+    height 36px
+    border-radius:4px
+    cursor pointer
+    img
+        width 100%
+        height 100%
+</style>

+ 193 - 0
src/pages/shop_setting/deliveryService/index.vue

@@ -0,0 +1,193 @@
+<template>
+  <div>
+    <Card :bordered="false" dis-hover class="ivu-mt">
+      <Row type="flex" class="mb20">
+        <Col span="24">
+          <Button v-auth="['setting-delivery_service-add']" type="primary" icon="md-add" @click="add" class="mr10"
+            >添加配送员</Button
+          >
+        </Col>
+      </Row>
+      <Table
+        :columns="columns1"
+        :data="data1"
+        :loading="loading"
+        highlight-row
+        no-userFrom-text="暂无数据"
+        no-filtered-userFrom-text="暂无筛选结果"
+      >
+        <template slot-scope="{ row, index }" slot="avatar">
+          <div class="tabBox_img" v-viewer>
+            <img v-lazy="row.avatar" />
+          </div>
+        </template>
+        <template slot-scope="{ row, index }" slot="status">
+          <i-switch
+            v-model="row.status"
+            :value="row.status"
+            :true-value="1"
+            :false-value="0"
+            @on-change="onchangeIsShow(row)"
+            size="large"
+          >
+            <span slot="open">显示</span>
+            <span slot="close">隐藏</span>
+          </i-switch>
+        </template>
+        <template slot-scope="{ row, index }" slot="add_time">
+          <span> {{ row.add_time | formatDate }}</span>
+        </template>
+
+        <template slot-scope="{ row, index }" slot="action">
+          <a @click="edit(row)">编辑</a>
+          <Divider type="vertical" />
+          <a @click="del(row, '删除配送员', index)">删除</a>
+        </template>
+      </Table>
+      <div class="acea-row row-right page">
+        <Page
+          :total="total"
+          :current="tableOptions.page"
+          show-elevator
+          show-total
+          :page-size="tableOptions.limit"
+          @on-change="pageChange"
+        />
+      </div>
+    </Card>
+  </div>
+</template>
+
+<script>
+import { mapState } from 'vuex';
+import { deliveryList, orderDeliveryAdd, orderDeliveryEdit, orderDeliveryStatus } from '@/api/order';
+
+export default {
+  name: 'index',
+  computed: {
+    ...mapState('media', ['isMobile']),
+  },
+  data() {
+    return {
+      columns1: [
+        {
+          title: 'ID',
+          key: 'id',
+          width: 80,
+        },
+        {
+          title: '头像',
+          slot: 'avatar',
+          minWidth: 60,
+        },
+        {
+          title: '名称',
+          key: 'nickname',
+          minWidth: 120,
+        },
+        {
+          title: '手机号码',
+          key: 'phone',
+          minWidth: 120,
+        },
+        {
+          title: '是否显示',
+          slot: 'status',
+          minWidth: 120,
+        },
+        {
+          title: '添加时间',
+          key: 'add_time',
+          minWidth: 120,
+        },
+        {
+          title: '操作',
+          slot: 'action',
+          fixed: 'right',
+          minWidth: 150,
+        },
+      ],
+      data1: [],
+      total: 0,
+      tableOptions: {
+        page: 1,
+        limit: 15,
+      },
+      loading: false,
+    };
+  },
+  created() {
+    this.getOrderDeliveryList();
+  },
+  methods: {
+    // 配送员列表
+    getOrderDeliveryList() {
+      this.loading = true;
+      deliveryList(this.tableOptions)
+        .then((res) => {
+          this.data1 = res.data.list;
+          this.total = res.data.count;
+          this.loading = false;
+        })
+        .catch((err) => {
+          this.loading = false;
+          this.$Message.error(err.msg);
+        });
+    },
+    // 添加配送员
+    add() {
+      this.$modalForm(orderDeliveryAdd()).then(() => this.getOrderDeliveryList());
+    },
+    // 编辑
+    edit(row) {
+      this.$modalForm(orderDeliveryEdit(row.id)).then(() => this.getOrderDeliveryList());
+    },
+    // 删除
+    del(row, tit, num) {
+      let delfromData = {
+        title: tit,
+        num: num,
+        url: `/order/delivery/del/${row.id}`,
+        method: 'DELETE',
+        ids: '',
+      };
+      this.$modalSure(delfromData)
+        .then((res) => {
+          this.$Message.success(res.msg);
+          this.data1.splice(num, 1);
+        })
+        .catch((res) => {
+          this.$Message.error(res.msg);
+        });
+    },
+    // 是否显示
+    onchangeIsShow(row) {
+      orderDeliveryStatus(row)
+        .then((res) => {
+          this.$Message.success(res.msg);
+        })
+        .catch((err) => {
+          this.$Message.error(err.msg);
+        });
+    },
+    pageChange(index) {
+      this.tableOptions.page = index;
+      this.getOrderDeliveryList();
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.tabBox_img {
+  width: 36px;
+  height: 36px;
+  border-radius: 4px;
+  cursor: pointer;
+
+  img {
+    width: 100%;
+    height: 100%;
+  }
+}
+</style>

+ 295 - 0
src/pages/shop_setting/devise/components/uploadPic.vue

@@ -0,0 +1,295 @@
+<template>
+  <div class="hot_imgs">
+    <div class="list-box">
+      <draggable class="dragArea list-group" :list="listData" group="peoples" handle=".move-icon">
+        <div class="item" v-for="(item, index) in listData" :key="index">
+          <div class="move-icon">
+            <span class="iconfont-diy icondrag"></span>
+          </div>
+          <div class="img-box" @click="modalPicTap('单选', index)">
+            <img :src="item.pic" alt="" v-if="item.pic && item.pic != ''" />
+            <div class="upload-box" v-else>
+              <Icon type="ios-camera-outline" size="36" />
+            </div>
+          </div>
+          <div class="info">
+            <div class="info-item" v-if="item.hasOwnProperty('name')">
+              <span>{{ type == 1 ? '管理名称:' : type == 2 ? '广告名称' : '服务名称:' }}</span>
+              <div class="input-box">
+                <Input v-model="item.name" :placeholder="type == 2 ? '请输入名称' : '服务中心'" :maxlength="4" />
+              </div>
+            </div>
+            <div class="info-item">
+              <span>链接地址:</span>
+              <div class="input-box" @click="getLink(index)">
+                <Input v-model="item.url" icon="ios-arrow-forward" readonly placeholder="选择链接" />
+              </div>
+            </div>
+          </div>
+          <div v-if="type != 1" class="delect-btn" @click.stop="bindDelete(item, index)">
+            <span class="iconfont-diy icondel_1"></span>
+          </div>
+        </div>
+      </draggable>
+      <div>
+        <Modal
+          v-model="modalPic"
+          width="950px"
+          scrollable
+          footer-hide
+          closable
+          title="上传商品图"
+          :mask-closable="false"
+          :z-index="1"
+        >
+          <uploadPictures
+            :isChoice="isChoice"
+            @getPic="getPic"
+            :gridBtn="gridBtn"
+            :gridPic="gridPic"
+            v-if="modalPic"
+          ></uploadPictures>
+        </Modal>
+      </div>
+    </div>
+    <template v-if="listData">
+      <div class="add-btn" v-if="(type != 1 && type != 2) || (type == 2 && listData.length < 5)">
+        <Button
+          type="primary"
+          ghost
+          style="width: 100px; height: 30px; background: #1890ff; color: #fff; font-size: 13px"
+          @click="addBox"
+          >添加板块</Button
+        >
+      </div>
+    </template>
+    <linkaddress ref="linkaddres" @linkUrl="linkUrl"></linkaddress>
+  </div>
+</template>
+
+<script>
+import vuedraggable from 'vuedraggable';
+import uploadPictures from '@/components/uploadPictures';
+import linkaddress from '@/components/linkaddress';
+export default {
+  name: 'uploadPic',
+  props: {
+    listData: {
+      type: Array,
+    },
+    type: {
+      type: Number,
+    },
+  },
+  components: {
+    draggable: vuedraggable,
+    uploadPictures,
+    linkaddress,
+  },
+  data() {
+    return {
+      modalPic: false,
+      isChoice: '单选',
+      gridBtn: {
+        xl: 4,
+        lg: 8,
+        md: 8,
+        sm: 8,
+        xs: 8,
+      },
+      gridPic: {
+        xl: 6,
+        lg: 8,
+        md: 12,
+        sm: 12,
+        xs: 12,
+      },
+      activeIndex: 0,
+      lastObj: {
+        name: '',
+        pic: '',
+        url: '',
+      },
+    };
+  },
+  mounted() {},
+  watch: {
+    configObj: {
+      handler(nVal, oVal) {},
+      deep: true,
+    },
+  },
+  methods: {
+    linkUrl(e) {
+      this.listData[this.activeIndex].url = e;
+    },
+    getLink(index) {
+      this.activeIndex = index;
+      this.$refs.linkaddres.modals = true;
+    },
+    addBox() {
+      if (this.listData.length == 0) {
+        this.listData.push(this.lastObj);
+      } else {
+        let obj = JSON.parse(JSON.stringify(this.listData[this.listData.length - 1]));
+        obj.name = '';
+        obj.pic = '';
+        obj.url = '';
+        this.listData.push(obj);
+      }
+      // this.$emit('parentFun',this.listData)
+    },
+    // 点击图文封面
+    modalPicTap(title, index) {
+      this.activeIndex = index;
+      this.modalPic = true;
+    },
+    // 添加自定义弹窗
+    addCustomDialog(editorId) {
+      window.UE.registerUI(
+        'test-dialog',
+        function (editor, uiName) {
+          let dialog = new window.UE.ui.Dialog({
+            iframeUrl: this.$routeProStr + '/widget.images/index.html?fodder=dialog',
+            editor: editor,
+            name: uiName,
+            title: '上传图片',
+            cssRules: 'width:960px;height:550px;padding:20px;',
+          });
+          this.dialog = dialog;
+          // 参考上面的自定义按钮
+          var btn = new window.UE.ui.Button({
+            name: 'dialog-button',
+            title: '上传图片',
+            cssRules: `background-image: url(../../../assets/images/icons.png);background-position: -726px -77px;`,
+            onclick: function () {
+              // 渲染dialog
+              dialog.render();
+              dialog.open();
+            },
+          });
+
+          return btn;
+        },
+        37,
+      );
+    },
+    // 获取图片信息
+    getPic(pc) {
+      this.$nextTick(() => {
+        this.listData[this.activeIndex].pic = pc.att_dir;
+        this.modalPic = false;
+      });
+    },
+    // 删除
+    bindDelete(item, index) {
+      if (this.listData.length == 1) {
+        this.lastObj = this.listData[0];
+      }
+      this.listData.splice(index, 1);
+      // this.$emit('parentFun',this.listData)
+    },
+  },
+};
+</script>
+
+<style scoped lang="stylus">
+.hot_imgs {
+  margin-bottom: 20px;
+
+  // border-top 1px solid rgba(0,0,0,0.05)
+  .title {
+    padding: 13px 0;
+    color: #999;
+    font-size: 12px;
+    border-bottom: 1px solid rgba(0, 0, 0, 0.05);
+  }
+
+  .list-box {
+    .item {
+      position: relative;
+      display: flex;
+      margin-top: 20px;
+      border: 1px dashed rgba(0, 0, 0, 0.15);
+      padding: 18px 10px 18px 0;
+      border-radius: 6px;
+
+      .move-icon {
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        width: 30px;
+        cursor: move;
+      }
+
+      .img-box {
+        position: relative;
+        width: 70px;
+        height: 70px;
+
+        img {
+          width: 100%;
+          height: 100%;
+        }
+      }
+
+      .info {
+        flex: 1;
+        margin-left: 16px;
+
+        .info-item {
+          display: flex;
+          align-items: center;
+          margin-bottom: 10px;
+
+          span {
+            width: 70px;
+            font-size: 13px;
+          }
+
+          .input-box {
+            flex: 1;
+
+            /deep/input {
+              cursor: pointer;
+            }
+          }
+
+          /deep/ .ivu-input {
+            font-size: 13px !important;
+          }
+        }
+      }
+
+      .delect-btn {
+        position: absolute;
+        right: -11px;
+        top: -15px;
+
+        .iconfont-diy {
+          font-size: 25px;
+          color: #FF1818;
+        }
+      }
+    }
+  }
+
+  .add-btn {
+    margin-top: 24px;
+  }
+}
+
+.upload-box {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  width: 100%;
+  height: 100%;
+  background: #ccc;
+}
+
+.iconfont-diy {
+  color: #DDDDDD;
+  font-size: 28px;
+}
+</style>

+ 1467 - 0
src/pages/shop_setting/devise/diyIndex.vue

@@ -0,0 +1,1467 @@
+<template>
+  <div class="diy-page">
+    <div class="i-layout-page-header header-title">
+      <div class="fl_header">
+        <!-- <router-link :to="{ path: $routeProStr + '/setting/pages/devise' }"
+          ><Button icon="ios-arrow-back" size="small" type="text">返回</Button></router-link
+        > -->
+        <!-- <Divider type="vertical" /> -->
+        <span class="ivu-page-header-title mr20" style="padding: 0" v-text="$route.meta.title"></span>
+        <div class="rbtn">
+          <!-- <Button v-if="pageId !== 0" class="bnt" @click="setmoren" :loading="loading">保存默认</Button>
+          <Button v-if="pageId !== 0" class="bnt ml20" @click="getmoren" :loading="loading">恢复默认</Button> -->
+          <!-- <div class="data" @click="setmoren">设置默认</div>
+            <div class="data" @click="getmoren">恢复默认</div> -->
+          <Button class="bnt ml20" type="info" @click="preview" :loading="loading">预览</Button>
+          <Button class="bnt ml20" type="primary" @click="saveConfig(0)" :loading="loading">保存</Button>
+          <Button class="ml20" type="error" @click="closeWindow" :loading="loading">关闭</Button>
+        </div>
+      </div>
+    </div>
+
+    <Card :bordered="false" dis-hover class="ivu-mt" style="margin: 0 10px">
+      <div class="diy-wrapper">
+        <!-- 左侧 -->
+        <div class="left">
+          <div class="title-bar">
+            <div
+              class="title-item"
+              :class="{ on: tabCur == index }"
+              v-for="(item, index) in tabList"
+              :key="index"
+              @click="bindTab(index)"
+            >
+              {{ item.title }}
+            </div>
+          </div>
+          <div class="wrapper" v-if="tabCur == 0">
+            <div v-for="(item, index) in leftMenu" :key="index">
+              <div class="tips" @click="item.isOpen = !item.isOpen">
+                {{ item.title }}
+
+                <Icon type="ios-arrow-forward" size="16" v-if="!item.isOpen" />
+                <Icon type="ios-arrow-down" size="16" v-else />
+              </div>
+              <draggable
+                class="dragArea list-group"
+                :list="item.list"
+                :group="{ name: 'people', pull: 'clone', put: false }"
+                :clone="cloneDog"
+                dragClass="dragClass"
+                filter=".search , .navbar"
+              >
+                <!--filter=".search , .navbar"-->
+                <!--:class="{ search: element.cname == '搜索框' , navbar: element.cname == '商品分类' }"-->
+                <div
+                  class="list-group-item"
+                  :class="{
+                    search: element.cname == '搜索框',
+                    navbar: element.cname == '商品分类',
+                  }"
+                  v-for="(element, index) in item.list"
+                  :key="element.id"
+                  @click="addDom(element, 1)"
+                  v-show="item.isOpen"
+                >
+                  <div>
+                    <div class="position" style="display: none">释放鼠标将组建添加到此处</div>
+                    <span class="conter iconfont-diy" :class="element.icon"></span>
+                    <p class="conter">{{ element.cname }}</p>
+                  </div>
+                </div>
+              </draggable>
+            </div>
+          </div>
+          <!--                    <div style="padding: 0 20px"><Button type="primary" style="width: 100%" @click="saveConfig">保存</Button></div>-->
+          <div class="wrapper" v-else :style="'height:' + (clientHeight - 200) + 'px;'">
+            <div class="link-item" v-for="(item, index) in urlList" :key="index">
+              <div class="name">{{ item.name }}</div>
+              <div class="link-txt">地址:{{ item.url }}</div>
+              <div class="params">
+                <span class="txt">参数:</span>
+                <span>{{ item.parameter }}</span>
+              </div>
+              <div class="lable">
+                <p class="txt">例如:{{ item.example }}</p>
+                <Button size="small" @click="onCopy(item.example)">复制 </Button>
+              </div>
+            </div>
+          </div>
+        </div>
+        <!-- 中间 -->
+        <div
+          class="wrapper-con"
+          style="flex: 1; background: #f0f2f5; display: flex; justify-content: center; padding-top: 20px; height: 100%"
+        >
+          <div class="acticon">
+            <Button class="bnt mb10" @click="showTitle">页面设置</Button>
+            <Button class="bnt mb10" @click="nameModal = true">另存模板</Button>
+            <Button class="bnt" @click="reast">重置</Button>
+          </div>
+          <div class="content">
+            <div class="contxt" style="display: flex; flex-direction: column; overflow: hidden; height: 100%">
+              <div class="overflowy">
+                <div class="picture">
+                  <img src="@/assets/images/electric.png" />
+                </div>
+                <div class="page-title" :class="{ on: activeIndex == -100 }" @click="showTitle">
+                  {{ titleTxt }}
+                  <div class="delete-box"></div>
+                  <div class="handle"></div>
+                </div>
+              </div>
+              <div class="scrollCon">
+                <div style="width: 460px; margin: 0 auto">
+                  <div
+                    class="scroll-box"
+                    :class="
+                      picTxt && tabValTxt == 2
+                        ? 'fullsize noRepeat'
+                        : picTxt && tabValTxt == 1
+                        ? 'repeat ysize'
+                        : 'noRepeat ysize'
+                    "
+                    :style="
+                      'background-color:' +
+                      (colorTxt ? colorPickerTxt : '') +
+                      ';background-image: url(' +
+                      (picTxt ? picUrlTxt : '') +
+                      ');height:calc(100vh - 200px)'
+                    "
+                    ref="imgContainer"
+                  >
+                    <draggable
+                      class="dragArea list-group"
+                      :list="mConfig"
+                      group="people"
+                      @change="log"
+                      filter=".top"
+                      :move="onMove"
+                      animation="300"
+                    >
+                      <div
+                        class="mConfig-item"
+                        :class="{
+                          on: activeIndex == key,
+                          top: item.name == 'search_box' || item.name == 'nav_bar',
+                        }"
+                        v-for="(item, key) in mConfig"
+                        :key="key"
+                        @click.stop="bindconfig(item, key)"
+                        :style="colorTxt ? 'background-color:' + colorPickerTxt + ';' : 'background-color:#fff;'"
+                      >
+                        <component
+                          :is="item.name"
+                          ref="getComponentData"
+                          :configData="propsObj"
+                          :index="key"
+                          :num="item.num"
+                        ></component>
+                        <div class="delete-box">
+                          <div class="handleType">
+                            <Tooltip content="删除当前模块" placement="top">
+                              <div class="iconfont iconshanchu2" @click.stop="bindDelete(item, key)"></div>
+                            </Tooltip>
+
+                            <div class="iconfont iconfuzhi" @click.stop="bindAddDom(item, 0, key)"></div>
+                            <div
+                              class="iconfont iconshangyi"
+                              :class="key === 0 ? 'on' : ''"
+                              @click.stop="movePage(item, key, 1)"
+                            ></div>
+                            <div
+                              class="iconfont iconxiayi"
+                              :class="key === mConfig.length - 1 ? 'on' : ''"
+                              @click.stop="movePage(item, key, 0)"
+                            ></div>
+                          </div>
+                        </div>
+                        <div class="handle"></div>
+                      </div>
+                    </draggable>
+                  </div>
+                </div>
+              </div>
+              <div class="overflowy">
+                <div class="page-foot" @click="showFoot" :class="{ on: activeIndex == -101 }">
+                  <footPage></footPage>
+                  <div class="delete-box"></div>
+                  <div class="handle"></div>
+                </div>
+              </div>
+              <!-- <div class="defaultData" v-if="pageId !== 0">
+                <div class="data" @click="setmoren">设置默认</div>
+                <div class="data" @click="getmoren">恢复默认</div>
+              </div> -->
+            </div>
+          </div>
+        </div>
+        <!-- 右侧 -->
+        <div class="right-box">
+          <div class="mConfig-item" style="background-color: #fff" v-for="(item, key) in rConfig" :key="key">
+            <div class="title-bar">{{ item.cname }}</div>
+            <component
+              :is="item.configName"
+              @config="config"
+              :activeIndex="activeIndex"
+              :num="item.num"
+              :index="key"
+            ></component>
+          </div>
+        </div>
+      </div>
+    </Card>
+    <!--<div class="foot-box">-->
+    <!--<Button @click="reast">重置</Button>-->
+    <!--<Button type="primary" @click="saveConfig" :loading="loading"-->
+    <!--&gt;保存-->
+    <!--</Button-->
+    <!--&gt;-->
+    <!--</div>-->
+    <Modal v-model="modal" title="预览" footer-hide>
+      <div>
+        <div v-viewer class="acea-row row-around code">
+          <div class="acea-row row-column-around row-between-wrapper">
+            <div class="QRpic" ref="qrCodeUrl"></div>
+            <span class="mt10">公众号二维码</span>
+          </div>
+          <div class="acea-row row-column-around row-between-wrapper">
+            <div class="QRpic">
+              <img v-lazy="qrcodeImg" />
+            </div>
+            <span class="mt10">小程序二维码</span>
+          </div>
+        </div>
+      </div>
+    </Modal>
+    <Modal v-model="nameModal" title="设置模版名称" :closable="false" @on-ok="saveModal" @on-cancel="nameModal = false">
+      <Input v-model="saveName" placeholder="请输入模版名称"></Input>
+    </Modal>
+  </div>
+</template>
+
+<script crossorigin="anonymous">
+import { categoryList, getDiyInfo, saveDiy, getUrl, setDefault, recovery, getRoutineCode } from '@/api/diy';
+import vuedraggable from 'vuedraggable';
+import mPage from '@/components/mobilePageDiy/index.js';
+import mConfig from '@/components/mobileConfigDiy/index.js';
+import footPage from '@/components/pagesFoot';
+import { mapState } from 'vuex';
+import html2canvas from 'html2canvas';
+import QRCode from 'qrcodejs2';
+
+let idGlobal = 0;
+export default {
+  inject: ['reload'],
+  name: 'index.vue',
+  components: {
+    footPage,
+    html2canvas,
+    draggable: vuedraggable,
+    ...mPage,
+    ...mConfig,
+  },
+  filters: {
+    filterTxt(val) {
+      if (val) {
+        return (val = val.substr(0, val.length - 1));
+      }
+    },
+  },
+  computed: {
+    ...mapState({
+      titleTxt: (state) => state.mobildConfig.pageTitle || '首页',
+      nameTxt: (state) => state.mobildConfig.pageName || '模板',
+      showTxt: (state) => state.mobildConfig.pageShow,
+      colorTxt: (state) => state.mobildConfig.pageColor,
+      picTxt: (state) => state.mobildConfig.pagePic,
+      colorPickerTxt: (state) => state.mobildConfig.pageColorPicker,
+      tabValTxt: (state) => state.mobildConfig.pageTabVal,
+      picUrlTxt: (state) => state.mobildConfig.pagePicUrl,
+    }),
+  },
+  data() {
+    return {
+      clientHeight: '', //页面动态高度
+      rollHeight: '',
+      leftMenu: [], // 左侧菜单
+      lConfig: [], // 左侧组件
+      mConfig: [], // 中间组件渲染
+      rConfig: [], // 右侧组件配置
+      activeConfigName: '',
+      propsObj: {}, // 组件传递的数据,
+      activeIndex: -100, // 选中的下标
+      number: 0,
+      pageId: '',
+      pageName: '',
+      pageType: '',
+      category: [],
+      tabList: [
+        {
+          title: '组件库',
+          key: 0,
+        },
+        {
+          title: '页面链接',
+          key: 1,
+        },
+      ],
+      tabCur: 0,
+      urlList: [],
+      footActive: false,
+      loading: false,
+      isSearch: false,
+      isTab: false,
+      isFllow: false,
+      qrcodeImg: '',
+      modal: false,
+      nameModal: false,
+      saveName: '',
+    };
+  },
+  beforeRouteLeave(to, from, next) {
+    // 导航离开该组件的对应路由时调用
+  },
+  beforeCreate() {
+    this.$store.commit('mobildConfig/titleUpdata', '');
+    this.$store.commit('mobildConfig/nameUpdata', '');
+    this.$store.commit('mobildConfig/showUpdata', 1);
+    this.$store.commit('mobildConfig/colorUpdata', 0);
+    this.$store.commit('mobildConfig/picUpdata', 0);
+    this.$store.commit('mobildConfig/pickerUpdata', '#f5f5f5');
+    this.$store.commit('mobildConfig/radioUpdata', 0);
+    this.$store.commit('mobildConfig/picurlUpdata', '');
+    this.$store.commit('mobildConfig/SETEMPTY');
+  },
+  created() {
+    window.onbeforeunload = () => {
+      return '刷新页面将丢失内容,是否继续?';
+    };
+    this.categoryList();
+    this.getUrlList();
+    this.pageId = this.$route.query.id;
+    this.pageName = this.$route.query.name;
+    this.pageType = this.$route.query.type;
+    this.lConfig = this.objToArr(mPage);
+  },
+  mounted() {
+    // window.addEventListener('onbeforeunload', this.beforeUnload);
+    let imgList = {
+      imgList: [require('@/assets/images/foot-005.png'), require('@/assets/images/foot-006.png')],
+      name: '购物车',
+      link: '/pages/order_addcart/order_addcart',
+    };
+    this.$nextTick(() => {
+      this.$store.commit('mobildConfig/FOOTER', {
+        title: '专题页是否显示',
+        name: imgList,
+      });
+      this.arraySort();
+      if (this.pageId != 0) {
+        this.getDefaultConfig();
+      } else {
+        this.showTitle();
+      }
+      this.clientHeight = `${document.documentElement.clientHeight}`; //获取浏览器可视区域高度
+      let H = `${document.documentElement.clientHeight}` - 180;
+      this.rollHeight = H > 650 ? 650 : H;
+      let that = this;
+      window.onresize = function () {
+        that.clientHeight = `${document.documentElement.clientHeight}`;
+        let H = `${document.documentElement.clientHeight}` - 180;
+        that.rollHeight = H > 650 ? 650 : H;
+      };
+    });
+  },
+  methods: {
+    saveModal() {
+      if (!this.saveName) return this.$Message.warning('请先输入模板名称');
+      this.saveConfig(1, this.saveName);
+    },
+    //小程序二维码
+    routineCode(id) {
+      getRoutineCode(id)
+        .then((res) => {
+          this.qrcodeImg = res.data.image;
+        })
+        .catch((err) => {
+          this.$Message.error(err);
+        });
+    },
+    preview(row) {
+      this.modal = true;
+      this.creatQrCode(row.id);
+      this.routineCode(this.$route.query.id);
+    },
+    //生成二维码
+    creatQrCode(id) {
+      this.$refs.qrCodeUrl.innerHTML = '';
+      let url = `${this.BaseURL}pages/annex/special/index?id=${id}`;
+      var qrcode = new QRCode(this.$refs.qrCodeUrl, {
+        text: url, // 需要转换为二维码的内容
+        width: 160,
+        height: 160,
+        colorDark: '#000000',
+        colorLight: '#ffffff',
+        correctLevel: QRCode.CorrectLevel.H,
+      });
+    },
+    closeWindow() {
+      this.$Modal.confirm({
+        title: '确定关闭当前页吗?',
+        content: '关闭页面前请先保存数据,未保存的话数据会丢失',
+        okText: '确定',
+        cancelText: '取消',
+        loading: true,
+        onOk: () => {
+          setTimeout(() => {
+            // this.saveConfig();
+            this.$Modal.remove();
+            window.close();
+          }, 1000);
+        },
+        onCancel: () => {
+          this.$Modal.remove();
+        },
+      });
+    },
+    leftRemove({ to, from, item, clone, oldIndex, newIndex }) {
+      if (this.isSearch && newIndex == 0) {
+        if (item._underlying_vm_.name == 'z_wechat_attention') {
+          this.isFllow = true;
+        } else {
+          this.$store.commit('mobildConfig/ARRAYREAST', this.mConfig[0].num);
+          this.mConfig.splice(0, 1);
+        }
+      }
+      if ((this.isFllow = true && newIndex >= 1)) {
+        this.$store.commit('mobildConfig/ARRAYREAST', this.mConfig[0].num);
+      }
+    },
+    onMove(e) {
+      if (e.relatedContext.element.name == 'search_box') return false;
+      if (e.relatedContext.element.name == 'nav_bar') return false;
+      return true;
+    },
+    onCopy(copyData) {
+      this.$copyText(copyData)
+        .then((message) => {
+          this.$Message.success('复制成功');
+        })
+        .catch((err) => {
+          this.$Message.error('复制失败');
+        });
+    },
+    onError() {
+      this.$Message.error('复制失败');
+    },
+    //设置默认数据
+    setmoren() {
+      this.$Modal.confirm({
+        title: '保存为默认数据',
+        content: '您确定将当前设计设为默认数据吗?',
+        onOk: () => {
+          setDefault(this.pageId)
+            .then((res) => {
+              this.$Message.success(res.msg);
+            })
+            .catch((err) => {
+              this.$Message.error(err.msg);
+            });
+        },
+        onCancel: () => {},
+      });
+    },
+    //恢复默认
+    getmoren() {
+      this.$Modal.confirm({
+        title: '恢复默认数据',
+        content: '您确定恢复为之前保存的默认数据吗?',
+        onOk: () => {
+          recovery(this.pageId)
+            .then((res) => {
+              this.$Message.success(res.msg);
+              this.reload();
+            })
+            .catch((err) => {
+              this.$Message.error(err.msg);
+            });
+        },
+        onCancel: () => {},
+      });
+    },
+    // 获取url
+    getUrlList() {
+      getUrl().then((res) => {
+        this.urlList = res.data.url;
+      });
+    },
+    // 左侧tab
+    bindTab(index) {
+      this.tabCur = index;
+    },
+    // 页面标题点击
+    showTitle() {
+      this.activeIndex = -100;
+      let obj = {};
+      for (var i in mConfig) {
+        if (i == 'pageTitle') {
+          // this.rConfig = obj
+          obj = mConfig[i];
+          obj.configName = mConfig[i].name;
+          obj.cname = '页面设置';
+        }
+      }
+      let abc = obj;
+      this.rConfig = [];
+      this.rConfig[0] = JSON.parse(JSON.stringify(obj));
+    },
+    // 页面底部点击
+    showFoot() {
+      this.activeIndex = -101;
+      let obj = {};
+      for (var i in mConfig) {
+        if (i == 'pageFoot') {
+          // this.rConfig = obj
+          obj = mConfig[i];
+          obj.configName = mConfig[i].name;
+          obj.cname = '底部菜单';
+        }
+      }
+      let abc = obj;
+      this.rConfig = [];
+      this.rConfig[0] = JSON.parse(JSON.stringify(obj));
+    },
+    // 对象转数组
+    objToArr(data) {
+      let obj = Object.keys(data);
+      let m = obj.map((key) => data[key]);
+      return m;
+    },
+    log(evt) {
+      // 中间拖拽排序
+      if (evt.moved) {
+        if (evt.moved.element.name == 'search_box' || evt.moved.element.name == 'nav_bar') {
+          return this.$Message.warning('该组件禁止拖拽');
+        }
+
+        // if (evt.moved.element.name == "nav_bar") {
+        //     return this.$Message.warning("该组件禁止拖拽");
+        // }
+        evt.moved.oldNum = this.mConfig[evt.moved.oldIndex].num;
+        evt.moved.newNum = this.mConfig[evt.moved.newIndex].num;
+        evt.moved.status = evt.moved.oldIndex > evt.moved.newIndex;
+        this.mConfig.forEach((el, index) => {
+          el.num = new Date().getTime() * 1000 + index;
+        });
+        evt.moved.list = this.mConfig;
+        this.rConfig = [];
+        let item = evt.moved.element;
+        let tempItem = JSON.parse(JSON.stringify(item));
+        this.rConfig.push(tempItem);
+        this.activeIndex = evt.moved.newIndex;
+        this.$store.commit('mobildConfig/SETCONFIGNAME', item.name);
+        this.$store.commit('mobildConfig/defaultArraySort', evt.moved);
+      }
+      // 从左向右拖拽排序
+      if (evt.added) {
+        let data = evt.added.element;
+        let obj = {};
+        let timestamp = new Date().getTime() * 1000;
+        data.num = timestamp;
+        this.activeConfigName = data.name;
+        let tempItem = JSON.parse(JSON.stringify(data));
+        tempItem.id = 'id' + tempItem.num;
+        this.mConfig[evt.added.newIndex] = tempItem;
+        this.rConfig = [];
+        this.rConfig.push(tempItem);
+        this.mConfig.forEach((el, index) => {
+          el.num = new Date().getTime() * 1000 + index;
+        });
+        evt.added.list = this.mConfig;
+        this.activeIndex = evt.added.newIndex;
+        // 保存组件名称
+        this.$store.commit('mobildConfig/SETCONFIGNAME', data.name);
+        this.$store.commit('mobildConfig/defaultArraySort', evt.added);
+      }
+    },
+    cloneDog(data) {
+      // this.mConfig.push(tempItem)
+      return {
+        ...data,
+      };
+    },
+    //数组元素互换位置
+    swapArray(arr, index1, index2) {
+      arr[index1] = arr.splice(index2, 1, arr[index1])[0];
+      return arr;
+    },
+    //点击上下移动;
+    movePage(item, index, type) {
+      if (type) {
+        if (index == 0) {
+          return;
+        }
+      } else {
+        if (index == this.mConfig.length - 1) {
+          return;
+        }
+      }
+      if (item.name == 'search_box' || item.name == 'nav_bar') {
+        return this.$Message.warning('该组件禁止移动');
+      }
+      // if (item.name == "nav_bar") {
+      //     return this.$Message.warning("该组件禁止移动");
+      // }
+      if (type) {
+        // if(this.mConfig[index-1].name  == "search_box" || this.mConfig[index-1].name  == "nav_bar"){
+        if (this.mConfig[index - 1].name == 'search_box') {
+          return this.$Message.warning('搜索框必须为顶部');
+        }
+        this.swapArray(this.mConfig, index - 1, index);
+      } else {
+        this.swapArray(this.mConfig, index, index + 1);
+      }
+      let obj = {};
+      this.rConfig = [];
+      obj.oldIndex = index;
+      if (type) {
+        obj.newIndex = index - 1;
+      } else {
+        obj.newIndex = index + 1;
+      }
+      this.mConfig.forEach((el, index) => {
+        el.num = new Date().getTime() * 1000 + index;
+      });
+      let tempItem = JSON.parse(JSON.stringify(item));
+      this.rConfig.push(tempItem);
+      obj.element = item;
+      obj.list = this.mConfig;
+      if (type) {
+        this.activeIndex = index - 1;
+      } else {
+        this.activeIndex = index + 1;
+      }
+      this.$store.commit('mobildConfig/SETCONFIGNAME', item.name);
+      this.$store.commit('mobildConfig/defaultArraySort', obj);
+    },
+    // 组件添加
+    addDomCon(item, type, index) {
+      if (item.name == 'search_box') {
+        if (this.isSearch) return this.$Message.error('该组件只能添加一次');
+        this.isSearch = true;
+      }
+      if (item.name == 'nav_bar') {
+        if (this.isTab) return this.$Message.error('该组件只能添加一次');
+        this.isTab = true;
+      }
+      idGlobal += 1;
+      let obj = {};
+      let timestamp = new Date().getTime() * 1000;
+      item.num = `${timestamp}`;
+      item.id = `id${timestamp}`;
+      this.activeConfigName = item.name;
+      let tempItem = JSON.parse(JSON.stringify(item));
+      if (item.name == 'search_box') {
+        this.rConfig = [];
+        this.mConfig.unshift(tempItem);
+        this.activeIndex = 0;
+        this.rConfig.push(tempItem);
+      }
+      // 动态拖动可上传此部分代码
+      else if (item.name == 'nav_bar') {
+        this.rConfig = [];
+        if (this.mConfig[0] && this.mConfig[0].name === 'search_box') {
+          this.mConfig.splice(1, 0, tempItem);
+          this.activeIndex = 1;
+        } else {
+          this.mConfig.splice(0, 0, tempItem);
+          this.activeIndex = 0;
+        }
+        this.rConfig.push(tempItem);
+      } else {
+        if (type) {
+          this.rConfig = [];
+          this.mConfig.push(tempItem);
+          this.activeIndex = this.mConfig.length - 1;
+          this.rConfig.push(tempItem);
+        } else {
+          this.mConfig.splice(index + 1, 0, tempItem);
+          this.activeIndex = index;
+        }
+      }
+      this.mConfig.forEach((el, index) => {
+        el.num = new Date().getTime() * 1000 + index;
+      });
+      // 保存组件名称
+      obj.element = item;
+      obj.list = this.mConfig;
+      this.$store.commit('mobildConfig/SETCONFIGNAME', item.name);
+      this.$store.commit('mobildConfig/defaultArraySort', obj);
+    },
+    //中间页点击添加模块;
+    bindAddDom(item, type, index) {
+      let i = item;
+      this.lConfig.forEach((j) => {
+        if (item.name == j.name) {
+          i = j;
+        }
+      });
+      this.addDomCon(i, type, index);
+    },
+    //左边配置模块点击添加;
+    addDom(item, type) {
+      this.addDomCon(item, type);
+    },
+    // 点击显示相应的配置
+    bindconfig(item, index) {
+      console.log(item, index);
+      this.rConfig = [];
+      let tempItem = JSON.parse(JSON.stringify(item));
+      this.rConfig.push(tempItem);
+      this.activeIndex = index;
+      this.$store.commit('mobildConfig/SETCONFIGNAME', item.name);
+    },
+    // 组件删除
+    bindDelete(item, key) {
+      if (item.name == 'search_box') {
+        this.isSearch = false;
+      }
+      if (item.name == 'nav_bar') {
+        this.isTab = false;
+      }
+      this.mConfig.splice(key, 1);
+      this.rConfig.splice(0, 1);
+      if (this.mConfig.length != key) {
+        this.rConfig.push(this.mConfig[key]);
+      } else {
+        if (this.mConfig.length) {
+          this.activeIndex = key - 1;
+          this.rConfig.push(this.mConfig[key - 1]);
+        } else {
+          this.showTitle();
+        }
+      }
+      // 删除第几个配置
+      this.$store.commit('mobildConfig/DELETEARRAY', item);
+    },
+    // 组件返回
+    config(data) {
+      let propsObj = this.propsObj;
+      propsObj.data = data;
+      propsObj.name = this.activeConfigName;
+    },
+    addSort(arr, index1, index2) {
+      arr[index1] = arr.splice(index2, 1, arr[index1])[0];
+      return arr;
+    },
+    // 数组排序
+    arraySort() {
+      let tempArr = [];
+      let basis = {
+        title: '基础组件',
+        list: [],
+        isOpen: true,
+      };
+      let marketing = {
+        title: '营销组件',
+        list: [],
+        isOpen: true,
+      };
+      let tool = {
+        title: '工具组件',
+        list: [],
+        isOpen: true,
+      };
+      this.lConfig.map((el, index) => {
+        if (el.type == 0) {
+          basis.list.push(el);
+        }
+        if (el.type == 1) {
+          marketing.list.push(el);
+        }
+        if (el.type == 2) {
+          tool.list.push(el);
+        }
+      });
+      tempArr.push(basis, marketing, tool);
+      this.leftMenu = tempArr;
+    },
+    // toImage(val){
+    //     html2canvas(this.$refs.imgContainer,{
+    //         useCORS:true,
+    //         logging:true,
+    //         taintTest: false,
+    //         backgroundColor: null
+    //     }).then((canvas) => {
+    //         let imgUrl = canvas.toDataURL('image/jpeg');
+    //         this.diySaveDate(val,imgUrl)
+    //     });
+    // },
+    diySaveDate(val, init, name) {
+      console.log(init, name);
+      saveDiy(init ? 0 : this.pageId, {
+        type: this.pageType,
+        value: val,
+        title: this.titleTxt,
+        name: name || this.nameTxt,
+        is_show: this.showTxt ? 1 : 0,
+        is_bg_color: this.colorTxt ? 1 : 0,
+        color_picker: this.colorPickerTxt,
+        bg_pic: this.picUrlTxt,
+        bg_tab_val: this.tabValTxt,
+        is_bg_pic: this.picTxt ? 1 : 0,
+      })
+        .then((res) => {
+          this.loading = false;
+          if (!init) {
+            this.pageId = res.data.id;
+          }
+          this.saveName = '';
+          this.$Message.success(res.msg);
+        })
+        .catch((res) => {
+          this.loading = false;
+          this.$Message.error(res.msg);
+        });
+    },
+    // 保存配置
+    saveConfig(init, name) {
+      if (this.mConfig.length == 0) {
+        return this.$Message.error('暂未添加任何组件,保存失败!');
+      }
+      this.loading = true;
+      let val = this.$store.state.mobildConfig.defaultArray;
+      if (!this.footActive) {
+        let timestamp = new Date().getTime() * 1000;
+        val[timestamp] = this.$store.state.mobildConfig.pageFooter;
+        this.footActive = true;
+      }
+      this.$nextTick(() => {
+        this.diySaveDate(val, init, name);
+      });
+    },
+    // 获取默认配置
+    getDefaultConfig() {
+      getDiyInfo(this.pageId).then(({ data }) => {
+        let obj = {};
+        let tempARR = [];
+        this.$store.commit('mobildConfig/titleUpdata', data.info.title);
+        this.$store.commit('mobildConfig/nameUpdata', data.info.name);
+        this.$store.commit('mobildConfig/showUpdata', data.info.is_show);
+        this.$store.commit('mobildConfig/colorUpdata', data.info.is_bg_color || 0);
+        this.$store.commit('mobildConfig/picUpdata', data.info.is_bg_pic || 0);
+        this.$store.commit('mobildConfig/pickerUpdata', data.info.color_picker || '#f5f5f5');
+        this.$store.commit('mobildConfig/radioUpdata', data.info.bg_tab_val || 0);
+        this.$store.commit('mobildConfig/picurlUpdata', data.info.bg_pic || '');
+        let newArr = this.objToArr(data.info.value);
+
+        function sortNumber(a, b) {
+          return a.timestamp - b.timestamp;
+        }
+
+        newArr.sort(sortNumber);
+        newArr.map((el, index) => {
+          if (el.name == 'headerSerch') {
+            this.isSearch = true;
+          }
+          if (el.name == 'tabNav') {
+            this.isTab = true;
+          }
+          if (el.name == 'goodList') {
+            let storage = window.localStorage;
+            storage.setItem(el.timestamp, el.selectConfig.activeValue);
+          }
+          el.id = 'id' + el.timestamp;
+          this.lConfig.map((item, j) => {
+            if (el.name == item.defaultName) {
+              item.num = el.timestamp;
+              item.id = 'id' + el.timestamp;
+              let tempItem = JSON.parse(JSON.stringify(item));
+              tempARR.push(tempItem);
+              obj[el.timestamp] = el;
+              this.mConfig.push(tempItem);
+              // 保存默认组件配置
+              this.$store.commit('mobildConfig/ADDARRAY', {
+                num: el.timestamp,
+                val: el,
+              });
+            }
+          });
+        });
+
+        let objs = newArr[newArr.length - 1];
+
+        if (objs.name == 'pageFoot') {
+          this.$store.commit('mobildConfig/footPageUpdata', objs);
+        }
+        this.showTitle();
+        // this.rConfig = [];
+        // this.activeIndex = 0;
+        // this.rConfig.push(this.mConfig[0]);
+      });
+    },
+    categoryList() {
+      categoryList((res) => {
+        this.category = res.data;
+      });
+    },
+    // 重置
+    reast() {
+      if (this.pageId == 0) {
+        this.$Message.error('新增页面,无法重置');
+      } else {
+        this.$Modal.confirm({
+          title: '提示',
+          content: '<p>重置会恢复到上次保存的数据,确定不保存当前操作吗?</p>',
+          onOk: () => {
+            this.mConfig = [];
+            this.rConfig = [];
+            this.activeIndex = -99;
+            this.getDefaultConfig();
+          },
+          onCancel: () => {},
+        });
+      }
+    },
+  },
+  beforeDestroy() {
+    this.$store.commit('mobildConfig/titleUpdata', '');
+    this.$store.commit('mobildConfig/nameUpdata', '');
+    this.$store.commit('mobildConfig/showUpdata', 1);
+    this.$store.commit('mobildConfig/colorUpdata', 0);
+    this.$store.commit('mobildConfig/picUpdata', 0);
+    this.$store.commit('mobildConfig/pickerUpdata', '#f5f5f5');
+    this.$store.commit('mobildConfig/radioUpdata', 0);
+    this.$store.commit('mobildConfig/picurlUpdata', '');
+    this.$store.commit('mobildConfig/SETEMPTY');
+  },
+  destroyed() {
+    this.$store.commit('mobildConfig/titleUpdata', '');
+    this.$store.commit('mobildConfig/nameUpdata', '');
+    this.$store.commit('mobildConfig/showUpdata', 1);
+    this.$store.commit('mobildConfig/colorUpdata', 0);
+    this.$store.commit('mobildConfig/picUpdata', 0);
+    this.$store.commit('mobildConfig/pickerUpdata', '#f5f5f5');
+    this.$store.commit('mobildConfig/radioUpdata', 0);
+    this.$store.commit('mobildConfig/picurlUpdata', '');
+    this.$store.commit('mobildConfig/SETEMPTY');
+  },
+};
+</script>
+
+<style scoped lang="stylus">
+
+.ysize {
+  background-size: 100%;
+}
+
+.fullsize {
+  background-size: 100% 100%;
+}
+
+.repeat {
+  background-repeat: repeat;
+}
+
+.noRepeat {
+  background-repeat: no-repeat;
+}
+
+.wrapper-con {
+  position relative
+  .acticon{
+    position absolute
+    right: 20px
+    top 20px
+    display: flex;
+    flex-direction: column;
+    z-index: 1000;
+  }
+  /* min-width 700px; */
+}
+.main .content-wrapper{
+  padding: 0 !important;
+}
+.defaultData {
+  /* margin-left 20px; */
+  cursor: pointer;
+  position: absolute;
+  left: 50%;
+  margin-left: 245px;
+
+  .data {
+    margin-top: 20px;
+    color: #282828;
+    background-color: #fff;
+    width: 94px;
+    text-align: center;
+    height: 32px;
+    line-height: 32px;
+    border-radius: 3px;
+    font-size: 12px;
+  }
+
+  .data:hover {
+    background-color: #2d8cf0;
+    color: #fff;
+    border: 0;
+  }
+}
+
+.overflowy {
+  overflow-y: scroll;
+
+  .picture {
+    width: 379px;
+    height: 20px;
+    margin: 0 auto;
+    background-color: #fff;
+  }
+}
+
+.bnt {
+  width: 80px !important;
+}
+
+/* 定义滑块 内阴影+圆角 */
+::-webkit-scrollbar-thumb {
+  -webkit-box-shadow: inset 0 0 6px #fff;
+  display: none;
+}
+
+.left:hover::-webkit-scrollbar-thumb, .right-box:hover::-webkit-scrollbar-thumb {
+  display: block;
+}
+
+.contxt:hover ::-webkit-scrollbar-thumb {
+  display: block;
+}
+
+::-webkit-scrollbar {
+  width: 4px !important; /* 对垂直流动条有效 */
+}
+
+.scrollCon {
+  overflow-y: scroll;
+  overflow-x: hidden;
+}
+
+.scroll-box .position {
+  display: block !important;
+  height: 40px;
+  text-align: center;
+  line-height: 40px;
+  border: 1px dashed #1890ff;
+  color: #1890ff;
+  background-color: #edf4fb;
+}
+
+.scroll-box .conter {
+  display: none !important;
+}
+
+.dragClass {
+  background-color: #fff;
+}
+
+.ivu-mt {
+  display: flex;
+  justify-content: space-between;
+  margin-bottom: 10px;
+}
+
+.iconfont-diy {
+  font-size: 24px;
+  color: var(--prev-color-primary);
+}
+
+.diy-wrapper {
+  max-width: 100%;
+  min-width: 1100px;
+  display: flex;
+  justify-content: space-between;
+  height: 100%;
+  .left {
+    min-width: 300px;
+    max-width: 300px;
+    /* border 1px solid #DDDDDD */
+    border-radius: 4px;
+    height: 100%;
+
+    .title-bar {
+      display: flex;
+      color: #333;
+      border-bottom: 1px solid #eee;
+      border-radius: 4px;
+      cursor: pointer;
+
+      .title-item {
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        flex: 1;
+        height: 45px;
+
+        &.on {
+          color: var(--prev-color-primary);
+          font-size: 14px;
+          border-bottom: 1px solid var(--prev-color-primary);
+        }
+      }
+    }
+
+    .wrapper {
+      padding: 15px;
+      overflow-y: scroll;
+      -webkit-overflow-scrolling: touch;
+
+      .tips {
+        display: flex;
+        justify-content: space-between;
+        padding-bottom: 15px;
+        font-size: 13px;
+        color: #000;
+        cursor: pointer;
+
+        .ivu-icon {
+          color: #000;
+        }
+      }
+    }
+
+    .link-item {
+      padding: 10px;
+      border-bottom: 1px solid #F5F5F5;
+      font-size: 12px;
+      color: #323232;
+
+      .name {
+        font-size: 14px;
+        color: #1890FF;
+      }
+
+      .link-txt {
+        margin-top: 2px;
+        word-break: break-all;
+      }
+
+      .params {
+        margin-top: 5px;
+        color: #1CBE6B;
+        word-break: break-all;
+
+        .txt {
+          color: #323232;
+        }
+
+        span {
+          &:last-child i {
+            display: none;
+            color: red;
+          }
+        }
+      }
+
+      .lable {
+        display: flex;
+        margin-top: 5px;
+        color: #999;
+
+        p {
+          flex: 1;
+          word-break: break-all;
+        }
+
+        button {
+          margin-left: 30px;
+          width: 38px;
+        }
+      }
+    }
+
+    .dragArea.list-group {
+      display: flex;
+      flex-wrap: wrap;
+
+      .list-group-item {
+        display: flex;
+        flex-direction: column;
+        align-items: center;
+        justify-content: center;
+        width: 74px;
+        height: 66px;
+        margin-right: 17px;
+        margin-bottom: 10px;
+        font-size: 12px;
+        color: #666;
+        cursor: pointer;
+        border-radius: 5px;
+        text-align: center;
+
+        &:hover {
+          box-shadow: 0 0 5px 0 rgba(24, 144, 255, 0.3);
+          border-right: 5px;
+          transform: scale(1.1);
+          transition: all 0.2s;
+        }
+
+        &:nth-child(3n) {
+          margin-right: 0;
+        }
+      }
+    }
+  }
+
+  .content {
+    position: relative;
+    height: 100%;
+    width: 100%;
+
+    .page-foot {
+      position: relative;
+      width: 379px;
+      margin: 0 auto 20px auto;
+
+      .delete-box {
+        display: none;
+        position: absolute;
+        left: -2px;
+        top: 0;
+        width: 383px;
+        height: 100%;
+        border: 2px dashed var(--prev-color-primary);
+        padding: 10px 0;
+      }
+
+      &:hover, &.on {
+        /* cursor: move; */
+        .delete-box {
+          /* display: block; */
+        }
+      }
+
+      &.on {
+        cursor: move;
+
+        .delete-box {
+          display: block;
+          border: 2px solid var(--prev-color-primary);
+          box-shadow: 0 0 10px 0 rgba(24, 144, 255, 0.3);
+        }
+      }
+    }
+
+    .page-title {
+      position: relative;
+      height: 35px;
+      line-height: 35px;
+      background: #fff;
+      font-size: 15px;
+      color: #333333;
+      text-align: center;
+      width: 379px;
+      margin: 0 auto;
+
+      .delete-box {
+        display: none;
+        position: absolute;
+        left: -2px;
+        top: 0;
+        width: 383px;
+        height: 100%;
+        border: 2px dashed var(--prev-color-primary);
+        padding: 10px 0;
+
+        span {
+          position: absolute;
+          right: 0;
+          bottom: 0;
+          width: 32px;
+          height: 16px;
+          line-height: 16px;
+          display: inline-block;
+          text-align: center;
+          font-size: 10px;
+          color: #fff;
+          background: rgba(0, 0, 0, 0.4);
+          margin-left: 2px;
+          cursor: pointer;
+          z-index: 11;
+        }
+      }
+
+      &:hover, &.on {
+        /* cursor: move; */
+        .delete-box {
+          /* display: block; */
+        }
+      }
+
+      &.on {
+        cursor: move;
+
+        .delete-box {
+          display: block;
+          border: 2px solid var(--prev-color-primary);
+          box-shadow: 0 0 10px 0 rgba(24, 144, 255, 0.3);
+        }
+      }
+    }
+
+    .scroll-box {
+      flex: 1;
+      background-color: #fff;
+      width: 379px;
+      margin: 0 auto;
+      padding-top: 1px;
+    }
+
+    .dragArea.list-group {
+      width: 100%;
+      height: 100%;
+
+      .mConfig-item {
+        position: relative;
+        cursor: move;
+
+        .delete-box {
+          display: none;
+          position: absolute;
+          left: -2px;
+          top: 0;
+          width: 383px;
+          height: 100%;
+          border: 2px dashed var(--prev-color-primary);
+
+          /* padding: 10px 0; */
+          .handleType {
+            position: absolute;
+            right: -43px;
+            top: 0;
+            width: 36px;
+            height: 143px;
+            border-radius: 4px;
+            background-color: #1890ff;
+            cursor: pointer;
+            color: #fff;
+            font-weight: bold;
+            text-align: center;
+            padding: 4px 0;
+
+            .iconfont {
+              padding: 5px 0;
+
+              &.on {
+                opacity: 0.4;
+              }
+            }
+          }
+        }
+
+        &.on {
+          cursor: move;
+
+          .delete-box {
+            display: block;
+            border: 2px solid var(--prev-color-primary);
+            box-shadow: 0 0 10px 0 rgba(24, 144, 255, 0.3);
+          }
+        }
+      }
+
+      .mConfig-item:hover {
+        transform: scale(1.01);
+        box-shadow: 0 0 10px 0 rgba(24, 144, 255, 0.3);
+        transition: all 0.2s;
+      }
+    }
+  }
+
+  .right-box {
+    max-width: 400px;
+    min-width: 400px;
+    height: 100%;
+    border-radius: 4px;
+    overflow: scroll;
+    -webkit-overflow-scrolling: touch;
+
+    /deep/ .ivu-tabs-bar {
+      margin-bottom: 16px;
+    }
+
+    .title-bar {
+      width: 100%;
+      height: 45px;
+      line-height: 45px;
+      padding-left: 24px;
+      color: #000;
+      border-radius: 4px;
+      border-bottom: 1px solid #eee;
+      font-size: 14px;
+    }
+  }
+
+  ::-webkit-scrollbar {
+    width: 6px;
+    background-color: transparent;
+  }
+
+  ::-webkit-scrollbar-track {
+    border-radius: 10px;
+  }
+
+  ::-webkit-scrollbar-thumb {
+    background-color: #bfc1c4;
+  }
+}
+
+.foot-box {
+  position: relative;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  height: 80px;
+  background: #fff;
+  box-shadow: 0px -2px 4px 0px rgba(0, 0, 0, 0.03);
+
+  button {
+    width: 100px;
+    height: 32px;
+    font-size: 13px;
+
+    &:first-child {
+      margin-right: 20px;
+    }
+  }
+}
+
+/deep/ .ivu-scroll-loader {
+  display: none;
+}
+
+/deep/ .ivu-card-body {
+  width: 100%;
+  padding:0;
+  height: calc(100vh - 73px);
+
+}
+
+.rbtn {
+  position: absolute;
+  right: 20px;
+}
+.code {
+  position: relative;
+}
+
+.QRpic {
+  width: 160px;
+  height: 160px;
+
+  img {
+    width: 100%;
+    height: 100%;
+  }
+}
+</style>

+ 115 - 0
src/pages/shop_setting/devise/goodClass.vue

@@ -0,0 +1,115 @@
+<template>
+  <div class="goodClass">
+    <Card :bordered="false" dis-hover>
+      <!-- <div class="title">页面设置</div> -->
+      <div class="list acea-row row-top">
+        <div
+          class="item"
+          :class="activeStyle == index ? 'on' : ''"
+          v-for="(item, index) in classList"
+          :key="index"
+          @click="selectTap(index)"
+        >
+          <div class="pictrue"><img :src="item.image" /></div>
+          <div class="name">{{ item.name }}</div>
+        </div>
+      </div>
+    </Card>
+  </div>
+</template>
+
+<script>
+import { colorChange, getColorChange } from '@/api/diy';
+export default {
+  name: 'goodClass',
+  props: {},
+  data() {
+    return {
+      classList: [
+        { image: require('@/assets/images/sort01.jpg'), name: '样式1' },
+        { image: require('@/assets/images/sort02.jpg'), name: '样式2' },
+        { image: require('@/assets/images/sort03.png'), name: '样式3' },
+      ],
+      activeStyle: '-1',
+    };
+  },
+  created() {
+    this.getInfo();
+  },
+  methods: {
+    getInfo() {
+      getColorChange('category').then((res) => {
+        this.activeStyle = res.data.status ? res.data.status - 1 : 0;
+      });
+    },
+    selectTap(index) {
+      this.activeStyle = index;
+    },
+    onSubmit(num) {
+      this.$emit('parentFun', true);
+      this.activeStyle = num == 1 ? 0 : this.activeStyle;
+      colorChange(num == 1 ? 1 : this.activeStyle + 1, 'category')
+        .then((res) => {
+          this.$emit('parentFun', false);
+          this.$Message.success(res.msg);
+        })
+        .catch((err) => {
+          this.$Message.error(err.msg);
+          this.$emit('parentFun', false);
+        });
+    },
+  },
+};
+</script>
+<style scoped lang="stylus">
+.goodClass{
+    .title{
+        font-size 14px;
+        color: rgba(0, 0, 0, 0.85);
+        position relative;
+        padding-left 11px;
+        font-weight bold;
+        &:after{
+            position absolute;
+            content ' ';
+            width 2px;
+            height 14px;
+            background-color #1890FF;
+            left:0;
+            top:3px;
+        }
+    }
+    .list{
+        .item{
+            width 264px;
+            margin 20px 30px 0 0;
+            cursor pointer;
+            .pictrue{
+                width 100%;
+                height 496px;
+                border: 1px solid #EEEEEE;
+                border-radius: 10px;
+                img{
+                    width 100%
+                    height 100%
+                    border-radius: 10px;
+                }
+            }
+            .name{
+                font-size: 13px;
+                color: rgba(0, 0, 0, 0.85);
+                margin-top 26px;
+                text-align center;
+            }
+            &.on{
+                .pictrue{
+                    border: 2px solid #1890FF;
+                }
+                .name{
+                    color #1890FF;
+                }
+            }
+        }
+    }
+}
+</style>

+ 1279 - 0
src/pages/shop_setting/devise/index.vue

@@ -0,0 +1,1279 @@
+<template>
+  <div class="diy-page">
+    <Card :bordered="false" dis-hover class="ivu-mt" style="margin: 0 10px">
+      <div class="diy-wrapper" :style="'height:' + clientHeight + 'px;'">
+        <!-- 左侧 -->
+        <div class="left">
+          <div class="title-bar">
+            <div
+              class="title-item"
+              :class="{ on: tabCur == index }"
+              v-for="(item, index) in tabList"
+              :key="index"
+              @click="bindTab(index)"
+            >
+              {{ item.title }}
+            </div>
+          </div>
+          <div class="wrapper" :style="'height:' + (clientHeight - 46) + 'px;'" v-if="tabCur == 0">
+            <div v-for="(item, index) in leftMenu" :key="index">
+              <div class="tips" @click="item.isOpen = !item.isOpen">
+                {{ item.title }}
+
+                <Icon type="ios-arrow-forward" size="16" v-if="!item.isOpen" />
+                <Icon type="ios-arrow-down" size="16" v-else />
+              </div>
+              <draggable
+                class="dragArea list-group"
+                :list="item.list"
+                :group="{ name: 'people', pull: 'clone', put: false }"
+                :clone="cloneDog"
+                dragClass="dragClass"
+                filter=".search"
+              >
+                <!--filter=".search , .navbar"-->
+                <!--:class="{ search: element.cname == '搜索框' , navbar: element.cname == '商品分类' }"-->
+                <div
+                  class="list-group-item"
+                  :class="{ search: element.cname == '搜索框' }"
+                  v-for="(element, index) in item.list"
+                  :key="element.id"
+                  @click="addDom(element, 1)"
+                  v-show="item.isOpen"
+                >
+                  <div>
+                    <div class="position" style="display: none">释放鼠标将组建添加到此处</div>
+                    <span class="conter iconfont-diy" :class="element.icon"></span>
+                    <p class="conter">{{ element.cname }}</p>
+                  </div>
+                </div>
+              </draggable>
+            </div>
+          </div>
+          <!--                    <div style="padding: 0 20px"><Button type="primary" style="width: 100%" @click="saveConfig">保存</Button></div>-->
+          <div class="wrapper" v-else :style="'height:' + (clientHeight - 46) + 'px;'">
+            <div class="link-item" v-for="(item, index) in urlList" :key="index">
+              <div class="name">{{ item.name }}</div>
+              <div class="link-txt">地址:{{ item.url }}</div>
+              <div class="params">
+                <span class="txt">参数:</span>
+                <span>{{ item.parameter }}</span>
+              </div>
+              <div class="lable">
+                <p class="txt">例如:{{ item.example }}</p>
+                <Button size="small" @click="onCopy(item.example)">复制 </Button>
+              </div>
+            </div>
+          </div>
+        </div>
+        <!-- 中间 -->
+        <div
+          class="wrapper-con"
+          style="flex: 1; background: #f0f2f5; display: flex; justify-content: center; padding-top: 20px; height: 100%"
+        >
+          <div class="content">
+            <div class="contxt" style="display: flex; flex-direction: column; overflow: hidden; height: 100%">
+              <div class="overflowy">
+                <div class="picture">
+                  <img src="@/assets/images/electric.png" />
+                </div>
+                <div class="page-title" :class="{ on: activeIndex == -100 }" @click="showTitle">
+                  {{ titleTxt }}
+                  <div class="delete-box"></div>
+                  <div class="handle"></div>
+                </div>
+              </div>
+              <div class="scrollCon">
+                <div style="width: 460px; margin: 0 auto">
+                  <div
+                    class="scroll-box"
+                    :class="
+                      picTxt && tabValTxt == 2
+                        ? 'fullsize noRepeat'
+                        : picTxt && tabValTxt == 1
+                        ? 'repeat ysize'
+                        : 'noRepeat ysize'
+                    "
+                    :style="
+                      'background-color:' +
+                      (colorTxt ? colorPickerTxt : '') +
+                      ';background-image: url(' +
+                      (picTxt ? picUrlTxt : '') +
+                      ');height:' +
+                      rollHeight +
+                      'px;'
+                    "
+                    ref="imgContainer"
+                  >
+                    <draggable
+                      class="dragArea list-group"
+                      :list="mConfig"
+                      group="people"
+                      @change="log"
+                      filter=".top"
+                      :move="onMove"
+                      animation="300"
+                    >
+                      <div
+                        class="mConfig-item"
+                        :class="{
+                          on: activeIndex == key,
+                          top: item.name == 'search_box' || item.name == 'nav_bar',
+                        }"
+                        v-for="(item, key) in mConfig"
+                        :key="key"
+                        @click.stop="bindconfig(item, key)"
+                        :style="colorTxt ? 'background-color:' + colorPickerTxt + ';' : 'background-color:#fff;'"
+                      >
+                        <component
+                          :is="item.name"
+                          ref="getComponentData"
+                          :configData="propsObj"
+                          :index="key"
+                          :num="item.num"
+                        ></component>
+                        <div class="delete-box">
+                          <div class="handleType">
+                            <div class="iconfont iconshanchu2" @click.stop="bindDelete(item, key)"></div>
+                            <div class="iconfont iconfuzhi" @click.stop="bindAddDom(item, 0, key)"></div>
+                            <div
+                              class="iconfont iconshangyi"
+                              :class="key === 0 ? 'on' : ''"
+                              @click.stop="movePage(item, key, 1)"
+                            ></div>
+                            <div
+                              class="iconfont iconxiayi"
+                              :class="key === mConfig.length - 1 ? 'on' : ''"
+                              @click.stop="movePage(item, key, 0)"
+                            ></div>
+                          </div>
+                        </div>
+                        <div class="handle"></div>
+                      </div>
+                    </draggable>
+                  </div>
+                </div>
+              </div>
+              <div class="overflowy">
+                <div class="page-foot" @click="showFoot" :class="{ on: activeIndex == -101 }">
+                  <footPage></footPage>
+                  <div class="delete-box"></div>
+                  <div class="handle"></div>
+                </div>
+              </div>
+              <div class="defaultData" v-if="pageId !== 0">
+                <div class="data" @click="setmoren">设置默认</div>
+                <div class="data" @click="getmoren">恢复默认</div>
+              </div>
+            </div>
+          </div>
+        </div>
+        <!-- 右侧 -->
+        <div class="right-box">
+          <div class="mConfig-item" style="background-color: #fff" v-for="(item, key) in rConfig" :key="key">
+            <div class="title-bar">{{ item.cname }}</div>
+            <component
+              :is="item.configName"
+              @config="config"
+              :activeIndex="activeIndex"
+              :num="item.num"
+              :index="key"
+            ></component>
+          </div>
+        </div>
+      </div>
+    </Card>
+    <!--<div class="foot-box">-->
+    <!--<Button @click="reast">重置</Button>-->
+    <!--<Button type="primary" @click="saveConfig" :loading="loading"-->
+    <!--&gt;保存-->
+    <!--</Button-->
+    <!--&gt;-->
+    <!--</div>-->
+  </div>
+</template>
+
+<script crossorigin="anonymous">
+import { categoryList, diyGetInfo, diySave, getUrl, setDefault, recovery } from '@/api/diy';
+import vuedraggable from 'vuedraggable';
+import footPage from '@/components/pagesFoot';
+import { mapState } from 'vuex';
+import html2canvas from 'html2canvas';
+
+let idGlobal = 0;
+export default {
+  inject: ['reload'],
+  name: 'index.vue',
+  components: {
+    footPage,
+    html2canvas,
+    draggable: vuedraggable,
+  },
+  filters: {
+    filterTxt(val) {
+      if (val) {
+        return (val = val.substr(0, val.length - 1));
+      }
+    },
+  },
+  computed: {
+    ...mapState({
+      titleTxt: (state) => state.mobildConfig.pageTitle || '首页',
+      nameTxt: (state) => state.mobildConfig.pageName || '模板',
+      showTxt: (state) => state.mobildConfig.pageShow,
+      colorTxt: (state) => state.mobildConfig.pageColor,
+      picTxt: (state) => state.mobildConfig.pagePic,
+      colorPickerTxt: (state) => state.mobildConfig.pageColorPicker,
+      tabValTxt: (state) => state.mobildConfig.pageTabVal,
+      picUrlTxt: (state) => state.mobildConfig.pagePicUrl,
+    }),
+  },
+  data() {
+    return {
+      clientHeight: '', //页面动态高度
+      rollHeight: '',
+      leftMenu: [], // 左侧菜单
+      lConfig: [], // 左侧组件
+      mConfig: [], // 中间组件渲染
+      rConfig: [], // 右侧组件配置
+      activeConfigName: '',
+      propsObj: {}, // 组件传递的数据,
+      activeIndex: -100, // 选中的下标
+      number: 0,
+      pageId: '',
+      pageName: '',
+      pageType: '',
+      category: [],
+      tabList: [
+        {
+          title: '组件库',
+          key: 0,
+        },
+        {
+          title: '页面链接',
+          key: 1,
+        },
+      ],
+      tabCur: 0,
+      urlList: [],
+      footActive: false,
+      loading: false,
+      isSearch: false,
+      isTab: false,
+      isFllow: false,
+    };
+  },
+  created() {
+    this.categoryList();
+    this.getUrlList();
+    this.pageId = this.$route.query.id;
+    this.pageName = this.$route.query.name;
+    this.pageType = this.$route.query.type;
+    this.lConfig = this.objToArr(mPage);
+  },
+  mounted() {
+    let imgList = {
+      imgList: [require('@/assets/images/foot-005.png'), require('@/assets/images/foot-006.png')],
+      name: '购物车',
+      link: '/pages/order_addcart/order_addcart',
+    };
+    this.$nextTick(() => {
+      this.$store.commit('mobildConfig/FOOTER', {
+        title: '是否自定义',
+        name: imgList,
+      });
+      this.arraySort();
+      if (this.pageId != 0) {
+        this.getDefaultConfig();
+      } else {
+        this.showTitle();
+      }
+      this.clientHeight = `${document.documentElement.clientHeight}` - 65.81; //获取浏览器可视区域高度
+      let H = `${document.documentElement.clientHeight}` - 180;
+      this.rollHeight = H > 650 ? 650 : H;
+      let that = this;
+      window.onresize = function () {
+        that.clientHeight = `${document.documentElement.clientHeight}` - 65.81;
+        let H = `${document.documentElement.clientHeight}` - 180;
+        that.rollHeight = H > 650 ? 650 : H;
+      };
+    });
+  },
+  methods: {
+    leftRemove({ to, from, item, clone, oldIndex, newIndex }) {
+      if (this.isSearch && newIndex == 0) {
+        if (item._underlying_vm_.name == 'z_wechat_attention') {
+          this.isFllow = true;
+        } else {
+          this.$store.commit('mobildConfig/ARRAYREAST', this.mConfig[0].num);
+          this.mConfig.splice(0, 1);
+        }
+      }
+      if ((this.isFllow = true && newIndex >= 1)) {
+        this.$store.commit('mobildConfig/ARRAYREAST', this.mConfig[0].num);
+      }
+    },
+    onMove(e) {
+      if (e.relatedContext.element.name == 'search_box') return false;
+      if (e.relatedContext.element.name == 'nav_bar') return false;
+      return true;
+    },
+    onCopy(copyData) {
+      this.$copyText(copyData)
+        .then((message) => {
+          this.$Message.success('复制成功');
+        })
+        .catch((err) => {
+          this.$Message.error('复制失败');
+        });
+    },
+    onError() {
+      this.$Message.error('复制失败');
+    },
+    //设置默认数据
+    setmoren() {
+      setDefault(this.pageId)
+        .then((res) => {
+          this.$Message.success(res.msg);
+        })
+        .catch((err) => {
+          this.$Message.error(err.msg);
+        });
+    },
+    //恢复默认
+    getmoren() {
+      recovery(this.pageId)
+        .then((res) => {
+          this.$Message.success(res.msg);
+          this.reload();
+        })
+        .catch((err) => {
+          this.$Message.error(err.msg);
+        });
+    },
+    // 获取url
+    getUrlList() {
+      getUrl().then((res) => {
+        this.urlList = res.data.url;
+      });
+    },
+    // 左侧tab
+    bindTab(index) {
+      this.tabCur = index;
+    },
+    // 页面标题点击
+    showTitle() {
+      this.activeIndex = -100;
+      let obj = {};
+      for (var i in mConfig) {
+        if (i == 'pageTitle') {
+          // this.rConfig = obj
+          obj = mConfig[i];
+          obj.configName = mConfig[i].name;
+          obj.cname = '页面设置';
+        }
+      }
+      let abc = obj;
+      this.rConfig = [];
+      this.rConfig[0] = JSON.parse(JSON.stringify(obj));
+    },
+    // 页面底部点击
+    showFoot() {
+      this.activeIndex = -101;
+      let obj = {};
+      for (var i in mConfig) {
+        if (i == 'pageFoot') {
+          // this.rConfig = obj
+          obj = mConfig[i];
+          obj.configName = mConfig[i].name;
+          obj.cname = '底部菜单';
+        }
+      }
+      let abc = obj;
+      this.rConfig = [];
+      this.rConfig[0] = JSON.parse(JSON.stringify(obj));
+    },
+    // 对象转数组
+    objToArr(data) {
+      let obj = Object.keys(data);
+      let m = obj.map((key) => data[key]);
+      return m;
+    },
+    log(evt) {
+      // 中间拖拽排序
+      if (evt.moved) {
+        if (evt.moved.element.name == 'search_box' || evt.moved.element.name == 'nav_bar') {
+          return this.$Message.warning('该组件禁止拖拽');
+        }
+        // if (evt.moved.element.name == "nav_bar") {
+        //     return this.$Message.warning("该组件禁止拖拽");
+        // }
+        evt.moved.oldNum = this.mConfig[evt.moved.oldIndex].num;
+        evt.moved.newNum = this.mConfig[evt.moved.newIndex].num;
+        evt.moved.status = evt.moved.oldIndex > evt.moved.newIndex;
+        this.mConfig.forEach((el, index) => {
+          el.num = new Date().getTime() * 1000 + index;
+        });
+        evt.moved.list = this.mConfig;
+        this.rConfig = [];
+        let item = evt.moved.element;
+        let tempItem = JSON.parse(JSON.stringify(item));
+        this.rConfig.push(tempItem);
+        this.activeIndex = evt.moved.newIndex;
+        this.$store.commit('mobildConfig/SETCONFIGNAME', item.name);
+        this.$store.commit('mobildConfig/defaultArraySort', evt.moved);
+      }
+      // 从左向右拖拽排序
+      if (evt.added) {
+        let data = evt.added.element;
+        let obj = {};
+        let timestamp = new Date().getTime() * 1000;
+        data.num = timestamp;
+        this.activeConfigName = data.name;
+        let tempItem = JSON.parse(JSON.stringify(data));
+        tempItem.id = 'id' + tempItem.num;
+        this.mConfig[evt.added.newIndex] = tempItem;
+        this.rConfig = [];
+        this.rConfig.push(tempItem);
+        this.mConfig.forEach((el, index) => {
+          el.num = new Date().getTime() * 1000 + index;
+        });
+        evt.added.list = this.mConfig;
+        this.activeIndex = evt.added.newIndex;
+        // 保存组件名称
+        this.$store.commit('mobildConfig/SETCONFIGNAME', data.name);
+        this.$store.commit('mobildConfig/defaultArraySort', evt.added);
+      }
+    },
+    cloneDog(data) {
+      // this.mConfig.push(tempItem)
+      return {
+        ...data,
+      };
+    },
+    //数组元素互换位置
+    swapArray(arr, index1, index2) {
+      arr[index1] = arr.splice(index2, 1, arr[index1])[0];
+      return arr;
+    },
+    //点击上下移动;
+    movePage(item, index, type) {
+      if (type) {
+        if (index == 0) {
+          return;
+        }
+      } else {
+        if (index == this.mConfig.length - 1) {
+          return;
+        }
+      }
+      if (item.name == 'search_box' || item.name == 'nav_bar') {
+        return this.$Message.warning('该组件禁止移动');
+      }
+      // if (item.name == "nav_bar") {
+      //     return this.$Message.warning("该组件禁止移动");
+      // }
+      if (type) {
+        // if(this.mConfig[index-1].name  == "search_box" || this.mConfig[index-1].name  == "nav_bar"){
+        if (this.mConfig[index - 1].name == 'search_box') {
+          return this.$Message.warning('搜索框必须为顶部');
+        }
+        this.swapArray(this.mConfig, index - 1, index);
+      } else {
+        this.swapArray(this.mConfig, index, index + 1);
+      }
+      let obj = {};
+      this.rConfig = [];
+      obj.oldIndex = index;
+      if (type) {
+        obj.newIndex = index - 1;
+      } else {
+        obj.newIndex = index + 1;
+      }
+      this.mConfig.forEach((el, index) => {
+        el.num = new Date().getTime() * 1000 + index;
+      });
+      let tempItem = JSON.parse(JSON.stringify(item));
+      this.rConfig.push(tempItem);
+      obj.element = item;
+      obj.list = this.mConfig;
+      if (type) {
+        this.activeIndex = index - 1;
+      } else {
+        this.activeIndex = index + 1;
+      }
+      this.$store.commit('mobildConfig/SETCONFIGNAME', item.name);
+      this.$store.commit('mobildConfig/defaultArraySort', obj);
+    },
+    // 组件添加
+    addDomCon(item, type, index) {
+      if (item.name == 'search_box') {
+        if (this.isSearch) return this.$Message.error('该组件只能添加一次');
+        this.isSearch = true;
+      }
+      if (item.name == 'nav_bar') {
+        if (this.isTab) return this.$Message.error('该组件只能添加一次');
+        this.isTab = true;
+      }
+      idGlobal += 1;
+      let obj = {};
+      let timestamp = new Date().getTime() * 1000;
+      item.num = `${timestamp}`;
+      item.id = `id${timestamp}`;
+      this.activeConfigName = item.name;
+      let tempItem = JSON.parse(JSON.stringify(item));
+      if (item.name == 'search_box') {
+        this.rConfig = [];
+        this.mConfig.unshift(tempItem);
+        this.activeIndex = 0;
+        this.rConfig.push(tempItem);
+      }
+      // else if (item.name == "nav_bar") {
+      //     this.rConfig = [];
+      //     if (this.mConfig[0]&&this.mConfig[0].name === "search_box") {
+      //         this.mConfig.splice(1, 0, tempItem);
+      //         this.activeIndex = 1;
+      //     } else {
+      //         this.mConfig.splice(0, 0, tempItem);
+      //         this.activeIndex = 0;
+      //     }
+      //     this.rConfig.push(tempItem);
+      // }
+      else {
+        if (type) {
+          this.rConfig = [];
+          this.mConfig.push(tempItem);
+          this.activeIndex = this.mConfig.length - 1;
+          this.rConfig.push(tempItem);
+        } else {
+          this.mConfig.splice(index + 1, 0, tempItem);
+          this.activeIndex = index;
+        }
+      }
+      this.mConfig.forEach((el, index) => {
+        el.num = new Date().getTime() * 1000 + index;
+      });
+      // 保存组件名称
+      obj.element = item;
+      obj.list = this.mConfig;
+      this.$store.commit('mobildConfig/SETCONFIGNAME', item.name);
+      this.$store.commit('mobildConfig/defaultArraySort', obj);
+    },
+    //中间页点击添加模块;
+    bindAddDom(item, type, index) {
+      let i = item;
+      this.lConfig.forEach((j) => {
+        if (item.name == j.name) {
+          i = j;
+        }
+      });
+      this.addDomCon(i, type, index);
+    },
+    //左边配置模块点击添加;
+    addDom(item, type) {
+      this.addDomCon(item, type);
+    },
+    // 点击显示相应的配置
+    bindconfig(item, index) {
+      this.rConfig = [];
+      let tempItem = JSON.parse(JSON.stringify(item));
+      this.rConfig.push(tempItem);
+      this.activeIndex = index;
+      this.$store.commit('mobildConfig/SETCONFIGNAME', item.name);
+    },
+    // 组件删除
+    bindDelete(item, key) {
+      if (item.name == 'search_box') {
+        this.isSearch = false;
+      }
+      if (item.name == 'nav_bar') {
+        this.isTab = false;
+      }
+      this.mConfig.splice(key, 1);
+      this.rConfig.splice(0, 1);
+      if (this.mConfig.length != key) {
+        this.rConfig.push(this.mConfig[key]);
+      } else {
+        if (this.mConfig.length) {
+          this.activeIndex = key - 1;
+          this.rConfig.push(this.mConfig[key - 1]);
+        } else {
+          this.showTitle();
+        }
+      }
+      // 删除第几个配置
+      this.$store.commit('mobildConfig/DELETEARRAY', item);
+    },
+    // 组件返回
+    config(data) {
+      let propsObj = this.propsObj;
+      propsObj.data = data;
+      propsObj.name = this.activeConfigName;
+    },
+    addSort(arr, index1, index2) {
+      arr[index1] = arr.splice(index2, 1, arr[index1])[0];
+      return arr;
+    },
+    // 数组排序
+    arraySort() {
+      let tempArr = [];
+      let basis = {
+        title: '基础组件',
+        list: [],
+        isOpen: true,
+      };
+      let marketing = {
+        title: '营销组件',
+        list: [],
+        isOpen: true,
+      };
+      let tool = {
+        title: '工具组件',
+        list: [],
+        isOpen: true,
+      };
+      this.lConfig.map((el, index) => {
+        if (el.type == 0) {
+          basis.list.push(el);
+        }
+        if (el.type == 1) {
+          marketing.list.push(el);
+        }
+        if (el.type == 2) {
+          tool.list.push(el);
+        }
+      });
+      tempArr.push(basis, marketing, tool);
+      this.leftMenu = tempArr;
+    },
+    // toImage(val){
+    //     html2canvas(this.$refs.imgContainer,{
+    //         useCORS:true,
+    //         logging:true,
+    //         taintTest: false,
+    //         backgroundColor: null
+    //     }).then((canvas) => {
+    //         let imgUrl = canvas.toDataURL('image/jpeg');
+    //         this.diySaveDate(val,imgUrl)
+    //     });
+    // },
+    diySaveDate(val) {
+      diySave(this.pageId, {
+        type: this.pageType,
+        value: val,
+        title: this.titleTxt,
+        name: this.nameTxt,
+        is_show: this.showTxt ? 1 : 0,
+        is_bg_color: this.colorTxt ? 1 : 0,
+        color_picker: this.colorPickerTxt,
+        bg_pic: this.picUrlTxt,
+        bg_tab_val: this.tabValTxt,
+        is_bg_pic: this.picTxt ? 1 : 0,
+      })
+        .then((res) => {
+          this.loading = false;
+          this.pageId = res.data.id;
+          this.$Message.success(res.msg);
+        })
+        .catch((res) => {
+          this.loading = false;
+          this.$Message.error(res.msg);
+        });
+    },
+    // 保存配置
+    saveConfig() {
+      if (this.mConfig.length == 0) {
+        return this.$Message.error('暂未添加任何组件,保存失败!');
+      }
+      this.loading = true;
+      let val = this.$store.state.mobildConfig.defaultArray;
+      if (!this.footActive) {
+        let timestamp = new Date().getTime() * 1000;
+        val[timestamp] = this.$store.state.mobildConfig.pageFooter;
+        this.footActive = true;
+      }
+      this.$nextTick(function () {
+        this.diySaveDate(val);
+      });
+    },
+    // 获取默认配置
+    getDefaultConfig() {
+      diyGetInfo(this.pageId, {
+        type: 1,
+      }).then(({ data }) => {
+        let obj = {};
+        let tempARR = [];
+        this.$store.commit('mobildConfig/titleUpdata', data.info.title);
+        this.$store.commit('mobildConfig/nameUpdata', data.info.name);
+        this.$store.commit('mobildConfig/showUpdata', data.info.is_show);
+        this.$store.commit('mobildConfig/colorUpdata', data.info.is_bg_color || 0);
+        this.$store.commit('mobildConfig/picUpdata', data.info.is_bg_pic || 0);
+        this.$store.commit('mobildConfig/pickerUpdata', data.info.color_picker || '#f5f5f5');
+        this.$store.commit('mobildConfig/radioUpdata', data.info.bg_tab_val || 0);
+        this.$store.commit('mobildConfig/picurlUpdata', data.info.bg_pic || '');
+        let newArr = this.objToArr(data.info.value);
+
+        function sortNumber(a, b) {
+          return a.timestamp - b.timestamp;
+        }
+
+        newArr.sort(sortNumber);
+        newArr.map((el, index) => {
+          if (el.name == 'headerSerch') {
+            this.isSearch = true;
+          }
+          if (el.name == 'tabNav') {
+            this.isTab = true;
+          }
+          if (el.name == 'goodList') {
+            let storage = window.localStorage;
+            storage.setItem(el.timestamp, el.selectConfig.activeValue);
+          }
+          el.id = 'id' + el.timestamp;
+          this.lConfig.map((item, j) => {
+            if (el.name == item.defaultName) {
+              item.num = el.timestamp;
+              item.id = 'id' + el.timestamp;
+              let tempItem = JSON.parse(JSON.stringify(item));
+              tempARR.push(tempItem);
+              obj[el.timestamp] = el;
+              this.mConfig.push(tempItem);
+              // 保存默认组件配置
+              this.$store.commit('mobildConfig/ADDARRAY', {
+                num: el.timestamp,
+                val: el,
+              });
+            }
+          });
+        });
+
+        let objs = newArr[newArr.length - 1];
+
+        if (objs.name == 'pageFoot') {
+          this.$store.commit('mobildConfig/footPageUpdata', objs);
+        }
+        this.showTitle();
+        // this.rConfig = [];
+        // this.activeIndex = 0;
+        // this.rConfig.push(this.mConfig[0]);
+      });
+    },
+    categoryList() {
+      categoryList((res) => {
+        this.category = res.data;
+      });
+    },
+    // 重置
+    reast() {
+      if (this.pageId == 0) {
+        this.$Message.error('新增页面,无法重置');
+      } else {
+        this.$Modal.confirm({
+          title: '提示',
+          content: '<p>重置会恢复到上次保存的数据,确定不保存当前操作吗?</p>',
+          onOk: () => {
+            this.mConfig = [];
+            this.rConfig = [];
+            this.activeIndex = -99;
+            this.getDefaultConfig();
+          },
+          onCancel: () => {},
+        });
+      }
+    },
+  },
+  beforeDestroy() {
+    this.$store.commit('mobildConfig/titleUpdata', '');
+    this.$store.commit('mobildConfig/nameUpdata', '');
+    this.$store.commit('mobildConfig/showUpdata', 1);
+    this.$store.commit('mobildConfig/colorUpdata', 0);
+    this.$store.commit('mobildConfig/picUpdata', 0);
+    this.$store.commit('mobildConfig/pickerUpdata', '#f5f5f5');
+    this.$store.commit('mobildConfig/radioUpdata', 0);
+    this.$store.commit('mobildConfig/picurlUpdata', '');
+    this.$store.commit('mobildConfig/SETEMPTY');
+  },
+  destroyed() {
+    this.$store.commit('mobildConfig/titleUpdata', '');
+    this.$store.commit('mobildConfig/nameUpdata', '');
+    this.$store.commit('mobildConfig/showUpdata', 1);
+    this.$store.commit('mobildConfig/colorUpdata', 0);
+    this.$store.commit('mobildConfig/picUpdata', 0);
+    this.$store.commit('mobildConfig/pickerUpdata', '#f5f5f5');
+    this.$store.commit('mobildConfig/radioUpdata', 0);
+    this.$store.commit('mobildConfig/picurlUpdata', '');
+    this.$store.commit('mobildConfig/SETEMPTY');
+  },
+};
+</script>
+
+<style scoped lang="stylus">
+.ysize {
+  background-size: 100%;
+}
+
+.fullsize {
+  background-size: 100% 100%;
+}
+
+.repeat {
+  background-repeat: repeat;
+}
+
+.noRepeat {
+  background-repeat: no-repeat;
+}
+
+.wrapper-con {
+  /* min-width 700px; */
+}
+
+.defaultData {
+  /* margin-left 20px; */
+  cursor: pointer;
+  position: absolute;
+  left: 50%;
+  margin-left: 245px;
+
+  .data {
+    margin-top: 20px;
+    color: #282828;
+    background-color: #fff;
+    width: 94px;
+    text-align: center;
+    height: 32px;
+    line-height: 32px;
+    border-radius: 3px;
+    font-size: 12px;
+  }
+
+  .data:hover {
+    background-color: #2d8cf0;
+    color: #fff;
+    border: 0;
+  }
+}
+
+.overflowy {
+  overflow-y: scroll;
+
+  .picture {
+    width: 379px;
+    height: 20px;
+    margin: 0 auto;
+    background-color: #fff;
+  }
+}
+
+.bnt {
+  width: 80px !important;
+}
+
+/* 定义滑块 内阴影+圆角 */
+::-webkit-scrollbar-thumb {
+  -webkit-box-shadow: inset 0 0 6px #fff;
+  display: none;
+}
+
+.left:hover::-webkit-scrollbar-thumb, .right-box:hover::-webkit-scrollbar-thumb {
+  display: block;
+}
+
+.contxt:hover ::-webkit-scrollbar-thumb {
+  display: block;
+}
+
+::-webkit-scrollbar {
+  width: 4px !important; /* 对垂直流动条有效 */
+}
+
+.scrollCon {
+  overflow-y: scroll;
+  overflow-x: hidden;
+}
+
+.scroll-box .position {
+  display: block !important;
+  height: 40px;
+  text-align: center;
+  line-height: 40px;
+  border: 1px dashed #1890ff;
+  color: #1890ff;
+  background-color: #edf4fb;
+}
+
+.scroll-box .conter {
+  display: none !important;
+}
+
+.dragClass {
+  background-color: #fff;
+}
+
+.ivu-mt {
+  display: flex;
+  justify-content: space-between;
+}
+
+.iconfont-diy {
+  font-size: 24px;
+  color: #1890ff;
+}
+
+.diy-wrapper {
+  max-width: 100%;
+  min-width: 1100px;
+  display: flex;
+  justify-content: space-between;
+
+  /* height: 84.5vh; */
+  .left {
+    min-width: 300px;
+    max-width: 300px;
+    /* border 1px solid #DDDDDD */
+    border-radius: 4px;
+    height: 100%;
+
+    .title-bar {
+      display: flex;
+      color: #333;
+      border-bottom: 1px solid #eee;
+      border-radius: 4px;
+      cursor: pointer;
+
+      .title-item {
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        flex: 1;
+        height: 45px;
+
+        &.on {
+          color: #1890FF;
+          font-size: 14px;
+          border-bottom: 1px solid #1890FF;
+        }
+      }
+    }
+
+    .wrapper {
+      padding: 15px;
+      overflow-y: scroll;
+      -webkit-overflow-scrolling: touch;
+
+      .tips {
+        display: flex;
+        justify-content: space-between;
+        padding-bottom: 15px;
+        font-size: 13px;
+        color: #000;
+        cursor: pointer;
+
+        .ivu-icon {
+          color: #000;
+        }
+      }
+    }
+
+    .link-item {
+      padding: 10px;
+      border-bottom: 1px solid #F5F5F5;
+      font-size: 12px;
+      color: #323232;
+
+      .name {
+        font-size: 14px;
+        color: #1890FF;
+      }
+
+      .link-txt {
+        margin-top: 2px;
+        word-break: break-all;
+      }
+
+      .params {
+        margin-top: 5px;
+        color: #1CBE6B;
+        word-break: break-all;
+
+        .txt {
+          color: #323232;
+        }
+
+        span {
+          &:last-child i {
+            display: none;
+            color: red;
+          }
+        }
+      }
+
+      .lable {
+        display: flex;
+        margin-top: 5px;
+        color: #999;
+
+        p {
+          flex: 1;
+          word-break: break-all;
+        }
+
+        button {
+          margin-left: 30px;
+          width: 38px;
+        }
+      }
+    }
+
+    .dragArea.list-group {
+      display: flex;
+      flex-wrap: wrap;
+
+      .list-group-item {
+        display: flex;
+        flex-direction: column;
+        align-items: center;
+        justify-content: center;
+        width: 74px;
+        height: 66px;
+        margin-right: 17px;
+        margin-bottom: 10px;
+        font-size: 12px;
+        color: #666;
+        cursor: pointer;
+        border-radius: 5px;
+        text-align: center;
+
+        &:hover {
+          box-shadow: 0 0 5px 0 rgba(24, 144, 255, 0.3);
+          border-right: 5px;
+        }
+
+        &:nth-child(3n) {
+          margin-right: 0;
+        }
+      }
+    }
+  }
+
+  .content {
+    position: relative;
+    height: 100%;
+    width: 100%;
+
+    .page-foot {
+      position: relative;
+      width: 379px;
+      margin: 0 auto 20px auto;
+
+      .delete-box {
+        display: none;
+        position: absolute;
+        left: -2px;
+        top: 0;
+        width: 383px;
+        height: 100%;
+        border: 2px dashed #1890ff;
+        padding: 10px 0;
+      }
+
+      &:hover, &.on {
+        /* cursor: move; */
+        .delete-box {
+          /* display: block; */
+        }
+      }
+
+      &.on {
+        cursor: move;
+
+        .delete-box {
+          display: block;
+          border: 2px solid #1890ff;
+          box-shadow: 0 0 10px 0 rgba(24, 144, 255, 0.3);
+        }
+      }
+    }
+
+    .page-title {
+      position: relative;
+      height: 35px;
+      line-height: 35px;
+      background: #fff;
+      font-size: 15px;
+      color: #333333;
+      text-align: center;
+      width: 379px;
+      margin: 0 auto;
+
+      .delete-box {
+        display: none;
+        position: absolute;
+        left: -2px;
+        top: 0;
+        width: 383px;
+        height: 100%;
+        border: 2px dashed #1890ff;
+        padding: 10px 0;
+
+        span {
+          position: absolute;
+          right: 0;
+          bottom: 0;
+          width: 32px;
+          height: 16px;
+          line-height: 16px;
+          display: inline-block;
+          text-align: center;
+          font-size: 10px;
+          color: #fff;
+          background: rgba(0, 0, 0, 0.4);
+          margin-left: 2px;
+          cursor: pointer;
+          z-index: 11;
+        }
+      }
+
+      &:hover, &.on {
+        /* cursor: move; */
+        .delete-box {
+          /* display: block; */
+        }
+      }
+
+      &.on {
+        cursor: move;
+
+        .delete-box {
+          display: block;
+          border: 2px solid #1890ff;
+          box-shadow: 0 0 10px 0 rgba(24, 144, 255, 0.3);
+        }
+      }
+    }
+
+    .scroll-box {
+      flex: 1;
+      background-color: #fff;
+      width: 379px;
+      margin: 0 auto;
+      padding-top: 1px;
+    }
+
+    .dragArea.list-group {
+      width: 100%;
+      height: 100%;
+
+      .mConfig-item {
+        position: relative;
+        cursor: move;
+
+        .delete-box {
+          display: none;
+          position: absolute;
+          left: -2px;
+          top: 0;
+          width: 383px;
+          height: 100%;
+          border: 2px dashed #1890ff;
+
+          /* padding: 10px 0; */
+          .handleType {
+            position: absolute;
+            right: -43px;
+            top: 0;
+            width: 36px;
+            height: 143px;
+            border-radius: 4px;
+            background-color: #1890ff;
+            cursor: pointer;
+            color: #fff;
+            font-weight: bold;
+            text-align: center;
+            padding: 4px 0;
+
+            .iconfont {
+              padding: 5px 0;
+
+              &.on {
+                opacity: 0.4;
+              }
+            }
+          }
+        }
+
+        &.on {
+          cursor: move;
+
+          .delete-box {
+            display: block;
+            border: 2px solid #1890ff;
+            box-shadow: 0 0 10px 0 rgba(24, 144, 255, 0.3);
+          }
+        }
+      }
+    }
+  }
+
+  .right-box {
+    max-width: 400px;
+    min-width: 400px;
+    height: 100%;
+    border-radius: 4px;
+    overflow: scroll;
+    -webkit-overflow-scrolling: touch;
+
+    .title-bar {
+      width: 100%;
+      height: 45px;
+      line-height: 45px;
+      padding-left: 24px;
+      color: #000;
+      border-radius: 4px;
+      border-bottom: 1px solid #eee;
+      font-size: 14px;
+    }
+  }
+
+  ::-webkit-scrollbar {
+    width: 6px;
+    background-color: transparent;
+  }
+
+  ::-webkit-scrollbar-track {
+    border-radius: 10px;
+  }
+
+  ::-webkit-scrollbar-thumb {
+    background-color: #bfc1c4;
+  }
+}
+
+.foot-box {
+  position: relative;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  height: 80px;
+  background: #fff;
+  box-shadow: 0px -2px 4px 0px rgba(0, 0, 0, 0.03);
+
+  button {
+    width: 100px;
+    height: 32px;
+    font-size: 13px;
+
+    &:first-child {
+      margin-right: 20px;
+    }
+  }
+}
+
+/deep/ .ivu-scroll-loader {
+  display: none;
+}
+
+/deep/ .ivu-card-body {
+  width: 100%;
+}
+</style>

+ 134 - 0
src/pages/shop_setting/devise/links.vue

@@ -0,0 +1,134 @@
+<template>
+  <div class="right-box">
+    <div class="link-item" v-for="(item, index) in list" :key="index">
+      <div class="title">{{ item.name }}</div>
+      <div class="txt"><span>地址:</span>{{ item.url }}</div>
+      <div class="txt" v-if="item.parameter">
+        <p><span>参数:</span></p>
+        <span v-for="(val, key, index) in item.parameter" :key="index"
+          >{{ key + '=' + val }}<i style="font-style: normal">&</i></span
+        >
+      </div>
+      <div class="tips">
+        例如:{{ item.example }}
+        <!--<Button size="small" style="margin-left: 10px" v-clipboard:copy="item.example"-->
+        <!--v-clipboard:success="onCopy"-->
+        <!--v-clipboard:error="onError">复制</Button>-->
+        <span class="copy copy-data" @click="onCopy(item.example)">复制</span>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import ClipboardJS from 'clipboard';
+import { getUrl } from '@/api/diy';
+export default {
+  name: 'links',
+  data() {
+    return {
+      list: [
+        {
+          name: '商城首页',
+          url: '/pages/goods/order_list/index',
+          parameter: [{}],
+          example: '/pages/activity/bargain/index',
+        },
+        {
+          name: '商城首页',
+          url: '/pages/goods/order_list/index',
+          parameter: [{}],
+          example: '/pages/activity/bargain/index',
+        },
+      ],
+    };
+  },
+  created() {
+    getUrl().then((res) => {
+      this.list = res.data.url;
+    });
+  },
+  mounted: function () {
+    this.$nextTick(function () {
+      const clipboard = new ClipboardJS('.copy-data');
+      clipboard.on('success', () => {
+        this.$Message.success('复制成功');
+      });
+    });
+  },
+  methods: {
+    onCopy(copyData) {
+      this.$copyText(copyData)
+        .then((message) => {
+          this.$Message.success('复制成功');
+        })
+        .catch((err) => {
+          this.$Message.error('复制失败');
+        });
+    },
+    // onError () {
+    //     this.$Message.error('复制成功');
+    // }
+  },
+};
+</script>
+
+<style scoped lang="stylus">
+.right-box
+    width 400px
+    margin-left 50px
+    border:1px solid #ddd;
+    border-radius 4px
+    height: 700px;
+    overflow-y: scroll;
+    padding 0 10px
+    &::-webkit-scrollbar {
+        /*滚动条整体样式*/
+        width : 4px;  /*高宽分别对应横竖滚动条的尺寸*/
+        height: 1px;
+    }
+    &::-webkit-scrollbar-thumb {
+        /*滚动条里面小方块*/
+        border-radius: 4px;
+        box-shadow   : inset 0 0 5px rgba(0, 0, 0, 0.2);
+        background   : #535353;
+    }
+    &::-webkit-scrollbar-track {
+        /*滚动条里面轨道*/
+        box-shadow   : inset 0 0 5px #fff;
+        border-radius: 4px;
+        background   : #fff;
+    }
+    .link-item
+        padding 10px 0
+        border-bottom 1px solid #f5f5f5
+        .title
+            font-size: 14px;
+            color: #2d8cf0;
+        .txt
+            margin 5px 0
+            font-size 12px
+            span
+                color #333
+            p
+                display inline-block
+                color #19be6b
+                margin-right 10px
+                span
+                    color #333
+                &.red
+                    color #f00
+        .tips
+            font-size 12px
+            color #999
+            .copy
+                padding 3px 5px
+                border 1px solid #cccccc
+                border-radius 5px
+                color #333
+                cursor pointer
+                margin-left 5px
+                &:hover
+                    border-color #2d8cf0
+                    color #2d8cf0
+</style>

+ 663 - 0
src/pages/shop_setting/devise/list.vue

@@ -0,0 +1,663 @@
+<template>
+  <div>
+    <div class="i-layout-page-header header-title">
+      <span class="ivu-page-header-title mr20">{{ $route.meta.title }}</span>
+      <div>
+        <div style="float: right" v-if="cardShow == 1 || cardShow == 2">
+          <Button class="bnt" type="primary" @click="submit" :loading="loadingExist">保存</Button>
+          <Button class="bnt ml20" @click="reast">重置</Button>
+        </div>
+      </div>
+    </div>
+
+    <Row class="ivu-mt box-wrapper">
+      <Col span="3" class="left-wrapper">
+        <Menu :theme="theme3" :active-name="1" width="auto">
+          <MenuGroup>
+            <MenuItem
+              :name="item.id"
+              v-for="(item, index) in menuList"
+              :key="index"
+              @click.native="bindMenuItem(index)"
+            >
+              {{ item.name }}
+            </MenuItem>
+          </MenuGroup>
+        </Menu>
+      </Col>
+      <Col span="21" class="right-wrapper">
+        <Card :bordered="false" dis-hover v-if="cardShow == 0">
+          <Row v-if="cardShow == 0">
+            <Col style="width: 310px; height: 550px; margin-right: 30px; position: relative" v-if="isDiy">
+              <iframe class="iframe-box" :src="iframeUrl" frameborder="0" ref="iframe"></iframe>
+              <div class="mask"></div>
+            </Col>
+            <Col :span="isDiy ? '' : 24" v-bind="isDiy ? grid : ''" :class="isDiy ? 'table' : ''">
+              <div class="acea-row row-between-wrapper">
+                <Row type="flex">
+                  <Col v-bind="grid">
+                    <div class="button acea-row row-middle">
+                      <Button type="primary" icon="md-add"
+                        ><a
+                          class="target-add"
+                          ref="target"
+                          :href="`${url}${$routeProStr}/setting/pages/diy_index?id=0&name=首页&type=0`"
+                          target="_blank"
+                          >添加专题页
+                        </a></Button
+                      >
+                    </div>
+                  </Col>
+                </Row>
+              </div>
+              <Table
+                :columns="columns1"
+                :data="list"
+                ref="table"
+                class="mt25"
+                :loading="loading"
+                highlight-row
+                no-userFrom-text="暂无数据"
+                no-filtered-userFrom-text="暂无筛选结果"
+              >
+                <template slot-scope="{ row, index }" slot="region">
+                  <div class="font-blue">首页</div>
+                </template>
+                <template slot-scope="{ row, index }" slot="type_name">
+                  <Tag color="primary" v-if="row.is_diy">{{ row.type_name }}{{ row.id }}</Tag>
+                  <Tag color="warning" v-else>{{ row.type_name }}</Tag>
+                  <Tag color="success" v-if="row.status == 1">首页</Tag>
+                </template>
+                <template slot-scope="{ row, index }" slot="action">
+                  <div style="display: inline-block" v-if="row.status || row.is_diy" @click="edit(row)">
+                    <a
+                      v-if="row.is_diy === 1"
+                      class="target"
+                      ref="target"
+                      :href="`${url}${$routeProStr}/setting/pages/diy_index?id=${row.id}&name=${
+                        row.template_name || 'moren'
+                      }`"
+                      target="_blank"
+                    >
+                      编辑</a
+                    >
+                    <a v-else class="target">编辑</a>
+                  </div>
+                  <Divider type="vertical" v-if="(row.status || row.is_diy) && row.id != 1 && row.status != 1" />
+
+                  <div style="display: inline-block" v-if="row.id != 1 && row.status != 1">
+                    <a @click="del(row, '删除此模板', index)">删除</a>
+                  </div>
+                  <Divider type="vertical" v-if="(row.id != 1 && row.status != 1) || row.is_diy" />
+                  <div style="display: inline-block" v-if="row.is_diy">
+                    <a @click="preview(row, index)">预览</a>
+                  </div>
+                  <Divider type="vertical" v-if="row.is_diy && row.status != 1" />
+                  <div style="display: inline-block" v-if="row.status != 1">
+                    <a @click="setStatus(row, index)">设为首页</a>
+                  </div>
+
+                  <!-- <Divider type="vertical" v-if="row.status != 1" />
+                  <template>
+                    <Dropdown @on-click="changeMenu(row, index, $event)">
+                      <a href="javascript:void(0)"
+                        >更多
+                        <Icon type="ios-arrow-down"></Icon>
+                      </a>
+                      <DropdownMenu slot="list">
+                        <DropdownItem name="1" v-show="!row.type"
+                          >设置默认数据</DropdownItem
+                        >
+                        <DropdownItem name="2" v-show="!row.type"
+                          >恢复默认数据</DropdownItem
+                        >
+                        <DropdownItem name="3" v-show="row.id != 1"
+                          >删除模板</DropdownItem
+                        >
+                      </DropdownMenu>
+                    </Dropdown>
+                  </template> -->
+                </template>
+              </Table>
+              <div class="acea-row row-right page">
+                <Page
+                  :total="total"
+                  :current="diyFrom.page"
+                  show-elevator
+                  show-total
+                  @on-change="pageChange"
+                  :page-size="diyFrom.limit"
+                />
+              </div>
+            </Col>
+          </Row>
+        </Card>
+        <goodClass v-else-if="cardShow == 1" ref="category" @parentFun="getChildData"></goodClass>
+        <users v-else ref="users" @parentFun="getChildData"></users>
+      </Col>
+    </Row>
+    <Modal
+      v-model="isTemplate"
+      scrollable
+      footer-hide
+      closable
+      title="开发移动端链接"
+      :z-index="1"
+      width="500"
+      @on-cancel="cancel"
+    >
+      <div class="article-manager">
+        <Card :bordered="false" dis-hover class="ivu-mt">
+          <Form
+            ref="formItem"
+            :model="formItem"
+            :label-width="120"
+            label-position="right"
+            :rules="ruleValidate"
+            @submit.native.prevent
+          >
+            <Row type="flex" :gutter="24">
+              <Col span="24">
+                <Col v-bind="grid">
+                  <FormItem label="开发移动端链接:" prop="link" label-for="link">
+                    <Input v-model="formItem.link" placeholder="http://localhost:8080" />
+                  </FormItem>
+                </Col>
+              </Col>
+            </Row>
+            <Row type="flex">
+              <Col v-bind="grid">
+                <Button type="primary" class="ml20" @click="handleSubmit('formItem')" style="width: 100%">提交</Button>
+              </Col>
+            </Row>
+          </Form>
+        </Card>
+      </div>
+    </Modal>
+    <Modal v-model="modal" title="预览" footer-hide>
+      <div>
+        <div v-viewer class="acea-row row-around code">
+          <div class="acea-row row-column-around row-between-wrapper">
+            <div class="QRpic" ref="qrCodeUrl"></div>
+            <span class="mt10">公众号二维码</span>
+          </div>
+          <div class="acea-row row-column-around row-between-wrapper">
+            <div class="QRpic">
+              <img v-lazy="qrcodeImg" />
+            </div>
+            <span class="mt10">小程序二维码</span>
+          </div>
+        </div>
+      </div>
+    </Modal>
+  </div>
+</template>
+
+<script>
+import Setting from '@/setting';
+import ClipboardJS from 'clipboard';
+import { diyList, diyDel, setStatus, recovery, getRoutineCode, getDiyCreate, setDefault } from '@/api/diy';
+import { mapState } from 'vuex';
+import QRCode from 'qrcodejs2';
+import goodClass from './goodClass';
+import users from './users';
+import { getCookies, setCookies } from '@/libs/util';
+export default {
+  name: 'devise_list',
+  computed: {
+    ...mapState('admin/layout', ['menuCollapse']),
+  },
+  components: {
+    goodClass,
+    users,
+  },
+  data() {
+    return {
+      grid: {
+        sm: 10,
+        md: 12,
+        lg: 19,
+      },
+      loading: false,
+      theme3: 'light',
+      menuList: [
+        {
+          name: '商城首页',
+          id: 1,
+        },
+        {
+          name: '商品分类',
+          id: 2,
+        },
+        {
+          name: '个人中心',
+          id: 3,
+        },
+      ],
+      columns1: [
+        {
+          title: '页面ID',
+          key: 'id',
+          width: 80,
+        },
+        {
+          title: '模板名称',
+          key: 'name',
+          minWidth: 100,
+        },
+        {
+          title: '模板类型',
+          slot: 'type_name',
+          minWidth: 100,
+        },
+        {
+          title: '添加时间',
+          key: 'add_time',
+          minWidth: 100,
+        },
+        {
+          title: '更新时间',
+          key: 'update_time',
+          minWidth: 100,
+        },
+        {
+          title: '操作',
+          slot: 'action',
+          // fixed: "right",
+          minWidth: 180,
+        },
+      ],
+      list: [],
+      iframeUrl: '',
+      modal: false,
+      BaseURL: Setting.apiBaseURL.replace(/adminapi/, ''),
+      cardShow: 0,
+      loadingExist: false,
+      isDiy: 1,
+      qrcodeImg: '',
+      diyFrom: {
+        type: '',
+        page: 1,
+        limit: 10,
+      },
+      total: 0,
+      formItem: {
+        id: 0,
+        link: '',
+      },
+      isTemplate: false,
+      ruleValidate: {
+        link: [{ required: true, message: '请输入移动端链接', trigger: 'blur' }],
+      },
+      url: window.location.origin,
+    };
+  },
+  created() {
+    this.getList();
+    this.iframeUrl = `${location.origin}/pages/index/index?mdType=iframeWindow`;
+  },
+  mounted: function () {},
+  methods: {
+    cancel() {
+      this.$refs['formItem'].resetFields();
+    },
+    refreshFrame() {
+      this.iframeUrl = '';
+      setTimeout((e) => {
+        this.iframeUrl = `${location.origin}/pages/index/index?mdType=iframeWindow`;
+      }, 200);
+    },
+    getChildData(e) {
+      this.loadingExist = e;
+    },
+    submit() {
+      if (this.cardShow == 1) {
+        this.$refs.category.onSubmit();
+      } else {
+        this.$refs.users.onSubmit();
+      }
+    },
+    reast() {
+      if (this.cardShow == 1) {
+        this.$refs.category.onSubmit(1);
+      } else {
+        this.$refs.users.getInfo();
+      }
+    },
+    bindMenuItem(index) {
+      this.cardShow = index;
+    },
+    onCopy() {
+      this.$Message.success('复制预览链接成功');
+    },
+    onError() {
+      this.$Message.error('复制预览链接失败');
+    },
+    //生成二维码
+    creatQrCode(id) {
+      this.$refs.qrCodeUrl.innerHTML = '';
+      let url = `${this.BaseURL}pages/annex/special/index?id=${id}`;
+      var qrcode = new QRCode(this.$refs.qrCodeUrl, {
+        text: url, // 需要转换为二维码的内容
+        width: 160,
+        height: 160,
+        colorDark: '#000000',
+        colorLight: '#ffffff',
+        correctLevel: QRCode.CorrectLevel.H,
+      });
+    },
+    //小程序二维码
+    routineCode(id) {
+      getRoutineCode(id)
+        .then((res) => {
+          this.qrcodeImg = res.data.image;
+        })
+        .catch((err) => {
+          this.$Message.error(err);
+        });
+    },
+    preview(row) {
+      this.modal = true;
+      this.creatQrCode(row.id);
+      this.routineCode(row.id);
+    },
+    handleSubmit(name) {
+      this.$refs[name].validate((valid) => {
+        if (valid) {
+          setCookies('moveLink', this.formItem.link);
+          this.$router.push({
+            path: this.$routeProStr + '/setting/pages/diy',
+            query: { id: this.formItem.id, type: 1 },
+          });
+        } else {
+          return false;
+        }
+      });
+    },
+    changeMenu(row, index, name) {
+      switch (name) {
+        case '1':
+          this.setDefault(row);
+          break;
+        case '2':
+          this.recovery(row);
+          break;
+        case '3':
+          this.del(row, '删除此模板', index);
+          break;
+        default:
+      }
+    },
+    //设置默认数据
+    setDefault(row) {
+      setDefault(row.id)
+        .then((res) => {
+          this.$Message.success(res.msg);
+          this.getList();
+        })
+        .catch((err) => {
+          this.$Message.error(err.msg);
+        });
+    },
+    // 获取列表
+    getList() {
+      // let storage = window.localStorage;
+      // this.iframeUrl = storage.getItem("iframeUrl");
+      let that = this;
+      this.loading = true;
+      diyList(this.diyFrom).then((res) => {
+        this.loading = false;
+        let data = res.data;
+        this.list = data.list;
+        this.total = data.count;
+      });
+    },
+    pageChange(status) {
+      this.diyFrom.page = status;
+      this.getList();
+    },
+    // 编辑
+    edit(row) {
+      this.formItem.id = row.id;
+      if (!row.is_diy) {
+        if (!row.status) {
+          this.$Message.error('请先设为首页在进行编辑');
+        } else {
+          this.$router.push({
+            path: this.$routeProStr + '/setting/pages/diy',
+            query: { id: row.id, type: 0 },
+          });
+        }
+      }
+    },
+    // 添加
+    // add() {
+    //   this.$modalForm(getDiyCreate()).then(() => this.getList());
+    // },
+    // 添加
+    add() {
+      // this.$router.push({
+      //   path: this.$routeProStr + '/setting/pages/diy_index',
+      //   query: { id: 0, name: '首页', type: 1 },
+      // });
+    },
+    // 删除
+    del(row) {
+      let delfromData = {
+        title: '删除',
+        num: 2000,
+        url: 'diy/del/' + row.id,
+        method: 'DELETE',
+        data: {
+          type: 1,
+        },
+      };
+      this.$modalSure(delfromData)
+        .then((res) => {
+          this.getList();
+        })
+        .catch((res) => {
+          this.$Message.error(res.msg);
+        });
+    },
+    // 使用模板
+    async setStatus(row) {
+      this.$Modal.confirm({
+        title: '提示',
+        content: '<p>是否把该模板设为首页</p>',
+        onOk: () => {
+          setStatus(row.id, {
+            type: 1,
+          })
+            .then((res) => {
+              this.refreshFrame();
+              this.$Message.success(res.msg);
+              this.$Modal.remove();
+              this.getList();
+            })
+            .catch((res) => {
+              this.$Modal.remove();
+              this.$Message.error(res.msg);
+            });
+        },
+      });
+    },
+    recovery(row) {
+      recovery(row.id).then((res) => {
+        this.$Message.success(res.msg);
+        this.getList();
+      });
+    },
+  },
+};
+</script>
+
+<style scoped lang="stylus">
+.ivu-mt {
+  background-color: #fff;
+  padding-bottom: 50px;
+}
+
+.bnt {
+  width: 80px !important;
+}
+
+.iframe-box {
+  width: 100%;
+  height: 100%;
+  border-radius: 10px;
+  border: 1px solid #eee;
+}
+.target-add{
+  text-decoration: none;
+  color #fff
+}
+.mask {
+  position: absolute;
+  left: 0;
+  width: 100%;
+  top: 0;
+  height: 100%;
+  background-color: rgba(0, 0, 0, 0);
+}
+
+/deep/.ivu-menu-vertical .ivu-menu-item, .ivu-menu-vertical .ivu-menu-submenu-title {
+  text-align: center;
+}
+
+/deep/.i-layout-page-header {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+}
+
+/deep/.ivu-page-header {
+  border-bottom: unset;
+  position: fixed;
+  z-index: 9;
+  width: 100%;
+}
+
+/deep/ .ivu-menu-vertical .ivu-menu-item-group-title {
+  display: none;
+}
+
+/deep/ .ivu-menu-vertical.ivu-menu-light:after {
+  display: none;
+}
+
+/deep/ .ivu-menu {
+  z-index: 0 !important;
+}
+
+/deep/ .ivu-row {
+  display: flex;
+}
+
+@media (max-width: 2175px) {
+  .table {
+    display: block;
+    flex: 0 0 76%;
+    max-width: 76%;
+  }
+}
+
+@media (max-width: 2010px) {
+  .table {
+    display: block;
+    flex: 0 0 75%;
+    max-width: 75%;
+  }
+}
+
+@media (max-width: 1860px) {
+  .table {
+    display: block;
+    flex: 0 0 70%;
+    max-width: 70%;
+  }
+}
+
+@media (max-width: 1597px) {
+  .table {
+    display: block;
+    flex: 0 0 65%;
+    max-width: 65%;
+  }
+}
+
+@media (max-width: 1413px) {
+  .table {
+    display: block;
+    flex: 0 0 60%;
+    max-width: 60%;
+  }
+}
+
+@media (max-width: 1275px) {
+  .table {
+    display: block;
+    flex: 0 0 55%;
+    max-width: 55%;
+  }
+}
+
+@media (max-width: 1168px) {
+  .table {
+    display: block;
+    flex: 0 0 48%;
+    max-width: 48%;
+  }
+}
+
+.code {
+  position: relative;
+}
+
+.QRpic {
+  width: 160px;
+  height: 160px;
+
+  img {
+    width: 100%;
+    height: 100%;
+  }
+}
+
+.left-wrapper {
+  background: #fff;
+  border-right: 1px solid #f2f2f2;
+}
+
+.picCon {
+  width: 280px;
+  height: 510px;
+  background: #FFFFFF;
+  border: 1px solid #EEEEEE;
+  border-radius: 25px;
+
+  .pictrue {
+    width: 250px;
+    height: 417px;
+    border: 1px solid #EEEEEE;
+    opacity: 1;
+    border-radius: 10px;
+    margin: 30px auto 0 auto;
+
+    img {
+      width: 100%;
+      height: 100%;
+      border-radius: 10px;
+    }
+  }
+
+  .circle {
+    width: 36px;
+    height: 36px;
+    background: #FFFFFF;
+    border: 1px solid #EEEEEE;
+    border-radius: 50%;
+    margin: 13px auto 0 auto;
+  }
+}
+</style>

+ 115 - 0
src/pages/shop_setting/devise/template.vue

@@ -0,0 +1,115 @@
+<template>
+  <div>
+    <div class="i-layout-page-header">
+      <router-link :to="{ path: $routeProStr + '/setting/pages/devise' }"
+        ><Button icon="ios-arrow-back" size="small" class="mr20">返回</Button></router-link
+      >
+      <span class="ivu-page-header-title mr20">页面设计</span>
+    </div>
+    <Card :bordered="false" dis-hover class="ivu-mt">
+      <div class="flex-wrapper">
+        <!-- :src="iframeUrl" -->
+        <iframe class="iframe-box" :src="iframeUrl" frameborder="0" ref="iframe"></iframe>
+        <div>
+          <div class="content">
+            <rightConfig :name="configName" :pageId="pageId"></rightConfig>
+          </div>
+        </div>
+        <links></links>
+      </div>
+    </Card>
+  </div>
+</template>
+
+<script>
+import { diyGetInfo, diySave } from '@/api/diy';
+import { mapMutations } from 'vuex';
+import rightConfig from '@/components/rightConfig/index';
+import links from './links';
+export default {
+  name: 'index',
+  components: {
+    rightConfig,
+    links,
+  },
+  data() {
+    return {
+      configName: '',
+      iframeUrl: '',
+      setConfig: '',
+      updataConfig: '',
+      pageId: 0,
+    };
+  },
+  created() {
+    let pageId = this.$route.query.id;
+    let names = this.$route.query.name;
+    this.setConfig = 'admin/' + names + '/setConfig';
+    this.updataConfig = 'admin/' + names + '/updataConfig';
+    this.pageId = parseInt(pageId);
+    this.iframeUrl = `${location.origin}/pages/index/index?mdType=iframeWindow`;
+    diyGetInfo(parseInt(pageId)).then((datas) => {
+      let data = datas.data.info.value;
+      this.upData(data);
+    });
+  },
+  mounted() {
+    //监听子页面给当前页面传值
+    window.addEventListener('message', this.handleMessage, false);
+  },
+  methods: {
+    //接收iframe值
+    handleMessage(event) {
+      if (event.data.name) {
+        this.configName = event.data.name;
+        this.add(event.data.name);
+      }
+    },
+    add(data) {
+      this.$store.commit(this.setConfig, data);
+    },
+    upData(data) {
+      this.$store.commit(this.updataConfig, data);
+    },
+    // ...mapMutations({
+    //     add: 'diy/setConfig',
+    //     upData:'diy/updataConfig'
+    // })
+  },
+};
+</script>
+
+<style scoped lang="stylus">
+.content {
+  width: 450px;
+}
+
+.flex-wrapper {
+  display: flex;
+}
+
+.iframe-box {
+  width: 375px;
+  height: 700px;
+  /* border: 1px solid #ddd; */
+  border-radius: 4px;
+  box-shadow: 0 0 7px #cccccc;
+}
+
+.right-box {
+  width: 400px;
+  margin-left: 50px;
+  border: 1px solid #ddd;
+  border-radius: 4px;
+
+  .title-bar {
+    width: 100%;
+    height: 38px;
+    line-height: 38px;
+    padding-left: 24px;
+    color: #333;
+    border-radius: 4px;
+    border-bottom: 1px solid #eee;
+  }
+}
+</style>

+ 816 - 0
src/pages/shop_setting/devise/users.vue

@@ -0,0 +1,816 @@
+<template>
+  <div class="users">
+    <Card :bordered="false" dis-hover>
+      <div class="acea-row row-top">
+        <div class="left" :style="colorStyle">
+          <div class="header" :class="userData.status == 3 ? 'bgColor' : ''">
+            <div class="top acea-row row-between-wrapper">
+              <div class="picTxt acea-row row-middle">
+                <div class="pictrue">
+                  <img src="../../../assets/images/f.png" />
+                </div>
+                <div class="txt">
+                  <div class="name">用户名称用户名称</div>
+                  <div class="phone acea-row row-center-wrapper">
+                    绑定手机号<span class="iconfont iconjinru"></span>
+                  </div>
+                </div>
+              </div>
+              <div class="acea-row row-middle">
+                <div class="news">
+                  <span class="iconfont icons-kefu"></span>
+                  <div class="num">6</div>
+                </div>
+                <span class="iconfont iconshezhi"></span>
+              </div>
+            </div>
+            <div class="center acea-row row-around">
+              <div class="item">
+                <div class="num">0.00</div>
+                <div class="font">我的余额</div>
+              </div>
+              <div class="item">
+                <div class="num">65749</div>
+                <div class="font">当前积分</div>
+              </div>
+              <div class="item">
+                <div class="num">25</div>
+                <div class="font">优惠券</div>
+              </div>
+            </div>
+            <div class="bottom acea-row row-between-wrapper" v-if="userData.status == 1">
+              <div>会员到期 2022-12-31</div>
+              <div class="renew">立即续费<span class="iconfont iconjinru"></span></div>
+            </div>
+            <div class="bottomB acea-row row-between" v-if="userData.status == 3">
+              <div class="vip"><img src="../../../assets/images/member01.png" />开通会员VIP</div>
+              <div>会员可享多项权益<span class="iconfont iconjinru"></span></div>
+            </div>
+          </div>
+          <div class="member acea-row row-between-wrapper" v-if="userData.status == 2">
+            <div class="text">
+              <div class="title">会员可享多项权益</div>
+              <div>会员剩余360天</div>
+            </div>
+            <div class="bnt">立即续费</div>
+          </div>
+          <div class="orderCenter on dotted" :class="current == 4 ? 'solid' : ''" @click="currentShow(4)">
+            <div class="title acea-row row-between-wrapper">
+              <div>订单中心</div>
+              <div class="all">查看全部<span class="iconfont iconjinru"></span></div>
+            </div>
+            <div class="list acea-row row-around">
+              <div class="item">
+                <div class="iconfont" :class="order.dfk"></div>
+                <div>待付款</div>
+              </div>
+              <div class="item">
+                <div class="iconfont" :class="order.dfh"></div>
+                <div>待发货</div>
+              </div>
+              <div class="item">
+                <div class="iconfont" :class="order.dsh"></div>
+                <div>待收货</div>
+              </div>
+              <div class="item">
+                <div class="iconfont" :class="order.dpj"></div>
+                <div>待评价</div>
+              </div>
+              <div class="item">
+                <div class="iconfont" :class="order.sh"></div>
+                <div>售后/退款</div>
+              </div>
+            </div>
+          </div>
+          <div class="carousel dotted" :class="current == 1 ? 'solid' : ''" @click="currentShow(1)">
+            <swiper :options="swiperOption" class="swiperimg" v-if="userData.routine_my_banner.length">
+              <swiper-slide class="swiperimg" v-for="(item, index) in userData.routine_my_banner" :key="index">
+                <img :src="item.pic" />
+              </swiper-slide>
+              <div class="swiper-pagination" slot="pagination"></div>
+            </swiper>
+            <div v-else class="default">暂无广告数据</div>
+          </div>
+          <div class="orderCenter service dotted" :class="current == 2 ? 'solid' : ''" @click="currentShow(2)">
+            <div class="title acea-row row-between-wrapper">
+              <div>我的服务</div>
+            </div>
+            <div class="list acea-row">
+              <div class="item" v-for="(item, index) in MyMenus" :key="index" v-if="item.pic">
+                <div class="pictrue">
+                  <img :src="item.pic" v-if="item.pic && item.pic != ''" />
+                  <span class="iconfont icontupian1" v-else></span>
+                </div>
+                <div>{{ item.name ? item.name : '服务名称' }}</div>
+              </div>
+            </div>
+          </div>
+          <div class="orderCenter service dotted" :class="current == 3 ? 'solid' : ''" @click="currentShow(3)">
+            <div class="title acea-row row-between-wrapper">
+              <div>商家管理</div>
+            </div>
+            <div class="list acea-row">
+              <div class="item" v-for="(item, index) in storeMenu" :key="index" v-if="item.pic">
+                <div class="pictrue">
+                  <img :src="item.pic" />
+                </div>
+                <div>{{ item.name }}</div>
+              </div>
+            </div>
+          </div>
+        </div>
+        <div class="right">
+          <div class="title">页面设置</div>
+          <div class="c_row-item">
+            <Col class="label" span="4"> 页面风格: </Col>
+            <Col span="20" class="slider-box">
+              <RadioGroup v-model="userData.status">
+                <Radio :label="1">
+                  <Icon></Icon>
+                  <span>样式1</span>
+                </Radio>
+                <Radio :label="2">
+                  <Icon></Icon>
+                  <span>样式2</span>
+                </Radio>
+                <Radio :label="3">
+                  <Icon></Icon>
+                  <span>样式3</span>
+                </Radio>
+              </RadioGroup>
+            </Col>
+          </div>
+          <div class="c_row-item" v-if="current == 4">
+            <Col class="label" span="4"> 订单中心: </Col>
+            <Col span="20" class="slider-box">
+              <RadioGroup v-model="userData.order_status" @on-change="orderStyle">
+                <Radio :label="1">
+                  <Icon></Icon>
+                  <span>样式1</span>
+                </Radio>
+                <Radio :label="2">
+                  <Icon></Icon>
+                  <span>样式2</span>
+                </Radio>
+                <Radio :label="3">
+                  <Icon></Icon>
+                  <span>样式3</span>
+                </Radio>
+                <Radio :label="4">
+                  <Icon></Icon>
+                  <span>样式4</span>
+                </Radio>
+                <Radio :label="5">
+                  <Icon></Icon>
+                  <span>样式5</span>
+                </Radio>
+              </RadioGroup>
+            </Col>
+          </div>
+          <div class="c_row-item acea-row row-top" v-if="current == 1">
+            <Col class="label" span="4"> 广告位: </Col>
+            <Col span="20" class="slider-box">
+              <i-switch v-model="userData.my_banner_status" style="margin-bottom: 12px" />
+              <div class="info">建议尺寸:690 * 240px,拖拽图片可调整图片显示顺序哦,最多添加五张</div>
+              <uploadPic :listData="userData.routine_my_banner" :type="2"></uploadPic>
+            </Col>
+          </div>
+          <div class="c_row-item acea-row row-top" v-if="current == 2">
+            <Col class="label" span="4"> 我的服务: </Col>
+            <Col span="20" class="slider-box">
+              <div class="info">建议尺寸:86 * 86px,拖拽图片可调整图片显示顺序哦</div>
+              <uploadPic :listData="MyMenus"></uploadPic>
+            </Col>
+          </div>
+          <div class="c_row-item acea-row row-top" v-if="current == 3">
+            <Col class="label" span="4"> 商家管理: </Col>
+            <Col span="20" class="slider-box">
+              <div class="info">建议尺寸:86 * 86px,拖拽图片可调整图片显示顺序哦,最多添加五张</div>
+              <uploadPic :listData="storeMenu" :type="1"></uploadPic>
+            </Col>
+          </div>
+        </div>
+      </div>
+    </Card>
+  </div>
+</template>
+
+<script>
+import { getMember, memberSave } from '@/api/diy';
+import uploadPic from './components/uploadPic';
+export default {
+  name: 'users',
+  components: {
+    uploadPic,
+  },
+  props: {},
+  data() {
+    return {
+      swiperOption: {
+        //显示分页
+        pagination: {
+          el: '.swiper-pagination',
+        },
+        //自动轮播
+        autoplay: {
+          delay: 2000,
+          //当用户滑动图片后继续自动轮播
+          disableOnInteraction: false,
+        },
+        //开启循环模式
+        loop: false,
+      },
+      userData: {
+        my_banner_status: true,
+        routine_my_banner: [],
+        routine_my_menus: [],
+        status: '',
+        order_status: '',
+      },
+      MyMenus: [{ pic: '', url: '', name: '', sort: 1, status: 1 }],
+      storeMenu: [{ pic: '', url: '', name: '', sort: 1, status: 1 }],
+      current: 1,
+      colorStyle: '',
+      order: {},
+      order01: {
+        dfk: 'icondaifukuan1',
+        dfh: 'icondaifahuo1',
+        dsh: 'icondaishouhuo1',
+        dpj: 'icondaipingjia1',
+        sh: 'iconshouhou_tuikuan',
+      },
+      order02: {
+        dfk: 'icondaifukuan-lan',
+        dfh: 'icondaifahuo-lan',
+        dsh: 'icondaishouhuo-lan',
+        dpj: 'icondaipingjia-lan',
+        sh: 'iconshouhou-tuikuan-lan',
+      },
+      order03: {
+        dfk: 'icondaifukuan-ju',
+        dfh: 'icondaifahuo-ju',
+        dsh: 'icondaishouhuo-ju',
+        dpj: 'icondaipingjia-ju',
+        sh: 'iconshouhou-tuikuan-ju',
+      },
+      order04: {
+        dfk: 'icondaifukuan-fen',
+        dfh: 'icondaifahuo-fen',
+        dsh: 'icondaishouhuo-fen',
+        dpj: 'icondaipingjia-fen',
+        sh: 'icona-shouhoutuikuan-fen',
+      },
+      order05: {
+        dfk: 'icondaifukuan-lv',
+        dfh: 'icondaifahuo-lv',
+        dsh: 'icondaishouhuo-lv',
+        dpj: 'icondaipingjia-lv',
+        sh: 'iconshouhou-tuikuan-lv',
+      },
+    };
+  },
+  created() {
+    this.getInfo();
+  },
+  methods: {
+    currentShow(type) {
+      this.current = type;
+    },
+    switchOrder(status) {
+      switch (status) {
+        case 1:
+          this.order = this.order01;
+          break;
+        case 2:
+          this.order = this.order02;
+          break;
+        case 3:
+          this.order = this.order03;
+          break;
+        case 4:
+          this.order = this.order04;
+          break;
+        case 5:
+          this.order = this.order05;
+          break;
+        default:
+          this.order = this.order01;
+          break;
+      }
+    },
+    orderStyle(e) {
+      this.switchOrder(e);
+    },
+    getInfo() {
+      let green =
+        '--view-theme: #42CA4D;--view-priceColor:#FF7600;--view-minorColor:rgba(108, 198, 94, 0.5);--view-minorColorT:rgba(66, 202, 77, 0.1);--view-bntColor:#FE960F;';
+      let red =
+        '--view-theme: #e93323;--view-priceColor:#e93323;--view-minorColor:rgba(233, 51, 35, 0.5);--view-minorColorT:rgba(233, 51, 35, 0.1);--view-bntColor:#FE960F;';
+      let blue =
+        '--view-theme: #1DB0FC;--view-priceColor:#FD502F;--view-minorColor:rgba(58, 139, 236, 0.5);--view-minorColorT:rgba(9, 139, 243, 0.1);--view-bntColor:#22CAFD;';
+      let pink =
+        '--view-theme: #FF448F;--view-priceColor:#FF448F;--view-minorColor:rgba(255, 68, 143, 0.5);--view-minorColorT:rgba(255, 68, 143, 0.1);--view-bntColor:#282828;';
+      let orange =
+        '--view-theme: #FE5C2D;--view-priceColor:#FE5C2D;--view-minorColor:rgba(254, 92, 45, 0.5);--view-minorColorT:rgba(254, 92, 45, 0.1);--view-bntColor:#FDB000;';
+      getMember().then((res) => {
+        this.userData.status = res.data.status;
+        this.userData.order_status = res.data.order_status;
+        this.userData.my_banner_status = res.data.my_banner_status;
+        let storeMenu = [];
+        let myMenu = [];
+        this.switchOrder(res.data.order_status);
+        switch (res.data.color_change) {
+          case 1:
+            this.colorStyle = blue;
+            break;
+          case 2:
+            this.colorStyle = green;
+            break;
+          case 3:
+            this.colorStyle = red;
+            break;
+          case 4:
+            this.colorStyle = pink;
+            break;
+          case 5:
+            this.colorStyle = orange;
+            break;
+          default:
+            this.colorStyle = red;
+            break;
+        }
+        res.data.routine_my_banner.forEach((el, index, arr) => {
+          if (el.pic.length) {
+            el.pic = el.pic[0];
+          }
+        });
+        if (res.data.routine_my_banner.length) {
+          this.userData.routine_my_banner = res.data.routine_my_banner;
+        } else {
+          this.userData.routine_my_banner = [];
+        }
+        res.data.routine_my_menus.forEach((el, index, arr) => {
+          if (el.pic.length) {
+            el.pic = el.pic[0];
+          }
+          if (
+            el.url == '/pages/admin/order/index' ||
+            el.url == '/pages/admin/order_cancellation/index' ||
+            el.name == '客服接待'
+          ) {
+            storeMenu.push(el);
+          } else {
+            myMenu.push(el);
+          }
+        });
+        if (myMenu.length) {
+          this.MyMenus = myMenu;
+        }
+        if (storeMenu.length) {
+          this.storeMenu = storeMenu;
+        }
+      });
+    },
+    onSubmit() {
+      this.userData.routine_my_menus = this.MyMenus.concat(this.storeMenu);
+      this.$emit('parentFun', true);
+      memberSave(this.userData)
+        .then((res) => {
+          this.$emit('parentFun', false);
+          this.$Message.success(res.msg);
+        })
+        .catch((err) => {
+          this.$Message.error(err.msg);
+          this.$emit('parentFun', false);
+        });
+    },
+  },
+};
+</script>
+<style scoped lang="stylus">
+/* 定义滑块 内阴影+圆角 */
+::-webkit-scrollbar-thumb {
+  -webkit-box-shadow: inset 0 0 6px #ddd;
+}
+
+::-webkit-scrollbar {
+  width: 4px !important; /* 对垂直流动条有效 */
+}
+
+.default {
+  background-color: #fff;
+  text-align: center;
+  height: 50px;
+  line-height: 50px;
+  border-radius: 8px;
+}
+
+.bgColor {
+  background-color: unset !important;
+
+  .top {
+    .picTxt {
+      .txt {
+        .name {
+          color: #333 !important;
+        }
+
+        .phone {
+          color: rgba(51, 51, 51, 0.8) !important;
+          background-color: rgba(51, 51, 51, 0.13) !important;
+        }
+      }
+    }
+
+    .news {
+      .iconfont {
+        color: #333 !important;
+      }
+
+      .num {
+        background-color: var(--view-theme) !important;
+        color: #fff !important;
+      }
+    }
+
+    .iconshezhi {
+      color: #333 !important;
+    }
+  }
+
+  .center {
+    color: rgba(51, 51, 51, 0.7) !important;
+
+    .num {
+      color: #333 !important;
+    }
+  }
+}
+
+.dotted {
+  border: 1px dashed #2d8cf0;
+  cursor: pointer;
+}
+
+.solid {
+  border: 1px solid #2d8cf0 !important;
+}
+
+.c_row-item {
+  .slider-box {
+    .info {
+      font-size: 13px;
+      color: #999999;
+    }
+  }
+}
+
+.bottomB {
+  width: 270px;
+  height: 62px;
+  background: #343A48;
+  border-radius: 8px 8px 0px 0px;
+  padding: 11px 15px 0 15px;
+  margin: 10px auto 0 auto;
+  color: #BBBBBB;
+  font-size: 13px;
+  z-index: 0;
+  position: relative;
+
+  .iconfont {
+    font-size: 11px;
+  }
+
+  .vip {
+    font-size: 13px;
+    font-weight: bold;
+    color: #F8D5A8;
+
+    img {
+      width: 18px;
+      height: 18px;
+      display: inline-block;
+      vertical-align: middle;
+      margin-right: 9px;
+    }
+  }
+}
+
+.member {
+  background-image: url('../../../assets/images/user_vip.png');
+  background-repeat: no-repeat;
+  background-size: 100%;
+  width: 270px;
+  height: 48px;
+  margin: -42px auto 0 auto;
+  position: relative;
+  z-index: 9;
+  margin-bottom: 13px;
+  padding: 0 20px 0 45px;
+
+  .text {
+    color: rgba(174, 90, 42, 0.8);
+    font-size: 12px;
+
+    .title {
+      font-size: 12px;
+    }
+  }
+
+  .bnt {
+    width: 70px;
+    height: 23px;
+    background-color: #fff;
+    border-radius: 14px;
+    color: #AE5A2A;
+    text-align: center;
+    line-height: 26px;
+    font-size: 12px;
+  }
+}
+
+.carousel {
+  margin: 10px 18px 0 18px;
+
+  .swiperimg {
+    width: 100%;
+    height: 63px;
+    border-radius: 8px;
+
+    img {
+      width: 100%;
+      height: 100%;
+      border-radius: 8px;
+    }
+  }
+}
+
+.swiper-pagination-fraction, .swiper-pagination-custom, .swiper-container-horizontal > .swiper-pagination-bullets {
+  bottom: 2px;
+}
+
+/deep/.swiper-pagination-bullet {
+  width: 4px;
+  height: 4px;
+}
+
+/deep/.swiper-pagination-bullet-active {
+  background: #fff;
+}
+
+.users {
+  .left {
+    background: #F7F7F7;
+    width: 310px;
+    height: 550px;
+    overflow-x: hidden;
+    overflow-y: auto;
+    padding-bottom: 1px;
+    border-radius: 10px;
+    margin-right: 30px;
+    border: 1px solid #eee;
+
+    .header {
+      background-color: var(--view-theme);
+      background-image: url('../../../assets/images/user01.png');
+      background-size: 100%;
+      background-repeat: no-repeat;
+      width: 100%;
+      height: 150px;
+      position: relative;
+      margin-bottom: 14px;
+
+      .top {
+        padding: 19px 20px 0 20px;
+
+        .picTxt {
+          .pictrue {
+            width: 35px;
+            height: 35px;
+            border-radius: 50%;
+            margin-right: 10px;
+
+            img {
+              width: 100%;
+              height: 100%;
+              border-radius: 50%;
+            }
+          }
+
+          .txt {
+            .name {
+              font-size: 12px;
+              color: #fff;
+              font-weight: 600;
+
+              img {
+                width: 40px;
+                height: 15px;
+                margin-left: 7px;
+                vertical-align: middle;
+              }
+            }
+
+            .phone {
+              width: 86px;
+              height: 21px;
+              border-radius: 13px;
+              background-color: rgba(16, 55, 72, 0.2);
+              font-size: 11px;
+              color: #fff;
+              margin-top: 4px;
+
+              .iconfont {
+                font-size: 11px;
+              }
+            }
+          }
+        }
+
+        .news {
+          position: relative;
+          margin-right: 18px;
+
+          .iconfont {
+            font-size: 22px;
+            color: #fff;
+          }
+
+          .num {
+            position: absolute;
+            width: 14px;
+            height: 14px;
+            background: #FFFFFF;
+            border-radius: 50%;
+            font-size: 9px;
+            color: var(--view-theme);
+            text-align: center;
+            line-height: 14px;
+            top: 3px;
+            right: -4px;
+          }
+        }
+
+        .iconshezhi {
+          font-size: 22px;
+          color: #fff;
+        }
+      }
+
+      .center {
+        text-align: center;
+        color: rgba(255, 255, 255, 0.8);
+        margin-top: 9px;
+
+        .num {
+          font-size: 15px;
+          font-weight: 600;
+          color: rgba(255, 255, 255, 1);
+        }
+
+        .font {
+          font-size: 13px;
+        }
+
+        .item {
+          &~.item {
+            position: relative;
+
+            &:before {
+              position: absolute;
+              content: '';
+              width: 1px;
+              height: 14px;
+              background-color: rgba(255, 255, 255, 0.3);
+              left: -36px;
+              top: 50%;
+              margin-top: -7px;
+            }
+          }
+        }
+      }
+
+      .bottom {
+        background-image: url('../../../assets/images/member.png');
+        width: 287px;
+        height: 34px;
+        background-size: 100%;
+        background-repeat: no-repeat;
+        position: absolute;
+        bottom: -6px;
+        padding: 0 17px 0 44px;
+        font-size: 13px;
+        color: #905100;
+        right: 8px;
+
+        .renew {
+          font-size: 12px;
+
+          .iconjinru {
+            font-size: 11px;
+          }
+        }
+      }
+    }
+
+    .orderCenter {
+      background: #FFFFFF;
+      border-radius: 8px;
+      margin: 0 18px 10px 18px;
+      text-align: center;
+      padding: 15px 0;
+
+      &.on {
+        position: relative;
+        margin-top: -5px;
+      }
+
+      .title {
+        padding: 0 15px;
+        font-size: 13px;
+        color: #282828;
+        font-weight: 600px;
+
+        .all {
+          font-size: 12px;
+          color: #666666;
+
+          .iconfont {
+            font-size: 12px;
+            margin-left: 2px;
+          }
+        }
+      }
+
+      .list {
+        margin-top: 10px;
+
+        .item {
+          font-size: 12px;
+          color: #454545;
+
+          .iconfont {
+            font-size: 20px;
+            color: var(--view-theme);
+          }
+        }
+      }
+
+      &.service {
+        padding: 15px 0 0 0;
+        margin-top: 10px;
+
+        .list {
+          .item {
+            width: 25%;
+            margin-bottom: 10px;
+
+            .pictrue {
+              width: 23px;
+              height: 23px;
+              margin: 0 auto 8px auto;
+              font-size: 12px;
+
+              img {
+                width: 100%;
+                height: 100%;
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+
+  .right {
+    width: 540px;
+
+    /deep/.ivu-radio-wrapper {
+      font-size: 13px;
+      margin-right: 20px;
+    }
+
+    .title {
+      font-size: 14px;
+      color: rgba(0, 0, 0, 0.85);
+      position: relative;
+      font-weight: bold;
+
+      &:before {
+        content: '';
+        position: absolute;
+        width: 2px;
+        height: 14px;
+        background: #1890FF;
+        top: 50%;
+        margin-top: -7px;
+        left: -8px;
+      }
+    }
+
+    .c_row-item {
+      margin-top: 24px;
+    }
+  }
+}
+</style>

+ 132 - 0
src/pages/shop_setting/devisePage/index.vue

@@ -0,0 +1,132 @@
+<template>
+  <div>
+    <div class="i-layout-page-header header_top">
+      <div class="i-layout-page-header fl_header">
+        <router-link :to="{ path: $routeProStr + '/setting/pages/devise' }"
+          ><Button icon="ios-arrow-back" size="small" type="text">返回</Button></router-link
+        >
+        <Divider type="vertical" />
+        <span class="ivu-page-header-title mr20" style="padding: 0">页面设计</span>
+      </div>
+    </div>
+    <Card :bordered="false" dis-hover class="ivu-mt">
+      <div class="flex-wrapper">
+        <!-- :src="iframeUrl" -->
+        <iframe class="iframe-box" :src="iframeUrl" frameborder="0" ref="iframe"></iframe>
+        <div>
+          <div class="content">
+            <rightConfig :name="configName" :pageId="pageId" :configNum="configNum"></rightConfig>
+          </div>
+        </div>
+        <!-- <links v-if="show"></links> -->
+      </div>
+    </Card>
+  </div>
+</template>
+
+<script>
+import { diyGetInfo, diySave } from '@/api/diy';
+import { mapMutations } from 'vuex';
+import rightConfig from '@/components/rightConfig/index';
+import links from './links';
+import { getCookies, setCookies } from '@/libs/util';
+export default {
+  name: 'index',
+  components: {
+    rightConfig,
+    links,
+  },
+  data() {
+    return {
+      configName: {},
+      configNum: 'default',
+      iframeUrl: '',
+      setConfig: '',
+      updataConfig: '',
+      pageId: 0,
+    };
+  },
+  created() {
+    this.show = true;
+    let pageId = this.$route.query.id;
+    let defaultData = this.$store.state.moren.defaultConfig;
+    this.pageId = parseInt(pageId);
+    let moveLink = getCookies('moveLink');
+    if (Number(this.$route.query.type) === 1) {
+      this.iframeUrl = `${moveLink}/pages/index/index?mdType=iframeWindow`;
+    } else {
+      this.iframeUrl = `${location.origin}/pages/index/index?mdType=iframeWindow`;
+    }
+    diyGetInfo(parseInt(pageId)).then((datas) => {
+      let data = datas.data.info.value;
+      if (data) {
+        this.upData(data);
+      } else {
+        diySave(parseInt(pageId), {
+          value: defaultData,
+        }).then((res) => {});
+      }
+    });
+  },
+  mounted() {
+    //监听子页面给当前页面传值
+    window.addEventListener('message', this.handleMessage, false);
+  },
+  methods: {
+    //接收iframe值
+    handleMessage(event) {
+      if (event.data.name) {
+        let obj = { name: event.data.name, num: event.data.dataName };
+        this.configName = obj;
+        this.configNum = event.data.dataName;
+        this.add(event.data.name);
+      }
+    },
+    add(data) {
+      this.$store.commit('moren/setConfig', data);
+    },
+    upData(data) {
+      this.$store.commit('moren/updataConfig', data);
+    },
+    // ...mapMutations({
+    //     add: 'diy/setConfig',
+    //     upData:'diy/updataConfig'
+    // })
+  },
+};
+</script>
+
+<style scoped lang="stylus">
+.content {
+  // width: 500px;
+}
+
+.flex-wrapper {
+  display: flex;
+}
+
+.iframe-box {
+  min-width: 375px;
+  height: 700px;
+  /* border: 1px solid #ddd; */
+  border-radius: 4px;
+  box-shadow: 0 0 7px #cccccc;
+}
+
+.right-box {
+  width: 500px;
+  margin-left: 50px;
+  border: 1px solid #ddd;
+  border-radius: 4px;
+
+  .title-bar {
+    width: 100%;
+    height: 38px;
+    line-height: 38px;
+    padding-left: 24px;
+    color: #333;
+    border-radius: 4px;
+    border-bottom: 1px solid #eee;
+  }
+}
+</style>

+ 162 - 0
src/pages/shop_setting/devisePage/links.vue

@@ -0,0 +1,162 @@
+<template>
+  <div class="right-box">
+    <div class="link-item" v-for="(item, index) in list" :key="index">
+      <div class="title">{{ item.name }}</div>
+      <div class="txt"><span>地址:</span>{{ item.url }}</div>
+      <div class="txt" v-if="item.parameter">
+        <p><span>参数:</span></p>
+        <span>{{ item.parameter }}</span>
+        <!--<span v-for="(val, key, index) in item.parameter">{{key+"="+val}}<i style="font-style: normal">&</i></span>-->
+      </div>
+      <div class="tips">
+        例如:{{ item.example }}
+        <!--<Button size="small" style="margin-left: 10px" v-clipboard:copy="item.example"-->
+        <!--v-clipboard:success="onCopy"-->
+        <!--v-clipboard:error="onError">复制</Button>-->
+        <span class="copy copy-data" @click="onCopy(item.example)">复制</span>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import ClipboardJS from 'clipboard';
+import { getUrl } from '@/api/diy';
+export default {
+  name: 'links',
+  data() {
+    return {
+      list: [
+        {
+          name: '商城首页',
+          url: '/pages/goods/order_list/index',
+          parameter: [{}],
+          example: '/pages/activity/bargain/index',
+        },
+        {
+          name: '商城首页',
+          url: '/pages/goods/order_list/index',
+          parameter: [{}],
+          example: '/pages/activity/bargain/index',
+        },
+      ],
+      clipboard: undefined,
+    };
+  },
+  created() {
+    getUrl().then((res) => {
+      this.list = res.data.url;
+    });
+  },
+  mounted: function () {
+    this.$nextTick(function () {
+      this.clipboard = new ClipboardJS('.copy-data');
+      this.clipboard.on('success', () => {
+        this.$Message.success('复制成功');
+      });
+    });
+  },
+  destroyed() {
+    // 销毁Clipboard实例,避免在其它页面或组件中实例化Clipboard后造成再次监听,产生重复回调
+    this.clipboard.destroy();
+  },
+  methods: {
+    onCopy(copyData) {
+      this.$copyText(copyData)
+        .then((message) => {
+          this.$Message.success('复制成功');
+        })
+        .catch((err) => {
+          this.$Message.error('复制失败');
+        });
+    },
+    // onError () {
+    //     this.$Message.error('复制成功');
+    // }
+  },
+};
+</script>
+
+<style scoped lang="stylus">
+.right-box {
+  width: 400px;
+  margin-left: 50px;
+  border: 1px solid #ddd;
+  border-radius: 4px;
+  height: 700px;
+  overflow-y: scroll;
+  padding: 0 10px;
+
+  &::-webkit-scrollbar {
+    /* 滚动条整体样式 */
+    width: 4px; /* 高宽分别对应横竖滚动条的尺寸 */
+    height: 1px;
+  }
+
+  &::-webkit-scrollbar-thumb {
+    /* 滚动条里面小方块 */
+    border-radius: 4px;
+    box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
+    background: #535353;
+  }
+
+  &::-webkit-scrollbar-track {
+    /* 滚动条里面轨道 */
+    box-shadow: inset 0 0 5px #fff;
+    border-radius: 4px;
+    background: #fff;
+  }
+
+  .link-item {
+    padding: 10px 0;
+    border-bottom: 1px solid #f5f5f5;
+
+    .title {
+      font-size: 14px;
+      color: #2d8cf0;
+    }
+
+    .txt {
+      margin: 5px 0;
+      font-size: 12px;
+
+      span {
+        color: #333;
+      }
+
+      p {
+        display: inline-block;
+        color: #19be6b;
+        margin-right: 10px;
+
+        span {
+          color: #333;
+        }
+
+        &.red {
+          color: #f00;
+        }
+      }
+    }
+
+    .tips {
+      font-size: 12px;
+      color: #999;
+
+      .copy {
+        padding: 3px 5px;
+        border: 1px solid #cccccc;
+        border-radius: 5px;
+        color: #333;
+        cursor: pointer;
+        margin-left: 5px;
+
+        &:hover {
+          border-color: #2d8cf0;
+          color: #2d8cf0;
+        }
+      }
+    }
+  }
+}
+</style>

+ 253 - 0
src/pages/shop_setting/devisePage/list.vue

@@ -0,0 +1,253 @@
+<template>
+  <div>
+    <Card :bordered="false" dis-hover class="ivu-mt">
+      <Row type="flex">
+        <Col v-bind="grid">
+          <Button v-auth="['admin-template']" type="primary" icon="md-add" @click="add">添加模板</Button>
+        </Col>
+      </Row>
+      <Table
+        :columns="columns1"
+        :data="list"
+        ref="table"
+        class="mt25"
+        :loading="loading"
+        highlight-row
+        no-userFrom-text="暂无数据"
+        no-filtered-userFrom-text="暂无筛选结果"
+      >
+        <template slot-scope="{ row, index }" slot="region">
+          <div class="font-blue">首页</div>
+        </template>
+        <template slot-scope="{ row, index }" slot="action">
+          <div style="display: inline-block" v-if="row.status != 1">
+            <a @click="setStatus(row, index)">设为首页</a>
+          </div>
+          <Divider type="vertical" v-if="row.status != 1" />
+          <div style="display: inline-block" v-if="row.status || row.type">
+            <a @click="edit(row)">编辑</a>
+          </div>
+          <Divider type="vertical" v-if="row.status || row.type" />
+          <template>
+            <Dropdown @on-click="changeMenu(row, index, $event)" :transfer="true">
+              <a href="javascript:void(0)"
+                >更多
+                <Icon type="ios-arrow-down"></Icon>
+              </a>
+              <DropdownMenu slot="list">
+                <DropdownItem name="1" v-show="!row.type">设置默认数据</DropdownItem>
+                <DropdownItem name="2" v-show="!row.type">恢复默认数据</DropdownItem>
+                <DropdownItem name="3" v-show="row.id != 1">删除模板</DropdownItem>
+              </DropdownMenu>
+            </Dropdown>
+          </template>
+        </template>
+      </Table>
+    </Card>
+    <Modal
+      v-model="isTemplate"
+      scrollable
+      footer-hide
+      closable
+      title="开发移动端链接"
+      :z-index="1"
+      width="500"
+      @on-cancel="cancel"
+    >
+      <div class="article-manager">
+        <Card :bordered="false" dis-hover class="ivu-mt">
+          <Form
+            ref="formItem"
+            :model="formItem"
+            :label-width="120"
+            label-position="right"
+            :rules="ruleValidate"
+            @submit.native.prevent
+          >
+            <Row type="flex" :gutter="24">
+              <Col span="24">
+                <Col v-bind="grid">
+                  <FormItem label="开发移动端链接:" prop="link" label-for="link">
+                    <Input v-model="formItem.link" placeholder="http://localhost:8080" />
+                  </FormItem>
+                </Col>
+              </Col>
+            </Row>
+            <Row type="flex">
+              <Col v-bind="grid">
+                <Button type="primary" class="ml20" @click="handleSubmit('formItem')" style="width: 100%">提交</Button>
+              </Col>
+            </Row>
+          </Form>
+        </Card>
+      </div>
+    </Modal>
+  </div>
+</template>
+
+<script>
+import { diyList, diyDel, setStatus, recovery, getDiyCreate, getRecovery } from '@/api/diy';
+import { getCookies, setCookies } from '@/libs/util';
+import { mapState } from 'vuex';
+export default {
+  name: 'devise_list',
+  data() {
+    return {
+      grid: {
+        xl: 18,
+        lg: 18,
+        md: 18,
+        sm: 24,
+        xs: 24,
+      },
+      loading: false,
+      columns1: [
+        {
+          title: '页面ID',
+          key: 'id',
+          minWidth: 120,
+        },
+        {
+          title: '页面名称',
+          key: 'name',
+          minWidth: 170,
+        },
+        {
+          title: '页面类型',
+          key: 'template_name',
+          minWidth: 120,
+        },
+        {
+          title: '添加时间',
+          key: 'add_time',
+          minWidth: 170,
+        },
+        {
+          title: '更新时间',
+          key: 'update_time',
+          minWidth: 170,
+        },
+        {
+          title: '操作',
+          slot: 'action',
+          fixed: 'right',
+          minWidth: 300,
+        },
+      ],
+      list: [],
+      isTemplate: false,
+      formItem: {
+        id: 0,
+        link: '',
+      },
+      ruleValidate: {
+        link: [{ required: true, message: '请输入移动端链接', trigger: 'blur' }],
+      },
+    };
+  },
+  created() {
+    this.formItem.link = getCookies('moveLink');
+    this.getList();
+  },
+  methods: {
+    cancel() {
+      this.$refs['formItem'].resetFields();
+    },
+    handleSubmit(name) {
+      this.$refs[name].validate((valid) => {
+        if (valid) {
+          setCookies('moveLink', this.formItem.link);
+          this.$router.push({
+            path: this.$routeProStr + '/setting/pages/diy',
+            query: { id: this.formItem.id, type: 1 },
+          });
+        } else {
+          return false;
+        }
+      });
+    },
+    changeMenu(row, index, name) {
+      switch (name) {
+        case '1':
+          this.setDefault(row);
+          break;
+        case '2':
+          this.recovery(row);
+          break;
+        case '3':
+          this.del(row, '删除此模板', index);
+          break;
+        default:
+      }
+    },
+    //设置默认数据
+    setDefault(row) {
+      getRecovery(row.id)
+        .then((res) => {
+          this.$Message.success(res.msg);
+          this.getList();
+        })
+        .catch((err) => {
+          this.$Message.error(err.msg);
+        });
+    },
+    // 添加
+    add() {
+      this.$modalForm(getDiyCreate()).then(() => this.getList());
+    },
+    // 获取列表
+    getList() {
+      this.loading = true;
+      diyList().then((res) => {
+        this.loading = false;
+        this.list = res.data.list;
+      });
+    },
+    // 编辑
+    edit(row) {
+      this.formItem.id = row.id;
+      if (row.type) {
+        this.isTemplate = true;
+      } else {
+        this.$router.push({ path: this.$routeProStr + '/setting/pages/diy', query: { id: row.id, type: 0 } });
+      }
+    },
+    // 删除
+    del(row, tit, num) {
+      let delfromData = {
+        title: tit,
+        num: num,
+        url: `diy/del/${row.id}`,
+        method: 'DELETE',
+        ids: '',
+      };
+      this.$modalSure(delfromData)
+        .then((res) => {
+          this.getList();
+        })
+        .catch((res) => {
+          this.$Message.error(res.msg);
+        });
+    },
+    // 使用模板
+    setStatus(row) {
+      setStatus(row.id)
+        .then((res) => {
+          this.$Message.success(res.msg);
+          this.getList();
+        })
+        .catch((error) => {
+          this.$Message.error(error.msg);
+        });
+    },
+    recovery(row) {
+      recovery(row.id).then((res) => {
+        this.$Message.success(res.msg);
+        this.getList();
+      });
+    },
+  },
+};
+</script>
+
+<style scoped></style>

+ 248 - 0
src/pages/shop_setting/freight/index.vue

@@ -0,0 +1,248 @@
+<template>
+  <div>
+    <Card :bordered="false" dis-hover class="ivu-mt">
+      <Form
+        ref="levelFrom"
+        :model="levelFrom"
+        :label-width="labelWidth"
+        :label-position="labelPosition"
+        @submit.native.prevent
+      >
+        <Row type="flex" :gutter="24">
+          <Col v-bind="grid">
+            <FormItem label="搜索:" label-for="keyword">
+              <Input
+                search
+                enter-button
+                v-model="levelFrom.keyword"
+                placeholder="请输入物流公司名称或者编码"
+                @on-search="userSearchs"
+              />
+            </FormItem>
+          </Col>
+        </Row>
+        <Row type="flex">
+          <Col v-bind="grid">
+            <Button type="primary" icon="md-add" @click="syncExpress">同步物流公司</Button>
+          </Col>
+        </Row>
+      </Form>
+      <Table
+        :columns="columns1"
+        :data="levelLists"
+        ref="table"
+        class="mt25"
+        :loading="loading"
+        no-userFrom-text="暂无数据"
+        no-filtered-userFrom-text="暂无筛选结果"
+      >
+        <template slot-scope="{ row, index }" slot="is_shows">
+          <i-switch
+            v-model="row.is_show"
+            :value="row.is_show"
+            :true-value="1"
+            :false-value="0"
+            @on-change="onchangeIsShow(row)"
+            size="large"
+          >
+            <span slot="open">显示</span>
+            <span slot="close">隐藏</span>
+          </i-switch>
+        </template>
+        <template slot-scope="{ row, index }" slot="action">
+          <a @click="edit(row)">编辑</a>
+          <!--                    <Divider type="vertical" />-->
+          <!--                    <a @click="del(row, '删除物流公司', index)">删除</a>-->
+        </template>
+      </Table>
+      <div class="acea-row row-right page">
+        <Page
+          :total="total"
+          :current="levelFrom.page"
+          show-elevator
+          show-total
+          @on-change="pageChange"
+          :page-size="levelFrom.limit"
+        />
+      </div>
+    </Card>
+  </div>
+</template>
+<script>
+import { mapState } from 'vuex';
+import {
+  freightCreateApi,
+  freightListApi,
+  freightEditApi,
+  freightStatusApi,
+  freightSyncExpressApi,
+} from '@/api/setting';
+export default {
+  name: 'user_level',
+  data() {
+    return {
+      grid: {
+        xl: 7,
+        lg: 7,
+        md: 12,
+        sm: 24,
+        xs: 24,
+      },
+      loading: false,
+      columns1: [
+        {
+          title: 'ID',
+          key: 'id',
+          width: 80,
+        },
+        {
+          title: '物流公司名称',
+          key: 'name',
+          minWidth: 100,
+        },
+        {
+          title: '编码',
+          key: 'code',
+          minWidth: 120,
+        },
+        {
+          title: '排序',
+          key: 'sort',
+          sortable: true,
+          minWidth: 100,
+        },
+        {
+          title: '是否显示',
+          slot: 'is_shows',
+          minWidth: 120,
+        },
+        {
+          title: '操作',
+          slot: 'action',
+          fixed: 'right',
+          minWidth: 120,
+        },
+      ],
+      levelFrom: {
+        keyword: '',
+        page: 1,
+        limit: 20,
+      },
+      levelLists: [],
+      total: 0,
+      FromData: null,
+    };
+  },
+  created() {
+    this.getList();
+  },
+  computed: {
+    ...mapState('media', ['isMobile']),
+    labelWidth() {
+      return this.isMobile ? undefined : 75;
+    },
+    labelPosition() {
+      return this.isMobile ? 'top' : 'left';
+    },
+  },
+  methods: {
+    // 删除
+    del(row, tit, num) {
+      let delfromData = {
+        title: tit,
+        num: num,
+        url: `freight/express/${row.id}`,
+        method: 'DELETE',
+        ids: '',
+      };
+      this.$modalSure(delfromData)
+        .then((res) => {
+          this.$Message.success(res.msg);
+          this.levelLists.splice(num, 1);
+        })
+        .catch((res) => {
+          this.$Message.error(res.msg);
+        });
+    },
+    // 修改是否显示
+    onchangeIsShow(row) {
+      let data = {
+        id: row.id,
+        status: row.is_show,
+      };
+      freightStatusApi(data)
+        .then(async (res) => {
+          this.$Message.success(res.msg);
+        })
+        .catch((res) => {
+          this.$Message.error(res.msg);
+        });
+    },
+    // 等级列表
+    getList() {
+      this.loading = true;
+      freightListApi(this.levelFrom)
+        .then(async (res) => {
+          let data = res.data;
+          this.levelLists = data.list;
+          this.total = data.count;
+          this.loading = false;
+        })
+        .catch((res) => {
+          this.loading = false;
+          this.$Message.error(res.msg);
+        });
+    },
+    pageChange(index) {
+      this.levelFrom.page = index;
+      this.getList();
+    },
+    // 添加
+    add() {
+      this.$modalForm(freightCreateApi()).then(() => this.getList());
+      // freightCreateApi().then(async res => {
+      //     this.FromData = res.data;
+      //     this.$refs.edits.modals = true;
+      // }).catch(res => {
+      //     this.$Message.error(res.msg);
+      // })
+    },
+    // 编辑
+    edit(row) {
+      this.$modalForm(freightEditApi(row.id)).then(() => this.getList());
+      // freightEditApi(row.id).then(async res => {
+      //     this.FromData = res.data;
+      //     this.$refs.edits.modals = true;
+      // }).catch(res => {
+      //     this.$Message.error(res.msg);
+      // })
+    },
+    // 表格搜索
+    userSearchs() {
+      this.levelFrom.page = 1;
+      this.getList();
+    },
+    syncExpress() {
+      freightSyncExpressApi()
+        .then(async (res) => {
+          this.$Message.success(res.msg);
+          this.getList();
+        })
+        .catch((res) => {
+          this.$Message.error(res.msg);
+        });
+    },
+  },
+};
+</script>
+
+<style scoped lang="stylus">
+.tabBox_img
+    width 36px
+    height 36px
+    border-radius:4px
+    cursor pointer
+    img
+        width 100%
+        height 100%
+</style>

+ 562 - 0
src/pages/shop_setting/membershipLevel/index.vue

@@ -0,0 +1,562 @@
+<template>
+  <div>
+    <Card :bordered="false" dis-hover class="ivu-mt">
+      <div class="headers">
+        <div class="search">
+          <div>
+            <span>是否显示:</span>
+            <Select v-model="formValidate.status" style="width: 200px" clearable>
+              <!-- <Option value="">全部</Option> -->
+              <Option :value="1">显示</Option>
+              <Option :value="0">不显示</Option>
+            </Select>
+          </div>
+          <div>
+            <span>等级名称:</span>
+            <Input v-model="formValidate.keyword" placeholder="请输入等级名称" style="width: 200px" />
+          </div>
+          <Button type="primary" @click="search">搜索</Button>
+          <Button type="success" icon="md-add" @click="groupAdd()" class="ml20">添加等级</Button>
+        </div>
+      </div>
+      <Row type="flex">
+        <Col v-bind="grid"> </Col>
+      </Row>
+      <Table
+        :columns="columns1"
+        :data="tabList"
+        ref="table"
+        :loading="loading"
+        highlight-row
+        no-userFrom-text="暂无数据"
+        no-filtered-userFrom-text="暂无筛选结果"
+      >
+        <template slot-scope="{ row }" slot="image">
+          <viewer>
+            <div class="tabBox-img">
+              <img v-lazy="row.image" />
+            </div>
+          </viewer>
+        </template>
+        <template slot-scope="{ row }" slot="one_brokerage">
+          <span>{{ row.one_brokerage }}%</span>
+        </template>
+        <template slot-scope="{ row }" slot="one_brokerage_ratio">
+          <span>{{ row.one_brokerage_ratio }}%</span>
+        </template>
+        <template slot-scope="{ row }" slot="two_brokerage">
+          <span>{{ row.two_brokerage }}%</span>
+        </template>
+        <template slot-scope="{ row }" slot="two_brokerage_ratio">
+          <span>{{ row.two_brokerage_ratio }}%</span>
+        </template>
+        <template slot-scope="{ row }" slot="status">
+          <i-switch
+            v-model="row.status"
+            :value="row.status"
+            :true-value="1"
+            :false-value="0"
+            @on-change="onchangeIsShow(row)"
+            size="large"
+          >
+            <span slot="open">显示</span>
+            <span slot="close">隐藏</span>
+          </i-switch>
+        </template>
+        <template slot-scope="{ row, index }" slot="action">
+          <a @click="addTask(row)">等级任务</a>
+          <Divider type="vertical" />
+          <a @click="edit(row, '编辑')">编辑</a>
+          <Divider type="vertical" />
+          <a @click="del(row, '删除这条信息', index)">删除</a>
+        </template>
+      </Table>
+      <div class="acea-row row-right page">
+        <Page
+          :total="total"
+          :current="formValidate.page"
+          show-elevator
+          show-total
+          @on-change="pageChange"
+          :page-size="formValidate.limit"
+        />
+      </div>
+    </Card>
+    <div class="task-modal">
+      <Modal v-model="modal2" title="添加任务" footer-hide width="1000">
+        <div class="header">
+          <h4>搜索条件</h4>
+          <div class="search">
+            <div>
+              <span>是否显示:</span>
+              <Select v-model="taskData.status" style="width: 200px" clearable>
+                <!-- <Option :value="''">全部</Option> -->
+                <Option :value="1">显示</Option>
+                <Option :value="0">不显示</Option>
+              </Select>
+            </div>
+            <div>
+              <span>任务名称:</span>
+              <Input v-model="taskData.keyword" placeholder="请输入任务名称" style="width: 200px" />
+            </div>
+            <Button type="primary" @click="searchTask">搜索</Button>
+          </div>
+        </div>
+        <div>
+          <div class="add-task">
+            <Button type="primary" @click="taskAdd()">添加等级任务</Button>
+          </div>
+          <div>
+            <Table
+              :columns="columns2"
+              :data="taskTabList"
+              ref="table"
+              class="mt25"
+              :loading="taskLoading"
+              highlight-row
+              no-userFrom-text="暂无数据"
+              no-filtered-userFrom-text="暂无筛选结果"
+            >
+              <template slot-scope="{ row }" slot="status">
+                <i-switch
+                  v-model="row.status"
+                  :value="row.status"
+                  :true-value="1"
+                  :false-value="0"
+                  @on-change="onchangeTaskIsShow(row)"
+                  size="large"
+                >
+                  <span slot="open">开启</span>
+                  <span slot="close">关闭</span>
+                </i-switch>
+              </template>
+              <template slot-scope="{ row, index }" slot="action">
+                <a @click="editTask(row, '编辑')">编辑</a>
+                <Divider type="vertical" />
+                <a @click="delTask(row, '删除这条信息', index)">删除</a>
+              </template>
+            </Table>
+            <!-- <div class="acea-row row-right page">
+              <Page
+                :total="taskTotal"
+                :current="taskData.page"
+                show-elevator
+                show-total
+                @on-change="pageTaskChange"
+                :page-size="taskData.limit"
+              />
+            </div> -->
+          </div>
+        </div>
+      </Modal>
+    </div>
+  </div>
+</template>
+
+<script>
+import { mapState } from 'vuex';
+import {
+  membershipDataAddApi,
+  membershipDataListApi,
+  membershipDataEditApi,
+  membershipSetApi,
+  levelTaskSetApi,
+  levelTaskListDataAddApi,
+  levelTaskDataEditApi,
+  levelTaskDataAddApi,
+} from '@/api/membershipLevel';
+export default {
+  name: 'list',
+  data() {
+    return {
+      grid: {
+        xl: 7,
+        lg: 7,
+        md: 12,
+        sm: 24,
+        xs: 24,
+      },
+      modal1: false,
+      modal2: false,
+      formValidate: {
+        status: '',
+        page: 1,
+        limit: 20,
+        gid: 0,
+      },
+      taskData: {
+        keyword: '',
+        page: 1,
+        limit: 20,
+        status: '',
+      },
+      total: 0,
+      taskTotal: 0,
+      tabList: [],
+      taskTabList: [],
+      columns1: [
+        {
+          key: 'id',
+          minWidth: 35,
+          title: 'ID',
+        },
+        {
+          slot: 'image',
+          minWidth: 35,
+          title: '背景图',
+        },
+        {
+          key: 'name',
+          minWidth: 35,
+          title: '名称',
+        },
+        {
+          key: 'grade',
+          minWidth: 35,
+          title: '等级',
+        },
+        {
+          slot: 'one_brokerage',
+          minWidth: 35,
+          title: '一级上浮比例',
+        },
+        {
+          slot: 'one_brokerage_ratio',
+          minWidth: 35,
+          title: '一级分佣比例(上浮后)',
+        },
+        {
+          slot: 'two_brokerage',
+          minWidth: 35,
+          title: '二级上浮比例',
+        },
+        {
+          slot: 'two_brokerage_ratio',
+          minWidth: 35,
+          title: '二级分佣比例(上浮后)',
+        },
+        {
+          slot: 'status',
+          minWidth: 35,
+          title: '是否显示',
+        },
+        {
+          minWidth: 120,
+          slot: 'action',
+          title: '操作',
+        },
+      ],
+      columns2: [
+        {
+          key: 'id',
+          minWidth: 35,
+          title: 'ID',
+        },
+        {
+          key: 'name',
+          minWidth: 35,
+          title: '名称',
+        },
+        {
+          key: 'type_name',
+          minWidth: 35,
+          title: '任务类型',
+        },
+        {
+          key: 'number',
+          minWidth: 35,
+          title: '限定数量',
+        },
+        {
+          slot: 'status',
+          minWidth: 35,
+          title: '是否显示',
+        },
+        {
+          key: 'sort',
+          minWidth: 35,
+          title: '排序',
+        },
+        {
+          fixed: 'right',
+          minWidth: 120,
+          slot: 'action',
+          title: '操作',
+        },
+      ],
+      FromData: null,
+      loading: false,
+      taskLoading: false,
+      titleType: 'group',
+      groupAll: [],
+      theme3: 'light',
+      labelSort: [],
+      sortName: null,
+      current: 0,
+      model1: '',
+      value1: '',
+    };
+  },
+  computed: {
+    ...mapState('admin/layout', ['isMobile']),
+    labelWidth() {
+      return this.isMobile ? undefined : 75;
+    },
+    labelPosition() {
+      return this.isMobile ? 'top' : 'right';
+    },
+  },
+  watch: {
+    $route(to, from) {
+      if (this.$route.params.id) {
+      } else {
+      }
+    },
+  },
+  mounted() {
+    this.getList();
+  },
+  methods: {
+    bindMenuItem(name, index) {
+      this.current = index;
+      this.formValidate.gid = name.id;
+      this.getListHeader();
+      this.getList();
+    },
+    // 列表
+    getList() {
+      this.loading = true;
+      membershipDataListApi(this.formValidate)
+        .then(async (res) => {
+          let data = res.data;
+          this.tabList = data.list;
+          this.total = data.count;
+          this.loading = false;
+        })
+        .catch((res) => {
+          this.loading = false;
+          this.$Message.error(res.msg);
+        });
+    },
+    // 列表
+    getTaskList() {
+      this.taskLoading = true;
+      levelTaskListDataAddApi(this.taskData)
+        .then(async (res) => {
+          let data = res.data;
+          this.taskTabList = data.list;
+          this.taskTotal = data.count;
+          this.taskLoading = false;
+        })
+        .catch((res) => {
+          this.taskLoading = false;
+          this.$Message.error(res.msg);
+        });
+    },
+    pageChange(index) {
+      this.formValidate.page = index;
+      this.getList();
+    },
+    pageTaskChange(index) {
+      this.taskData.page = index;
+      this.getList();
+    },
+    // 表格搜索
+    search() {
+      this.formValidate.page = 1;
+      this.getList();
+    },
+    searchTask() {
+      this.taskData.page = 1;
+      this.getTaskList();
+    },
+    // 添加表单
+    groupAdd() {
+      this.$modalForm(membershipDataAddApi({}, '/agent/level/create')).then(() => this.getList());
+    },
+    taskAdd() {
+      this.$modalForm(levelTaskDataAddApi({}, '/agent/level_task/create?level_id=' + this.taskData.id)).then(() =>
+        this.getTaskList(),
+      );
+    },
+    // 修改是否显示
+    onchangeIsShow(row) {
+      membershipSetApi(`agent/level/set_status/${row.id}/${row.status}`)
+        .then(async (res) => {
+          this.$Message.success(res.msg);
+          this.getList();
+        })
+        .catch((res) => {
+          this.$Message.error(res.msg);
+        });
+    },
+    // 修改是否显示
+    onchangeTaskIsShow(row) {
+      levelTaskSetApi(`agent/level_task/set_status/${row.id}/${row.status}`)
+        .then(async (res) => {
+          this.$Message.success(res.msg);
+          this.getTaskList();
+        })
+        .catch((res) => {
+          this.$Message.error(res.msg);
+        });
+    },
+    //添加等级任务
+    addTask(row) {
+      this.id = row.id;
+      this.modal2 = true;
+      this.taskData.id = row.id;
+      this.getTaskList();
+    },
+    // 编辑
+    edit(row) {
+      let data = {
+        gid: row.gid,
+      };
+      this.$modalForm(membershipDataEditApi(data, `agent/level/${row.id}/edit`)).then(() => this.getList());
+    },
+    // 编辑
+    editTask(row) {
+      let data = {
+        gid: row.gid,
+      };
+      this.$modalForm(levelTaskDataEditApi(data, `agent/level_task/${row.id}/edit`)).then(() => this.getTaskList());
+    },
+    // 删除
+    del(row, tit, num) {
+      let delfromData = {
+        title: tit,
+        num: num,
+        url: `agent/level/${row.id}`,
+        method: 'DELETE',
+        ids: '',
+      };
+      this.$modalSure(delfromData)
+        .then((res) => {
+          this.$Message.success(res.msg);
+          this.tabList.splice(num, 1);
+        })
+        .catch((res) => {
+          this.$Message.error(res.msg);
+        });
+    },
+    // 删除
+    delTask(row, tit, num) {
+      let delfromData = {
+        title: tit,
+        num: num,
+        url: `agent/level_task/${row.id}`,
+        method: 'DELETE',
+        ids: '',
+      };
+      this.$modalSure(delfromData)
+        .then((res) => {
+          this.$Message.success(res.msg);
+          this.taskTabList.splice(num, 1);
+        })
+        .catch((res) => {
+          this.$Message.error(res.msg);
+        });
+    },
+  },
+};
+</script>
+
+<style scoped lang="stylus">
+/deep/ .ivu-menu-vertical .ivu-menu-item-group-title {
+  display: none;
+}
+
+/deep/ .ivu-menu-vertical.ivu-menu-light:after {
+  display: none;
+}
+
+.left-wrapper {
+  height: 904px;
+  background: #fff;
+  border-right: 1px solid #f2f2f2;
+}
+
+.menu-item {
+  // z-index 50
+  position: relative;
+  display: flex;
+  justify-content: space-between;
+  word-break: break-all;
+
+  .icon-box {
+    z-index: 3;
+    position: absolute;
+    right: 20px;
+    top: 50%;
+    transform: translateY(-50%);
+    display: none;
+  }
+
+  &:hover .icon-box {
+    display: block;
+  }
+
+  .right-menu {
+    z-index: 10;
+    position: absolute;
+    right: -106px;
+    top: -11px;
+    width: auto;
+    min-width: 121px;
+  }
+}
+
+.tabBox-img {
+  width: 36px;
+  height: 36px;
+  border-radius: 4px;
+  cursor: pointer;
+
+  img {
+    width: 100%;
+    height: 100%;
+  }
+}
+
+.ivu-menu {
+  z-index: auto;
+}
+
+.header, .headers {
+  display: flex;
+  flex-direction: column;
+  background-color: #f2f2f2;
+  padding: 8px;
+
+  .search {
+    display: flex;
+    align-items: center;
+
+    >div {
+      margin-right: 10px;
+    }
+  }
+}
+
+.search /deep/ .ivu-select-selection {
+  border: 1px solid #dcdee2 !important;
+}
+
+.headers {
+  background-color: #fff;
+  margin-bottom: 20px;
+}
+
+/deep/ .ivu-modal-mask {
+  z-index: 100 !important;
+}
+
+/deep/ .ivu-modal-wrap {
+  z-index: 100 !important;
+}
+
+.add-task {
+  margin: 10px 0;
+}
+</style>

+ 225 - 0
src/pages/shop_setting/multiLanguage/country.vue

@@ -0,0 +1,225 @@
+<template>
+  <div>
+    <Card :bordered="false" dis-hover class="ivu-mt mb10">
+      <Form
+        ref="formValidate"
+        :model="formValidate"
+        :label-width="labelWidth"
+        :label-position="labelPosition"
+        @submit.native.prevent
+      >
+        <Row :gutter="24" type="flex">
+          <Col span="24">
+            <FormItem label="搜索:">
+              <div class="acea-row row-middle">
+                <Input
+                  search
+                  enter-button
+                  @on-search="selChange"
+                  placeholder="请输入语言Code"
+                  element-id="name"
+                  v-model="formValidate.keyword"
+                  style="width: 30%"
+                />
+              </div>
+            </FormItem>
+          </Col>
+        </Row>
+      </Form>
+    </Card>
+    <Card :bordered="false" dis-hover>
+      <Row type="flex">
+        <Col v-bind="grid">
+          <Button type="primary" icon="md-add" @click="add">添加语言地区</Button>
+        </Col>
+      </Row>
+      <Table
+        ref="table"
+        :columns="columns"
+        :data="tabList"
+        class="ivu-mt mt25"
+        :loading="loading"
+        no-data-text="暂无数据"
+        no-filtered-data-text="暂无筛选结果"
+      >
+        <template slot-scope="{ row, index }" slot="action">
+          <a @click="edit(row)">编辑</a>
+          <Divider type="vertical" />
+          <a @click="del(row, '删除地区语言', index)">删除</a>
+        </template>
+      </Table>
+      <div class="acea-row row-right page">
+        <Page
+          :total="total"
+          :current="formValidate.page"
+          show-elevator
+          show-total
+          @on-change="pageChange"
+          :page-size="formValidate.limit"
+        />
+      </div>
+    </Card>
+  </div>
+</template>
+<script>
+import { mapState } from 'vuex';
+import { langCountryList, langCountryForm } from '@/api/setting';
+export default {
+  data() {
+    return {
+      grid: {
+        xl: 7,
+        lg: 7,
+        md: 12,
+        sm: 24,
+        xs: 24,
+      },
+      formValidate: {
+        keyword: '',
+        page: 1,
+        limit: 20,
+      },
+      total: 0,
+      loading: false,
+      columns: [
+        {
+          title: '编号',
+          key: 'id',
+          width: 120,
+        },
+        {
+          title: '浏览器语言识别码',
+          key: 'code',
+          minWidth: 150,
+        },
+        {
+          title: '语言说明',
+          key: 'name',
+          minWidth: 180,
+        },
+        {
+          title: '关联语言',
+          key: 'link_lang',
+          minWidth: 180,
+        },
+        {
+          title: '操作',
+          slot: 'action',
+          fixed: 'right',
+          width: 100,
+        },
+      ],
+      tabList: [],
+      code: null,
+    };
+  },
+  computed: {
+    ...mapState('media', ['isMobile']),
+    labelWidth() {
+      return this.isMobile ? undefined : 80;
+    },
+    labelPosition() {
+      return this.isMobile ? 'top' : 'left';
+    },
+  },
+  mounted() {
+    this.getList();
+  },
+  methods: {
+    // 添加
+    add() {
+      this.$modalForm(langCountryForm(0)).then(() => this.getList());
+    },
+    edit(row) {
+      this.$modalForm(langCountryForm(row.id)).then(() => this.getList());
+    },
+    // 删除
+    del(row, tit, num) {
+      let delfromData = {
+        title: tit,
+        num: num,
+        url: `setting/lang_country/del/${row.id}`,
+        method: 'DELETE',
+        ids: '',
+      };
+      this.$modalSure(delfromData)
+        .then((res) => {
+          this.$Message.success(res.msg);
+          this.tabList.splice(num, 1);
+          // this.getList();
+        })
+        .catch((res) => {
+          this.$Message.error(res.msg);
+        });
+    },
+    selChange() {
+      this.formValidate.page = 1;
+      this.getList();
+    },
+    // 列表
+    getList() {
+      this.loading = true;
+      langCountryList(this.formValidate)
+        .then(async (res) => {
+          this.loading = false;
+          this.tabList = res.data.list;
+          this.total = res.data.count;
+        })
+        .catch((res) => {
+          this.loading = false;
+          this.$Message.error(res.msg);
+        });
+    },
+    pageChange(index) {
+      this.formValidate.page = index;
+      this.getList();
+    },
+  },
+};
+</script>
+<style scoped lang="stylus">
+.ivu-mt .type .item {
+  margin: 3px 0;
+}
+
+.tabform {
+  margin-bottom: 10px;
+}
+
+.Refresh {
+  font-size: 12px;
+  color: #1890FF;
+  cursor: pointer;
+}
+
+.ivu-form-item {
+  margin-bottom: 10px;
+}
+
+.status >>> .item~.item {
+  margin-left: 6px;
+}
+
+.status >>> .statusVal {
+  margin-bottom: 7px;
+}
+
+/* .ivu-mt >>> .ivu-table-header */
+/* border-top:1px dashed #ddd!important */
+.type {
+  padding: 3px 0;
+  box-sizing: border-box;
+}
+
+.tabBox_img {
+  width: 36px;
+  height: 36px;
+  border-radius: 4px;
+  cursor: pointer;
+
+  img {
+    width: 100%;
+    height: 100%;
+  }
+}
+</style>

+ 403 - 0
src/pages/shop_setting/multiLanguage/langList.vue

@@ -0,0 +1,403 @@
+<template>
+  <div>
+    <Card :bordered="false" dis-hover class="ivu-mt">
+      <Form
+        ref="formValidate"
+        :model="formValidate"
+        :label-width="labelWidth"
+        :label-position="labelPosition"
+        class="tabform"
+        @submit.native.prevent
+      >
+        <Row :gutter="24" type="flex">
+          <Col span="24">
+            <FormItem label="语言分类:">
+              <RadioGroup type="button" v-model="formValidate.is_admin" class="mr15" @on-change="selChange">
+                <Radio :label="item.value" v-for="(item, index) in langType.isAdmin" :key="index"
+                  >{{ item.title }}
+                </Radio>
+              </RadioGroup>
+            </FormItem>
+          </Col>
+          <Col span="24">
+            <FormItem label="语言类型:">
+              <RadioGroup type="button" v-model="formValidate.type_id" class="mr15" @on-change="selChange">
+                <Radio :label="item.value" v-for="(item, index) in langType.langType" :key="index"
+                  >{{ item.title }}
+                </Radio>
+              </RadioGroup>
+            </FormItem>
+          </Col>
+          <Col span="24">
+            <FormItem label="搜索:">
+              <div class="acea-row row-middle">
+                <Input
+                  search
+                  enter-button
+                  @on-search="selChange"
+                  placeholder="请输入语言备注"
+                  element-id="name"
+                  v-model="formValidate.remarks"
+                  style="width: 30%"
+                />
+              </div>
+            </FormItem>
+          </Col>
+        </Row>
+      </Form>
+    </Card>
+    <Alert class="mt10" closable="true">
+      使用说明
+      <template slot="desc">
+        1、前端页面:添加用户端页面语言,添加完成之后状态码为中文文字,前端页面使用 $t(`xxxx`),js文件中使用
+        this.t(`xxxx`) 或者使用 that.t(`xxxx`)<br />
+        2、后端接口:添加后端接口语言,添加完成之后状态码为6位数字,后台抛错或者控制器返回文字的时候直接填写状态码数字
+      </template>
+    </Alert>
+    <Card :bordered="false" dis-hover>
+      <Row type="flex" class="mb15">
+        <Col>
+          <Button type="primary" icon="md-add" @click="add">添加语句</Button>
+        </Col>
+      </Row>
+      <Table
+        ref="table"
+        :columns="columns"
+        :data="tabList"
+        class="ivu-mt"
+        :loading="loading"
+        no-data-text="暂无数据"
+        no-filtered-data-text="暂无筛选结果"
+      >
+        <template slot-scope="{ row, index }" slot="action">
+          <a @click="edit(row)">编辑</a>
+          <Divider type="vertical" />
+          <a @click="del(row, '删除语言', index)">删除</a>
+        </template>
+      </Table>
+      <div class="acea-row row-right page">
+        <Page
+          :total="total"
+          :current="formValidate.page"
+          show-elevator
+          show-total
+          @on-change="pageChange"
+          :page-size="formValidate.limit"
+        />
+      </div>
+    </Card>
+    <Modal
+      v-model="addlangModal"
+      width="750"
+      title="添加需要翻译的语句"
+      :loading="FormLoading"
+      @on-ok="ok"
+      @on-cancel="addlangModal = false"
+      @on-visible-change="modalChange"
+    >
+      <Form ref="langFormData" :model="langFormData" :rules="ruleValidate">
+        <FormItem label="应用端:" class="mb20" :label-width="120">
+          <RadioGroup type="button" v-model="langFormData.is_admin" class="mr15">
+            <Radio :label="item.value" v-for="(item, index) in langType.isAdmin" :key="index">{{ item.title }}</Radio>
+          </RadioGroup>
+        </FormItem>
+        <Input v-model="langFormData.edit" v-show="false"></Input>
+        <FormItem label="需要翻译的语句:" prop="remarks" class="mb20">
+          <Input
+            v-model="langFormData.remarks"
+            placeholder="请输入需要添加翻译的语句"
+            style="width: 330px"
+            search
+            enter-button="翻译"
+            @on-search="translate"
+          ></Input>
+        </FormItem>
+        <FormItem prop="remark" class="mb20">
+          <Table
+            ref="langTable"
+            :loading="traTabLoading"
+            :columns="langColumns"
+            :data="langFormData.list"
+            no-data-text="暂无数据"
+            no-filtered-data-text="暂无筛选结果"
+          >
+            <template slot-scope="{ row, index }" slot="lang_explain">
+              <Input v-model="langFormData.list[index].lang_explain" class="priceBox"></Input>
+            </template>
+          </Table>
+        </FormItem>
+      </Form>
+    </Modal>
+  </div>
+</template>
+<script>
+import { mapState } from 'vuex';
+import { langCodeList, langCodeInfo, langCodeSettingSave, langCodeTranslate } from '@/api/setting';
+
+export default {
+  data() {
+    return {
+      addlangModal: false,
+      traTabLoading: false,
+      langType: {},
+      formValidate: {
+        is_admin: 0,
+        type_id: 1,
+        remarks: '',
+        page: 1,
+        limit: 20,
+      },
+      total: 0,
+      FormLoading: true,
+      loading: false,
+      ruleValidate: {
+        code: [{ required: true, message: '请输入状态码/文字', trigger: 'blur' }],
+        remarks: [{ required: true, message: '请输入文字', trigger: 'blur' }],
+      },
+      columns: [
+        {
+          title: '编号',
+          key: 'id',
+          width: 80,
+        },
+        {
+          title: '原语句',
+          key: 'remarks',
+          minWidth: 250,
+        },
+        {
+          title: '对应语言翻译',
+          key: 'lang_explain',
+          minWidth: 250,
+        },
+        {
+          title: '状态码/文字(接口/页面调用参考)',
+          key: 'code',
+          minWidth: 100,
+        },
+        {
+          title: '语言类型',
+          key: 'language_name',
+          minWidth: 100,
+        },
+        {
+          title: '操作',
+          slot: 'action',
+          fixed: 'right',
+          width: 100,
+        },
+      ],
+      langColumns: [
+        {
+          title: '语言类型',
+          key: 'language_name',
+          width: 120,
+        },
+        {
+          title: '对应语言翻译',
+          slot: 'lang_explain',
+          minWidth: 250,
+        },
+      ],
+      langData: [],
+      langFormData: {
+        is_admin: 0,
+        code: '',
+        remarks: '',
+        edit: 0,
+        list: [],
+      },
+      tabList: [],
+      FromData: null,
+      extractId: 0,
+      code: null,
+    };
+  },
+  computed: {
+    ...mapState('media', ['isMobile']),
+    labelWidth() {
+      return this.isMobile ? undefined : 80;
+    },
+    labelPosition() {
+      return this.isMobile ? 'top' : 'left';
+    },
+  },
+  mounted() {
+    this.getList();
+  },
+  methods: {
+    translate() {
+      if (!this.langFormData.remarks.trim()) {
+        return this.$Message.warning('请先输入翻译内容');
+      }
+      this.traTabLoading = true;
+      langCodeTranslate({
+        text: this.langFormData.remarks,
+      })
+        .then((res) => {
+          this.langFormData.list.map((e) => {
+            e.lang_explain = res.data[e.type_id];
+          });
+          this.traTabLoading = false;
+        })
+        .catch((err) => {
+          this.traTabLoading = false;
+          this.$Message.error(err.msg);
+        });
+    },
+    add() {
+      this.langFormData.list = this.langType.langType.map((e) => {
+        return {
+          language_name: e.title,
+          lang_explain: '',
+          remarks: '',
+          type_id: e.value,
+        };
+      });
+      this.addlangModal = true;
+    },
+    ok() {
+      if (!this.langFormData.remarks.trim()) {
+        this.FormLoading = false;
+        this.$nextTick(() => {
+          this.FormLoading = true;
+        });
+        return this.$Message.error('请先输入语言说明');
+      }
+      langCodeSettingSave(this.langFormData)
+        .then((res) => {
+          this.addlangModal = false;
+          this.$Message.success(res.msg);
+          this.getList();
+        })
+        .catch((err) => {
+          this.FormLoading = false;
+          this.$nextTick(() => {
+            this.FormLoading = true;
+          });
+          this.$Message.error(err.msg);
+        });
+    },
+    edit(row) {
+      this.langFormData.is_admin = this.formValidate.is_admin;
+      this.code = row.code;
+      langCodeInfo({ code: row.code })
+        .then((res) => {
+          this.langFormData.list = res.data.list;
+          this.langFormData.code = res.data.code;
+          this.langFormData.remarks = res.data.remarks;
+          this.langFormData.edit = 1;
+          this.addlangModal = true;
+        })
+        .catch((err) => {
+          this.loading = false;
+          this.$Message.error(err.msg);
+        });
+    },
+    // 删除
+    del(row, tit, num) {
+      let delfromData = {
+        title: tit,
+        num: num,
+        url: `setting/lang_code/del/${row.id}`,
+        method: 'DELETE',
+        ids: '',
+      };
+      this.$modalSure(delfromData)
+        .then((res) => {
+          this.$Message.success(res.msg);
+          this.tabList.splice(num, 1);
+          // this.getList();
+        })
+        .catch((res) => {
+          this.$Message.error(res.msg);
+        });
+    },
+    modalChange(status) {
+      if (!status) {
+        this.langFormData = {
+          is_admin: 0,
+          name: '',
+          code: '',
+          list: [],
+        };
+        this.code = null;
+      }
+    },
+    // 选择
+    selChange() {
+      this.formValidate.page = 1;
+      this.getList();
+    },
+    // 列表
+    getList() {
+      this.loading = true;
+      langCodeList(this.formValidate)
+        .then(async (res) => {
+          this.loading = false;
+          this.tabList = res.data.list;
+          this.total = res.data.count;
+          this.langType = res.data.langType;
+        })
+        .catch((res) => {
+          this.loading = false;
+          this.$Message.error(res.msg);
+        });
+    },
+    pageChange(index) {
+      this.formValidate.page = index;
+      this.getList();
+    },
+  },
+};
+</script>
+<style scoped lang="stylus">
+.ivu-mt .type .item {
+  margin: 3px 0;
+}
+
+.tabform {
+  margin-bottom: 10px;
+}
+
+.Refresh {
+  font-size: 12px;
+  color: #1890FF;
+  cursor: pointer;
+}
+
+.ivu-form-item {
+  margin-bottom: 10px;
+}
+
+.status >>> .item ~ .item {
+  margin-left: 6px;
+}
+
+.status >>> .statusVal {
+  margin-bottom: 7px;
+}
+
+/* .ivu-mt >>> .ivu-table-header */
+/* border-top:1px dashed #ddd!important */
+.type {
+  padding: 3px 0;
+  box-sizing: border-box;
+}
+
+.tabBox_img {
+  width: 36px;
+  height: 36px;
+  border-radius: 4px;
+  cursor: pointer;
+
+  img {
+    width: 100%;
+    height: 100%;
+  }
+}
+
+.mb20 /deep/ .ivu-table-wrapper > .ivu-spin-fix {
+  border: none;
+}
+</style>

+ 195 - 0
src/pages/shop_setting/multiLanguage/list.vue

@@ -0,0 +1,195 @@
+<template>
+  <div>
+    <Card :bordered="false" dis-hover class="ivu-mt">
+      <Row type="flex">
+        <Col v-bind="grid">
+          <Button type="primary" icon="md-add" @click="add">添加语言</Button>
+        </Col>
+      </Row>
+      <Table
+        :columns="columns"
+        :data="list"
+        ref="table"
+        class="mt25"
+        :loading="loading"
+        highlight-row
+        no-userFrom-text="暂无数据"
+        no-filtered-userFrom-text="暂无筛选结果"
+      >
+        <template slot-scope="{ row, index }" slot="icons">
+          <div class="tabBox_img" v-viewer>
+            <img v-lazy="row.icon" />
+          </div>
+        </template>
+        <template slot-scope="{ row, index }" slot="language_name">
+          <div class="acea-row row-middle">
+            <span>{{ row.language_name }}</span>
+            <Tag class="ml10" color="default" v-if="row.is_default">默认</Tag>
+          </div>
+        </template>
+        <template slot-scope="{ row, index }" slot="status">
+          <i-switch
+            v-model="row.status"
+            :value="row.status"
+            :true-value="1"
+            :false-value="0"
+            @on-change="changeSwitch(row)"
+            size="large"
+          >
+            <span slot="open">开启</span>
+            <span slot="close">关闭</span>
+          </i-switch>
+        </template>
+        <template slot-scope="{ row, index }" slot="action">
+          <a @click="edit(row, '编辑语言', index)">编辑</a>
+          <Divider type="vertical" />
+          <a @click="del(row, '删除语言', index)">删除</a>
+        </template>
+      </Table>
+      <div class="acea-row row-right page">
+        <Page :total="total" show-elevator show-total @on-change="pageChange" :page-size="langFrom.limit" />
+      </div>
+    </Card>
+  </div>
+</template>
+
+<script>
+import { mapState } from 'vuex';
+import { langTypeList, langTypeForm, langTypeStatus } from '@/api/setting';
+export default {
+  name: 'user_group',
+  data() {
+    return {
+      grid: {
+        xl: 7,
+        lg: 7,
+        md: 12,
+        sm: 24,
+        xs: 24,
+      },
+      loading: false,
+      columns: [
+        {
+          title: 'ID',
+          key: 'id',
+          width: 200,
+        },
+        {
+          title: '语言名称',
+          slot: 'language_name',
+          minWidth: 200,
+        },
+        {
+          title: '浏览器语言识别码',
+          key: 'file_name',
+          minWidth: 200,
+        },
+        {
+          title: '状态',
+          slot: 'status',
+          width: 100,
+          filters: [
+            {
+              label: '开启',
+              value: 1,
+            },
+            {
+              label: '关闭',
+              value: 0,
+            },
+          ],
+          filterMethod(value, row) {
+            return row.status === value;
+          },
+          filterMultiple: false,
+        },
+        {
+          title: '操作',
+          slot: 'action',
+          fixed: 'right',
+          minWidth: 120,
+        },
+      ],
+      langFrom: {
+        page: 1,
+        limit: 15,
+      },
+      list: [],
+      total: 0,
+    };
+  },
+  computed: {
+    ...mapState('media', ['isMobile']),
+    labelWidth() {
+      return this.isMobile ? undefined : 75;
+    },
+    labelPosition() {
+      return this.isMobile ? 'top' : 'left';
+    },
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    // 添加
+    add() {
+      this.$modalForm(langTypeForm(0)).then(() => this.getList());
+    },
+    // 分组列表
+    getList() {
+      this.loading = true;
+      langTypeList(this.langFrom)
+        .then(async (res) => {
+          let data = res.data;
+          this.list = data.list;
+          this.total = data.count;
+          this.loading = false;
+        })
+        .catch((res) => {
+          this.loading = false;
+          this.$Message.error(res.msg);
+        });
+    },
+    pageChange(index) {
+      this.langFrom.page = index;
+      this.getList();
+    },
+    // 编辑
+    edit(row) {
+      this.$modalForm(langTypeForm(row.id)).then(() => this.getList());
+    },
+    // 删除
+    del(row, tit, num) {
+      let delfromData = {
+        title: tit,
+        num: num,
+        url: `setting/lang_type/del/${row.id}`,
+        method: 'DELETE',
+        ids: '',
+      };
+      this.$modalSure(delfromData)
+        .then((res) => {
+          this.$Message.success(res.msg);
+          this.list.splice(num, 1);
+          this.getList();
+        })
+        .catch((res) => {
+          this.$Message.error(res.msg);
+        });
+    },
+    // 修改状态
+    changeSwitch(row) {
+      langTypeStatus(row.id, row.status)
+        .then((res) => {
+          this.$Message.success(res.msg);
+        })
+        .catch((res) => {
+          row.status = !row.status ? 1 : 0;
+          this.$Message.error(res.msg);
+        });
+    },
+  },
+};
+</script>
+
+<style scoped lang="stylus"></style>

+ 301 - 0
src/pages/shop_setting/notification/index.vue

@@ -0,0 +1,301 @@
+<template>
+  <div class="message">
+    <Card :bordered="false" dis-hover class="ivu-mt">
+      <div class="mb20">
+        <Tabs v-model="currentTab" @on-click="changeTab">
+          <TabPane :label="item.label" :name="item.value.toString()" v-for="(item, index) in headerList" :key="index" />
+        </Tabs>
+      </div>
+      <Row type="flex" class="mb20" v-if="currentTab == 1">
+        <Col>
+          <Button
+            v-auth="['app-wechat-template-sync']"
+            icon="md-list"
+            type="success"
+            @click="routineTemplate"
+            style="margin-left: 20px"
+            >同步小程序订阅消息</Button
+          >
+          <Button
+            v-auth="['app-wechat-template-sync']"
+            icon="md-list"
+            type="success"
+            @click="wechatTemplate"
+            style="margin-left: 20px"
+            >同步微信模版消息</Button
+          >
+        </Col>
+      </Row>
+      <Alert v-if="currentTab == 1" :closable="true">
+        <template slot="desc">
+          1、公众号:登录微信公众号后台,选择模版消息,将模版消息的所在行业修改副行业为《其他/其他》<br />
+          2、小程序:登录微信小程序后台,基本设置,服务类目增加《生活服务> 百货/超市/便利店》
+        </template>
+      </Alert>
+      <Table
+        :columns="currentTab == 1 ? columns : columns2"
+        :data="levelLists"
+        ref="table"
+        class="mt25"
+        :loading="loading"
+        highlight-row
+        no-userFrom-text="暂无数据"
+        no-filtered-userFrom-text="暂无筛选结果"
+      >
+        <template slot-scope="{ row, index }" slot="name">
+          <span class="table">
+            {{ row.name }}
+          </span>
+        </template>
+        <template slot-scope="{ row, index }" slot="title">
+          <span class="table">{{ row.title }}</span>
+        </template>
+        <template
+          slot-scope="{ row }"
+          v-for="item in ['is_system', 'is_wechat', 'is_routine', 'is_sms', 'is_ent_wechat']"
+          :slot="item"
+        >
+          <div v-if="item === 'is_ent_wechat' && currentTab == 1" :key="index">--</div>
+          <i-switch
+            v-model="row[item]"
+            :value="row[item]"
+            :true-value="1"
+            :false-value="2"
+            @on-change="changeSwitch(row, item)"
+            size="large"
+            v-if="row[item] > 0 && currentTab !== 1"
+          >
+            <span slot="open">开启</span>
+            <span slot="close">关闭</span>
+          </i-switch>
+        </template>
+        <template slot-scope="{ row, index }" slot="setting">
+          <span class="setting btn" @click="setting(item, row)">设置</span>
+        </template>
+      </Table>
+    </Card>
+  </div>
+</template>
+
+<script>
+import { getNotificationList, getNotificationInfo, noticeStatus } from '@/api/notification.js';
+import { routineSyncTemplate, wechatSyncTemplate } from '@/api/app';
+export default {
+  data() {
+    return {
+      modalTitle: '',
+      notificationModal: false,
+      headerList: [
+        { label: '通知会员', value: '1' },
+        { label: '通知平台', value: '2' },
+      ],
+      columns: [
+        {
+          title: 'ID',
+          key: 'id',
+          align: 'center',
+          width: 60,
+        },
+        {
+          title: '通知类型',
+          slot: 'name',
+          align: 'center',
+          width: 200,
+        },
+        {
+          title: '通知场景说明',
+          slot: 'title',
+          align: 'center',
+          minWidth: 200,
+        },
+        {
+          title: '站内信',
+          slot: 'is_system',
+          align: 'center',
+          minWidth: 100,
+        },
+        {
+          title: '公众号模板',
+          slot: 'is_wechat',
+          align: 'center',
+          minWidth: 100,
+        },
+        {
+          title: '小程序订阅',
+          slot: 'is_routine',
+          align: 'center',
+          minWidth: 100,
+        },
+        {
+          title: '发送短信',
+          slot: 'is_sms',
+          align: 'center',
+          minWidth: 100,
+        },
+        {
+          title: '设置',
+          slot: 'setting',
+          width: 150,
+          align: 'center',
+        },
+      ],
+      columns2: [
+        {
+          title: 'ID',
+          key: 'id',
+          align: 'center',
+          width: 60,
+        },
+        {
+          title: '通知类型',
+          slot: 'name',
+          align: 'center',
+          width: 200,
+        },
+        {
+          title: '通知场景说明',
+          slot: 'title',
+          align: 'center',
+          minWidth: 200,
+        },
+        {
+          title: '站内信',
+          slot: 'is_system',
+          align: 'center',
+          minWidth: 100,
+        },
+        {
+          title: '公众号模板',
+          slot: 'is_wechat',
+          align: 'center',
+          minWidth: 100,
+        },
+        {
+          title: '发送短信',
+          slot: 'is_sms',
+          align: 'center',
+          minWidth: 100,
+        },
+        {
+          title: '企业微信',
+          slot: 'is_ent_wechat',
+          align: 'center',
+          minWidth: 100,
+        },
+        {
+          title: '设置',
+          slot: 'setting',
+          width: 150,
+          align: 'center',
+        },
+      ],
+      levelLists: [],
+      currentTab: '1',
+      loading: false,
+      formData: {},
+    };
+  },
+  created() {
+    this.changeTab(this.currentTab);
+  },
+  methods: {
+    changeSwitch(row, item) {
+      noticeStatus(item, row[item], row.id)
+        .then((res) => {
+          this.$Message.success(res.msg);
+        })
+        .catch((err) => {
+          this.$Message.error(err.msg);
+        });
+    },
+    changeTab(data) {
+      getNotificationList(data).then((res) => {
+        this.levelLists = res.data;
+      });
+    },
+    // 同步订阅消息
+    routineTemplate() {
+      routineSyncTemplate()
+        .then((res) => {
+          this.$Message.success(res.msg);
+          this.changeTab(this.currentTab);
+        })
+        .catch((res) => {
+          this.$Message.error(res.msg);
+        });
+    },
+    // 同步微信模版消息
+    wechatTemplate() {
+      wechatSyncTemplate()
+        .then((res) => {
+          this.$Message.success(res.msg);
+          this.changeTab(this.currentTab);
+        })
+        .catch((res) => {
+          this.$Message.error(res.msg);
+        });
+    },
+    // 开启关闭
+    changeStatus() {},
+    // 列表
+    notice() {},
+    // 设置
+    setting(item, row) {
+      this.$router.push({
+        path: this.$routeProStr + '/setting/notification/notificationEdit?id=' + row.id,
+      });
+    },
+    getData(keys, row, item) {
+      this.formData = {};
+      getNotificationInfo(row.id, item).then((res) => {
+        keys.map((i, v) => {
+          this.formData[i] = res.data[i];
+        });
+        this.formData.type = item;
+        this.notificationModal = true;
+      });
+    },
+  },
+};
+</script>
+
+<style scoped>
+.message /deep/ .ivu-table-header table {
+  /* border-top: 1px solid #e8eaec !important;
+  border-left: 1px solid #e8eaec !important; */
+}
+.message /deep/ .ivu-table-header thead tr th {
+  padding: 8px 16px;
+}
+.message /deep/ .ivu-tabs-tab {
+  border-radius: 0 !important;
+}
+.table-box {
+  padding: 20px;
+}
+.is-table {
+  display: flex;
+  /* justify-content: space-around; */
+  justify-content: center;
+}
+.btn {
+  padding: 6px 12px;
+  cursor: pointer;
+  color: #2d8cf0;
+  font-size: 10px;
+  border-radius: 3px;
+}
+.is-switch-close {
+  background-color: #504444;
+}
+.is-switch {
+  background-color: #eb5252;
+}
+.notice-list {
+  background-color: #308cf5;
+  margin: 0 15px;
+}
+.table {
+  padding: 0 18px;
+}
+</style>

+ 340 - 0
src/pages/shop_setting/notification/notificationEdit.vue

@@ -0,0 +1,340 @@
+<template>
+  <div class="edit">
+    <!-- <div class="i-layout-page-header">
+      <router-link :to="{ path: '/admin/setting/notification/index' }"
+        ><Button icon="ios-arrow-back" size="small" class="mr20"
+          >返回</Button
+        ></router-link
+      >
+      <span class="ivu-page-header-title">{{ $route.meta.title }}</span>
+    </div> -->
+    <div class="i-layout-page-header header_top">
+      <div class="i-layout-page-header fl_header">
+        <router-link :to="{ path: $routeProStr + '/setting/notification/index' }"
+          ><Button icon="ios-arrow-back" size="small" type="text">返回</Button></router-link
+        >
+        <Divider type="vertical" />
+        <span class="ivu-page-header-title mr20" style="padding: 0" v-text="$route.meta.title"></span>
+      </div>
+    </div>
+    <div class="tabs">
+      <Row :gutter="32">
+        <Col span="32" class="demo-tabs-style1" style="padding: 16px">
+          <Tabs @on-click="changeTabs">
+            <TabPane v-for="(item, index) in tabsList" :key="index" :name="item.slot" :label="item.title">
+              <Form class="form-sty" ref="formData" :model="formData" :rules="ruleValidate" :label-width="80">
+                <div v-if="item.slot === 'is_system' && !loading">
+                  <FormItem label="通知标题">
+                    <Input v-model="formData.system_title" placeholder="请输入通知标题" style="width: 500px"></Input>
+                  </FormItem>
+                  <FormItem label="通知内容">
+                    <div class="content">
+                      <Input
+                        v-model="formData.system_text"
+                        type="textarea"
+                        :autosize="{ minRows: 5, maxRows: 8 }"
+                        placeholder="请输入通知内容"
+                        style="width: 500px"
+                      ></Input>
+                      <div class="trip">
+                        <div>请输入模板消息详细内容对应的变量。关键字个数需与已添加的模板一致。 可以使用如下变量:</div>
+                        <div v-for="(item, index) in formData.variable.split(',')" :key="index">
+                          {{ item }}
+                        </div>
+                      </div>
+                    </div>
+                  </FormItem>
+                  <FormItem label="状态" prop="is_system">
+                    <RadioGroup v-model="formData.is_system">
+                      <Radio :label="1">开启</Radio>
+                      <Radio :label="2">关闭</Radio>
+                    </RadioGroup>
+                  </FormItem>
+                </div>
+                <div v-if="item.slot === 'is_sms' && !loading">
+                  <FormItem label="短信模版ID">
+                    <Input v-model="formData.sms_id" placeholder="短信模版ID" style="width: 500px"></Input>
+                  </FormItem>
+                  <FormItem label="通知内容">
+                    <div class="content">
+                      <Input
+                        v-model="formData.content"
+                        type="textarea"
+                        disabled
+                        :autosize="{ minRows: 5, maxRows: 8 }"
+                        placeholder="请输入通知内容"
+                        style="width: 500px"
+                      ></Input>
+                    </div>
+                  </FormItem>
+                  <FormItem label="状态" prop="is_sms">
+                    <RadioGroup v-model="formData.is_sms">
+                      <Radio :label="1">开启</Radio>
+                      <Radio :label="2">关闭</Radio>
+                    </RadioGroup>
+                  </FormItem>
+                </div>
+                <div v-else-if="item.slot === 'is_wechat' && !loading">
+                  <FormItem label="ID">
+                    <Input
+                      v-model="formData.templage_message_id"
+                      disabled
+                      placeholder="请输入通模板编号"
+                      style="width: 500px"
+                    ></Input>
+                  </FormItem>
+                  <FormItem label="模板编号">
+                    <Input
+                      v-model="formData.tempkey"
+                      disabled
+                      placeholder="请输入通模板编号"
+                      style="width: 500px"
+                    ></Input>
+                  </FormItem>
+                  <FormItem label="模板">
+                    <Input
+                      disabled
+                      v-model="formData.content"
+                      type="textarea"
+                      :autosize="{ minRows: 5, maxRows: 8 }"
+                      placeholder="请输入模板"
+                      style="width: 500px"
+                    ></Input>
+                  </FormItem>
+                  <FormItem label="模板ID">
+                    <Input v-model="formData.tempid" placeholder="请输入模板ID" style="width: 500px"></Input>
+                  </FormItem>
+                  <FormItem label="状态" prop="is_wechat">
+                    <RadioGroup v-model="formData.is_wechat">
+                      <Radio :label="1">开启</Radio>
+                      <Radio :label="2">关闭</Radio>
+                    </RadioGroup>
+                  </FormItem>
+                </div>
+                <div v-else-if="item.slot === 'is_routine' && !loading">
+                  <FormItem label="ID">
+                    <Input
+                      v-model="formData.templage_message_id"
+                      disabled
+                      placeholder="请输入通模板编号"
+                      style="width: 500px"
+                    ></Input>
+                  </FormItem>
+                  <FormItem label="模板编号">
+                    <Input
+                      v-model="formData.tempkey"
+                      disabled
+                      placeholder="请输入通模板编号"
+                      style="width: 500px"
+                    ></Input>
+                  </FormItem>
+                  <FormItem label="模板">
+                    <Input
+                      disabled
+                      v-model="formData.content"
+                      type="textarea"
+                      :autosize="{ minRows: 5, maxRows: 8 }"
+                      placeholder="请输入模板"
+                      style="width: 500px"
+                    ></Input>
+                  </FormItem>
+                  <FormItem label="模板ID">
+                    <Input v-model="formData.tempid" placeholder="请输入模板ID" style="width: 500px"></Input>
+                  </FormItem>
+                  <FormItem label="状态" prop="is_routine">
+                    <RadioGroup v-model="formData.is_routine">
+                      <Radio :label="1">开启</Radio>
+                      <Radio :label="2">关闭</Radio>
+                    </RadioGroup>
+                  </FormItem>
+                </div>
+
+                <div v-else-if="item.slot === 'is_ent_wechat' && !loading">
+                  <FormItem label="通知内容">
+                    <div class="content">
+                      <Input
+                        v-model="formData.ent_wechat_text"
+                        type="textarea"
+                        :autosize="{ minRows: 5, maxRows: 8 }"
+                        placeholder="请输入通知内容"
+                        style="width: 500px"
+                      ></Input>
+                      <div class="trip">
+                        <div>请输入模板消息详细内容对应的变量。关键字个数需与已添加的模板一致。 可以使用如下变量:</div>
+                        <div v-for="(item, index) in formData.variable.split(',')" :key="index">
+                          {{ item }}
+                        </div>
+                      </div>
+                    </div>
+                  </FormItem>
+                  <FormItem label="机器人链接">
+                    <div class="content">
+                      <Input v-model="formData.url" placeholder="请输入机器人链接" style="width: 500px"></Input>
+                      <div class="trip">企业微信群机器人链接</div>
+                    </div>
+                  </FormItem>
+                  <FormItem label="状态" prop="is_ent_wechat">
+                    <RadioGroup v-model="formData.is_ent_wechat">
+                      <Radio :label="1">开启</Radio>
+                      <Radio :label="2">关闭</Radio>
+                    </RadioGroup>
+                  </FormItem>
+                </div>
+                <FormItem>
+                  <Button type="primary" @click="handleSubmit('formData')">提交</Button>
+                </FormItem>
+              </Form>
+            </TabPane>
+          </Tabs>
+        </Col>
+      </Row>
+    </div>
+  </div>
+</template>
+
+<script>
+import { getNotificationInfo, getNotificationSave } from '@/api/notification.js';
+export default {
+  data() {
+    return {
+      tabs: [
+        {
+          title: '系统通知',
+          slot: 'is_system',
+        },
+        {
+          title: '短信通知',
+          slot: 'is_sms',
+        },
+        {
+          title: '微信模板消息',
+          slot: 'is_wechat',
+        },
+        {
+          title: '微信小程序提醒',
+          slot: 'is_routine',
+        },
+        {
+          title: '企业微信',
+          slot: 'is_ent_wechat',
+        },
+      ],
+      tabsList: [],
+      formData: {},
+      id: 0,
+      loading: true,
+      ruleValidate: {
+        name: [
+          {
+            required: true,
+            message: '请输入通知场景',
+            trigger: 'blur',
+          },
+        ],
+        title: [
+          {
+            required: true,
+            message: '请输入通知场景',
+            trigger: 'blur',
+          },
+        ],
+        content: [
+          {
+            required: true,
+            message: '请输入通知内容',
+            trigger: 'blur',
+          },
+        ],
+      },
+    };
+  },
+  created() {
+    this.id = this.$route.query.id;
+    this.changeTabs('is_system');
+  },
+  methods: {
+    changeTabs(name) {
+      this.getData(this.id, name);
+    },
+    getData(id, name) {
+      this.loading = true;
+      this.formData = {};
+      getNotificationInfo(id, name)
+        .then((res) => {
+          if (!this.tabsList.length) {
+            this.tabs.map((v) => {
+              if (res.data[v.slot]) {
+                this.tabsList.push(v);
+              }
+            });
+          }
+          this.formData = res.data;
+          this.formData.type = name;
+          this.formData.id = id;
+          this.loading = false;
+        })
+        .catch((err) => {
+          this.$Message.error(err.msg);
+        });
+    },
+    handleSubmit(name) {
+      getNotificationSave(this.formData)
+        .then((res) => {
+          this.$Message.success('设置成功');
+        })
+        .catch((err) => {
+          this.$Message.error(err);
+        });
+    },
+    handleReset(name) {
+      this.$emit('close');
+    },
+  },
+};
+</script>
+
+<style scoped>
+.edit {
+}
+.header_top {
+  margin-bottom: 10px;
+}
+.demo-tabs-style1 > .ivu-tabs-card > .ivu-tabs-content {
+  height: 120px;
+  margin-top: -16px;
+}
+
+.demo-tabs-style1 > .ivu-tabs-card > .ivu-tabs-content > .ivu-tabs-tabpane {
+  background: #fff;
+  padding: 16px;
+}
+
+.demo-tabs-style1 > .ivu-tabs.ivu-tabs-card > .ivu-tabs-bar .ivu-tabs-tab {
+  border-color: transparent;
+}
+
+.demo-tabs-style1 > .ivu-tabs-card > .ivu-tabs-bar .ivu-tabs-tab-active {
+  border-color: #fff;
+}
+
+.tabs {
+  padding: 0 30px;
+  background-color: #fff;
+}
+
+.trip {
+  color: rgb(146, 139, 139);
+  background-color: #f2f2f2;
+  margin-left: 80px;
+  border-radius: 4px;
+  padding: 15px;
+}
+
+.content {
+  display: flex;
+}
+
+.form-sty {
+  margin-top: 20px;
+}
+</style>

+ 36 - 0
src/pages/shop_setting/setApp/index.vue

@@ -0,0 +1,36 @@
+<template>
+  <div class="article-manager">
+    <div class="i-layout-page-header">
+      <div class="i-layout-page-header">
+        <span class="ivu-page-header-title">系统设置</span>
+        <div>
+          <Tabs v-model="currentTab">
+            <TabPane label="公众号配置" name="onsale" />
+            <TabPane label="配置" name="forsale" />
+          </Tabs>
+        </div>
+      </div>
+    </div>
+    <Card :bordered="false" dis-hover class="ivu-mt" v-if="currentTab === 'onsale'">
+      <!--<form-create  :rule="Array.from(FromData.rules)" @submit="onSubmit" ></form-create>-->
+    </Card>
+  </div>
+</template>
+
+<script>
+import formCreate from '@form-create/iview';
+export default {
+  name: 'setApp',
+  components: { formCreate },
+  data() {
+    return {
+      FromData: null,
+      currentTab: '',
+    };
+  },
+  mounted() {},
+  methods: {},
+};
+</script>
+
+<style scoped></style>

+ 236 - 0
src/pages/shop_setting/setSystem/index.vue

@@ -0,0 +1,236 @@
+<template>
+  <div>
+    <div class="i-layout-page-header header-title" v-if="!headerList.length">
+      <span class="ivu-page-header-title">{{ $route.meta.title }}</span>
+    </div>
+    <div class="article-manager">
+      <Card :bordered="false" dis-hover class="ivu-mt fromBox">
+        <Tabs v-model="currentTab" @on-click="changeTab" v-if="headerList.length">
+          <TabPane
+            :icon="item.icon"
+            :label="item.label"
+            :name="item.value.toString()"
+            v-for="(item, index) in headerList"
+            :key="index"
+          />
+        </Tabs>
+        <Tabs type="card" v-model="childrenId" v-if="headerChildrenList.length" @on-click="changeChildrenTab">
+          <TabPane
+            :label="item.label"
+            :name="item.id.toString()"
+            v-for="(item, index) in headerChildrenList"
+            :key="index"
+          ></TabPane>
+        </Tabs>
+        <form-create :option="option" :rule="rules" @submit="onSubmit" v-if="rules.length !== 0"></form-create>
+        <Spin size="large" fix v-if="spinShow"></Spin>
+      </Card>
+    </div>
+  </div>
+</template>
+
+<script>
+import formCreate from '@form-create/iview';
+import { headerListApi, dataFromApi } from '@/api/setting';
+import request from '@/libs/request';
+import { getLogo } from '@/api/common';
+export default {
+  name: 'setting_setSystem',
+  components: { formCreate: formCreate.$form() },
+  data() {
+    return {
+      rules: [],
+      option: {
+        form: {
+          labelWidth: 185,
+        },
+        submitBtn: {
+          col: {
+            span: 3,
+            push: 3,
+          },
+        },
+        global: {
+          upload: {
+            props: {
+              onSuccess(res, file) {
+                if (res.status === 200) {
+                  file.url = res.data.src;
+                } else {
+                  this.$Message.error(res.msg);
+                }
+              },
+            },
+          },
+          frame: {
+            props: {
+              closeBtn: false,
+              okBtn: false,
+            },
+          },
+        },
+      },
+      spinShow: false,
+      FromData: null,
+      currentTab: '',
+      headerList: [],
+      headerChildrenList: [],
+      childrenId: '',
+      title: '',
+    };
+  },
+  created() {
+    this.getAllData();
+  },
+  watch: {
+    $route(to, from) {
+      this.headerChildrenList = [];
+      this.getAllData();
+    },
+    childrenId() {
+      this.getFrom();
+    },
+  },
+  methods: {
+    childrenList(index) {
+      let that = this;
+      that.headerList.forEach(function (item) {
+        if (item.value.toString() === that.currentTab) {
+          if (item.children === undefined) {
+            that.childrenId = item.id;
+            that.headerChildrenList = [];
+          } else {
+            that.headerChildrenList = item.children;
+            that.childrenId = item.children.length ? item.children[index ? index : 0].id.toString() : '';
+          }
+        }
+      });
+    },
+    // 头部tab
+    getHeader(index) {
+      this.spinShow = true;
+      return new Promise((resolve, reject) => {
+        let tab_id = this.$route.params.tab_id;
+        let data = {
+          type: this.$route.params.type ? this.$route.params.type : 0,
+          pid: tab_id ? tab_id : 0,
+        };
+        headerListApi(data)
+          .then(async (res) => {
+            let config = res.data.config_tab;
+            this.headerList = config;
+            this.currentTab = config[index ? index : 0].value.toString();
+            this.childrenList(index ? 1 : 0);
+            resolve(this.currentTab);
+            this.spinShow = false;
+          })
+          .catch((err) => {
+            this.spinShow = false;
+            this.$Message.error(err);
+          });
+      });
+    },
+    // 表单
+    getFrom() {
+      this.spinShow = true;
+      return new Promise((resolve, reject) => {
+        let ids = '';
+        if (this.$route.params.type === '3') {
+          ids = this.$route.params.tab_id;
+        } else {
+          if (this.childrenId) {
+            ids = this.childrenId;
+          } else {
+            ids = this.currentTab;
+          }
+        }
+        let data = {
+          tab_id: Number(ids),
+        };
+        let logistics = 'freight/config/edit_basics',
+          agent = 'agent/config/edit_basics',
+          integral = 'marketing/integral_config/edit_basics',
+          sms = 'serve/sms_config/edit_basics',
+          config = 'setting/config/edit_basics';
+        let url =
+          this.$route.name === 'setting_logistics'
+            ? logistics
+            : this.$route.name === 'setting_distributionSet'
+            ? agent
+            : this.$route.name === 'setting_message'
+            ? sms
+            : this.$route.name === 'setting_setSystem'
+            ? config
+            : integral;
+        dataFromApi(data, url)
+          .then(async (res) => {
+            this.spinShow = false;
+            if (res.data.status === false) {
+              return this.$authLapse(res.data);
+            }
+            this.FromData = res.data;
+            this.rules = res.data.rules;
+            this.title = res.data.title;
+          })
+          .catch((res) => {
+            this.spinShow = false;
+            this.$Message.error(res.msg);
+          });
+      });
+    },
+    async getAllData() {
+      if (this.$route.query.from === 'download') {
+        await this.getHeader(2);
+      } else if (this.$route.params.type !== '3') {
+        this.childrenId = '';
+        await this.getHeader();
+      } else {
+        this.headerList = [];
+        this.getFrom();
+      }
+    },
+    // 选择
+    changeTab() {
+      this.childrenList();
+    },
+    // 二级选择
+    changeChildrenTab(name) {
+      this.childrenId = name;
+    },
+    // 提交表单 group
+    onSubmit(formData) {
+      request({
+        url: this.FromData.action,
+        method: this.FromData.method,
+        data: formData,
+      })
+        .then((res) => {
+          this.$Message.success(res.msg);
+          if (formData.site_name) {
+            localStorage.setItem('ADMIN_TITLE', formData.site_name);
+            this.$store.commit('setAdminTitle', formData.site_name);
+            window.document.title = `${formData.site_name} - 系统设置`;
+          }
+        })
+        .catch((res) => {
+          this.$Message.error(res.msg);
+        });
+    },
+  },
+};
+</script>
+
+<style scoped lang="stylus">
+.ivu-tabs {
+  margin-bottom: 18px;
+}
+
+.fromBox {
+  min-height: calc(100vh - 200px);
+  margin-top: 0px !important;
+}
+
+.article-manager /deep/ .ivu-form-item {
+  margin-bottom: 20px !important;
+}
+</style>

+ 192 - 0
src/pages/shop_setting/shippingTemplates/index.vue

@@ -0,0 +1,192 @@
+<template>
+	<div>
+		<Card :bordered="false" dis-hover class="ivu-mt">
+			<Form ref="levelFrom" :model="levelFrom" :label-width="labelWidth" :label-position="labelPosition"
+				@submit.native.prevent>
+				<Row type="flex" :gutter="24">
+					<Col v-bind="grid">
+					<FormItem label="搜索:" label-for="keyword">
+						<Input search enter-button v-model="levelFrom.name" placeholder="请输入模板名称"
+							@on-search="userSearchs" />
+					</FormItem>
+					</Col>
+				</Row>
+				<Row type="flex">
+					<Col v-bind="grid">
+					<Button type="primary" icon="md-add" @click="freight">添加运费模板</Button>
+					</Col>
+				</Row>
+			</Form>
+			<Table :columns="columns1" :data="levelLists" ref="table" class="mt25" :loading="loading" highlight-row
+				no-userFrom-text="暂无数据" no-filtered-userFrom-text="暂无筛选结果">
+				<template slot-scope="{ row, index }" slot="icons">
+					<div class="tabBox_img" v-viewer>
+						<img v-lazy="row.icon" />
+					</div>
+				</template>
+				<template slot-scope="{ row, index }" slot="action">
+					<a @click="edit(row.id)">修改</a>
+					<Divider type="vertical" v-if="row.id !== 1" />
+					<a @click="del(row, '删除分组', index)" v-if="row.id !== 1">删除</a>
+				</template>
+			</Table>
+			<div class="acea-row row-right page">
+				<Page :total="total" :current="levelFrom.page" show-elevator show-total @on-change="pageChange"
+					:page-size="levelFrom.limit" />
+			</div>
+		</Card>
+		<!-- 运费模板-->
+		<freight-template v-if="isTemplate" ref="template" @addSuccess="getList" @close="
+        () => {
+          isTemplate = false;
+        }
+      "></freight-template>
+	</div>
+</template>
+
+<script>
+	import {
+		mapState
+	} from 'vuex';
+	import {
+		templatesApi
+	} from '@/api/shop_setting';
+	import freightTemplate from '@/components/freightTemplate2/index';
+
+	export default {
+		name: 'setting_templates',
+		components: {
+			freightTemplate
+		},
+		data() {
+			return {
+				grid: {
+					xl: 7,
+					lg: 7,
+					md: 12,
+					sm: 24,
+					xs: 24,
+				},
+				loading: false,
+				columns1: [{
+						title: 'ID',
+						key: 'id',
+						width: 80,
+					},
+					{
+						title: '模板名称',
+						key: 'name',
+						minWidth: 100,
+					},
+					{
+						title: '计费方式',
+						key: 'type',
+						minWidth: 120,
+					},
+					{
+						title: '指定包邮',
+						key: 'appoint',
+						minWidth: 120,
+					},
+					{
+						title: '排序',
+						key: 'sort',
+						minWidth: 120,
+					},
+					{
+						title: '添加时间',
+						key: 'add_time',
+						minWidth: 120,
+					},
+					{
+						title: '操作',
+						slot: 'action',
+						fixed: 'right',
+						minWidth: 120,
+					},
+				],
+				levelFrom: {
+					name: '',
+					page: 1,
+					limit: 15,
+				},
+				levelLists: [],
+				total: 0,
+				FromData: null,
+				isTemplate: false,
+			};
+		},
+		created() {
+			this.getList();
+		},
+		computed: {
+			...mapState('media', ['isMobile']),
+			labelWidth() {
+				return this.isMobile ? undefined : 75;
+			},
+			labelPosition() {
+				return this.isMobile ? 'top' : 'left';
+			},
+		},
+		methods: {
+			// 添加运费模板
+			freight() {
+				this.isTemplate = true;
+				this.$nextTick((e) => {
+					this.$refs.template.id = 0;
+					this.$refs.template.isTemplate = true;
+				});
+			},
+			// 删除
+			del(row, tit, num) {
+				let delfromData = {
+					title: tit,
+					num: num,
+					url: `mer/shipping_templates/del/${row.id}`,
+					method: 'DELETE',
+					ids: '',
+				};
+				this.$modalSure(delfromData)
+					.then((res) => {
+						this.$Message.success(res.msg);
+						this.levelLists.splice(num, 1);
+					})
+					.catch((res) => {
+						this.$Message.error(res.msg);
+					});
+			},
+			// 运费模板列表
+			getList() {
+				this.loading = true;
+				templatesApi(this.levelFrom)
+					.then(async (res) => {
+						let data = res.data;
+						this.levelLists = data.data;
+						this.total = data.count;
+						this.loading = false;
+					})
+					.catch((res) => {
+						this.loading = false;
+						this.$Message.error(res.msg);
+					});
+			},
+			pageChange(index) {
+				this.levelFrom.page = index;
+				this.getList();
+			},
+			// 编辑
+			edit(id) {
+				this.isTemplate = true;
+				this.$nextTick((e) => {
+					this.$refs.template.isTemplate = true;
+					this.$refs.template.editFrom(id);
+				});
+			},
+			// 表格搜索
+			userSearchs() {
+				this.levelFrom.page = 1;
+				this.getList();
+			},
+		},
+	};
+</script>

+ 934 - 0
src/pages/shop_setting/storage/index.vue

@@ -0,0 +1,934 @@
+<template>
+  <div>
+    <div class="message">
+      <Card :bordered="false" dis-hover class="">
+        <div class="mb20">
+          <Tabs v-model="currentTab" @on-click="changeTab">
+            <TabPane
+              :label="item.label"
+              :name="item.value.toString()"
+              v-for="(item, index) in headerList"
+              :key="index"
+            />
+          </Tabs>
+        </div>
+        <h3>使用说明</h3>
+        <template v-if="currentTab == 1">
+          <p>上传图片时会生成缩略图</p>
+          <p>未设置按照系统默认生成,系统默认:大图800*800,中图300*300,小图150*150</p>
+          <p>水印只在上传图片时生成,原图,大中小缩略图上都按照比例存在。</p>
+          <p>若上传图片时未开启水印,则该图在开启水印之后依旧无水印效果。</p>
+        </template>
+        <template v-else>
+          <!-- <p v-if="currentTab == 2">
+            七牛云开通方法:<a href="https://doc.crmeb.com/web/single/crmeb_v4/987" target="_blank">点击查看</a>
+          </p>
+          <p v-if="currentTab == 3">
+            阿里云oss开通方法:<a href="https://doc.crmeb.com/web/single/crmeb_v4/985" target="_blank">点击查看</a>
+          </p>
+          <p v-if="currentTab == 4">
+            腾讯云cos开通方法:<a href="https://doc.crmeb.com/web/single/crmeb_v4/986" target="_blank">点击查看</a>
+          </p> -->
+          <p>第一步: 添加【存储空间】(空间名称不能重复)</p>
+          <p>第二步: 开启【使用状态】</p>
+          <template v-if="currentTab == 2">
+            <p>第三步(必选): 选择云存储空间列表上的修改【空间域名操作】</p>
+            <p>第四步(必选): 选择云存储空间列表上的修改【CNAME配置】,打开后复制记录值到对应的平台解析</p>
+          </template>
+          <template v-else>
+            <p>第三步(可选): 选择云存储空间列表上的修改【空间域名操作】</p>
+            <p>第四步(可选): 选择云存储空间列表上的修改【CNAME配置】,打开后复制记录值到对应的平台解析</p>
+          </template>
+        </template>
+      </Card>
+    </div>
+    <div class="pt10" v-if="currentTab == 1">
+      <Card :bordered="false" dis-hover class="ivu-mt">
+        <Row type="flex">
+          <Col span="24">
+            <span class="save-type"> 存储方式: </span>
+            <RadioGroup v-model="formValidate.upload_type" @on-change="changeSave">
+              <Radio label="1">本地存储</Radio>
+              <Radio label="2">七牛云存储</Radio>
+              <Radio label="3">阿里云存储</Radio>
+              <Radio label="4">腾讯云存储</Radio>
+            </RadioGroup>
+            <!-- <i-switch
+              v-model="localStorage"
+              size="large"
+              @on-change="addSwitch"
+            >
+              <span slot="open">开启</span>
+              <span slot="close">关闭</span>
+            </i-switch> -->
+          </Col>
+        </Row>
+      </Card>
+      <Card :bordered="false" dis-hover class="ivu-mt">
+        <Form ref="formValidate" :model="formValidate" :rules="ruleValidate">
+          <div class="abbreviation">
+            <div class="top">
+              <div class="topBox">
+                <div class="topLeft">
+                  <div class="img">
+                    <img class="imgs" src="../../../assets/images/abbreviationBig.png" alt="" />
+                  </div>
+                  <div>缩略大图</div>
+                </div>
+                <div class="topRight">
+                  <FormItem label="宽:">
+                    <Input
+                      class="topIput"
+                      type="number"
+                      v-model="formValidate.thumb_big_width"
+                      placeholder="请输入宽度"
+                    >
+                      <span slot="append">px</span>
+                    </Input>
+                  </FormItem>
+                  <FormItem label="高:">
+                    <Input
+                      class="topIput"
+                      type="number"
+                      v-model="formValidate.thumb_big_height"
+                      placeholder="请输入高度"
+                    >
+                      <span slot="append">px</span>
+                    </Input>
+                  </FormItem>
+                </div>
+              </div>
+              <div class="topBox">
+                <div class="topLeft">
+                  <div class="img">
+                    <img class="imgs" src="../../../assets/images/abbreviation.png" alt="" />
+                  </div>
+                  <div>缩略中图</div>
+                </div>
+                <div class="topRight">
+                  <FormItem label="宽:">
+                    <Input
+                      class="topIput"
+                      type="number"
+                      v-model="formValidate.thumb_mid_width"
+                      placeholder="请输入宽度"
+                    >
+                      <span slot="append">px</span>
+                    </Input>
+                  </FormItem>
+                  <FormItem label="高:">
+                    <Input
+                      type="number"
+                      class="topIput"
+                      v-model="formValidate.thumb_mid_height"
+                      placeholder="请输入高度"
+                    >
+                      <span slot="append">px</span>
+                    </Input>
+                  </FormItem>
+                </div>
+              </div>
+              <div class="topBox">
+                <div class="topLeft">
+                  <div class="img">
+                    <img class="imgs" src="../../../assets/images/abbreviationSmall.png" alt="" />
+                  </div>
+                  <div>缩略小图</div>
+                </div>
+                <div class="topRight">
+                  <FormItem label="宽:">
+                    <Input
+                      class="topIput"
+                      type="number"
+                      v-model="formValidate.thumb_small_width"
+                      placeholder="请输入宽度"
+                    >
+                      <span slot="append">px</span>
+                    </Input>
+                  </FormItem>
+                  <FormItem label="高:">
+                    <Input
+                      class="topIput"
+                      type="number"
+                      v-model="formValidate.thumb_small_height"
+                      placeholder="请输入高度"
+                    >
+                      <span slot="append">px</span>
+                    </Input>
+                  </FormItem>
+                </div>
+              </div>
+            </div>
+            <Divider />
+            <div class="content">
+              <FormItem label="是否开启水印:">
+                <i-switch v-model="formValidate.image_watermark_status" size="large">
+                  <span slot="open">开启</span>
+                  <span slot="close">关闭</span>
+                </i-switch>
+              </FormItem>
+              <div v-if="formValidate.image_watermark_status == 1">
+                <FormItem label="水印类型:">
+                  <RadioGroup v-model="formValidate.watermark_type">
+                    <Radio :label="1">图片</Radio>
+                    <Radio :label="2">文字</Radio>
+                  </RadioGroup>
+                </FormItem>
+                <div v-if="formValidate.watermark_type == 1">
+                  <div class="flex">
+                    <FormItem class="contentIput" label="水印透明度:" prop="name">
+                      <Input
+                        class="topIput"
+                        type="number"
+                        v-model="formValidate.watermark_opacity"
+                        placeholder="请输入水印透明度"
+                      >
+                      </Input>
+                    </FormItem>
+                    <FormItem class="contentIput" label="水印倾斜度:" prop="mail">
+                      <Input
+                        class="topIput"
+                        type="number"
+                        v-model="formValidate.watermark_rotate"
+                        placeholder="请输入水印倾斜度"
+                      >
+                      </Input>
+                    </FormItem>
+                  </div>
+                  <div class="flex">
+                    <FormItem class="contentIput" label="水印图片:" prop="name">
+                      <div class="picBox" @click="modalPicTap('单选')">
+                        <div class="pictrue" v-if="formValidate.watermark_image">
+                          <img :src="formValidate.watermark_image" />
+                        </div>
+                        <div class="upLoad acea-row row-center-wrapper" v-else>
+                          <Icon type="ios-camera-outline" size="24" />
+                        </div>
+                      </div>
+                    </FormItem>
+                    <FormItem class="contentIput" label="水印位置:" prop="mail">
+                      <div class="conents">
+                        <div class="positionBox">
+                          <div
+                            class="topIput box"
+                            :class="positionId == item.id ? 'on' : ''"
+                            v-for="(item, index) in boxs"
+                            :key="index"
+                            @click="bindbox(item)"
+                          ></div>
+                        </div>
+                        <div class="title">{{ positiontlt }}</div>
+                      </div>
+                    </FormItem>
+                  </div>
+                  <div class="flex">
+                    <FormItem class="contentIput" label="水印横坐标偏移量:" width="200" prop="name">
+                      <Input
+                        class="topIput"
+                        type="number"
+                        v-model="formValidate.watermark_x"
+                        placeholder="请输入水印横坐标偏移量"
+                      >
+                        <span slot="append">px</span>
+                      </Input>
+                    </FormItem>
+                    <FormItem class="contentIput" label="水印纵坐标偏移量:" prop="mail">
+                      <Input
+                        class="topIput"
+                        type="number"
+                        v-model="formValidate.watermark_y"
+                        placeholder="请输入水印纵坐标偏移量"
+                      >
+                        <span slot="append">px</span>
+                      </Input>
+                    </FormItem>
+                  </div>
+                </div>
+                <!-- 水印类型为文字 -->
+                <div v-else>
+                  <div class="flex">
+                    <FormItem class="contentIput" label="水印文字:" prop="name">
+                      <Input class="topIput" v-model="formValidate.watermark_text" placeholder="请输入水印文字">
+                      </Input>
+                    </FormItem>
+                    <FormItem class="contentIput" label="水印文字大小:">
+                      <Input
+                        class="topIput"
+                        type="number"
+                        v-model="formValidate.watermark_text_size"
+                        placeholder="请输入水印文字大小"
+                      >
+                      </Input>
+                    </FormItem>
+                  </div>
+                  <div class="flex">
+                    <FormItem class="contentIput" label="水印字体颜色:" prop="name">
+                      <ColorPicker v-model="formValidate.watermark_text_color" />
+                    </FormItem>
+                    <FormItem class="contentIput" label="水印位置:" prop="mail">
+                      <div class="conents">
+                        <div class="positionBox">
+                          <div
+                            class="topIput box"
+                            :class="positionId == item.id ? 'on' : ''"
+                            v-for="(item, index) in boxs"
+                            :key="index"
+                            @click="bindbox(item)"
+                          ></div>
+                        </div>
+                        <div class="title">{{ positiontlt }}</div>
+                      </div>
+                    </FormItem>
+                  </div>
+                  <div class="flex">
+                    <FormItem class="contentIput" label="水印字体旋转角度:">
+                      <Input
+                        class="topIput"
+                        type="number"
+                        v-model="formValidate.watermark_text_angle"
+                        placeholder="请输入水印字体旋转角度"
+                      >
+                      </Input>
+                    </FormItem>
+                    <FormItem class="contentIput" label="水印横坐标偏移量:">
+                      <Input
+                        class="topIput"
+                        type="number"
+                        v-model="formValidate.watermark_x"
+                        placeholder="请输入水印横坐标偏移量"
+                      >
+                        <span slot="append">px</span>
+                      </Input>
+                    </FormItem>
+                  </div>
+                  <FormItem class="contentIput" label="水印横坐纵偏移量:" prop="mail">
+                    <Input
+                      class="topIput"
+                      type="number"
+                      v-model="formValidate.watermark_y"
+                      placeholder="请输入水印横坐纵偏移量"
+                    >
+                      <span slot="append">px</span>
+                    </Input>
+                  </FormItem>
+                </div>
+              </div>
+            </div>
+            <FormItem>
+              <Button type="primary" @click="handleSubmit('formValidate')">保存</Button>
+            </FormItem>
+          </div>
+        </Form>
+      </Card>
+    </div>
+    <!-- 缩略图配置 -->
+    <div class="pt10" v-else-if="currentTab == 5"></div>
+    <div class="pt10" v-else>
+      <Card :bordered="false" dis-hover class="ivu-mt">
+        <Row type="flex" class="mb20">
+          <Col span="24">
+            <Button type="primary" @click="addStorageBtn">添加存储空间</Button>
+            <Button type="success" @click="synchro" style="margin-left: 20px">同步存储空间</Button>
+            <Button @click="addConfigBtn" style="float: right">修改配置信息</Button>
+          </Col>
+        </Row>
+        <Table
+          :columns="columns"
+          :data="levelLists"
+          ref="table"
+          class="mt25"
+          :loading="loading"
+          highlight-row
+          no-userFrom-text="暂无数据"
+          no-filtered-userFrom-text="暂无筛选结果"
+        >
+          <template slot-scope="{ row, index }" slot="status">
+            <!-- {{row}}{{index}} -->
+            <i-switch
+              v-model="row.status"
+              :value="row.status"
+              :true-value="1"
+              :false-value="0"
+              @on-change="changeSwitch(row, index)"
+              size="large"
+            >
+              <span slot="open">开启</span>
+              <span slot="close">关闭</span>
+            </i-switch>
+          </template>
+          <template slot-scope="{ row, index }" slot="action">
+            <template v-if="row.domain && row.domain != row.cname">
+              <span class="btn" @click="config(row)">CNAME配置</span>
+              <Divider type="vertical" />
+            </template>
+            <span class="btn" @click="edit(row)">修改空间域名</span>
+            <Divider type="vertical" />
+            <span class="btn" @click="del(row, '删除该数据', index)">删除</span>
+          </template>
+        </Table>
+        <div class="acea-row row-right page">
+          <Page
+            :total="total"
+            :current="list.page"
+            show-elevator
+            show-total
+            @on-change="pageChange"
+            :page-size="list.limit"
+          />
+        </div>
+      </Card>
+    </div>
+    <Modal v-model="configuModal" title="CNAME配置">
+      <div>
+        <div class="confignv"><span class="configtit">主机记录:</span>{{ configData.domain }}</div>
+        <div class="confignv"><span class="configtit">记录类型:</span>CNAME</div>
+        <div class="confignv">
+          <span class="configtit">记录值:</span>{{ configData.cname }}
+          <span class="copy copy-data" @click="insertCopy(configData.cname)">复制</span>
+        </div>
+      </div>
+      <div slot="footer"></div>
+    </Modal>
+    <Modal
+      v-model="modalPic"
+      width="950px"
+      scrollable
+      footer-hide
+      closable
+      title="上传商品图"
+      :mask-closable="false"
+      :z-index="888"
+    >
+      <uploadPictures
+        :isChoice="isChoice"
+        @getPic="getPic"
+        :gridBtn="gridBtn"
+        :gridPic="gridPic"
+        v-if="modalPic"
+      ></uploadPictures>
+    </Modal>
+  </div>
+</template>
+
+<script>
+import ClipboardJS from 'clipboard';
+import uploadPictures from '@/components/uploadPictures';
+
+import {
+  storageConfigApi,
+  addConfigApi,
+  addStorageApi,
+  storageListApi,
+  storageSynchApi,
+  storageSwitchApi,
+  storageStatusApi,
+  editStorageApi,
+  positionInfoApi,
+  positionPostApi,
+  saveType,
+} from '@/api/setting';
+export default {
+  components: { uploadPictures },
+  data() {
+    return {
+      modalPic: false,
+      saveType: 0,
+      isChoice: '单选',
+      gridBtn: {
+        xl: 4,
+        lg: 8,
+        md: 8,
+        sm: 8,
+        xs: 8,
+      },
+      gridPic: {
+        xl: 6,
+        lg: 8,
+        md: 12,
+        sm: 12,
+        xs: 12,
+      },
+      positionId: 1,
+      positiontlt: '',
+      formValidate: {
+        thumb_big_height: '',
+        thumb_big_width: '',
+        thumb_mid_width: '',
+        thumb_mid_height: '',
+        thumb_small_height: '',
+        thumb_small_width: '',
+        image_watermark_status: false,
+        watermark_type: 1,
+        watermark_opacity: '',
+        watermark_rotate: '',
+        watermark_position: 1,
+      },
+      boxs: [
+        { content: '左上', id: 1 },
+        { content: '上', id: 2 },
+        { content: '右上', id: 3 },
+        { content: '左中', id: 4 },
+        { content: '中', id: 5 },
+        { content: '右中', id: 6 },
+        { content: '左下', id: 7 },
+        { content: '下', id: 8 },
+        { content: '右下', id: 9 },
+      ],
+      ruleValidate: {},
+      configuModal: false,
+      configData: '',
+      headerList: [
+        { label: '储存配置', value: '1' },
+        { label: '七牛云储存', value: '2' },
+        { label: '阿里云储存', value: '3' },
+        { label: '腾讯云储存', value: '4' },
+        // { label: "缩略图配置", value: "5" },
+      ],
+      columns: [
+        {
+          title: '储存空间名称',
+          key: 'name',
+          align: 'center',
+          minWidth: 200,
+        },
+        {
+          title: '区域',
+          key: '_region',
+          align: 'center',
+          minWidth: 100,
+        },
+        {
+          title: '空间域名',
+          key: 'domain',
+          align: 'center',
+          minWidth: 200,
+        },
+        {
+          title: '使用状态',
+          slot: 'status',
+          align: 'center',
+          width: 90,
+        },
+        {
+          title: '创建时间',
+          key: '_add_time',
+          align: 'center',
+          minWidth: 150,
+        },
+        {
+          title: '更新时间',
+          key: '_update_time',
+          align: 'center',
+          minWidth: 150,
+        },
+        {
+          title: '操作',
+          slot: 'action',
+          width: 210,
+          align: 'center',
+        },
+      ],
+      total: 0,
+      list: {
+        page: 1,
+        limit: 15,
+        type: '1',
+      },
+      levelLists: [],
+      currentTab: '1',
+      loading: false,
+      addData: {
+        input: '',
+        select: '',
+        jurisdiction: '1',
+        type: '1',
+      },
+      confData: {
+        AccessKeyId: '',
+        AccessKeySecret: '',
+      },
+      localStorage: false,
+    };
+  },
+  created() {
+    storageConfigApi().then((res) => {
+      if (res.data.type == 1) {
+        this.localStorage = true;
+      }
+      this.formValidate.upload_type = res.data.type;
+      this.changeTab(res.data.type.toString());
+    });
+  },
+  methods: {
+    insertCopy(text) {
+      this.$copyText(text)
+        .then((message) => {
+          this.$Message.success('复制成功');
+        })
+        .catch((err) => {
+          this.$Message.error('复制失败');
+        });
+    },
+    changeSave(type) {
+      saveType(type)
+        .then((res) => {
+          this.$Message.success(res.msg);
+        })
+        .catch((err) => {
+          this.$Message.error(err.msg);
+        });
+    },
+    bindbox(item) {
+      this.positionId = item.id;
+      this.positiontlt = item.content;
+      this.formValidate.watermark_position = item.id;
+    },
+    handleSubmit(name) {
+      if (this.formValidate.image_watermark_status) {
+        this.formValidate.image_watermark_status = 1;
+      } else {
+        this.formValidate.image_watermark_status = 0;
+      }
+      if (this.formValidate.image_watermark_status) {
+        this.$refs[name].validate((valid) => {
+          if (valid) {
+            this.postMessage(this.formValidate);
+          } else {
+            this.$Message.error('Fail!');
+          }
+        });
+      } else {
+        this.postMessage(this.formValidate);
+      }
+    },
+    //保存接口
+    postMessage(data) {
+      positionPostApi(data)
+        .then((res) => {
+          this.$Message.success(res.msg);
+        })
+        .catch((err) => {
+          this.$Message.error(err.msg);
+        });
+    },
+    // 选择图片
+    modalPicTap() {
+      this.modalPic = true;
+    },
+    // 选中图片
+    getPic(pc) {
+      this.formValidate.watermark_image = pc.att_dir;
+      this.modalPic = false;
+    },
+    config(row) {
+      this.configuModal = true;
+      this.configData = row;
+    },
+    //同步储存空间
+    synchro() {
+      storageSynchApi(this.currentTab)
+        .then((res) => {
+          this.$Message.success(res.msg);
+          this.getlist();
+        })
+        .catch((err) => {
+          this.$Message.error(err.msg);
+        });
+    },
+    // 添加存储空间
+    addStorageBtn() {
+      this.$modalForm(addStorageApi(this.currentTab)).then(() => {
+        this.getlist();
+      });
+    },
+    // 修改配置信息
+    addConfigBtn() {
+      this.$modalForm(addConfigApi(this.currentTab)).then(() => {
+        this.getlist();
+      });
+    },
+    //修改空间域名
+    edit(row) {
+      this.$modalForm(editStorageApi(row.id)).then(() => {
+        this.getlist();
+      });
+    },
+    changeSwitch(row, item) {
+      return new Promise((resolve) => {
+        this.$Modal.confirm({
+          title: '切换状态',
+          content: '您确认要切换使用状态吗?',
+          onOk: () => {
+            // resolve();
+            storageStatusApi(row.id)
+              .then((res) => {
+                this.$Message.success(res.msg);
+                this.getlist();
+              })
+              .catch((err) => {
+                this.$Message.error(err.msg);
+              });
+          },
+          onCancel: () => {
+            this.$Message.info('已取消');
+            this.getlist();
+          },
+        });
+      });
+    },
+    getlist() {
+      this.loading = true;
+      storageListApi(this.list).then((res) => {
+        this.total = res.data.count;
+        this.levelLists = res.data.list;
+        this.loading = false;
+      });
+    },
+    changeTab(data) {
+      this.currentTab = data;
+      this.list.type = data;
+      this.list.page = 1;
+      if (data == 1) {
+        this.getposition();
+      } else {
+        this.getlist();
+      }
+    },
+    getposition() {
+      let that = this;
+      positionInfoApi().then((res) => {
+        this.formValidate = res.data;
+        if (res.data.image_watermark_status == 1) {
+          that.formValidate.image_watermark_status = true;
+        } else {
+          that.formValidate.image_watermark_status = false;
+        }
+        this.positionId = res.data.watermark_position;
+        for (var i = 0; i < this.boxs.length; i++) {
+          if (this.boxs[i].id == res.data.watermark_position) {
+            that.bindbox(this.boxs[i]);
+          }
+        }
+      });
+    },
+    addSwitch(e) {
+      if (e) {
+        this.localStorage = 1;
+      }
+      storageSwitchApi({ type: this.localStorage })
+        .then((res) => {
+          this.$Message.success(res.msg);
+          this.getlist();
+        })
+        .catch((err) => {
+          this.$Message.error(err.msg);
+        });
+    },
+    // 删除
+    del(row, tit, num) {
+      let delfromData = {
+        title: tit,
+        num: num,
+        url: `system/config/storage/${row.id}`,
+        method: 'DELETE',
+        ids: '',
+      };
+      this.$modalSure(delfromData)
+        .then((res) => {
+          this.$Message.success(res.msg);
+          this.getlist();
+        })
+        .catch((res) => {
+          this.$Message.error(res.msg);
+        });
+    },
+    pageChange(index) {
+      this.list.page = index;
+      this.getlist();
+    },
+  },
+};
+</script>
+<style scoped lang="less">
+.ivu-input-group > .ivu-input:last-child,
+/deep/.ivu-input-group-append {
+  background: none;
+  color: #999999;
+}
+/deep/.ivu-input-group .ivu-input {
+  border-right: 0px !important;
+}
+.content /deep/.ivu-form .ivu-form-item-label {
+  width: 133px;
+}
+.topIput {
+  width: 186px;
+  background: #ffffff;
+  border-right: 0px !important;
+}
+.abbreviation {
+  .top {
+    display: flex;
+    justify-content: flex-start;
+    .topBox {
+      display: flex;
+      .topRight {
+        width: 254px;
+        margin-left: 36px;
+      }
+      .topLeft {
+        width: 94px;
+        height: 94px;
+
+        text-align: center;
+        font-size: 13px;
+        font-weight: 400;
+        color: #000000;
+        .img {
+          // width: 84px;
+          height: 67px;
+          background: #f7fbff;
+          border-radius: 4px;
+          margin-bottom: 9px;
+          .imgs {
+            width: 70px;
+            height: 51px;
+            display: inline-block;
+            text-align: center;
+            margin-top: 8px;
+          }
+        }
+      }
+    }
+  }
+  .content {
+    /deep/.ivu-form-item-label {
+      width: 120px;
+    }
+    .flex {
+      display: flex;
+      justify-content: flex-start;
+      // width: 400px;
+
+      .contentIput {
+        width: 400px;
+      }
+      .conents {
+        display: flex;
+        .title {
+          width: 30px;
+          margin-top: 70px;
+          margin-left: 6px;
+        }
+        .positionBox {
+          display: flex;
+          flex-wrap: wrap;
+          width: 101px;
+          height: 99px;
+          border-right: 1px solid #dddddd;
+          .box {
+            width: 33px;
+            height: 33px;
+            // border-radius: 4px 0px 0px 0px;
+            border: 1px solid #dddddd;
+            cursor: pointer;
+          }
+          .on {
+            background: rgba(24, 144, 255, 0.1);
+          }
+        }
+      }
+    }
+  }
+}
+</style>
+<style scoped>
+.message /deep/ .ivu-table-header thead tr th {
+  padding: 8px 16px;
+}
+.ivu-radio-wrapper {
+  margin-right: 15px;
+  font-size: 12px !important;
+}
+.message /deep/ .ivu-tabs-tab {
+  border-radius: 0 !important;
+}
+.table-box {
+  padding: 20px;
+}
+.is-table {
+  display: flex;
+  /* justify-content: space-around; */
+  justify-content: center;
+}
+.btn {
+  cursor: pointer;
+  color: #2d8cf0;
+  font-size: 10px;
+}
+.is-switch-close {
+  background-color: #504444;
+}
+.is-switch {
+  background-color: #eb5252;
+}
+.notice-list {
+  background-color: #308cf5;
+  margin: 0 15px;
+}
+.table {
+  padding: 0 18px;
+}
+.confignv {
+  margin: 10px 0px;
+}
+.configtit {
+  display: inline-block;
+  width: 60px;
+  text-align: right;
+}
+.copy {
+  padding: 3px 5px;
+  border: 1px solid #cccccc;
+  border-radius: 5px;
+  color: #333;
+  cursor: pointer;
+  margin-left: 5px;
+}
+.copy:hover {
+  border-color: #2d8cf0;
+  color: #2d8cf0;
+}
+.picBox {
+  display: inline-block;
+  cursor: pointer;
+}
+.picBox .pictrue {
+  width: 60px;
+  height: 60px;
+  border: 1px dotted rgba(0, 0, 0, 0.1);
+  margin-right: 10px;
+}
+
+.picBox .pictrue img {
+  width: 100%;
+  height: 100%;
+}
+.picBox .upLoad {
+  width: 58px;
+  height: 58px;
+  line-height: 58px;
+  border: 1px dotted rgba(0, 0, 0, 0.1);
+  border-radius: 4px;
+  background: rgba(0, 0, 0, 0.02);
+}
+h3 {
+  margin: 5px 0 15px 0;
+}
+.table-box p {
+  margin-bottom: 10px;
+}
+.save-type {
+  font-size: 13px;
+}
+</style>

+ 270 - 0
src/pages/shop_setting/storeList/index.vue

@@ -0,0 +1,270 @@
+<template>
+  <div>
+    <Card :bordered="false" dis-hover class="ivu-mt">
+      <div class="mb20">
+        <Tabs v-model="artFrom.type" @on-click="onClickTab">
+          <TabPane :label="headeNum.show.name + '(' + headeNum.show.num + ')'" name="0" />
+          <TabPane :label="headeNum.hide.name + '(' + headeNum.hide.num + ')'" name="1" />
+          <TabPane :label="headeNum.recycle.name + '(' + headeNum.recycle.num + ')'" name="2" />
+        </Tabs>
+      </div>
+      <Form
+        ref="artFrom"
+        :model="artFrom"
+        :label-width="labelWidth"
+        :label-position="labelPosition"
+        @submit.native.prevent
+      >
+        <Row type="flex" :gutter="24">
+          <Col v-bind="grid" class="mr">
+            <FormItem label="提货点搜索:" label-for="store_name">
+              <Input
+                search
+                enter-button
+                placeholder="请输入提货点名称,电话"
+                v-model="artFrom.keywords"
+                @on-search="userSearchs"
+              />
+            </FormItem>
+          </Col>
+          <!--                    <Col v-bind="grid">-->
+          <!--                        <Button class="mr">导出</Button>-->
+          <!--                    </Col>-->
+        </Row>
+      </Form>
+      <Row type="flex" v-auth="['setting-merchant-system_store-save']">
+        <Col v-bind="grid">
+          <Button v-auth="['setting-merchant-system_store-save']" type="primary" icon="md-add" @click="add"
+            >添加提货点</Button
+          >
+        </Col>
+      </Row>
+      <Table
+        :columns="columns"
+        :data="storeLists"
+        ref="table"
+        class="mt25"
+        :loading="loading"
+        highlight-row
+        no-userFrom-text="暂无数据"
+        no-filtered-userFrom-text="暂无筛选结果"
+      >
+        <template slot-scope="{ row, index }" slot="image">
+          <div class="tabBox_img" v-viewer>
+            <img v-lazy="row.image" />
+          </div>
+        </template>
+        <template slot-scope="{ row, index }" slot="is_show">
+          <i-switch
+            v-model="row.is_show"
+            :value="row.is_show"
+            :true-value="1"
+            :false-value="0"
+            @on-change="onchangeIsShow(row.id, row.is_show)"
+            size="large"
+            >>
+            <span slot="open">显示</span>
+            <span slot="close">隐藏</span>
+          </i-switch>
+        </template>
+        <template slot-scope="{ row, index }" slot="action">
+          <a @click="edit(row.id)">编辑</a>
+          <Divider type="vertical" />
+          <a v-if="row.is_del == 0" @click="del(row, '删除提货点', index)">删除</a>
+          <a v-else @click="del(row, '恢复提货点', index)">恢复</a>
+        </template>
+      </Table>
+      <div class="acea-row row-right page">
+        <Page
+          :total="total"
+          :current="artFrom.page"
+          show-elevator
+          show-total
+          @on-change="pageChange"
+          :page-size="artFrom.limit"
+        />
+      </div>
+    </Card>
+    <system-store ref="template"></system-store>
+  </div>
+</template>
+
+<script>
+import { mapState } from 'vuex';
+import { storeGetHeaderApi, merchantStoreApi, storeSetShowApi } from '@/api/setting';
+import systemStore from '@/components/systemStore/index';
+export default {
+  name: 'setting_store',
+  components: { systemStore },
+  computed: {
+    ...mapState('media', ['isMobile']),
+    ...mapState('userLevel', ['categoryId']),
+    labelWidth() {
+      return this.isMobile ? undefined : 85;
+    },
+    labelPosition() {
+      return this.isMobile ? 'top' : 'left';
+    },
+  },
+  data() {
+    return {
+      grid: {
+        xl: 10,
+        lg: 10,
+        md: 12,
+        sm: 24,
+        xs: 24,
+      },
+      headeNum: {
+        show: { name: '', num: 0 },
+        hide: { name: '', num: 0 },
+        recycle: { name: '', num: 0 },
+      },
+      artFrom: {
+        page: 1,
+        limit: 15,
+        type: '0',
+        keywords: '',
+      },
+      loading: false,
+      columns: [
+        {
+          title: 'ID',
+          key: 'id',
+          width: 80,
+          sortable: true,
+        },
+        {
+          title: '提货点图片',
+          slot: 'image',
+          minWidth: 100,
+        },
+        {
+          title: '提货点名称',
+          key: 'name',
+          minWidth: 100,
+        },
+        {
+          title: '提货点电话',
+          key: 'phone',
+          minWidth: 100,
+        },
+        {
+          title: '地址',
+          key: 'detailed_address',
+          minWidth: 100,
+        },
+        {
+          title: '营业时间',
+          key: 'day_time',
+          minWidth: 100,
+        },
+        {
+          title: '是否显示',
+          slot: 'is_show',
+          minWidth: 100,
+        },
+        {
+          title: '操作',
+          slot: 'action',
+          fixed: 'right',
+          minWidth: 120,
+        },
+      ],
+      storeLists: [],
+      total: 0,
+    };
+  },
+  mounted() {
+    this.storeHeade();
+    this.getList();
+  },
+  methods: {
+    // 获取表单头部信息;
+    storeHeade() {
+      let that = this;
+      storeGetHeaderApi()
+        .then((res) => {
+          that.headeNum = res.data.count;
+        })
+        .catch((res) => {
+          this.$Message.error(res.msg);
+        });
+    },
+    getList() {
+      let that = this;
+      that.loading = true;
+      merchantStoreApi(that.artFrom)
+        .then((res) => {
+          that.loading = false;
+          that.storeLists = res.data.list;
+          that.total = res.data.count;
+        })
+        .catch((res) => {
+          this.$Message.error(res.msg);
+        });
+    },
+    // 搜索;
+    userSearchs() {
+      this.artFrom.page = 1;
+      this.getList();
+    },
+    // 切换导航;
+    onClickTab() {
+      this.artFrom.page = 1;
+      this.artFrom.keywords = '';
+      this.getList();
+    },
+    pageChange(index) {
+      this.artFrom.page = index;
+      this.getList();
+    },
+    // 删除
+    del(row, tit, num) {
+      let delfromData = {
+        title: tit,
+        num: num,
+        url: `merchant/store/del/${row.id}`,
+        method: 'DELETE',
+        ids: '',
+      };
+      this.$modalSure(delfromData)
+        .then((res) => {
+          this.$Message.success(res.msg);
+          this.storeLists.splice(num, 1);
+          this.storeHeade();
+        })
+        .catch((res) => {
+          this.$Message.error(res.msg);
+        });
+    },
+    // 添加提货点;
+    add() {
+      this.$refs.template.isTemplate = true;
+    },
+    onchangeIsShow(id, is_show) {
+      let that = this;
+      storeSetShowApi(id, is_show).then((res) => {
+        that.$Message.success(res.msg);
+        that.getList();
+        that.storeHeade();
+      });
+    },
+    edit(id) {
+      this.$refs.template.isTemplate = true;
+      this.$refs.template.getInfo(id);
+    },
+  },
+};
+</script>
+
+<style scoped lang="stylus">
+.tabBox_img
+    width 36px
+    height 36px
+    border-radius:4px
+    cursor pointer
+    img
+        width 100%
+        height 100%
+</style>

+ 217 - 0
src/pages/shop_setting/storeService/feedback.vue

@@ -0,0 +1,217 @@
+<template>
+  <div>
+    <Card :bordered="false" dis-hover class="ivu-mt">
+      <Form
+        ref="formValidate"
+        :model="formValidate"
+        :label-width="labelWidth"
+        :label-position="labelPosition"
+        class="tabform"
+        @submit.native.prevent
+      >
+        <Row :gutter="24" type="flex" justify="end">
+          <Col span="24" class="ivu-text-left">
+            <FormItem label="留言信息:">
+              <Input
+                search
+                enter-button
+                @on-search="selChange"
+                placeholder="请输入用户昵称/电话/留言内容搜索"
+                element-id="name"
+                v-model="formValidate.title"
+                style="width: 30%; display: inline-table"
+                class="mr"
+              />
+            </FormItem>
+          </Col>
+          <Col span="24" class="ivu-text-left">
+            <FormItem label="留言时间:">
+              <RadioGroup
+                v-model="formValidate.time"
+                type="button"
+                @on-change="selectChange(formValidate.time)"
+                class="mr"
+              >
+                <Radio :label="item.val" v-for="(item, i) in fromList.fromTxt" :key="i">{{ item.text }}</Radio>
+              </RadioGroup>
+              <DatePicker
+                :editable="false"
+                @on-change="onchangeTime"
+                :value="timeVal"
+                format="yyyy/MM/dd"
+                type="daterange"
+                placement="bottom-end"
+                placeholder="请选择时间"
+                style="width: 200px"
+              ></DatePicker>
+            </FormItem>
+          </Col>
+        </Row>
+      </Form>
+      <Table
+        :columns="columns1"
+        :data="list"
+        :loading="loading"
+        no-userFrom-text="暂无数据"
+        no-filtered-userFrom-text="暂无筛选结果"
+      >
+        <template slot-scope="{ row, index }" slot="status">
+          <div>{{ row.status === 1 ? '已处理' : '未处理' }}</div>
+        </template>
+        <template slot-scope="{ row, index }" slot="action">
+          <a @click="remarks(row.id)">{{ row.status === 1 ? '备注' : '处理' }}</a>
+          <Divider type="vertical" />
+          <a @click="del(row, '删除反馈', index)">删除</a>
+        </template>
+      </Table>
+      <div class="acea-row row-right page">
+        <Page :total="count" show-elevator show-total @on-change="pageChange" :page-size="limit" />
+      </div>
+    </Card>
+  </div>
+</template>
+
+<script>
+import { kefuFeedBack, kefuFeedBackEdit } from '@/api/setting';
+import { mapState } from 'vuex';
+export default {
+  name: 'feedback',
+  data() {
+    return {
+      loading: false,
+      list: [],
+      page: 1,
+      limit: 15,
+      formValidate: {
+        time: '',
+        title: '',
+      },
+      fromList: {
+        title: '选择时间',
+        custom: true,
+        fromTxt: [
+          { text: '全部', val: '' },
+          { text: '今天', val: 'today' },
+          { text: '昨天', val: 'yesterday' },
+          { text: '最近7天', val: 'lately7' },
+          { text: '最近30天', val: 'lately30' },
+          { text: '本月', val: 'month' },
+          { text: '本年', val: 'year' },
+        ],
+      },
+      timeVal: [],
+      count: 0,
+      columns1: [
+        {
+          title: 'ID',
+          key: 'id',
+          width: 80,
+        },
+        {
+          title: '昵称',
+          key: 'rela_name',
+          minWidth: 120,
+        },
+        {
+          title: '电话',
+          key: 'phone',
+          minWidth: 120,
+        },
+        {
+          title: '内容',
+          key: 'content',
+          minWidth: 320,
+        },
+        {
+          title: '状态',
+          slot: 'status',
+          minWidth: 120,
+        },
+        {
+          title: '时间',
+          key: 'add_time',
+          minWidth: 120,
+        },
+        {
+          title: '操作',
+          slot: 'action',
+          fixed: 'right',
+          minWidth: 150,
+        },
+      ],
+    };
+  },
+  computed: {
+    ...mapState('media', ['isMobile']),
+    labelWidth() {
+      return this.isMobile ? undefined : 80;
+    },
+    labelPosition() {
+      return this.isMobile ? 'top' : 'right';
+    },
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    //备注;
+    remarks(id) {
+      this.$modalForm(kefuFeedBackEdit(id)).then(() => this.getList());
+    },
+    // 选择
+    selChange() {
+      this.page = 1;
+      this.getList();
+    },
+    // 选择时间
+    selectChange(tab) {
+      this.formValidate.time = tab;
+      this.timeVal = [];
+      this.page = 1;
+      this.getList();
+    },
+    // 具体日期
+    onchangeTime(e) {
+      this.timeVal = e;
+      this.formValidate.time = this.timeVal.join('-');
+      this.page = 1;
+      this.getList();
+    },
+    getList() {
+      kefuFeedBack({
+        page: this.page,
+        limit: this.limit,
+        time: this.formValidate.time,
+        title: this.formValidate.title,
+      }).then((res) => {
+        this.list = res.data.data;
+        this.count = res.data.count;
+      });
+    },
+    // 删除
+    del(row, tit, num) {
+      let delfromData = {
+        title: tit,
+        num: num,
+        url: `/app/feedback/${row.id}`,
+        method: 'DELETE',
+        ids: '',
+      };
+      this.$modalSure(delfromData)
+        .then((res) => {
+          this.$Message.success(res.msg);
+          this.list.splice(num, 1);
+        })
+        .catch((res) => {
+          this.$Message.error(res.msg);
+        });
+    },
+    pageChange(index) {
+      this.page = index;
+      this.getList();
+    },
+  },
+};
+</script>
+
+<style scoped></style>

+ 665 - 0
src/pages/shop_setting/storeService/index.vue

@@ -0,0 +1,665 @@
+<template>
+  <div>
+    <Card :bordered="false" dis-hover class="ivu-mt">
+      <Row type="flex" class="mb20">
+        <Col span="24">
+          <Button v-auth="['setting-store_service-add']" type="primary" icon="md-add" @click="add" class="mr10"
+            >添加客服</Button
+          >
+        </Col>
+      </Row>
+      <Table
+        :columns="columns1"
+        :data="tableList"
+        :loading="loading"
+        highlight-row
+        no-userFrom-text="暂无数据"
+        no-filtered-userFrom-text="暂无筛选结果"
+      >
+        <template slot-scope="{ row, index }" slot="avatar">
+          <div class="tabBox_img" v-viewer>
+            <img v-lazy="row.avatar" />
+          </div>
+        </template>
+        <template slot-scope="{ row, index }" slot="status">
+          <i-switch
+            v-model="row.status"
+            :value="row.status"
+            :true-value="1"
+            :false-value="0"
+            @on-change="onchangeIsShow(row)"
+            size="large"
+          >
+            <span slot="open">开启</span>
+            <span slot="close">关闭</span>
+          </i-switch>
+        </template>
+        <template slot-scope="{ row, index }" slot="stop_time">
+          <span> {{ row.stop_time | formatDate }}</span>
+        </template>
+
+        <template slot-scope="{ row, index }" slot="action">
+          <a @click="edit(row)">编辑</a>
+          <Divider type="vertical" />
+          <a @click="del(row, '删除客服', index)">删除</a>
+          <Divider type="vertical" v-if="row.status" />
+          <a @click="goChat(row)" v-if="row.status">进入工作台</a>
+        </template>
+      </Table>
+      <div class="acea-row row-right page">
+        <Page :total="total" show-elevator show-total @on-change="pageChange" :page-size="tableFrom.limit" />
+      </div>
+    </Card>
+
+    <!--添加客户-->
+    <!--<Modal v-model="modals" scrollable   closable title="添加客服"  width="1000"  @on-cancel="cancel">-->
+    <!--<Form ref="formValidate" :model="formValidate" :label-width="labelWidth" :label-position="labelPosition" @submit.native.prevent>-->
+    <!--<Row :gutter="24" type="flex">-->
+    <!--<Col span="24" class="ivu-text-left">-->
+    <!--<FormItem label="选择时间:">-->
+    <!--<RadioGroup v-model="formValidate.data" type="button" @on-change="selectChange(formValidate.data)"-->
+    <!--class="mr">-->
+    <!--<Radio :label=item.val v-for="(item,i) in fromList.fromTxt" :key="i">{{item.text}}</Radio>-->
+    <!--</RadioGroup>-->
+    <!--<DatePicker @on-change="onchangeTime" :value="timeVal" format="yyyy/MM/dd" type="daterange"-->
+    <!--placement="bottom-end" placeholder="请选择时间" style="width: 200px;"></DatePicker>-->
+    <!--</FormItem>-->
+    <!--</Col>-->
+    <!--<Col span="12" class="ivu-text-left">-->
+    <!--<FormItem label="用户名称:" >-->
+    <!--<Input search enter-button  placeholder="请输入用户名称" v-model="formValidate.nickname" style="width: 90%;" @on-search="userSearchs"></Input>-->
+    <!--</FormItem>-->
+    <!--</Col>-->
+    <!--<Col span="12" class="ivu-text-left">-->
+    <!--<FormItem label="用户类型:" >-->
+    <!--<Select v-model="formValidate.type" style="width:90%;" @on-change="userSearchs">-->
+    <!--<Option value="">全部用户</Option>-->
+    <!--<Option value="wechat">公众号</Option>-->
+    <!--<Option value="routine">小程序</Option>-->
+    <!--</Select>-->
+    <!--</FormItem>-->
+    <!--</Col>-->
+    <!--</Row>-->
+    <!--</Form>-->
+    <!--<Table :loading="loading2" highlight-row no-userFrom-text="暂无数据" max-height="400"-->
+    <!--@on-selection-change="onSelectTab"-->
+    <!--no-filtered-userFrom-text="暂无筛选结果" ref="selection" :columns="columns4" :data="tableList2">-->
+    <!--<template slot-scope="{ row, index }" slot="headimgurl">-->
+    <!--<viewer>-->
+    <!--<div class="tabBox_img">-->
+    <!--<img v-lazy="row.headimgurl">-->
+    <!--</div>-->
+    <!--</viewer>-->
+    <!--</template>-->
+    <!--<template slot-scope="{ row, index }" slot="user_type">-->
+    <!--<span>{{ row.user_type | typeFilter }}</span>-->
+    <!--</template>-->
+    <!--<template slot-scope="{ row, index }" slot="sex">-->
+    <!--<span v-show="row.sex ===1">男</span>-->
+    <!--<span v-show="row.sex ===2">女</span>-->
+    <!--<span v-show="row.sex ===0">保密</span>-->
+    <!--</template>-->
+    <!--<template slot-scope="{ row, index }" slot="country">-->
+    <!--<span>{{row.country + row.province + row.city}}</span>-->
+    <!--</template>-->
+    <!--<template slot-scope="{ row, index }" slot="subscribe">-->
+    <!--<span v-text="row.subscribe === 1?'关注':'未关注'"></span>-->
+    <!--</template>-->
+    <!--</Table>-->
+    <!--<div class="acea-row row-right page">-->
+    <!--<Page :total="total2" :current="formValidate.page" show-elevator show-total @on-change="pageChange2"-->
+    <!--:page-size="formValidate.limit"/>-->
+    <!--</div>-->
+    <!--<div slot="footer">-->
+    <!--<Button  type="primary"  @click="putRemark">提交</Button>-->
+    <!--</div>-->
+    <!--</Modal>-->
+
+    <!--聊天记录-->
+    <Modal v-model="modals3" footer-hide scrollable closable title="聊天记录" width="700">
+      <div v-if="isChat" class="modelBox">
+        <Table
+          :loading="loading3"
+          highlight-row
+          no-userFrom-text="暂无数据"
+          no-filtered-userFrom-text="暂无筛选结果"
+          :columns="columns3"
+          :data="tableList3"
+        >
+          <template slot-scope="{ row, index }" slot="headimgurl">
+            <div class="tabBox_img" v-viewer>
+              <img v-lazy="row.headimgurl" />
+            </div>
+          </template>
+          <template slot-scope="{ row, index }" slot="action">
+            <a @click="look(row)">查看对话</a>
+          </template>
+        </Table>
+        <div class="acea-row row-right page">
+          <Page :total="total3" show-elevator show-total @on-change="pageChange3" :page-size="formValidate3.limit" />
+        </div>
+      </div>
+      <div v-if="!isChat">
+        <Button type="primary" @click="isChat = true">返回聊天记录</Button>
+        <Table
+          :loading="loading5"
+          highlight-row
+          no-userFrom-text="暂无数据"
+          class="mt20"
+          no-filtered-userFrom-text="暂无筛选结果"
+          :columns="columns5"
+          :data="tableList5"
+        >
+          <template slot-scope="{ row, index }" slot="avatar">
+            <div class="tabBox_img" v-viewer>
+              <img v-lazy="row.avatar" />
+            </div>
+          </template>
+          <template slot-scope="{ row, index }" slot="action">
+            <a @click="look(row)">查看对话</a>
+          </template>
+        </Table>
+        <div class="acea-row row-right page">
+          <Page :total="total5" show-elevator show-total @on-change="pageChange5" :page-size="formValidate5.limit" />
+        </div>
+      </div>
+    </Modal>
+  </div>
+</template>
+
+<script>
+import { mapState } from 'vuex';
+import { setCookies } from '@/libs/util';
+import {
+  kefuListApi,
+  kefucreateApi,
+  kefuaddApi,
+  kefuAddApi,
+  kefusetStatusApi,
+  kefuEditApi,
+  kefuRecordApi,
+  kefuChatlistApi,
+  kefuLogin,
+} from '@/api/setting';
+export default {
+  name: 'index',
+  filters: {
+    typeFilter(status) {
+      const statusMap = {
+        wechat: '微信用户',
+        routine: '小程序用户',
+      };
+      return statusMap[status];
+    },
+  },
+  computed: {
+    ...mapState('media', ['isMobile']),
+    ...mapState('userLevel', ['categoryId']),
+    labelWidth() {
+      return this.isMobile ? undefined : 80;
+    },
+    labelPosition() {
+      return this.isMobile ? 'top' : 'left';
+    },
+  },
+  data() {
+    return {
+      isChat: true,
+      formValidate3: {
+        page: 1,
+        limit: 15,
+      },
+      total3: 0,
+      loading3: false,
+      modals3: false,
+      tableList3: [],
+      columns3: [
+        {
+          title: '用户名称',
+          key: 'nickname',
+          width: 200,
+        },
+        {
+          title: '客服头像',
+          slot: 'headimgurl',
+        },
+        {
+          title: '操作',
+          slot: 'action',
+        },
+      ],
+      formValidate5: {
+        page: 1,
+        limit: 15,
+        uid: 0,
+        to_uid: 0,
+        id: 0,
+      },
+      total5: 0,
+      loading5: false,
+      tableList5: [],
+      columns5: [
+        {
+          title: '用户名称',
+          key: 'nickname',
+          width: 200,
+        },
+        {
+          title: '用户头像',
+          slot: 'avatar',
+        },
+        {
+          title: '发送消息',
+          key: 'msn',
+          width: 250,
+        },
+        {
+          title: '发送时间',
+          key: 'add_time',
+        },
+      ],
+      FromData: null,
+      formValidate: {
+        page: 1,
+        limit: 15,
+        data: '',
+        type: '',
+        nickname: '',
+      },
+      tableList2: [],
+      modals: false,
+      total: 0,
+      tableFrom: {
+        page: 1,
+        limit: 15,
+      },
+      timeVal: [],
+      fromList: {
+        title: '选择时间',
+        custom: true,
+        fromTxt: [
+          { text: '全部', val: '' },
+          { text: '今天', val: 'today' },
+          { text: '昨天', val: 'yesterday' },
+          { text: '最近7天', val: 'lately7' },
+          { text: '最近30天', val: 'lately30' },
+          { text: '本月', val: 'month' },
+          { text: '本年', val: 'year' },
+        ],
+      },
+      loading: false,
+      tableList: [],
+      columns1: [
+        {
+          title: 'ID',
+          key: 'id',
+          width: 80,
+        },
+        {
+          title: '微信用户名称',
+          key: 'nickname',
+          minWidth: 120,
+        },
+        {
+          title: '客服头像',
+          slot: 'avatar',
+          minWidth: 60,
+        },
+        {
+          title: '客服名称',
+          key: 'wx_name',
+          minWidth: 120,
+        },
+        {
+          title: '客服状态',
+          slot: 'status',
+          minWidth: 120,
+        },
+        {
+          title: '添加时间',
+          key: 'add_time',
+          minWidth: 120,
+        },
+        {
+          title: '操作',
+          slot: 'action',
+          fixed: 'right',
+          minWidth: 150,
+        },
+      ],
+      columns4: [
+        {
+          type: 'selection',
+          width: 60,
+          align: 'center',
+        },
+        {
+          title: 'ID',
+          key: 'uid',
+          width: 80,
+        },
+        {
+          title: '微信用户名称',
+          key: 'nickname',
+          minWidth: 160,
+        },
+        {
+          title: '客服头像',
+          slot: 'headimgurl',
+          minWidth: 60,
+        },
+        {
+          title: '用户类型',
+          slot: 'user_type',
+          width: 100,
+        },
+        {
+          title: '性别',
+          slot: 'sex',
+          minWidth: 60,
+        },
+        {
+          title: '地区',
+          slot: 'country',
+          minWidth: 120,
+        },
+        {
+          title: '是否关注公众号',
+          slot: 'subscribe',
+          minWidth: 120,
+        },
+      ],
+      loading2: false,
+      total2: 0,
+      addFrom: {
+        uids: [],
+      },
+      selections: [],
+      rows: {},
+      rowRecord: {},
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    // 进入工作台
+    goChat(item) {
+      kefuLogin(item.id)
+        .then((res) => {
+          var url = '';
+          if (res.data.token) {
+            let expires = this.getExpiresTime(res.data.exp_time);
+            setCookies('kefu_token', res.data.token, expires);
+            setCookies('kefu_uuid', res.data.kefuInfo.uid, expires);
+            setCookies('kefu_expires_time', res.data.exp_time, expires);
+            setCookies('kefuInfo', res.data.kefuInfo, expires);
+            if (this.$store.state.media.isMobile) {
+              url = window.location.protocol + '//' + window.location.host + '/kefu/mobile_list';
+            } else {
+              url = window.location.protocol + '//' + window.location.host + '/kefu/pc_list';
+            }
+
+            window.open(url, '_blank');
+          }
+        })
+        .catch((error) => {
+          this.$Message.error(error.msg);
+        });
+    },
+    getExpiresTime(expiresTime) {
+      let nowTimeNum = Math.round(new Date() / 1000);
+      let expiresTimeNum = expiresTime - nowTimeNum;
+      return parseFloat(parseFloat(parseFloat(expiresTimeNum / 60) / 60) / 24);
+    },
+    cancel() {
+      this.formValidate = {
+        page: 1,
+        limit: 10,
+        data: '',
+        type: '',
+        nickname: '',
+      };
+    },
+    handleReachBottom() {
+      return new Promise((resolve) => {
+        this.formValidate.page = this.formValidate.page + 1;
+        setTimeout(() => {
+          // this.loading2 = true;
+          kefucreateApi(this.formValidate)
+            .then(async (res) => {
+              let data = res.data;
+              // this.tableList2 = data.list;
+              if (data.list.length > 0) {
+                for (let i = 0; i < data.list.length; i++) {
+                  this.tableList2.push(data.list[i]);
+                }
+              }
+              this.total2 = data.count;
+              this.loading2 = false;
+            })
+            .catch((res) => {
+              this.loading2 = false;
+              this.$Message.error(res.msg);
+            });
+          resolve();
+        }, 2000);
+      });
+    },
+    // 查看对话
+    look(row) {
+      this.isChat = false;
+      this.rowRecord = row;
+      this.getChatlist();
+    },
+    // 查看对话列表
+    getChatlist() {
+      this.loading5 = true;
+      this.formValidate5.uid = this.rows.uid;
+      this.formValidate5.to_uid = this.rowRecord.uid;
+      this.formValidate5.id = this.rows.id;
+      kefuChatlistApi(this.formValidate5)
+        .then(async (res) => {
+          let data = res.data;
+          this.tableList5 = data.list;
+          this.total5 = data.count;
+          this.loading5 = false;
+        })
+        .catch((res) => {
+          this.loading5 = false;
+          this.$Message.error(res.msg);
+        });
+    },
+    pageChange5(index) {
+      this.formValidate5.page = index;
+      this.getChatlist();
+    },
+    // 修改成功
+    submitFail() {
+      this.getList();
+    },
+    // 聊天记录
+    record(row) {
+      this.rows = row;
+      this.modals3 = true;
+      this.isChat = true;
+      this.getListRecord();
+    },
+    // 聊天记录列表
+    getListRecord() {
+      this.loading3 = true;
+      kefuRecordApi(this.formValidate3, this.rows.id)
+        .then(async (res) => {
+          let data = res.data;
+          this.tableList3 = data.list ? data.list : [];
+          this.total3 = data.count;
+          this.loading3 = false;
+        })
+        .catch((res) => {
+          this.loading3 = false;
+          this.$Message.error(res.msg);
+        });
+    },
+    pageChange3(index) {
+      this.formValidate3.page = index;
+      this.getListRecord();
+    },
+    // 编辑
+    edit(row) {
+      this.$modalForm(kefuEditApi(row.id)).then(() => this.getList());
+    },
+    // 添加
+    add() {
+      // this.modals = true;
+      // this.formValidate.data = '';
+      // this.getListService();
+      this.$modalForm(kefuaddApi()).then(() => this.getList());
+    },
+    // 全选
+    onSelectTab(selection) {
+      this.selections = selection;
+      let data = [];
+      this.selections.map((item) => {
+        data.push(item.uid);
+      });
+      this.addFrom.uids = data;
+    },
+    // 具体日期
+    onchangeTime(e) {
+      this.timeVal = e;
+      this.formValidate.data = this.timeVal.join('-');
+      this.formValidate.page = 1;
+      this.getListService();
+    },
+    // 选择时间
+    selectChange(tab) {
+      this.formValidate.data = tab;
+      this.timeVal = [];
+      this.formValidate.page = 1;
+      this.getListService();
+    },
+    // 客服列表
+    getListService() {
+      this.loading2 = true(this.formValidate)
+        .then(async (res) => {
+          let data = res.data;
+          this.tableList2 = data.list;
+          this.total2 = data.count;
+          this.tableList2.map((item) => {
+            item._isChecked = false;
+          });
+          this.loading2 = false;
+        })
+        .catch((res) => {
+          tkefucreateApihis.loading2 = false;
+          this.$Message.error(res.msg);
+        });
+    },
+    pageChange2(pageIndex) {
+      this.formValidate.page = pageIndex;
+      this.getListService();
+      this.addFrom.uids = [];
+    },
+    // 搜索
+    userSearchs() {
+      this.formValidate.page = 1;
+      this.getListService();
+    },
+    // 删除
+    del(row, tit, num) {
+      let delfromData = {
+        title: tit,
+        num: num,
+        url: `app/wechat/kefu/${row.id}`,
+        method: 'DELETE',
+        ids: '',
+      };
+      this.$modalSure(delfromData)
+        .then((res) => {
+          this.$Message.success(res.msg);
+          this.tableList.splice(num, 1);
+        })
+        .catch((res) => {
+          this.$Message.error(res.msg);
+        });
+    },
+    // 列表
+    getList() {
+      this.loading = true;
+      kefuListApi(this.tableFrom)
+        .then(async (res) => {
+          let data = res.data;
+          this.tableList = data.list;
+          this.total = res.data.count;
+          this.loading = false;
+        })
+        .catch((res) => {
+          this.loading = false;
+          this.$Message.error(res.msg);
+        });
+    },
+    pageChange(index) {
+      this.tableFrom.page = index;
+      this.getList();
+    },
+    // 修改是否显示
+    onchangeIsShow(row) {
+      let data = {
+        id: row.id,
+        status: row.status,
+      };
+      kefusetStatusApi(data)
+        .then(async (res) => {
+          this.$Message.success(res.msg);
+          this.getList();
+        })
+        .catch((res) => {
+          this.$Message.error(res.msg);
+        });
+    },
+    // 添加客服
+    putRemark() {
+      if (this.addFrom.uids.length === 0) {
+        return this.$Message.warning('请选择要添加的客服');
+      }
+      kefuAddApi(this.addFrom)
+        .then(async (res) => {
+          this.$Message.success(res.msg);
+          this.modals = false;
+          this.getList();
+        })
+        .catch((res) => {
+          this.loading = false;
+          this.$Message.error(res.msg);
+        });
+    },
+  },
+};
+</script>
+
+<style scoped lang="stylus">
+.tabBox_img
+    width 36px
+    height 36px
+    border-radius:4px;
+    cursor pointer
+    img
+        width 100%
+        height 100%
+.modelBox
+    >>>
+    .ivu-table-header
+        width 100% !important
+.trees-coadd
+    width: 100%;
+    height: 385px;
+    .scollhide
+        width: 100%;
+        height: 100%;
+        overflow-x: hidden;
+        overflow-y: scroll;
+// margin-left: 18px;
+.scollhide::-webkit-scrollbar {
+    display: none;
+}
+</style>

+ 640 - 0
src/pages/shop_setting/storeService/speechcraft.vue

@@ -0,0 +1,640 @@
+<template>
+  <div>
+    <Row class="ivu-mt box-wrapper">
+      <Col v-bind="grid1" class="left-wrapper">
+        <Menu :theme="theme3" :active-name="sortName" width="auto">
+          <MenuGroup>
+            <MenuItem
+              :name="item.id"
+              class="menu-item"
+              :class="index === current ? 'showOn' : ''"
+              v-for="(item, index) in labelSort"
+              :key="index"
+              @click.native="bindMenuItem(item, index)"
+            >
+              {{ item.name }}
+              <div class="icon-box" v-if="item.id != 0">
+                <Icon type="ios-more" size="24" @click.stop="showMenu(item)" />
+              </div>
+              <div class="right-menu ivu-poptip-inner" v-show="item.status" v-if="item.id != 0">
+                <div class="ivu-poptip-body" @click="labelEdit(item)">
+                  <div class="ivu-poptip-body-content"><div class="ivu-poptip-body-content-inner">编辑小组</div></div>
+                </div>
+                <div class="ivu-poptip-body" @click="deleteSort(item, '删除分类', index)">
+                  <div class="ivu-poptip-body-content"><div class="ivu-poptip-body-content-inner">删除小组</div></div>
+                </div>
+              </div>
+            </MenuItem>
+          </MenuGroup>
+        </Menu>
+      </Col>
+      <Col v-bind="grid2" ref="rightBox">
+        <Card :bordered="false" dis-hover>
+          <Row type="flex" class="mb20">
+            <Col span="24">
+              <Button v-auth="['setting-store_service-add']" type="primary" icon="md-add" @click="add" class="mr10"
+                >添加话术</Button
+              >
+              <Button
+                v-auth="['setting-store_service-add']"
+                type="success"
+                icon="md-add"
+                @click="addSort"
+                style="margin-left: 10px"
+                >添加分类</Button
+              >
+            </Col>
+          </Row>
+          <Table
+            :columns="columns1"
+            :data="tableList"
+            :loading="loading"
+            highlight-row
+            no-userFrom-text="暂无数据"
+            no-filtered-userFrom-text="暂无筛选结果"
+          >
+            <template slot-scope="{ row, index }" slot="avatar">
+              <div class="tabBox_img" v-viewer>
+                <img v-lazy="row.avatar" />
+              </div>
+            </template>
+            <template slot-scope="{ row, index }" slot="add_time">
+              <span> {{ row.add_time }}</span>
+            </template>
+
+            <template slot-scope="{ row, index }" slot="action">
+              <a @click="edit(row)">编辑</a>
+              <Divider type="vertical" />
+              <a @click="del(row, '删除客服', index)">删除</a>
+            </template>
+          </Table>
+          <div class="acea-row row-right page">
+            <Page :total="total" show-elevator show-total @on-change="pageChange" :page-size="tableFrom.limit" />
+          </div>
+        </Card>
+      </Col>
+    </Row>
+  </div>
+</template>
+
+<script>
+import { mapState } from 'vuex';
+import {
+  wechatSpeechcraft,
+  speechcraftCreate,
+  speechcraftEdit,
+  speechcraftcate,
+  speechcraftcateCreate,
+  speechcraftcateEdit,
+} from '@/api/setting';
+export default {
+  name: 'index',
+  filters: {
+    typeFilter(status) {
+      const statusMap = {
+        wechat: '微信用户',
+        routine: '小程序用户',
+      };
+      return statusMap[status];
+    },
+  },
+  computed: {
+    ...mapState('media', ['isMobile']),
+    labelWidth() {
+      return this.isMobile ? undefined : 80;
+    },
+    labelPosition() {
+      return this.isMobile ? 'top' : 'left';
+    },
+  },
+  data() {
+    return {
+      grid1: {
+        xl: 4,
+        lg: 4,
+        md: 6,
+        sm: 8,
+        xs: 0,
+      },
+      grid2: {
+        xl: 20,
+        lg: 20,
+        md: 18,
+        sm: 16,
+        xs: 24,
+      },
+      isChat: true,
+      formValidate3: {
+        page: 1,
+        limit: 15,
+      },
+      total3: 0,
+      loading3: false,
+      modals3: false,
+      tableList3: [],
+      columns3: [
+        {
+          title: '用户名称',
+          key: 'nickname',
+          width: 200,
+        },
+        {
+          title: '客服头像',
+          slot: 'headimgurl',
+        },
+        {
+          title: '操作',
+          slot: 'action',
+        },
+      ],
+      formValidate5: {
+        page: 1,
+        limit: 15,
+        uid: 0,
+        to_uid: 0,
+        id: 0,
+      },
+      total5: 0,
+      loading5: false,
+      tableList5: [],
+      FromData: null,
+      formValidate: {
+        page: 1,
+        limit: 15,
+        data: '',
+        type: '',
+        nickname: '',
+      },
+      tableList2: [],
+      modals: false,
+      total: 0,
+      tableFrom: {
+        page: 1,
+        limit: 15,
+        cate_id: 0,
+      },
+      timeVal: [],
+      fromList: {
+        title: '选择时间',
+        custom: true,
+        fromTxt: [
+          { text: '全部', val: '' },
+          { text: '今天', val: 'today' },
+          { text: '昨天', val: 'yesterday' },
+          { text: '最近7天', val: 'lately7' },
+          { text: '最近30天', val: 'lately30' },
+          { text: '本月', val: 'month' },
+          { text: '本年', val: 'year' },
+        ],
+      },
+      loading: false,
+      tableList: [],
+      columns1: [
+        {
+          title: 'ID',
+          key: 'id',
+          width: 80,
+        },
+        {
+          title: '分类',
+          key: 'cate_name',
+          minWidth: 120,
+        },
+        {
+          title: '标题',
+          key: 'title',
+          minWidth: 120,
+        },
+        {
+          title: '详情',
+          key: 'message',
+          minWidth: 320,
+        },
+        {
+          title: '排序',
+          key: 'sort',
+          minWidth: 60,
+        },
+        {
+          title: '添加时间',
+          slot: 'add_time',
+          minWidth: 120,
+        },
+        {
+          title: '操作',
+          slot: 'action',
+          fixed: 'right',
+          minWidth: 150,
+        },
+      ],
+      columns4: [
+        {
+          type: 'selection',
+          width: 60,
+          align: 'center',
+        },
+        {
+          title: 'ID',
+          key: 'uid',
+          width: 80,
+        },
+        {
+          title: '微信用户名称',
+          key: 'nickname',
+          minWidth: 160,
+        },
+        {
+          title: '客服头像',
+          slot: 'headimgurl',
+          minWidth: 60,
+        },
+        {
+          title: '用户类型',
+          slot: 'user_type',
+          width: 100,
+        },
+        {
+          title: '性别',
+          slot: 'sex',
+          minWidth: 60,
+        },
+        {
+          title: '地区',
+          slot: 'country',
+          minWidth: 120,
+        },
+        {
+          title: '是否关注公众号',
+          slot: 'subscribe',
+          minWidth: 120,
+        },
+      ],
+      loading2: false,
+      total2: 0,
+      addFrom: {
+        uids: [],
+      },
+      selections: [],
+      rows: {},
+      rowRecord: {},
+      theme3: 'light',
+      labelSort: [],
+      sortName: '',
+      current: 0,
+    };
+  },
+  created() {
+    this.getUserLabelAll();
+  },
+  methods: {
+    getUserLabelAll(key) {
+      speechcraftcate().then((res) => {
+        let data = res.data.data;
+        let obj = {
+          name: '全部',
+          id: '',
+        };
+        data.unshift(obj);
+        data.forEach((el) => {
+          el.status = false;
+        });
+        if (!key) {
+          this.sortName = data[0].id;
+          this.tableFrom.cate_id = data[0].id;
+          this.getList();
+        }
+        this.labelSort = data;
+      });
+    },
+    // 添加分类
+    addSort() {
+      this.$modalForm(speechcraftcateCreate()).then(() => this.getUserLabelAll());
+    },
+    //编辑标签
+    labelEdit(item) {
+      this.$modalForm(speechcraftcateEdit(item.id)).then(() => this.getUserLabelAll(1));
+    },
+    deleteSort(row, tit, num) {
+      let delfromData = {
+        title: tit,
+        num: num,
+        url: `app/wechat/speechcraftcate/${row.id}`,
+        method: 'DELETE',
+        ids: '',
+      };
+      this.$modalSure(delfromData)
+        .then((res) => {
+          this.$Message.success(res.msg);
+          this.labelSort.splice(num, 1);
+          this.labelSort = [];
+          this.getUserLabelAll();
+        })
+        .catch((res) => {
+          this.$Message.error(res.msg);
+        });
+    },
+    // 显示标签小菜单
+    showMenu(item) {
+      this.labelSort.forEach((el) => {
+        if (el.id == item.id) {
+          el.status = item.status ? false : true;
+        } else {
+          el.status = false;
+        }
+      });
+    },
+    bindMenuItem(name, index) {
+      this.tableFrom.page = 1;
+      this.current = index;
+      this.labelSort.forEach((el) => {
+        el.status = false;
+      });
+      this.tableFrom.cate_id = name.id;
+      this.getList();
+    },
+    cancel() {
+      this.formValidate = {
+        page: 1,
+        limit: 10,
+        data: '',
+        type: '',
+        nickname: '',
+      };
+    },
+    handleReachBottom() {
+      return new Promise((resolve) => {
+        this.formValidate.page = this.formValidate.page + 1;
+        setTimeout(() => {
+          // this.loading2 = true;
+          kefucreateApi(this.formValidate)
+            .then(async (res) => {
+              let data = res.data;
+              // this.tableList2 = data.list;
+              if (data.list.length > 0) {
+                for (let i = 0; i < data.list.length; i++) {
+                  this.tableList2.push(data.list[i]);
+                }
+              }
+              this.total2 = data.count;
+              this.loading2 = false;
+            })
+            .catch((res) => {
+              this.loading2 = false;
+              this.$Message.error(res.msg);
+            });
+          resolve();
+        }, 2000);
+      });
+    },
+    // 查看对话
+    look(row) {
+      this.isChat = false;
+      this.rowRecord = row;
+      this.getChatlist();
+    },
+    // 查看对话列表
+    getChatlist() {
+      this.loading5 = true;
+      this.formValidate5.uid = this.rows.uid;
+      this.formValidate5.to_uid = this.rowRecord.uid;
+      this.formValidate5.id = this.rows.id;
+      kefuChatlistApi(this.formValidate5)
+        .then(async (res) => {
+          let data = res.data;
+          this.tableList5 = data.list;
+          this.total5 = data.count;
+          this.loading5 = false;
+        })
+        .catch((res) => {
+          this.loading5 = false;
+          this.$Message.error(res.msg);
+        });
+    },
+    pageChange5(index) {
+      this.formValidate5.page = index;
+      this.getChatlist();
+    },
+    // 修改成功
+    submitFail() {
+      this.getList();
+    },
+    // 聊天记录
+    record(row) {
+      this.rows = row;
+      this.modals3 = true;
+      this.isChat = true;
+      this.getListRecord();
+    },
+    // 聊天记录列表
+    getListRecord() {
+      this.loading3 = true;
+      kefuRecordApi(this.formValidate3, this.rows.id)
+        .then(async (res) => {
+          let data = res.data;
+          this.tableList3 = data.list ? data.list : [];
+          this.total3 = data.count;
+          this.loading3 = false;
+        })
+        .catch((res) => {
+          this.loading3 = false;
+          this.$Message.error(res.msg);
+        });
+    },
+    pageChange3(index) {
+      this.formValidate3.page = index;
+      this.getListRecord();
+    },
+    // 编辑
+    edit(row) {
+      this.$modalForm(speechcraftEdit(row.id)).then(() => this.getList());
+    },
+    // 添加
+    add() {
+      this.$modalForm(speechcraftCreate()).then(() => this.getList());
+    },
+    // 全选
+    onSelectTab(selection) {
+      this.selections = selection;
+      let data = [];
+      this.selections.map((item) => {
+        data.push(item.uid);
+      });
+      this.addFrom.uids = data;
+    },
+    // 具体日期
+    onchangeTime(e) {
+      this.timeVal = e;
+      this.formValidate.data = this.timeVal.join('-');
+      this.formValidate.page = 1;
+      this.getListService();
+    },
+    // 选择时间
+    selectChange(tab) {
+      this.formValidate.data = tab;
+      this.timeVal = [];
+      this.formValidate.page = 1;
+      this.getListService();
+    },
+    // 客服列表
+    getListService() {
+      this.loading2 = true;
+      kefucreateApi(this.formValidate)
+        .then(async (res) => {
+          let data = res.data;
+          this.tableList2 = data.list;
+          this.total2 = data.count;
+          this.tableList2.map((item) => {
+            item._isChecked = false;
+          });
+          this.loading2 = false;
+        })
+        .catch((res) => {
+          this.loading2 = false;
+          this.$Message.error(res.msg);
+        });
+    },
+    pageChange2(pageIndex) {
+      this.formValidate.page = pageIndex;
+      this.getListService();
+      this.addFrom.uids = [];
+    },
+    // 搜索
+    userSearchs() {
+      this.formValidate.page = 1;
+      this.getListService();
+    },
+    // 删除
+    del(row, tit, num) {
+      let delfromData = {
+        title: tit,
+        num: num,
+        url: `/app/wechat/speechcraft/${row.id}`,
+        method: 'DELETE',
+        ids: '',
+      };
+      this.$modalSure(delfromData)
+        .then((res) => {
+          this.$Message.success(res.msg);
+          this.tableList.splice(num, 1);
+        })
+        .catch((res) => {
+          this.$Message.error(res.msg);
+        });
+    },
+    // 列表
+    getList() {
+      this.loading = true;
+      wechatSpeechcraft(this.tableFrom)
+        .then(async (res) => {
+          let data = res.data;
+          this.tableList = data.list;
+          this.total = res.data.count;
+          this.loading = false;
+        })
+        .catch((res) => {
+          this.loading = false;
+          this.$Message.error(res.msg);
+        });
+    },
+    pageChange(index) {
+      this.tableFrom.page = index;
+      this.getList();
+    },
+    // 修改是否显示
+    onchangeIsShow(row) {
+      let data = {
+        id: row.id,
+        status: row.status,
+      };
+      kefusetStatusApi(data)
+        .then(async (res) => {
+          this.$Message.success(res.msg);
+        })
+        .catch((res) => {
+          this.$Message.error(res.msg);
+        });
+    },
+    // 添加客服
+    putRemark() {
+      if (this.addFrom.uids.length === 0) {
+        return this.$Message.warning('请选择要添加的客服');
+      }
+      kefuAddApi(this.addFrom)
+        .then(async (res) => {
+          this.$Message.success(res.msg);
+          this.modals = false;
+          this.getList();
+        })
+        .catch((res) => {
+          this.loading = false;
+          this.$Message.error(res.msg);
+        });
+    },
+  },
+};
+</script>
+
+<style scoped lang="stylus">
+.showOn{
+    color: #2d8cf0;
+    background: #f0faff;
+    z-index: 2;
+}
+.tabBox_img
+    width 36px
+    height 36px
+    border-radius:4px;
+    cursor pointer
+    img
+        width 100%
+        height 100%
+.modelBox
+    >>>
+    .ivu-table-header
+        width 100% !important
+.trees-coadd
+    width: 100%;
+    height: 385px;
+    .scollhide
+        width: 100%;
+        height: 100%;
+        overflow-x: hidden;
+        overflow-y: scroll;
+// margin-left: 18px;
+.scollhide::-webkit-scrollbar {
+    display: none;
+}
+/deep/ .ivu-menu-vertical .ivu-menu-item-group-title{
+    display: none;
+}
+/deep/ .ivu-menu-vertical.ivu-menu-light:after{
+    display none
+}
+
+.left-wrapper
+    height 904px
+    background #fff
+    border-right 1px solid #f2f2f2
+.menu-item
+    z-index 50
+    position: relative;
+    display flex
+    justify-content space-between
+    word-break break-all
+    .icon-box
+        z-index 3
+        position absolute
+        right 20px
+        top 50%
+        transform translateY(-50%)
+        display none
+    &:hover .icon-box
+        display block
+    .right-menu
+        z-index 10
+        position absolute
+        right: -106px;
+        top: -11px;
+        width auto
+        min-width: 121px;
+</style>

+ 266 - 0
src/pages/shop_setting/systemAdmin/index.vue

@@ -0,0 +1,266 @@
+<template>
+  <div>
+    <Card :bordered="false" dis-hover class="ivu-mt">
+      <Form
+        ref="formValidate"
+        :model="formValidate"
+        :label-width="labelWidth"
+        :label-position="labelPosition"
+        @submit.native.prevent
+      >
+        <Row type="flex" :gutter="24">
+          <Col v-bind="grid">
+            <FormItem label="状态:" label-for="status1">
+              <Select v-model="status" placeholder="请选择" @on-change="userSearchs" clearable>
+                <Option value="all">全部</Option>
+                <Option value="1">开启</Option>
+                <Option value="0">关闭</Option>
+              </Select>
+            </FormItem>
+          </Col>
+          <Col v-bind="grid">
+            <FormItem label="搜索:" label-for="status2">
+              <Input
+                search
+                enter-button
+                placeholder="请输入姓名或者账号"
+                v-model="formValidate.name"
+                @on-search="userSearchs"
+              />
+            </FormItem>
+          </Col>
+        </Row>
+        <Row type="flex">
+          <Col v-bind="grid">
+            <Button v-auth="['setting-system_admin-add']" type="primary" @click="add" icon="md-add">添加管理员</Button>
+          </Col>
+        </Row>
+      </Form>
+      <Table
+        :columns="columns1"
+        :data="list"
+        class="mt25"
+        no-userFrom-text="暂无数据"
+        no-filtered-userFrom-text="暂无筛选结果"
+        :loading="loading"
+        highlight-row
+      >
+        <template slot-scope="{ row, index }" slot="roles">
+          <div v-if="row.roles.length !== 0">
+            <Tag color="blue" v-for="(item, index) in row.roles.split(',')" :key="index" v-text="item"></Tag>
+          </div>
+        </template>
+        <template slot-scope="{ row, index }" slot="status">
+          <i-switch
+            v-model="row.status"
+            :value="row.status"
+            :true-value="1"
+            :false-value="0"
+            @on-change="onchangeIsShow(row)"
+            size="large"
+          >
+            <span slot="open">开启</span>
+            <span slot="close">关闭</span>
+          </i-switch>
+        </template>
+        <template slot-scope="{ row, index }" slot="action">
+          <a @click="edit(row)">编辑</a>
+          <Divider type="vertical" />
+          <a @click="del(row, '删除管理员', index)">删除</a>
+        </template>
+      </Table>
+      <div class="acea-row row-right page">
+        <Page
+          :total="total"
+          :current="formValidate.page"
+          show-elevator
+          show-total
+          @on-change="pageChange"
+          :page-size="formValidate.limit"
+        />
+      </div>
+    </Card>
+    <!-- 添加 编辑 -->
+    <admin-from :FromData="FromData" ref="adminfrom" @submitFail="submitFail"></admin-from>
+  </div>
+</template>
+
+<script>
+import { mapState } from 'vuex';
+import { adminListApi, adminFromApi, adminEditFromApi, setShowApi } from '@/api/systemAdmin';
+import adminFrom from '../../../components/from/from';
+export default {
+  name: 'systemAdmin',
+  components: { adminFrom },
+  data() {
+    return {
+      grid: {
+        xl: 7,
+        lg: 7,
+        md: 12,
+        sm: 24,
+        xs: 24,
+      },
+      total: 0,
+      loading: false,
+      roleData: {
+        status1: '',
+      },
+      formValidate: {
+        roles: '',
+        status: '',
+        name: '',
+        page: 1, // 当前页
+        limit: 20, // 每页显示条数
+      },
+      status: '',
+      list: [],
+      columns1: [
+        {
+          title: '姓名',
+          key: 'real_name',
+          minWidth: 120,
+        },
+        {
+          title: '账号',
+          key: 'account',
+          minWidth: 150,
+        },
+        {
+          title: '身份',
+          slot: 'roles',
+          minWidth: 250,
+        },
+        {
+          title: '最后一次登录时间',
+          key: '_last_time',
+          minWidth: 180,
+        },
+        {
+          title: '最后一次登录ip',
+          key: 'last_ip',
+          minWidth: 180,
+        },
+        {
+          title: '开启',
+          slot: 'status',
+          minWidth: 90,
+        },
+        {
+          title: '操作',
+          key: 'action',
+          slot: 'action',
+          fixed: 'right',
+          minWidth: 120,
+        },
+      ],
+      FromData: null,
+      modalTitleSs: '',
+      ids: Number,
+    };
+  },
+  computed: {
+    ...mapState('media', ['isMobile']),
+    labelWidth() {
+      return this.isMobile ? undefined : 50;
+    },
+    labelPosition() {
+      return this.isMobile ? 'top' : 'left';
+    },
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    // 修改是否开启
+    onchangeIsShow(row) {
+      let data = {
+        id: row.id,
+        status: row.status,
+      };
+      setShowApi(data)
+        .then(async (res) => {
+          this.$Message.success(res.msg);
+        })
+        .catch((res) => {
+          this.$Message.error(res.msg);
+        });
+    },
+    // 请求列表
+    submitFail() {
+      this.getList();
+    },
+    // 列表
+    getList() {
+      this.loading = true;
+      this.formValidate.roles = this.formValidate.roles || '';
+      adminListApi(this.formValidate)
+        .then(async (res) => {
+          this.total = res.data.count;
+          this.list = res.data.list;
+          this.loading = false;
+        })
+        .catch((res) => {
+          this.loading = false;
+          this.$Message.error(res.msg);
+        });
+    },
+    pageChange(index) {
+      this.formValidate.page = index;
+      this.getList();
+    },
+    // 添加表单
+    add() {
+      adminFromApi()
+        .then(async (res) => {
+          this.FromData = res.data;
+          this.$refs.adminfrom.modals = true;
+        })
+        .catch((res) => {
+          this.$Message.error(res.msg);
+        });
+    },
+    // 编辑
+    edit(row) {
+      adminEditFromApi(row.id)
+        .then(async (res) => {
+          if (res.data.status === false) {
+            return this.$authLapse(res.data);
+          }
+          this.FromData = res.data;
+          this.$refs.adminfrom.modals = true;
+        })
+        .catch((res) => {
+          this.$Message.error(res.msg);
+        });
+    },
+    // 删除
+    del(row, tit, num) {
+      let delfromData = {
+        title: tit,
+        num: num,
+        url: `setting/admin/${row.id}`,
+        method: 'DELETE',
+        ids: '',
+      };
+      this.$modalSure(delfromData)
+        .then((res) => {
+          this.$Message.success(res.msg);
+          this.list.splice(num, 1);
+        })
+        .catch((res) => {
+          this.$Message.error(res.msg);
+        });
+    },
+    // 表格搜索
+    userSearchs() {
+      this.formValidate.status = this.status === 'all' ? '' : this.status;
+      this.formValidate.page = 1;
+      this.list = [];
+      this.getList();
+    },
+  },
+};
+</script>
+
+<style scoped></style>

+ 491 - 0
src/pages/shop_setting/systemMenus/components/menusFrom.vue

@@ -0,0 +1,491 @@
+<template>
+  <div>
+    <Modal
+      v-model="modals"
+      width="500"
+      scrollable
+      closable
+      :title="titleFrom"
+      :mask-closable="false"
+      :z-index="1"
+      @on-cancel="handleReset"
+      @on-visible-change="visible"
+    >
+      <Form ref="formValidate" :model="formValidate" :label-width="110" @submit.native.prevent>
+        <Row type="flex" :gutter="24">
+          <Col v-bind="grid">
+            <FormItem :label="!authType ? '接口名称:' : '按钮名称:'" prop="menu_name">
+              <div class="add">
+                <Input v-model="formValidate.menu_name" :placeholder="!authType ? '请输入接口名称' : '请输入按钮名称'">
+                </Input>
+              </div>
+            </FormItem>
+          </Col>
+          <Col v-bind="grid">
+            <FormItem label="父级分类:">
+              <Cascader :data="menuList" change-on-select v-model="formValidate.path" filterable></Cascader>
+            </FormItem>
+          </Col>
+          <Col v-bind="grid" v-if="authType">
+            <FormItem label="图标:">
+              <Input
+                v-model="formValidate.icon"
+                placeholder="请选择图标,点击右面图标"
+                icon="ios-appstore"
+                @on-click="iconClick"
+              ></Input>
+            </FormItem>
+          </Col>
+          <Col v-bind="grid" v-if="authType">
+            <FormItem label="排序:">
+              <Input type="number" v-model="formValidate.sort" placeholder="请输入排序" number></Input>
+            </FormItem>
+          </Col>
+          <Col v-bind="grid">
+            <FormItem label="是否显示:">
+              <RadioGroup v-model="formValidate.is_show_path">
+                <Radio :label="item.value" v-for="(item, i) in isShowPathRadio" :key="i">
+                  <Icon type="social-apple"></Icon>
+                  <span>{{ item.label }}</span>
+                </Radio>
+              </RadioGroup>
+            </FormItem>
+          </Col>
+        </Row>
+      </Form>
+      <template #footer>
+        <Button @click="modals = false">取消</Button>
+        <Button type="primary" @click="handleSubmit('formValidate')" :disabled="valids">提交</Button>
+      </template>
+    </Modal>
+    <Modal v-model="modal12" scrollable width="600" title="图标选择" footer-hide>
+      <Input
+        v-model="iconVal"
+        placeholder="输入关键词搜索,注意全是英文"
+        clearable
+        style="width: 300px"
+        @on-change="upIcon(iconVal)"
+        ref="search"
+      />
+      <div class="trees-coadd">
+        <div class="scollhide">
+          <div class="iconlist">
+            <ul class="list-inline">
+              <li class="icons-item" v-for="(item, i) in list" :key="i" :title="item.type">
+                <Icon :type="item.type" @click="iconChange(item.type)" class="ivu-icon" />
+              </li>
+            </ul>
+          </div>
+        </div>
+      </div>
+    </Modal>
+    <Modal v-model="ruleModal" scrollable width="1100" title="权限列表" footer-hide @on-visible-change="modalchange">
+      <div class="search-rule">
+        <Input
+          class="mr10"
+          v-model="searchRule"
+          placeholder="输入关键词搜索"
+          clearable
+          style="width: 300px"
+          ref="search"
+        />
+        <Button class="mr10" type="primary" @click="searchRules">搜索</Button>
+        <Button @click="init">重置</Button>
+      </div>
+      <div class="rule">
+        <div
+          class="rule-list"
+          v-show="!arrs.length || arrs.includes(index)"
+          :class="{ 'select-rule': arrs.includes(index) }"
+          v-for="(item, index) in ruleList"
+          :key="index"
+          @click="selectRule(item)"
+        >
+          <div>接口名称:{{ item.real_name }}</div>
+          <div>请求方式:{{ item.method }}</div>
+          <div>接口地址:{{ item.rule }}</div>
+        </div>
+      </div>
+    </Modal>
+  </div>
+</template>
+
+<script>
+import { addMenusApi, addMenus, getRuleList } from '@/api/systemMenus';
+import icon from '@/utils/icon';
+
+export default {
+  name: 'menusFrom',
+  props: {
+    formValidate: {
+      type: Object,
+      default: null,
+    },
+    titleFrom: {
+      type: String,
+      default: '',
+    },
+  },
+  data() {
+    return {
+      arrs: [],
+      searchRule: '',
+      iconVal: '',
+      grid: {
+        xl: 22,
+        lg: 22,
+        md: 22,
+        sm: 22,
+        xs: 22,
+      },
+      modals: false,
+      modal12: false,
+      FromData: [],
+      valids: false,
+      list2: [],
+      list: icon,
+      authType: true,
+      search: icon,
+      ruleModal: false,
+      ruleList: [],
+    };
+  },
+  watch: {
+    'formValidate.header': function (n) {
+      this.formValidate.is_header = n ? 1 : 0;
+    },
+    'formValidate.auth_type': function (n) {
+      if (n === undefined) {
+        n = 1;
+      }
+      this.authType = n === 1;
+    },
+    'formValidate.data': function (n) {},
+  },
+  computed: {
+    /* eslint-disable */
+    optionsList() {
+      let a = [];
+      this.FromData.map((item) => {
+        if ('pid' === item.field) {
+          a = item.options;
+        }
+      });
+      return a;
+    },
+    headerOptionsList() {
+      let a = [];
+      this.FromData.map((item) => {
+        if ('header' === item.field) {
+          a = item.options;
+        }
+      });
+      return a;
+    },
+    optionsListmodule() {
+      let a = [];
+      this.FromData.map((item) => {
+        if ('module' === item.field) {
+          a = item.options;
+        }
+      });
+      return a;
+    },
+    optionsRadio() {
+      let a = [];
+      this.FromData.map((item) => {
+        if ('auth_type' === item.field) {
+          a = item.options;
+        }
+      });
+      return a;
+    },
+    isheaderRadio() {
+      let a = [];
+      this.FromData.map((item) => {
+        if ('is_header' === item.field) {
+          a = item.options;
+        }
+      });
+      return a;
+    },
+    isShowRadio() {
+      let a = [];
+      this.FromData.map((item) => {
+        if ('is_show' === item.field) {
+          a = item.options;
+        }
+      });
+      return a;
+    },
+    isShowPathRadio() {
+      let a = [];
+      this.FromData.map((item) => {
+        if ('is_show_path' === item.field) {
+          a = item.options;
+        }
+      });
+      return a;
+    },
+    menuList() {
+      let a = [];
+      this.FromData.map((item) => {
+        if ('menu_list' === item.field) {
+          a = item.props.data;
+        }
+      });
+      return a;
+    },
+  },
+  methods: {
+    // 获取权限列表
+    getRuleList() {
+      getRuleList().then((res) => {
+        this.ruleList = res.data;
+        this.ruleModal = true;
+      });
+    },
+    modalchange(type) {
+      if (!type) {
+        this.arrs = [];
+        this.ruleModal = '';
+        this.ruleModal = false;
+      }
+    },
+    changeUnique(val) {
+      let value = this.$routeProStr + val.target.value;
+      if (value.slice(0, 1) === '/') value = value.replace('/', '');
+      this.formValidate.unique_auth = value.replaceAll('/', '-');
+    },
+    visible(type) {
+      if (!type) {
+        this.authType = true;
+      }
+    },
+    selectRule(data) {
+      this.$emit('selectRule', data);
+      this.$nextTick((e) => {
+        this.ruleModal = false;
+      });
+    },
+    changeRadio(n) {
+      this.authType = n === 1 ? true : false;
+    },
+    // 搜索
+    upIcon(n) {
+      let arrs = [];
+      for (var i = 0; i < this.search.length; i++) {
+        if (this.search[i].type.indexOf(n) !== -1) {
+          arrs.push(this.search[i]);
+          this.list = arrs;
+        }
+      }
+    },
+    // 搜索规则
+    searchRules() {
+      if (this.searchRule.trim()) {
+        this.arrs = [];
+        for (var i = 0; i < this.ruleList.length; i++) {
+          if (this.ruleList[i].real_name.indexOf(this.searchRule) !== -1) {
+            this.arrs.push(i);
+          }
+        }
+      } else {
+        this.arrs = [];
+      }
+    },
+    init() {
+      this.searchRule = '';
+      this.arrs = [];
+    },
+    handleCreate1(val) {
+      this.headerOptionsList.push({
+        value: val,
+        label: val,
+      });
+    },
+    // 获取新增表单
+    getAddFrom() {
+      addMenus()
+        .then(async (res) => {
+          this.FromData = res.data.rules;
+        })
+        .catch((res) => {
+          this.$Message.error(res.msg);
+        });
+    },
+    iconClick() {
+      this.modal12 = true;
+    },
+    iconChange(n) {
+      this.formValidate.icon = n;
+      this.modal12 = false;
+    },
+    // 提交
+    handleSubmit(name) {
+      //判断是否选择父级分类
+      if (this.formValidate.path) {
+        let length = this.formValidate.path.length;
+        this.formValidate.pid = this.formValidate.path[length - 1] || 0;
+      }
+      let data = {
+        url: this.formValidate.id ? `/setting/menus/${this.formValidate.id}` : '/setting/menus',
+        method: this.formValidate.id ? 'put' : 'post',
+        datas: this.formValidate,
+      };
+      if (this.authType) {
+        if (!this.formValidate.menu_name) {
+          return this.$Message.warning('请填写按钮名称');
+        }
+        if (!this.formValidate.menu_path) {
+          return this.$Message.warning('请填写路由地址');
+        }
+      } else {
+        if (!this.formValidate.menu_name) {
+          return this.$Message.warning('请填写接口名称');
+        }
+        if (!this.formValidate.methods) {
+          return this.$Message.warning('请选择请求方式');
+        }
+        if (!this.formValidate.api_url) {
+          return this.$Message.warning('请选择接口地址');
+        }
+      }
+      this.valids = true;
+      addMenusApi(data)
+        .then(async (res) => {
+          this.$Message.success(res.msg);
+          this.modals = false;
+          this.$emit('changeMenu', this.formValidate);
+          this.getAddFrom();
+          // this.$store.dispatch('menus/getMenusNavList');
+        })
+        .catch((res) => {
+          this.valids = false;
+          this.$Message.error(res.msg);
+        });
+    },
+    handleReset() {
+      this.modals = false;
+      this.authType = true;
+      this.$refs['formValidate'].resetFields();
+      this.$emit('clearFrom');
+    },
+  },
+  created() {
+    this.list = this.search;
+    this.getAddFrom();
+  },
+};
+</script>
+
+<style scoped>
+.trees-coadd {
+  width: 100%;
+  height: 500px;
+  border-radius: 4px;
+  overflow: hidden;
+}
+
+.scollhide {
+  width: 100%;
+  height: 100%;
+  overflow: auto;
+  margin-left: 18px;
+  padding: 10px 0 10px 0;
+  box-sizing: border-box;
+}
+
+.content {
+  font-size: 12px;
+}
+
+.time {
+  font-size: 12px;
+  color: #2d8cf0;
+}
+
+.icons-item {
+  float: left;
+  margin: 6px 6px 6px 0;
+  width: 53px;
+  text-align: center;
+  list-style: none;
+  cursor: pointer;
+  height: 50px;
+  color: #5c6b77;
+  transition: all 0.2s ease;
+  position: relative;
+  padding-top: 10px;
+}
+
+.icons-item .ivu-icon {
+  font-size: 16px;
+}
+
+.search-rule {
+  display: flex;
+  align-items: center;
+  padding: 10px;
+  background-color: #f2f2f2;
+}
+
+.rule {
+  display: flex;
+  flex-wrap: wrap;
+  max-height: 700px;
+  overflow: scroll;
+}
+
+/*定义滚动条高宽及背景 高宽分别对应横竖滚动条的尺寸*/
+.rule::-webkit-scrollbar {
+  width: 10px;
+  height: 10px;
+  background-color: #f5f5f5;
+}
+
+/*定义滚动条轨道 内阴影+圆角*/
+.rule::-webkit-scrollbar-track {
+  border-radius: 4px;
+  background-color: #f5f5f5;
+}
+
+/*定义滑块 内阴影+圆角*/
+.rule::-webkit-scrollbar-thumb {
+  border-radius: 4px;
+  background-color: #555;
+}
+
+.rule-list {
+  background-color: #f8f5f5;
+  width: 32%;
+  margin: 5px;
+  border-radius: 3px;
+  padding: 10px;
+  color: #333;
+  cursor: pointer;
+  transition: all 0.1s;
+}
+
+.rule-list:hover {
+  background-color: #c5d1dd;
+}
+
+.rule-list div {
+  white-space: nowrap;
+}
+
+.select-rule {
+  background-color: #c5d1dd;
+}
+
+.add {
+  display: flex;
+  align-items: center;
+}
+
+.df {
+  display: flex;
+  justify-content: center;
+}
+</style>

+ 577 - 0
src/pages/shop_setting/systemMenus/index.vue

@@ -0,0 +1,577 @@
+<template>
+  <div>
+    <Card :bordered="false" dis-hover class="ivu-mt">
+      <Form
+        ref="roleData"
+        :model="roleData"
+        :label-width="labelWidth"
+        :label-position="labelPosition"
+        @submit.native.prevent
+      >
+        <Row type="flex" :gutter="24">
+          <!-- <Col v-bind="grid">
+            <FormItem label="规则状态:">
+              <Select v-model="roleData.is_show" placeholder="请选择" clearable @on-change="getData">
+                <Option value="1">显示</Option>
+                <Option value="0">不显示</Option>
+              </Select>
+            </FormItem>
+          </Col> -->
+          <Col v-bind="grid">
+            <FormItem label="按钮名称:" prop="status2" label-for="status2">
+              <Input v-model="roleData.keyword" search enter-button placeholder="请输入按钮名称" @on-search="getData" />
+            </FormItem>
+          </Col>
+        </Row>
+        <!-- <Row type="flex">
+          <Col v-bind="grid">
+            <Button type="primary" @click="menusAdd('添加规则')" icon="md-add">添加规则 </Button>
+          </Col>
+        </Row> -->
+      </Form>
+      <vxe-table
+        :border="false"
+        class="vxeTable mt25"
+        highlight-hover-row
+        highlight-current-row
+        :loading="loading"
+        ref="xTable"
+        header-row-class-name="false"
+        :tree-config="tabconfig"
+        :data="tableData"
+        row-id="id"
+      >
+        <vxe-table-column field="menu_name" tree-node title="按钮名称" min-width="100"></vxe-table-column>
+        <vxe-table-column field="menu_path" title="类型" min-width="240" tooltip="true">
+          <template v-slot="{ row }">
+            <span v-if="row.auth_type == 1">菜单:{{ row.menu_path }}</span>
+            <span v-if="row.auth_type == 3">按钮</span>
+            <span v-if="row.auth_type == 2">数据权限</span>
+          </template>
+        </vxe-table-column>
+        <vxe-table-column field="sort" title="排序" width="150"></vxe-table-column>
+        <vxe-table-column field="flag" title="是否显示" width="150">
+          <template v-slot="{ row }">
+            <i-switch
+              v-model="row.is_show_path"
+              :value="row.is_show_path"
+              :true-value="1"
+              :false-value="0"
+              @on-change="onchangeIsShow(row)"
+              size="large"
+            >
+              <span slot="open">显示</span>
+              <span slot="close">隐藏</span>
+            </i-switch>
+          </template>
+        </vxe-table-column>
+        <vxe-table-column field="date" title="操作" align="center" width="150" fixed="right">
+          <template v-slot="{ row }">
+            <a @click="edit(row, '编辑')">编辑</a>
+          </template>
+        </vxe-table-column>
+      </vxe-table>
+    </Card>
+    <menus-from
+      :formValidate="formValidate"
+      :titleFrom="titleFrom"
+      @getList="getList"
+      @changeMenu="changeMenu"
+      ref="menusFrom"
+      @clearFrom="clearFrom"
+    ></menus-from>
+    <Modal
+      v-model="ruleModal"
+      scrollable
+      width="1100"
+      title="权限列表"
+      @on-ok="addRouters"
+      @on-cancel="ruleModal = false"
+      @on-visible-change="modalchange"
+    >
+      <div class="search-rule">
+        <Alert
+          >基础接口,可多选,并且添加后不会再展示出现;删除权限后才会出现;公共接口,可多选,并且添加后会继续展示;</Alert
+        >
+        <Input
+          class="mr10"
+          v-model="searchRule"
+          placeholder="输入关键词搜索"
+          clearable
+          style="width: 300px"
+          ref="search"
+          @on-enter="searchRules"
+          @on-clear="searchRules"
+        />
+        <Button class="mr10" type="primary" @click="searchRules">搜索</Button>
+        <Button @click="init">重置</Button>
+      </div>
+      <div class="route-list">
+        <div class="tree">
+          <el-tree
+            ref="treeBox"
+            :data="ruleCateList"
+            :highlight-current="true"
+            :props="defaultProps"
+            node-key="id"
+            :default-expanded-keys="expandedKeys"
+            :current-node-key="nodeKey"
+            @node-click="handleNodeClick"
+          ></el-tree>
+        </div>
+        <div class="rule">
+          <div
+            class="rule-list"
+            v-show="!arrs.length || arrs.includes(item.id)"
+            :class="{ 'select-rule': seletRouteIds.includes(item.id) }"
+            v-for="(item, index) in children"
+            :key="index"
+            @click="selectRule(item)"
+          >
+            <div>接口名称:{{ item.name }}</div>
+            <div>请求方式:{{ item.method }}</div>
+            <div>接口地址:{{ item.path }}</div>
+          </div>
+        </div>
+      </div>
+      <!-- <Tabs v-model="routeType" @on-click="changTab">
+        <TabPane :label="item.name" :name="'' + index" v-for="(item, index) in foundationList" :key="item"></TabPane>
+      </Tabs> -->
+    </Modal>
+  </div>
+</template>
+
+<script>
+import { mapState } from 'vuex';
+import {
+  getTable,
+  menusDetailsApi,
+  isShowApi,
+  editMenus,
+  getRuleList,
+  menusBatch,
+  getMenusUnique,
+  menusRuleCate,
+} from '@/api/systemMenus';
+import formCreate from '@form-create/iview';
+import menusFrom from './components/menusFrom';
+import { formatFlatteningRoutes, findFirstNonNullChildren, findFirstNonNullChildrenKeys } from '@/libs/system';
+
+export default {
+  name: 'systemMenus',
+  data() {
+    return {
+      children: [],
+      expandedKeys: [],
+      tabconfig: { children: 'children', reserve: true, accordion: true },
+      spinShow: false,
+      ruleModal: false,
+      searchRule: '',
+      grid: {
+        xl: 7,
+        lg: 7,
+        md: 12,
+        sm: 24,
+        xs: 24,
+      },
+      roleData: {
+        is_show: 1,
+        keyword: '',
+        // auth_type: 3,
+      },
+      defaultProps: {
+        children: 'children',
+        label: 'name',
+      },
+      ruleCateList: [], //权限树
+      loading: false,
+      tableData: [],
+      FromData: null,
+      icons: '',
+      formValidate: {},
+      titleFrom: '',
+      modalTitleSs: '',
+      routeType: '0',
+      arrs: [],
+      foundationList: [], // 基础接口列表
+      openList: [], // 公开接口列表
+      seletRoute: [], // 选中路由
+      seletRouteIds: [], // 选中id
+      menusId: 0, // 选中分类id
+      nodeKey: 0, // 选中节点
+      openId: '',
+    };
+  },
+  components: { menusFrom, formCreate: formCreate.$form() },
+  computed: {
+    ...mapState('admin/layout', ['isMobile']),
+    labelWidth() {
+      return this.isMobile ? undefined : 75;
+    },
+    labelPosition() {
+      return this.isMobile ? 'top' : 'right';
+    },
+  },
+  mounted() {
+    this.getData();
+  },
+  methods: {
+    init() {
+      this.searchRule = '';
+      this.searchRules();
+    },
+    addRouters() {
+      let data = {
+        menus: this.seletRoute,
+      };
+      menusBatch(data)
+        .then((res) => {
+          this.getData();
+        })
+        .catch((res) => {
+          this.$Message.error(res.msg);
+        });
+    },
+    selectRule(data) {
+      if (this.seletRouteIds.includes(data.id)) {
+        let i = this.seletRouteIds.findIndex((e) => e == data.id);
+        this.seletRouteIds.splice(i, 1);
+        this.seletRoute.splice(i, 1);
+      } else {
+        this.seletRouteIds.push(data.id);
+        this.seletRoute.push({
+          menu_name: data.name,
+          unique_auth: '',
+          api_url: data.path,
+          path: this.menusId,
+          method: data.method,
+        });
+      }
+    },
+    changTab(name) {
+      this.routeType = name;
+      let index = parseInt(name);
+      this.children = this.foundationList[index] ? this.foundationList[index].children : [];
+      this.searchRules();
+    },
+    // 搜索规则
+    searchRules() {
+      if (this.searchRule.trim()) {
+        this.arrs = [];
+        let arr = this.foundationList;
+        for (var i = 0; i < arr.length; i++) {
+          if (arr[i].name.indexOf(this.searchRule) !== -1) {
+            this.arrs.push(arr[i].id);
+          }
+        }
+      } else {
+        this.arrs = [];
+      }
+    },
+    addRoute(row) {
+      this.menusId = row.id;
+      this.routeType = '0';
+      // this.getRuleList();
+      menusRuleCate().then((res) => {
+        this.ruleCateList = res.data;
+        this.ruleModal = true;
+        if (res.data.length) {
+          this.$nextTick((e) => {
+            this.expandedKeys = findFirstNonNullChildrenKeys(res.data[0], []);
+            this.nodeKey = findFirstNonNullChildren(res.data).id;
+            this.$refs.treeBox.setCurrentKey(this.nodeKey);
+            this.getRuleList(this.nodeKey);
+          });
+        }
+      });
+    },
+    handleNodeClick(data) {
+      this.getRuleList(data.id);
+    },
+    modalchange() {
+      this.seletRouteIds = [];
+      this.seletRoute = [];
+    },
+    // 获取权限列表
+    getRuleList(cate_id) {
+      getRuleList(cate_id).then((res) => {
+        this.foundationList = res.data;
+        this.children = res.data;
+        this.searchRules();
+
+        // this.openList = [];
+        // this.seletRouteIds = [];
+        // this.seletRoute = [];
+      });
+    },
+    // 修改规则状态
+    onchangeIsShow(row) {
+      let data = {
+        id: row.id,
+        is_show_path: row.is_show_path,
+        is_show: -1,
+      };
+      isShowApi(data)
+        .then(async (res) => {
+          this.$Message.success(res.msg);
+          this.$store.dispatch('menus/getMenusNavList');
+        })
+        .catch((res) => {
+          this.$Message.error(res.msg);
+        });
+    },
+    // 请求列表
+    getList() {
+      this.formValidate = Object.assign({}, this.$options.data().formValidate);
+      this.getData();
+    },
+
+    // 清除表单数据
+    clearFrom() {
+      this.formValidate = Object.assign({}, this.$options.data().formValidate);
+    },
+    // 添加子菜单
+    addE(row, title) {
+      this.formValidate = {};
+      let pid = row.id.toString();
+      if (pid) {
+        menusDetailsApi(row.id)
+          .then(async (res) => {
+            this.formValidate.path = res.data.path;
+            this.formValidate.path.push(row.id);
+            this.formValidate.pid = pid;
+            this.$refs.menusFrom.modals = true;
+            this.$refs.menusFrom.valids = false;
+            this.titleFrom = title;
+            this.formValidate.auth_type = 1;
+            this.formValidate.is_show = 0;
+            this.formValidate.is_show_path = 0;
+          })
+          .catch((res) => {
+            this.$Message.error(res.msg);
+          });
+      } else {
+        this.formValidate.pid = pid;
+        this.$refs.menusFrom.modals = true;
+        this.$refs.menusFrom.valids = false;
+        this.titleFrom = title;
+        this.formValidate.auth_type = 1;
+        this.formValidate.is_show = 0;
+        this.formValidate.is_show_path = 0;
+      }
+      // this.formValidate.pid = row.id.toString();
+      // this.$refs.menusFrom.modals = true;
+      // this.$refs.menusFrom.valids = false;
+      // this.titleFrom = title;
+      // this.formValidate.auth_type = 1;
+      // this.formValidate.is_show = '0';
+    },
+    // 删除
+    del(row, tit) {
+      let delfromData = {
+        title: tit,
+        url: `/setting/menus/${row.id}`,
+        method: 'DELETE',
+        ids: '',
+      };
+
+      this.$modalSure(delfromData)
+        .then((res) => {
+          this.$Message.success(res.msg);
+          this.getData();
+          this.getMenusUnique();
+          // this.$store.dispatch('menus/getMenusNavList');
+        })
+        .catch((res) => {
+          this.$Message.error(res.msg);
+        });
+    },
+    // 规则详情
+    menusDetails(id) {
+      menusDetailsApi(id)
+        .then(async (res) => {
+          this.formValidate = res.data;
+          this.$refs.menusFrom.modals = true;
+        })
+        .catch((res) => {
+          this.$Message.error(res.msg);
+        });
+    },
+    // 编辑
+    edit(row, title, index) {
+      this.openId = row.id;
+      this.formValidate = {};
+      this.menusDetails(row.id);
+      this.titleFrom = title;
+      this.$refs.menusFrom.valids = false;
+      this.$refs.menusFrom.getAddFrom(row.id);
+    },
+    // 添加
+    menusAdd(title) {
+      this.formValidate = {};
+      this.$refs.menusFrom.modals = true;
+      this.$refs.menusFrom.valids = false;
+      // this.formValidate = Object.assign(this.$data, this.$options.formValidate());
+      this.titleFrom = title;
+      this.formValidate.auth_type = 1;
+      this.formValidate.is_show = 0;
+      this.formValidate.is_show_path = 0;
+    },
+    // 新增页面表单
+    // getAddFrom () {
+    //     this.spinShow = true;
+    //     addMenus(this.roleData).then(async res => {
+    //         this.FromData = res.data;
+    //         this.$refs.menusFrom.modals = true;
+    //         this.spinShow = false;
+    //     }).catch(res => {
+    //         this.spinShow = false;
+    //         this.$Message.error(res.msg);
+    //     })
+    // },
+    // 列表
+    getData() {
+      this.loading = true;
+      getTable(this.roleData)
+        .then(async (res) => {
+          this.tableData = res.data;
+          this.loading = false;
+        })
+        .catch((res) => {
+          this.loading = false;
+          this.$Message.error(res.msg);
+        });
+    },
+    changeMenu(data) {
+      console.log(data)
+      this.changeData(this.tableData, data);
+      this.getMenusUnique();
+    },
+    changeData(arr, data) {
+      let arrKey = Object.keys(data);
+      arr.map((e) => {
+        if (e.id == this.openId) {
+          arrKey.map((el) => {
+            e[el] = data[el];
+          });
+          console.log(e);
+        } else if (e.children) {
+          this.changeData(e.children, data);
+        }
+      });
+    },
+    getMenusUnique() {
+      getMenusUnique().then((res) => {
+        let data = res.data;
+        this.$store.commit('userInfo/uniqueAuth', data.uniqueAuth);
+        this.$store.commit('menus/getmenusNav', data.menus);
+        this.$store.dispatch('routesList/setRoutesList', data.menus);
+        let arr = formatFlatteningRoutes(this.$router.options.routes);
+        this.formatTwoStageRoutes(arr);
+        let routes = formatFlatteningRoutes(data.menus);
+        this.$store.commit('menus/setOneLvRoute', routes);
+        this.bus.$emit('routesListChange');
+      });
+    },
+    formatTwoStageRoutes(arr) {
+      if (arr.length <= 0) return false;
+      const newArr = [];
+      const cacheList = [];
+      arr.forEach((v) => {
+        if (v && v.meta && v.meta.keepAlive) {
+          newArr.push({ ...v });
+          cacheList.push(v.name);
+          this.$store.dispatch('keepAliveNames/setCacheKeepAlive', cacheList);
+        }
+      });
+      return newArr;
+    },
+    // 关闭按钮
+    cancel() {
+      this.$emit('onCancel');
+    },
+  },
+};
+</script>
+
+<style scoped lang="scss">
+.vxeTable {
+  > .vxe-table--header-wrapper {
+    background: #fff !important;
+  }
+
+  .icon {
+    font-size: 20px;
+  }
+}
+/deep/ .vxe-table--render-default .vxe-table--border-line {
+  z-index: 2 !important;
+}
+.rule {
+  display: flex;
+  flex-wrap: wrap;
+  overflow-y: scroll;
+  height: max-content;
+  max-height: 600px;
+  flex: 1;
+}
+.tree::-webkit-scrollbar {
+  width: 2px;
+  background-color: #f5f5f5;
+}
+/*定义滚动条高宽及背景 高宽分别对应横竖滚动条的尺寸*/
+.rule::-webkit-scrollbar {
+  width: 10px;
+  height: 10px;
+  background-color: #f5f5f5;
+}
+
+/*定义滚动条轨道 内阴影+圆角*/
+.rule::-webkit-scrollbar-track {
+  border-radius: 4px;
+  background-color: #f5f5f5;
+}
+
+/*定义滑块 内阴影+圆角*/
+.rule::-webkit-scrollbar-thumb {
+  border-radius: 4px;
+  background-color: #ccc;
+}
+
+.rule-list {
+  background-color: #f2f2f2;
+  width: 48.5%;
+  height: max-content;
+  margin: 5px;
+  border-radius: 3px;
+  padding: 10px;
+  color: #333;
+  cursor: pointer;
+  transition: all 0.1s;
+}
+
+.rule-list:hover {
+  background-color: #badbfb;
+}
+
+.rule-list div {
+  white-space: nowrap;
+}
+
+.select-rule {
+  background-color: #badbfb;
+}
+.route-list {
+  display: flex;
+  margin-top: 10px;
+
+  .tree {
+    width: 200px;
+    overflow-y: scroll;
+    max-height: 600px;
+    /deep/ .el-tree-node__children .el-tree-node .el-tree-node__content {
+      padding-left: 14px !important;
+    }
+  }
+}
+</style>

+ 575 - 0
src/pages/shop_setting/systemOutAccount/index.vue

@@ -0,0 +1,575 @@
+<template>
+  <div>
+    <Card :bordered="false" dis-hover class="ivu-mt">
+      <Form
+        ref="formValidate"
+        :model="formValidate"
+        :label-width="labelWidth"
+        :label-position="labelPosition"
+        @submit.native.prevent
+      >
+        <!-- <Row type="flex" :gutter="24">
+          <Col v-bind="grid">
+            <FormItem label="状态:" label-for="status1">
+              <Select v-model="status" placeholder="请选择" @on-change="userSearchs" clearable>
+                <Option value="all">全部</Option>
+                <Option value="1">开启</Option>
+                <Option value="0">关闭</Option>
+              </Select>
+            </FormItem>
+          </Col>
+          <Col v-bind="grid">
+            <FormItem label="搜索:" label-for="status2">
+              <Input
+                search
+                enter-button
+                placeholder="请输入账号"
+                v-model="formValidate.name"
+                @on-search="userSearchs"
+              />
+            </FormItem>
+          </Col>
+        </Row> -->
+        <Row type="flex">
+          <Col v-bind="grid">
+            <Button v-auth="['setting-system_admin-add']" type="primary" @click="add" icon="md-add">添加账号</Button>
+          </Col>
+        </Row>
+      </Form>
+      <Table
+        :columns="columns1"
+        :data="list"
+        class="mt25"
+        no-userFrom-text="暂无数据"
+        no-filtered-userFrom-text="暂无筛选结果"
+        :loading="loading"
+        highlight-row
+      >
+        <template slot-scope="{ row }" slot="roles">
+          <div v-if="row.roles.length !== 0">
+            <Tag color="blue" v-for="(item, index) in row.roles.split(',')" :key="index" v-text="item"></Tag>
+          </div>
+        </template>
+        <template slot-scope="{ row }" slot="status">
+          <i-switch
+            v-model="row.status"
+            :value="row.status"
+            :true-value="1"
+            :false-value="0"
+            @on-change="onchangeIsShow(row)"
+            size="large"
+          >
+            <span slot="open">开启</span>
+            <span slot="close">关闭</span>
+          </i-switch>
+        </template>
+        <template slot-scope="{ row, index }" slot="action">
+          <a @click="setUp(row)">设置</a>
+          <Divider type="vertical" />
+          <a @click="edit(row)">编辑</a>
+          <Divider type="vertical" />
+          <a @click="del(row, '删除账号', index)">删除</a>
+        </template>
+      </Table>
+      <div class="acea-row row-right page">
+        <Page
+          :total="total"
+          :current="formValidate.page"
+          show-elevator
+          show-total
+          @on-change="pageChange"
+          :page-size="formValidate.limit"
+        />
+      </div>
+    </Card>
+    <Modal
+      v-model="modals"
+      scrollable
+      :title="type == 0 ? '添加账号' : '编辑账号'"
+      :mask-closable="false"
+      width="700"
+      :closable="false"
+    >
+      <Form
+        ref="modalsdate"
+        :model="modalsdate"
+        :rules="type == 0 ? ruleValidate : editValidate"
+        :label-width="70"
+        label-position="right"
+      >
+        <FormItem label="账号" prop="appid">
+          <div style="display: flex">
+            <Input type="text" v-model="modalsdate.appid" :disabled="type != 0"></Input>
+          </div>
+        </FormItem>
+        <FormItem label="密码" prop="appsecret">
+          <div style="display: flex">
+            <Input type="text" v-model="modalsdate.appsecret" class="input"></Input>
+            <Button type="primary" @click="reset" class="reset">重置</Button>
+          </div>
+        </FormItem>
+        <FormItem label="描述" prop="title">
+          <div style="display: flex">
+            <Input type="textarea" v-model="modalsdate.title"></Input>
+          </div>
+        </FormItem>
+        <FormItem label="接口权限" prop="title">
+          <!-- <CheckboxGroup v-model="modalsdate.rules">
+            <Checkbox
+              :disabled="[2, 3].includes(item.id)"
+              style="width: 30%"
+              v-for="item in intList"
+              :key="item.id"
+              :label="item.id"
+              >{{ item.name }}</Checkbox
+            >
+          </CheckboxGroup> -->
+          <Tree :data="intList" multiple show-checkbox ref="tree" @on-check-change="selectTree"></Tree>
+        </FormItem>
+      </Form>
+      <div slot="footer">
+        <Button type="primary" @click="ok('modalsdate')">确定</Button>
+        <Button @click="cancel">取消</Button>
+      </div>
+    </Modal>
+    <Modal v-model="settingModals" scrollable title="设置推送" :mask-closable="false" width="900" :closable="false">
+      <Form
+        class="setting-style"
+        ref="settingData"
+        :model="settingData"
+        :rules="type == 0 ? ruleValidate : editValidate"
+        :label-width="140"
+        label-position="right"
+      >
+        <FormItem label="推送开关" prop="switch">
+          <Switch v-model="settingData.push_open" :true-value="1" :false-value="0" />
+        </FormItem>
+        <FormItem label="推送账号" prop="push_account">
+          <div class="form-content">
+            <Input type="text" v-model="settingData.push_account" placeholder="请输入推送账号"></Input>
+            <span class="trip">接受推送方获取token的账号</span>
+          </div>
+        </FormItem>
+        <FormItem label="推送密码" prop="push_password">
+          <div class="form-content">
+            <Input type="text" v-model="settingData.push_password" placeholder="请输入推送密码"></Input>
+            <span class="trip">接受推送方获取token的密码</span>
+          </div>
+        </FormItem>
+        <FormItem label="获取TOKEN接口" prop="push_token_url">
+          <div class="form-content">
+            <div class="input-button">
+              <Input type="text" v-model="settingData.push_token_url" placeholder="请输入获取TOKEN接口"></Input>
+              <Button class="ml10" type="primary" @click="textOutUrl(settingData.id)">测试链接</Button>
+            </div>
+            <span class="trip"
+              >接受推送方获取token的URL地址,POST方法,传入push_account和push_password,返回token和有效时间time(秒)</span
+            >
+          </div>
+        </FormItem>
+        <FormItem label="用户数据修改推送接口" prop="user_update_push">
+          <div class="form-content">
+            <Input type="text" v-model="settingData.user_update_push" placeholder="请输入用户数据修改推送接口"></Input>
+            <span class="trip">用户修改积分,余额,经验等将用户信息推送至该地址,POST方法</span>
+          </div>
+        </FormItem>
+        <FormItem label="订单创建推送接口" prop="order_create_push">
+          <div class="form-content">
+            <Input type="text" v-model="settingData.order_create_push" placeholder="请输入订单创建推送接口"></Input>
+            <span class="trip">订单创建时推送订单信息至该地址,POST方法</span>
+          </div>
+        </FormItem>
+        <FormItem label="订单支付推送接口" prop="order_pay_push">
+          <div class="form-content">
+            <Input type="text" v-model="settingData.order_pay_push" placeholder="请输入订单支付推送接口"></Input>
+            <span class="trip">订单完成支付时推送订单已支付信息至该地址,POST方法</span>
+          </div>
+        </FormItem>
+        <FormItem label="售后订单创建推送接口" prop="refund_create_push">
+          <div class="form-content">
+            <Input
+              type="text"
+              v-model="settingData.refund_create_push"
+              placeholder="请输入售后订单创建推送接口"
+            ></Input>
+            <span class="trip">售后订单生成时推送售后单信息至该地址,POST方法</span>
+          </div>
+        </FormItem>
+        <FormItem label="售后订单取消推送接口" prop="refund_cancel_push">
+          <div class="form-content">
+            <Input
+              type="text"
+              v-model="settingData.refund_cancel_push"
+              placeholder="请输入售后订单取消推送接口"
+            ></Input>
+            <span class="trip">售后订单取消时推送售后单取消信息至该地址,POST方法</span>
+          </div>
+        </FormItem>
+      </Form>
+      <div slot="footer">
+        <Button type="primary" @click="submit('settingData')">确定</Button>
+        <Button @click="settingModals = false">取消</Button>
+      </div>
+    </Modal>
+  </div>
+</template>
+
+<script>
+import { mapState } from 'vuex';
+import {
+  accountListApi,
+  outSaveApi,
+  outSavesApi,
+  setShowApi,
+  outSetUp,
+  interfaceList,
+  setUpPush,
+  textOutUrl,
+} from '@/api/systemOutAccount';
+export default {
+  name: 'systemOut',
+  data() {
+    return {
+      grid: {
+        xl: 7,
+        lg: 7,
+        md: 12,
+        sm: 24,
+        xs: 24,
+      },
+      total: 0,
+      loading: false,
+      roleData: {
+        status1: '',
+      },
+      formValidate: {
+        roles: '',
+        status: '',
+        name: '',
+        page: 1, // 当前页
+        limit: 20, // 每页显示条数
+      },
+      status: '',
+      list: [],
+      intList: [],
+      columns: [
+        {
+          type: 'selection',
+          width: 60,
+          align: 'center',
+        },
+        {
+          title: '接口名称',
+          key: 'name',
+        },
+      ],
+      columns1: [
+        {
+          title: '编号',
+          key: 'id',
+          minWidth: 80,
+        },
+        {
+          title: '账号',
+          key: 'appid',
+          minWidth: 150,
+        },
+        {
+          title: '描述',
+          key: 'title',
+          minWidth: 250,
+        },
+        {
+          title: '添加时间',
+          key: 'add_time',
+          minWidth: 180,
+        },
+        {
+          title: '最后登录时间',
+          key: 'last_time',
+          minWidth: 180,
+        },
+        {
+          title: '最后登录ip',
+          key: 'ip',
+          minWidth: 180,
+        },
+        {
+          title: '状态',
+          slot: 'status',
+          minWidth: 90,
+        },
+        {
+          title: '操作',
+          key: 'action',
+          slot: 'action',
+          fixed: 'right',
+          minWidth: 120,
+        },
+      ],
+      FromData: null,
+      modalTitleSs: '',
+      ids: Number,
+      modals: false,
+      modalsid: '',
+      type: 0,
+      modalsdate: {
+        appid: '',
+        appsecret: '',
+        title: '',
+        rules: [],
+      },
+      settingModals: false,
+      settingData: {
+        switch: 1,
+        name: '',
+      },
+      ruleValidate: {
+        appid: [{ required: true, message: '请输入正确的账号 (4到30位之间)', trigger: 'blur', min: 4, max: 30 }],
+        appsecret: [{ required: true, message: '请输入正确的密码 (6到32位之间)', trigger: 'blur', min: 6, max: 32 }],
+        title: [{ message: '请输入正确的描述 (不能多于200位数)', trigger: 'blur', max: 200 }],
+      },
+      editValidate: {
+        appsecret: [{ required: false, message: '请输入正确的密码 (6到32位之间)', trigger: 'blur', min: 6, max: 32 }],
+      },
+    };
+  },
+  computed: {
+    ...mapState('media', ['isMobile']),
+    labelWidth() {
+      return this.isMobile ? undefined : 50;
+    },
+    labelPosition() {
+      return this.isMobile ? 'top' : 'left';
+    },
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    // 开启状态
+    onchangeIsShow(row) {
+      let data = {
+        id: row.id,
+        status: row.status,
+      };
+      setShowApi(data)
+        .then(async (res) => {
+          this.$Message.success(res.msg);
+        })
+        .catch((res) => {
+          this.$Message.error(res.msg);
+        });
+    },
+    // 请求列表
+    submitFail() {
+      this.getList();
+    },
+    // 列表
+    getList() {
+      this.loading = true;
+      this.formValidate.roles = this.formValidate.roles || '';
+      accountListApi(this.formValidate)
+        .then(async (res) => {
+          this.total = res.data.count;
+          this.list = res.data.list;
+          this.loading = false;
+        })
+        .catch((res) => {
+          this.loading = false;
+          this.$Message.error(res.msg);
+        });
+    },
+    pageChange(index) {
+      this.formValidate.page = index;
+      this.getList();
+    },
+    // 添加
+    add() {
+      this.modals = true;
+      this.type = 0;
+      this.modalsdate = {
+        appid: '',
+        appsecret: '',
+        title: '',
+        rules: [],
+      };
+      this.getIntList();
+    },
+    selectTree(e, i) {},
+    getIntList(type, list) {
+      interfaceList().then((res) => {
+        this.intList = res.data;
+        if (!type) {
+          this.intList.map((item) => {
+            if (item.id === 1) {
+              item.checked = true;
+              item.disableCheckbox = true;
+              if (item.children.length) {
+                item.children.map((v) => {
+                  v.checked = true;
+                  v.disableCheckbox = true;
+                });
+              }
+            }
+          });
+        } else {
+          list.map((item) => {
+            this.intList.map((e) => {
+              if (e.id === 1) {
+                e.checked = true;
+                e.disableCheckbox = true;
+                if (e.children.length) {
+                  e.children.map((v) => {
+                    v.checked = true;
+                    v.disableCheckbox = true;
+                  });
+                }
+              }
+              listData(e.children || [], item);
+            });
+          });
+        }
+        function listData(list, id) {
+          if (list.length) {
+            list.map((v) => {
+              if (v.id == id) {
+                v.checked = true;
+              }
+              if (v.children) {
+                listData(v.children);
+              }
+            });
+          }
+        }
+      });
+    },
+    // 编辑
+    edit(row) {
+      this.modals = true;
+      this.modalsdate.appid = row.appid;
+      this.modalsdate.title = row.title;
+      this.modalsdate.rules = row.rules.map((e) => {
+        return Number(e);
+      });
+      this.modalsid = row.id;
+      this.type = 1;
+      this.getIntList('edit', this.modalsdate.rules);
+    },
+    // 删除
+    del(row, tit, num) {
+      let delfromData = {
+        title: tit,
+        num: num,
+        url: `setting/system_out_account/${row.id}`,
+        method: 'DELETE',
+        ids: '',
+      };
+      this.$modalSure(delfromData)
+        .then((res) => {
+          this.$Message.success(res.msg);
+          this.list.splice(num, 1);
+        })
+        .catch((res) => {
+          this.$Message.error(res.msg);
+        });
+    },
+    // 编辑
+    setUp(row) {
+      this.settingModals = true;
+      this.settingData = row;
+    },
+    // 搜索
+    userSearchs() {
+      this.formValidate.status = this.status === 'all' ? '' : this.status;
+      this.formValidate.page = 1;
+      this.list = [];
+      this.getList();
+    },
+    submit(name) {
+      setUpPush(this.settingData).then((res) => {
+        this.$Message.success(res.msg);
+        this.settingModals = false;
+        this.getList();
+      });
+    },
+    textOutUrl() {
+      textOutUrl(this.settingData)
+        .then((res) => {
+          this.$Message.success(res.msg);
+        })
+        .catch((err) => {
+          this.$Message.error(err.msg);
+        });
+    },
+    ok(name) {
+      let fuc = this.modalsid ? outSavesApi : outSaveApi;
+      this.$refs[name].validate((valid) => {
+        if (valid) {
+          this.modalsdate.rules = [];
+          this.$refs.tree.getCheckedAndIndeterminateNodes().map((node) => {
+            this.modalsdate.rules.push(node.id);
+          });
+          if (this.modalsid) this.modalsdate.id = this.modalsid;
+          fuc(this.modalsdate)
+            .then((res) => {
+              this.modalsdate = {
+                appid: '',
+                appsecret: '',
+                title: '',
+                rules: [],
+              };
+              (this.modals = false), this.$Message.success(res.msg);
+              this.modalsid = '';
+              this.getList();
+            })
+            .catch((err) => {
+              this.$Message.error(err.msg);
+            });
+        } else {
+          this.$Message.warning('请完善数据');
+        }
+      });
+    },
+    cancel() {
+      this.modalsid = '';
+      this.modalsdate = {
+        appid: '',
+        appsecret: '',
+        title: '',
+      };
+      this.modals = false;
+    },
+    reset() {
+      let len = 16;
+      let chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678';
+      let maxPos = chars.length;
+      let pwd = '';
+      for (let i = 0; i < len; i++) {
+        pwd += chars.charAt(Math.floor(Math.random() * maxPos));
+      }
+      this.modalsdate.appsecret = pwd;
+    },
+  },
+};
+</script>
+
+<style scoped>
+.reset {
+  margin-left: 10px;
+}
+.form-content {
+  display: flex;
+  flex-direction: column;
+}
+.input-button {
+  display: flex;
+}
+w .trip {
+  color: #aaa;
+  line-height: 20px;
+}
+.setting-style /deep/ .ivu-form-item {
+  margin-bottom: 14px;
+}
+</style>

+ 75 - 0
src/pages/shop_setting/systemOutInterface/components/MonacoEditor.vue

@@ -0,0 +1,75 @@
+<template>
+  <div class="monaco-container">
+    <div ref="container" class="monaco-editor"></div>
+  </div>
+</template>
+
+<script>
+import * as monaco from 'monaco-editor';
+export default {
+  name: '',
+  props: {
+    // 编辑器中呈现的内容
+    codes: {
+      type: String,
+      default: function () {
+        return '';
+      },
+    },
+    readOnly: {
+      type: Boolean,
+      default: function () {
+        return false;
+      },
+    },
+    // 主要配置
+    editorOptions: {
+      type: Object,
+      default: function () {
+        return {
+          selectOnLineNumbers: true,
+          roundedSelection: false,
+          readOnly: this.readOnly, // 只读
+          cursorStyle: 'line', // 光标样式
+          automaticLayout: false, // 自动布局
+          glyphMargin: true, // 字形边缘
+          useTabStops: false,
+          fontSize: 28, // 字体大小
+          autoIndent: true, // 自动布局
+        };
+      },
+    },
+  },
+
+  data() {
+    return {};
+  },
+  created() {},
+  mounted() {
+    this.monacoEditor = monaco.editor.create(this.$refs.container, {
+      value: this.codes, // 见props
+      language: 'json',
+      theme: 'vs', // 编辑器主题:vs, hc-black, or vs-dark,更多选择详见官网
+      automaticLayout: true, //自动布局
+      //   foldingStrategy: 'indentation', // 代码可分小段折叠
+      scrollbar: {
+        // 滚动条设置
+        verticalScrollbarSize: 4, // 竖滚动条
+        horizontalScrollbarSize: 10, // 横滚动条
+      },
+      lineNumbersMinChars: 5,
+      editorOptions: this.editorOptions, // 同codes
+    });
+    setTimeout(() => {
+      this.monacoEditor.trigger('anyString', 'editor.action.formatDocument');
+      this.monacoEditor.setValue(this.monacoEditor.getValue());
+    }, 100);
+  },
+  methods: {},
+};
+</script>
+<style lang="stylus" scoped>
+.monaco-editor{
+    min-height: 300px
+}
+</style>

+ 456 - 0
src/pages/shop_setting/systemOutInterface/debugging.vue

@@ -0,0 +1,456 @@
+<template>
+  <div class="content" v-if="interfaceData">
+    <div class="head">
+      <Input v-model="interfaceData.url">
+        <template #prepend>
+          <Select v-model="interfaceData.method" style="width: 120px">
+            <Option v-for="(item, index) in requestTypeList" :key="index" :value="item.value">{{ item.label }}</Option>
+          </Select>
+        </template>
+      </Input>
+      <Button class="ml20" type="primary" @click="requestData">请求</Button>
+      <Button class="ml10 copy-btn" type="success" @click="insertCopy()">复制</Button>
+    </div>
+    <div class="params">
+      <Tabs class="mt10" v-model="paramsType" @on-click="changeTab">
+        <TabPane label="Params" name="Params"> </TabPane>
+        <TabPane label="Body" name="Body"> </TabPane>
+        <TabPane label="Header" name="Header"> </TabPane>
+      </Tabs>
+      <div v-show="paramsType === 'Params'">
+        <vxe-table
+          class="mt10"
+          resizable
+          show-overflow
+          keep-source
+          ref="xTable"
+          row-id="id"
+          :print-config="{}"
+          :export-config="{}"
+          :tree-config="{ transform: true, rowField: 'id', parentField: 'parentId' }"
+          :data="interfaceData.request_params"
+        >
+          <vxe-column field="attribute" width="150" title="属性" tree-node :edit-render="{}">
+            <template #default="{ row }">
+              <vxe-input v-model="row.attribute" type="text"></vxe-input>
+            </template>
+          </vxe-column>
+          <vxe-column field="value" title="参数值" :edit-render="{}">
+            <template #default="{ row }">
+              <vxe-input v-model="row.value" type="text"></vxe-input>
+            </template>
+          </vxe-column>
+          <vxe-column field="type" title="类型" width="120" :edit-render="{}">
+            <template #default="{ row }">
+              <vxe-select v-model="row.type" transfer>
+                <vxe-option
+                  v-for="item in typeList"
+                  :key="item.value"
+                  :value="item.value"
+                  :label="item.label"
+                ></vxe-option>
+              </vxe-select>
+            </template>
+          </vxe-column>
+          <vxe-column field="must" title="必填" width="50" :edit-render="{}">
+            <template #default="{ row }">
+              <span>{{ row.must == '1' ? '是' : '否' }}</span>
+            </template>
+          </vxe-column>
+          <vxe-column field="trip" width="150" title="说明" :edit-render="{}">
+            <template #default="{ row }">
+              <vxe-input v-model="row.trip" type="text"></vxe-input>
+            </template>
+          </vxe-column>
+          <vxe-column title="操作" width="120">
+            <template #default="{ row }">
+              <vxe-button type="text" v-if="row.type === 'array'" status="primary" @click="insertRow(row, 'xTable')"
+                >插入</vxe-button
+              >
+              <vxe-button type="text" status="primary" @click="removeRow(row, 'xTable')">删除</vxe-button>
+            </template>
+          </vxe-column>
+        </vxe-table>
+        <Button class="mt10" type="primary" @click="insertEvent('xTable')">添加参数</Button>
+      </div>
+      <div v-show="paramsType === 'Body'">
+        <vxe-table
+          class="mt10"
+          resizable
+          show-overflow
+          keep-source
+          ref="yTable"
+          row-id="id"
+          :print-config="{}"
+          :export-config="{}"
+          :tree-config="{ transform: true, rowField: 'id', parentField: 'parentId' }"
+          :data="interfaceData.request_body"
+        >
+          <vxe-column field="attribute" width="150" title="属性" tree-node :edit-render="{}">
+            <template #default="{ row }">
+              <vxe-input v-model="row.attribute" type="text"></vxe-input>
+            </template>
+          </vxe-column>
+          <vxe-column field="value" title="参数值" :edit-render="{}">
+            <template #default="{ row }">
+              <vxe-input v-model="row.value" type="text"></vxe-input>
+            </template>
+          </vxe-column>
+          <vxe-column field="type" title="类型" width="120" :edit-render="{}">
+            <template #default="{ row }">
+              <vxe-select v-model="row.type" transfer>
+                <vxe-option
+                  v-for="item in typeList"
+                  :key="item.value"
+                  :value="item.value"
+                  :label="item.label"
+                ></vxe-option>
+              </vxe-select>
+            </template>
+          </vxe-column>
+          <vxe-column field="must" title="必填" width="50" :edit-render="{}">
+            <template #default="{ row }">
+              <span>{{ row.must == '1' ? '是' : '否' }}</span>
+            </template>
+          </vxe-column>
+          <vxe-column field="trip" title="说明" width="150" :edit-render="{}">
+            <template #default="{ row }">
+              <vxe-input v-model="row.trip" type="text"></vxe-input>
+            </template>
+          </vxe-column>
+          <vxe-column title="操作" width="120">
+            <template #default="{ row }">
+              <vxe-button type="text" v-if="row.type === 'array'" status="primary" @click="insertRow(row, 'yTable')"
+                >插入</vxe-button
+              >
+              <vxe-button type="text" status="primary" @click="removeRow(row, 'yTable')">删除</vxe-button>
+            </template>
+          </vxe-column>
+        </vxe-table>
+        <Button class="mt10" type="primary" @click="insertEvent('yTable')">添加参数</Button>
+      </div>
+      <div v-show="paramsType === 'Header'">
+        <vxe-table
+          class="mt10"
+          resizable
+          show-overflow
+          keep-source
+          ref="zTable"
+          row-id="id"
+          :print-config="{}"
+          :export-config="{}"
+          :tree-config="{ transform: true, rowField: 'id', parentField: 'parentId' }"
+          :data="interfaceData.headerData"
+        >
+          <vxe-column field="attribute" width="300" title="属性" tree-node :edit-render="{}">
+            <template #default="{ row }">
+              <vxe-input v-model="row.attribute" type="text"></vxe-input>
+            </template>
+          </vxe-column>
+          <vxe-column field="value" title="参数值" :edit-render="{}">
+            <template #default="{ row }">
+              <vxe-input v-model="row.value" type="text"></vxe-input>
+            </template>
+          </vxe-column>
+          <vxe-column field="type" title="类型" width="200" :edit-render="{}">
+            <template #default="{ row }">
+              <vxe-select v-model="row.type" transfer>
+                <vxe-option
+                  v-for="item in typeList"
+                  :key="item.value"
+                  :value="item.value"
+                  :label="item.label"
+                ></vxe-option>
+              </vxe-select>
+            </template>
+          </vxe-column>
+          <vxe-column title="操作" width="100">
+            <template #default="{ row }">
+              <vxe-button type="text" v-if="row.type === 'array'" status="primary" @click="insertRow(row, 'zTable')"
+                >插入</vxe-button
+              >
+              <vxe-button type="text" status="primary" @click="removeRow(row, 'zTable')">删除</vxe-button>
+            </template>
+          </vxe-column>
+        </vxe-table>
+        <Button class="mt10" type="primary" @click="insertEvent('zTable')">添加参数</Button>
+        <h4 class="mt10 title">全局Header参数</h4>
+        <vxe-table
+          class="mt10"
+          resizable
+          show-overflow
+          keep-source
+          ref="zaTable"
+          row-id="id"
+          :print-config="{}"
+          :export-config="{}"
+          :tree-config="{ transform: true, rowField: 'id', parentField: 'parentId' }"
+          :data="interfaceData.allHeaderData"
+        >
+          <vxe-column field="attribute" width="300" title="属性" tree-node :edit-render="{}">
+            <template #default="{ row }">
+              <span>{{ row.attribute || '' }}</span>
+            </template>
+          </vxe-column>
+          <vxe-column field="value" title="参数值" :edit-render="{}">
+            <template #default="{ row }">
+              <span>{{ row.value || '' }}</span>
+            </template>
+          </vxe-column>
+          <vxe-column field="type" title="类型" width="200" :edit-render="{}">
+            <template #default="{ row }">
+              <span>{{ row.type || '' }}</span>
+            </template>
+          </vxe-column>
+          <vxe-column field="trip" title="说明" :edit-render="{}">
+            <template #default="{ row }">
+              <span>{{ row.trip || '' }}</span>
+            </template>
+          </vxe-column>
+        </vxe-table>
+      </div>
+    </div>
+    <div class="res mt10 mb10" v-if="codes">
+      <MonacoEditor :codes="codes" :readOnly="true" />
+    </div>
+  </div>
+</template>
+
+<script>
+import request from './request';
+import MonacoEditor from './components/MonacoEditor.vue';
+function requestMethod(url, method, params, data, headerItem) {
+  return request({
+    url,
+    method,
+    params,
+    data,
+    headerItem,
+  });
+}
+export default {
+  components: { MonacoEditor },
+  props: {
+    formValidate: {
+      type: Object,
+      default: () => {
+        return {};
+      },
+    },
+    requestTypeList: {
+      type: Array,
+      default: () => {
+        return [];
+      },
+    },
+    typeList: {
+      type: Array,
+      default: () => {
+        return [];
+      },
+    },
+  },
+  data() {
+    return {
+      interfaceData: undefined,
+      paramsType: 'Params',
+      editor: '', //当前编辑器对象
+      codes: '',
+    };
+  },
+  created() {
+    this.interfaceData = this.formValidate;
+    this.interfaceData.request_body = JSON.parse(JSON.stringify(this.interfaceData.request_params));
+  },
+  mounted() {},
+  methods: {
+    insertCopy() {
+      this.$copyText(this.codes)
+        .then((message) => {
+          this.$Message.success('复制成功');
+        })
+        .catch((err) => {
+          this.$Message.error('复制失败');
+        });
+    },
+    async requestData() {
+      let url, method, params, body, headers;
+      url = this.interfaceData.url;
+      method = this.interfaceData.method;
+      params = this.filtersData((await this.$refs.xTable.getTableData().tableData) || []);
+      body = this.filtersData((await this.$refs.yTable.getTableData().tableData) || []);
+      let h = this.filtersData((await this.$refs.zTable.getTableData().tableData) || []);
+      let h1 = this.filtersData((await this.$refs.zaTable.getTableData().tableData) || []);
+      headers = {
+        ...h,
+        ...h1,
+      };
+      requestMethod(url, method, params, body, headers)
+        .then((res) => {
+          this.codes = res + '';
+        })
+        .catch((err) => {
+          this.codes = JSON.stringify(err);
+        });
+    },
+    filtersData(arr) {
+      try {
+        let x = {};
+        arr.map((e) => {
+          if (!e.parentId) {
+            for (let i in e) {
+              if (i == 'attribute') {
+                if (e.type !== 'array') {
+                  x[e[i]] = e.value || '';
+                } else {
+                  let arr = [];
+                  e.children.map((item, index) => {
+                    arr[index] = this.filtersObj(item);
+                  });
+                  x[e[i]] = arr;
+                }
+              }
+            }
+          }
+        });
+        return x;
+      } catch (error) {
+        console.log(error);
+      }
+    },
+    filtersObj(obj) {
+      let x = {};
+      for (let i in obj) {
+        if (i == 'attribute') {
+          if (obj.type !== 'array') {
+            x[obj[i]] = obj.value || '';
+          } else {
+            let arr = [];
+            obj.children.map((item, index) => {
+              arr[index] = this.filtersObj(item);
+            });
+            x[obj[i]] = arr;
+          }
+        }
+      }
+      return x;
+    },
+    changeTab(name) {
+      if (name === 'Header') {
+        if (!this.interfaceData.headerData) {
+          this.insertEvent('zTable', {
+            attribute: 'Content-Type',
+            value: 'application/x-www-form-urlencoded',
+          });
+          this.insertEvent('zaTable');
+        }
+      }
+    },
+    async insertEvent(type, d) {
+      const $table = this.$refs[type];
+      let newRow;
+      if (type == 'xTable') {
+        newRow = {
+          attribute: '',
+          type: 'string',
+          must: 0,
+          value: '',
+          trip: '',
+        };
+      } else if (type == 'yTable') {
+        newRow = {
+          attribute: '',
+          type: 'string',
+          value: '',
+          must: 0,
+          trip: '',
+        };
+      } else if (type == 'zTable') {
+        newRow = {
+          attribute: '',
+          type: '',
+          value: '',
+          trip: '',
+        };
+        newRow = { ...newRow, ...d };
+      } else if (type == 'zaTable') {
+        newRow = {
+          attribute: 'token',
+          type: 'string',
+          value: '',
+          must: 0,
+          trip: '',
+        };
+      } else {
+        newRow = {
+          code: '',
+          value: '',
+          solution: '',
+        };
+      }
+      const { row: data } = await $table.insertAt(newRow, -1);
+      await $table.setActiveCell(data, 'name');
+    },
+    async insertRow(currRow, type) {
+      const $table = this.$refs[type];
+      // 如果 null 则插入到目标节点顶部
+      // 如果 -1 则插入到目标节点底部
+      // 如果 row 则有插入到效的目标节点该行的位置
+      let record;
+      if (type == 'xTable') {
+        record = {
+          attribute: '',
+          type: 'string',
+          must: 0,
+          value: '',
+          trip: '',
+          id: Date.now(),
+          parentId: currRow.id, // 需要指定父节点,自动插入该节点中
+        };
+      } else {
+        record = {
+          code: '',
+          value: '',
+          solution: '',
+          id: Date.now(),
+          parentId: currRow.id, // 需要指定父节点,自动插入该节点中
+        };
+      }
+      const { row: newRow } = await $table.insertAt(record, -1);
+      await $table.setTreeExpand(currRow, true); // 将父节点展开
+      await $table.setActiveRow(newRow); // 插入子节点
+    },
+    async removeRow(row, type) {
+      const $table = this.$refs[type];
+      await $table.remove(row);
+    },
+  },
+};
+</script>
+<style>
+.vxe-select--panel.is--transfer {
+  z-index: 99999 !important;
+}
+</style>
+<style lang="scss" scoped>
+.content {
+  padding: 12px;
+  .head {
+    display: flex;
+    align-items: center;
+    .item {
+      display: flex;
+      align-items: center;
+      margin-bottom: 12px;
+      font-size: 14px;
+      .title {
+        margin-right: 14px;
+      }
+    }
+  }
+}
+.copy-btn {
+  display: flex;
+  justify-content: right;
+}
+</style>

+ 1077 - 0
src/pages/shop_setting/systemOutInterface/index.vue

@@ -0,0 +1,1077 @@
+<template>
+  <div>
+    <div class="main">
+      <!-- <Tree class="tree" :data="treeData"  @on-contextmenu="handleContextMenu">
+          <template #contextMenu>
+            <DropdownItem @click.native="handleContextCreateFolder()">新建文件夹</DropdownItem>
+            <DropdownItem @click.native="handleContextCreateFile()">新建文件</DropdownItem>
+            <DropdownItem @click.native="handleContextDelFolder()" style="color: #ed4014">删除</DropdownItem>
+          </template>
+        </Tree> -->
+      <!-- <Tree :data="treeData" :render="renderContent" class="demo-tree-render"></Tree> -->
+      <Card :bordered="false" dis-hover class="ivu-mt mr20 card-tree">
+        <div class="tree">
+          <div class="main-btn">
+            <Button class="mb10" type="primary" @click="clickMenu(4)" long>新增分类</Button>
+          </div>
+
+          <vue-tree-list
+            class="tree-list"
+            @change-name="onChangeName"
+            @delete-node="onDel"
+            :model="treeData"
+            default-tree-node-name="默认文件夹"
+            default-leaf-node-name="默认接口名"
+            v-bind:default-expanded="true"
+          >
+            <template v-slot:leafNameDisplay="slotProps">
+              <div></div>
+              <div
+                class="tree-node"
+                :class="{ node: slotProps.model.method, open: formValidate.id == slotProps.model.id }"
+                @click.stop="onClick(slotProps.model)"
+              >
+                <span class="" :class="{ open: formValidate.id == slotProps.model.id }">{{
+                  slotProps.model.name
+                }}</span>
+                <Dropdown
+                  transfer
+                  @on-click="
+                    (name) => {
+                      clickMenu(name, slotProps.model);
+                    }
+                  "
+                >
+                  <a href="javascript:void(0)">
+                    <Icon class="add" type="ios-more" />
+                  </a>
+                  <template #list>
+                    <DropdownMenu>
+                      <DropdownItem name="1" v-if="!slotProps.model.method">新增接口</DropdownItem>
+                      <DropdownItem name="2" v-if="!slotProps.model.method">编辑分类名</DropdownItem>
+                      <DropdownItem name="3">删除</DropdownItem>
+                    </DropdownMenu>
+                  </template>
+                </Dropdown>
+              </div>
+            </template>
+            <!-- 新建文件夹 -->
+
+            <span class="icon" slot="addTreeNodeIcon"></span>
+            <span class="icon" slot="addLeafNodeIcon">
+              <!-- <Icon type="md-create" /> -->
+            </span>
+            <span class="icon" slot="editNodeIcon">
+              <!-- <Icon type="md-create" /> -->
+            </span>
+            <span class="icon" slot="delNodeIcon">
+              <!-- <Icon type="ios-cut" /> -->
+            </span>
+            <template v-slot:treeNodeIcon="slotProps">
+              <span
+                v-if="slotProps.model.method"
+                class="req-method"
+                :style="{
+                  color: methodsColor(slotProps.model.method),
+                  'font-weight': slotProps.model.id == formValidate.id ? '500' : '500',
+                }"
+                >{{ slotProps.model.method == 'delete' ? 'DEL' : slotProps.model.method || '' }}</span
+              >
+
+              <!-- <span v-if="slotProps.model.method"></span> -->
+            </template>
+          </vue-tree-list>
+        </div>
+      </Card>
+      <Card :bordered="false" dis-hover class="ivu-mt right-card">
+        <div class="data">
+          <div class="eidt-sub">
+            <div class="name">
+              {{ formValidate.name }}
+            </div>
+            <div>
+              <!-- <Button type="primary" class="submission mr20" @click="debugging()">调试</Button> -->
+              <Button v-if="formValidate.id" type="primary" class="submission mr20" @click="isEdit = !isEdit">{{
+                isEdit ? '返回' : '编辑'
+              }}</Button>
+              <Button v-if="isEdit" type="primary" class="submission" @click="handleSubmit('formValidate')"
+                >保存</Button
+              >
+            </div>
+          </div>
+          <Form
+            class="formValidate mt20"
+            ref="formValidate"
+            :rules="ruleValidate"
+            :model="formValidate"
+            :label-width="100"
+            :label-position="labelPosition"
+            @submit.native.prevent
+          >
+            <Row :gutter="24" type="flex">
+              <Col span="24">
+                <div class="title">接口信息</div>
+                <FormItem label="接口名称:" prop="name">
+                  <Input
+                    v-if="isEdit"
+                    class="perW20"
+                    type="text"
+                    :rows="4"
+                    v-model.trim="formValidate.name"
+                    placeholder="请输入"
+                  />
+                  <span v-else>{{ formValidate.name || '' }}</span>
+                </FormItem>
+                <FormItem label="请求类型:" prop="name">
+                  <Select v-if="isEdit" v-model="formValidate.method" style="width: 120px">
+                    <Option v-for="(item, index) in requestTypeList" :key="index" :value="item.value">{{
+                      item.label
+                    }}</Option>
+                  </Select>
+                  <span v-else class="req-method" :style="'background-color:' + methodColor">{{
+                    formValidate.method || ''
+                  }}</span>
+                </FormItem>
+                <FormItem label="功能描述:" prop="name">
+                  <Input
+                    v-if="isEdit"
+                    class="perW20"
+                    type="textarea"
+                    :rows="4"
+                    v-model.trim="formValidate.describe"
+                    placeholder="请输入"
+                  />
+                  <span v-else class="text-area">{{ formValidate.describe || '' }}</span>
+                </FormItem>
+              </Col>
+            </Row>
+            <Row :gutter="24" type="flex">
+              <Col span="24">
+                <div class="title">调用方式</div>
+                <FormItem label="调用内容:" prop="url">
+                  <Input
+                    v-if="isEdit"
+                    class="perW20"
+                    type="text"
+                    :rows="4"
+                    v-model.trim="formValidate.url"
+                    placeholder="请输入"
+                  />
+                  <span v-else>{{ formValidate.url || '' }}</span>
+                </FormItem>
+                <FormItem label="请求参数:">
+                  <vxe-table
+                    resizable
+                    show-overflow
+                    keep-source
+                    ref="xTable"
+                    row-id="id"
+                    :print-config="{}"
+                    :export-config="{}"
+                    :loading="loading"
+                    :tree-config="{ transform: true, rowField: 'id', parentField: 'parentId' }"
+                    :data="formValidate.request_params"
+                  >
+                    <!-- <vxe-column type="checkbox" width="60"></vxe-column> -->
+                    <vxe-column field="attribute" width="300" title="属性" tree-node :edit-render="{}">
+                      <template #default="{ row }">
+                        <vxe-input v-if="isEdit" v-model="row.attribute" type="text"></vxe-input>
+                        <span v-else>{{ row.attribute || '' }}</span>
+                      </template>
+                    </vxe-column>
+                    <vxe-column field="type" title="类型" width="200" :edit-render="{}">
+                      <template #default="{ row }">
+                        <!-- <vxe-select v-if="isEdit" v-model="row.type" type="text" :optionGroups="typeList"></vxe-select> -->
+                        <vxe-select v-if="isEdit" v-model="row.type" transfer>
+                          <vxe-option
+                            v-for="item in typeList"
+                            :key="item.value"
+                            :value="item.value"
+                            :label="item.label"
+                          ></vxe-option>
+                        </vxe-select>
+                        <span v-else>{{ row.type || '' }}</span>
+
+                        <!-- <vxe-select v-model="row.type">
+                      <vxe-option v-for="num in 12" :key="num" :value="num" :label="num"></vxe-option>
+                    </vxe-select> -->
+                      </template>
+                    </vxe-column>
+                    <vxe-column field="must" title="必填" width="100" :edit-render="{}">
+                      <template #default="{ row }">
+                        <vxe-checkbox
+                          v-if="isEdit"
+                          v-model="row.must"
+                          :unchecked-value="'0'"
+                          :checked-value="'1'"
+                        ></vxe-checkbox>
+                        <span v-else>{{ row.must == '1' ? '是' : '否' }}</span>
+                      </template>
+                    </vxe-column>
+                    <vxe-column field="trip" title="说明" :edit-render="{}">
+                      <template #default="{ row }">
+                        <vxe-input v-if="isEdit" v-model="row.trip" type="text"></vxe-input>
+                        <span v-else>{{ row.trip || '' }}</span>
+                      </template>
+                    </vxe-column>
+                    <vxe-column title="操作" width="200" v-if="isEdit">
+                      <template #default="{ row }">
+                        <vxe-button
+                          type="text"
+                          v-if="row.type === 'array'"
+                          status="primary"
+                          @click="insertRow(row, 'xTable')"
+                          >插入</vxe-button
+                        >
+                        <vxe-button type="text" status="primary" @click="removeRow(row, 'xTable')">删除</vxe-button>
+                      </template>
+                    </vxe-column>
+                  </vxe-table>
+
+                  <Button class="mt10" v-if="isEdit" type="primary" @click="insertEvent('xTable')">添加参数</Button>
+                </FormItem>
+                <FormItem label="返回参数:">
+                  <vxe-table
+                    resizable
+                    show-overflow
+                    keep-source
+                    ref="resTable"
+                    row-id="id"
+                    :print-config="{}"
+                    :export-config="{}"
+                    :loading="loading"
+                    :tree-config="{ transform: true, rowField: 'id', parentField: 'parentId' }"
+                    :data="formValidate.return_params"
+                  >
+                    <!-- <vxe-column type="checkbox" width="60"></vxe-column> -->
+                    <vxe-column field="attribute" title="属性" width="300" tree-node :edit-render="{}">
+                      <template #default="{ row }">
+                        <vxe-input v-if="isEdit" v-model="row.attribute" type="text"></vxe-input>
+                        <span v-else>{{ row.attribute || '' }}</span>
+                      </template>
+                    </vxe-column>
+                    <vxe-column field="type" title="类型" width="200" :edit-render="{}">
+                      <template #default="{ row }">
+                        <vxe-select v-if="isEdit" v-model="row.type" transfer>
+                          <vxe-option
+                            v-for="item in typeList"
+                            :key="item.value"
+                            :value="item.value"
+                            :label="item.label"
+                          ></vxe-option>
+                        </vxe-select>
+                        <span v-else>{{ row.type || '' }}</span>
+                      </template>
+                    </vxe-column>
+                    <!-- <vxe-column field="type" title="必填" :edit-render="{}">
+                  <template #default="{ row }">
+                    <vxe-checkbox v-model="row.must" :unchecked-value="0" :checked-value="1"></vxe-checkbox
+                    >{{ row.must }}
+                  </template>
+                </vxe-column> -->
+                    <vxe-column field="trip" title="说明" :edit-render="{}">
+                      <template #default="{ row }">
+                        <vxe-input v-if="isEdit" v-model="row.trip" type="text"></vxe-input>
+                        <span v-else>{{ row.trip || '' }}</span>
+                      </template>
+                    </vxe-column>
+                    <vxe-column title="操作" width="200" v-if="isEdit">
+                      <template #default="{ row }">
+                        <vxe-button
+                          type="text"
+                          v-if="row.type === 'array'"
+                          status="primary"
+                          @click="insertRow(row, 'resTable')"
+                          >插入</vxe-button
+                        >
+                        <vxe-button type="text" status="primary" @click="removeRow(row, 'resTable')">删除</vxe-button>
+                      </template>
+                    </vxe-column>
+                  </vxe-table>
+                  <Button class="mt10" v-if="isEdit" type="primary" @click="insertEvent('resTable')">添加参数</Button>
+                </FormItem>
+              </Col>
+            </Row>
+            <Row :gutter="24" type="flex">
+              <Col span="24">
+                <div class="title">调用示例</div>
+                <FormItem label="请求数据示例:" prop="request_example">
+                  <Input
+                    v-if="isEdit"
+                    class="perW20"
+                    type="textarea"
+                    :rows="4"
+                    v-model.trim="formValidate.request_example"
+                    placeholder="请输入"
+                  />
+                  <span v-else class="text-area">{{ formValidate.request_example || '' }}</span>
+                </FormItem>
+                <FormItem label="返回数据示例:" prop="return_example">
+                  <Input
+                    v-if="isEdit"
+                    class="perW20"
+                    type="textarea"
+                    :rows="4"
+                    v-model.trim="formValidate.return_example"
+                    placeholder="请输入"
+                  />
+                  <span v-else class="text-area">{{ formValidate.return_example || '' }}</span>
+                </FormItem>
+                <FormItem label="错误码:">
+                  <vxe-table
+                    resizable
+                    show-overflow
+                    keep-source
+                    ref="codeTable"
+                    row-id="id"
+                    :print-config="{}"
+                    :export-config="{}"
+                    :loading="loading"
+                    :tree-config="{ transform: true, rowField: 'id', parentField: 'parentId' }"
+                    :data="formValidate.error_code"
+                  >
+                    <!-- <vxe-column type="checkbox" width="60"></vxe-column> -->
+                    <vxe-column field="code" title="错误码" tree-node :edit-render="{}">
+                      <template #default="{ row }">
+                        <vxe-input v-if="isEdit" v-model="row.code" type="text"></vxe-input>
+                        <span v-else>{{ row.code || '' }}</span>
+                      </template>
+                    </vxe-column>
+                    <vxe-column field="value" title="错误码取值" :edit-render="{}">
+                      <template #default="{ row }">
+                        <vxe-input v-if="isEdit" v-model="row.value" type="text"></vxe-input>
+                        <span v-else>{{ row.value || '' }}</span>
+                      </template>
+                    </vxe-column>
+                    <vxe-column field="solution" title="解决方案" :edit-render="{}">
+                      <template #default="{ row }">
+                        <vxe-input v-if="isEdit" v-model="row.solution" type="text"></vxe-input>
+                        <span v-else>{{ row.solution || '' }}</span>
+                      </template>
+                    </vxe-column>
+                    <vxe-column title="操作" v-if="isEdit">
+                      <template #default="{ row }">
+                        <vxe-button type="text" status="primary" @click="removeRow(row, 'codeTable')">删除</vxe-button>
+                      </template>
+                    </vxe-column>
+                  </vxe-table>
+                  <Button class="mt10" v-if="isEdit" type="primary" @click="insertEvent('codeTable')">添加参数</Button>
+                </FormItem>
+              </Col>
+            </Row>
+            <!-- <Row :gutter="24" type="flex">
+              <Col span="24">
+                <FormItem>
+                  <Button type="primary" class="submission" @click="handleSubmit('formValidate')">保存</Button>
+                </FormItem>
+              </Col>
+            </Row> -->
+          </Form>
+        </div>
+        <!-- <div v-else class="nothing">
+          <div class="box" @click="clickMenu(4)">
+            <div class="icon">
+              <Icon type="ios-folder" />
+            </div>
+            <div class="text">新建文件</div>
+          </div>
+          <div class="box" @click="clickMenu(1)">
+            <div class="icon">
+              <Icon type="logo-linkedin" />
+            </div>
+            <div class="text">新建接口</div>
+          </div>
+        </div> -->
+      </Card>
+    </div>
+    <Modal v-model="nameModal" title="分组名称" :loading="loading" @on-ok="asyncOK">
+      <label>分组名称:</label>
+      <Input v-model="value" placeholder="请输入分组名称" style="width: 85%" />
+    </Modal>
+    <Modal v-model="debuggingModal" :title="formValidate.name" width="70%" footer-hide :loading="loading">
+      <debugging
+        v-if="debuggingModal"
+        :formValidate="formValidate"
+        :typeList="typeList"
+        :requestTypeList="requestTypeList"
+      />
+    </Modal>
+  </div>
+</template>
+
+<script>
+import { interfaceList, interfaceDet, interfaceSave, interfaceEditName, interfaceDel } from '@/api/systemOutAccount';
+import { VueTreeList, Tree, TreeNode } from 'vue-tree-list';
+import debugging from './debugging.vue';
+import { mapState } from 'vuex';
+export default {
+  name: 'systemOutInterface',
+  components: {
+    VueTreeList,
+    debugging,
+  },
+  data() {
+    return {
+      value: '',
+      isEdit: false,
+      nameModal: false,
+      debuggingModal: false,
+      formValidate: {},
+      grid: {
+        xl: 7,
+        lg: 7,
+        md: 12,
+        sm: 24,
+        xs: 24,
+      },
+      ruleValidate: {
+        title: [{ message: '请输入正确的描述 (不能多于200位数)', trigger: 'blur', max: 200 }],
+      },
+      loading: false,
+
+      typeList: [
+        {
+          value: 'string',
+          label: 'String',
+        },
+        {
+          value: 'array',
+          label: 'Array',
+        },
+        {
+          value: 'number',
+          label: 'Number',
+        },
+        {
+          value: 'boolean',
+          label: 'Boolean',
+        },
+        {
+          value: 'null',
+          label: 'Null',
+        },
+        {
+          value: 'any',
+          label: 'Any',
+        },
+      ],
+      requestTypeList: [
+        {
+          value: 'get',
+          label: 'get',
+        },
+        {
+          value: 'post',
+          label: 'post',
+        },
+        {
+          value: 'delete',
+          label: 'delete',
+        },
+        {
+          value: 'put',
+          label: 'put',
+        },
+        {
+          value: 'options',
+          label: 'options',
+        },
+      ],
+      contextData: null, //左侧导航右键点击是产生的数据对象
+      treeData: undefined,
+      buttonProps: {
+        type: 'default',
+        size: 'small',
+      },
+      methodColor: '#fff',
+    };
+  },
+  watch: {
+    ['formValidate.method']: {
+      deep: true,
+      handler(newVal, oldVal) {
+        let method = newVal.toUpperCase();
+        if (method == 'GET') {
+          this.methodColor = '#61affe';
+        } else if (method == 'POST') {
+          this.methodColor = '#49cc90';
+        } else if (method == 'PUT') {
+          this.methodColor = '#fca130';
+        } else if (method == 'DELETE') {
+          this.methodColor = '#f93e3e';
+        }
+      },
+    },
+  },
+  computed: {
+    ...mapState('media', ['isMobile']),
+    labelWidth() {
+      return this.isMobile ? undefined : 50;
+    },
+    labelPosition() {
+      return this.isMobile ? 'top' : 'right';
+    },
+  },
+  created() {
+    this.getInterfaceList('one');
+  },
+  methods: {
+    debugging() {
+      this.debuggingModal = true;
+    },
+    onClicksss(e) {},
+    methodsColor(newVal) {
+      let method = newVal.toUpperCase();
+      if (method == 'GET') {
+        return '#61affe';
+      } else if (method == 'POST') {
+        return '#49cc90';
+      } else if (method == 'PUT') {
+        return '#fca130';
+      } else if (method == 'DELETE') {
+        return '#f93e3e';
+      }
+    },
+    insertBefore(params) {},
+    insertAfter(params) {},
+    moveInto(params) {},
+    async addTableData() {
+      const { row: data } = await $table.insertAt(newRow, -1);
+      await $table.setActiveCell(data, 'name');
+    },
+    getInterfaceList(disk_type) {
+      interfaceList()
+        .then((res) => {
+          res.data[0].expand = false;
+          this.treeData = new Tree(res.data);
+
+          if (res.data.length) {
+            if (res.data[0].children.length) {
+              this.onClick(res.data[0].children[0]);
+            }
+          }
+        })
+        .catch((err) => {
+          this.$Message.error(err);
+        });
+    },
+    onClick(params) {
+      if (params.method) {
+        this.isEdit = false;
+        interfaceDet(params.id)
+          .then((res) => {
+            this.formValidate = res.data;
+          })
+          .catch((err) => {
+            this.$Message.error(err);
+          });
+      }
+    },
+    async handleSubmit() {
+      if (!this.formValidate.name) {
+        return this.$Message.warning('请输入接口名称');
+      } else if (!this.formValidate.method) {
+        return this.$Message.warning('请选择请求类型');
+      } else if (!this.formValidate.url) {
+        return this.$Message.warning('请输入调用方式');
+      }
+      this.formValidate.request_params = await this.$refs.xTable.getTableData().tableData;
+      this.formValidate.return_params = await this.$refs.resTable.getTableData().tableData;
+      this.formValidate.error_code = await this.$refs.codeTable.getTableData().tableData;
+      await interfaceSave(this.formValidate)
+        .then((res) => {
+          this.isEdit = false;
+          this.$Message.success(res.msg);
+          this.getInterfaceList();
+        })
+        .catch((err) => {
+          this.$Message.error(err);
+        });
+    },
+    async insertEvent(type) {
+      const $table = this.$refs[type];
+      let newRow;
+      if (type == 'xTable') {
+        newRow = {
+          attribute: '',
+          type: '',
+          must: 0,
+          trip: '',
+        };
+      } else if (type == 'resTable') {
+        newRow = {
+          attribute: '',
+          type: '',
+          trip: '',
+        };
+      } else {
+        newRow = {
+          code: '',
+          value: '',
+          solution: '',
+        };
+      }
+      // $table.insert(newRow).then(({ row }) => $table.setEditRow(row, -1));
+      const { row: data } = await $table.insertAt(newRow, -1);
+      await $table.setActiveCell(data, 'name');
+    },
+    async insertRow(currRow, type) {
+      const $table = this.$refs[type];
+      // 如果 null 则插入到目标节点顶部
+      // 如果 -1 则插入到目标节点底部
+      // 如果 row 则有插入到效的目标节点该行的位置
+      let record;
+      if (type == 'xTable') {
+        record = {
+          attribute: '',
+          type: '',
+          must: 0,
+          trip: '',
+          id: Date.now(),
+          parentId: currRow.id, // 需要指定父节点,自动插入该节点中
+        };
+      } else if (type == 'resTable') {
+        record = {
+          attribute: '',
+          type: '',
+          trip: '',
+          id: Date.now(),
+          parentId: currRow.id, // 需要指定父节点,自动插入该节点中
+        };
+      } else {
+        record = {
+          code: '',
+          value: '',
+          solution: '',
+          id: Date.now(),
+          parentId: currRow.id, // 需要指定父节点,自动插入该节点中
+        };
+      }
+      const { row: newRow } = await $table.insertAt(record, -1);
+      await $table.setTreeExpand(currRow, true); // 将父节点展开
+      await $table.setActiveRow(newRow); // 插入子节点
+    },
+    async removeRow(row, type) {
+      const $table = this.$refs[type];
+      await $table.remove(row);
+    },
+    // 修改名字
+    add() {
+      this.value = '';
+      this.formValidate.id = 0;
+      this.nameModal = true;
+    },
+    // 点击菜单
+    clickMenu(name, params) {
+      if (name == 1) {
+        this.formValidate = {};
+        this.formValidate.pid = params ? params.id : 0;
+        this.formValidate.id = 0;
+        this.isEdit = true;
+      } else if (name == 2) {
+        this.value = params.name || '';
+        this.formValidate.id = params ? params.id : 0;
+        this.nameModal = true;
+      } else if (name == 3) {
+        this.onDel(params);
+      } else if (name == 4) {
+        this.add();
+      }
+    },
+
+    addFac(params) {
+      this.formValidate = {
+        id: params ? params.id : 0,
+      };
+      this.isEdit = true;
+    },
+    asyncOK() {
+      let data = {
+        id: this.formValidate.id || 0,
+        type: 0,
+        name: this.value,
+      };
+      interfaceSave(data)
+        .then((res) => {
+          this.$Message.success(res.msg);
+          this.getInterfaceList();
+        })
+        .catch((err) => {
+          this.$Message.error(err);
+        });
+    },
+    //侧边栏右键点击事件
+    handleContextMenu(data, event, position) {
+      position.left = Number(position.left.slice(0, -2)) + 75 + 'px';
+      this.contextData = data;
+    },
+    handleContextCreateFolder() {},
+    handleContextCreateFile() {},
+    // 自定义显示
+    renderContent(h, { root, node, data }) {
+      let that = this;
+      return h(
+        'span',
+        {
+          style: {
+            display: 'inline-block',
+            width: '100%',
+          },
+        },
+        [
+          h('span', [
+            h(resolveComponent('Icon'), {
+              type: 'ios-paper-outline',
+              style: {
+                marginRight: '8px',
+              },
+            }),
+            h('span', data.title),
+          ]),
+          h(
+            'span',
+            {
+              style: {
+                display: 'inline-block',
+                float: 'right',
+                marginRight: '32px',
+              },
+            },
+            [
+              h(resolveComponent('Button'), {
+                ...this.buttonProps,
+                icon: 'ios-add',
+                style: {
+                  marginRight: '8px',
+                },
+                onClick: () => {
+                  this.append(data);
+                },
+              }),
+              h(resolveComponent('Button'), {
+                ...this.buttonProps,
+                icon: 'ios-remove',
+                onClick: () => {
+                  this.remove(root, node, data);
+                },
+              }),
+            ],
+          ),
+        ],
+      );
+    },
+    /**
+     * 侧边栏点击事件
+     * @param {Object} data
+     */
+    clickDir(data, root, node) {
+      let that = this;
+      that.navItem = data;
+      that.pathname = data.pathname;
+    },
+    append(data) {
+      const children = data.children || [];
+      children.push({
+        title: 'appended node',
+        expand: true,
+      });
+      this.$set(data, 'children', children);
+    },
+    remove(root, node, data) {
+      const parentKey = root.find((el) => el === node).parent;
+      const parent = root.find((el) => el.nodeKey === parentKey).node;
+      const index = parent.children.indexOf(data);
+      parent.children.splice(index, 1);
+    },
+    onMouseOver(root, node, data, e, d) {
+      console.log(root, node, data);
+    },
+    onMouseOver(root, node, data, e, d) {
+      console.log(root, node, data, e, d);
+    },
+    //
+    onDel(node) {
+      this.$Modal.confirm({
+        title: '警告',
+        content: '<p>删除后无法恢复,请确认后删除!</p>',
+        onOk: () => {
+          interfaceDel(node.id)
+            .then((res) => {
+              this.$Message.success(res.msg);
+              node.remove();
+            })
+            .catch((err) => {
+              this.$Message.error(err);
+            });
+        },
+        onCancel: () => {},
+      });
+    },
+
+    onChangeName(params) {
+      if (params.eventType == 'blur') {
+        let data = {
+          name: params.newName,
+          id: params.id,
+        };
+        interfaceEditName(data)
+          .then((res) => {
+            this.$Message.success(res.msg);
+          })
+          .catch((err) => {
+            this.$Message.error(err);
+          });
+      }
+    },
+
+    onAddNode(params) {
+      // this.$router.push({
+      //   path: '/admin/setting/system_out_interface/add',
+      //   query: {
+      //     pid: params.pid,
+      //   },
+      // });
+    },
+
+    addNode() {
+      var node = new TreeNode({ name: 'new node', isLeaf: false });
+      if (!this.data.children) this.data.children = [];
+      this.data.addChildren(node);
+    },
+
+    getNewTree() {
+      var vm = this;
+      function _dfs(oldNode) {
+        var newNode = {};
+
+        for (var k in oldNode) {
+          if (k !== 'children' && k !== 'parent') {
+            newNode[k] = oldNode[k];
+          }
+        }
+
+        if (oldNode.children && oldNode.children.length > 0) {
+          newNode.children = [];
+          for (var i = 0, len = oldNode.children.length; i < len; i++) {
+            newNode.children.push(_dfs(oldNode.children[i]));
+          }
+        }
+        return newNode;
+      }
+
+      vm.newTree = _dfs(vm.data);
+    },
+  },
+};
+</script>
+
+<style lang="stylus" scoped>
+.reset {
+  margin-left: 10px;
+}
+.card-tree {
+   height: 72px;
+   box-sizing: border-box;
+   overflow-x: scroll; /* 设置溢出滚动 */
+   white-space: nowrap;
+   overflow-y: hidden;
+   /* 隐藏滚动条 */
+   scrollbar-width: none; /* firefox */
+   -ms-overflow-style: none; /* IE 10+ */
+}
+.card-tree::-webkit-scrollbar {
+    display: none; /* Chrome Safari */
+}
+.main {
+  width: 100%;
+  display: flex;
+  .main-btn {}
+  .card-tree{
+    width: 270px;
+    height: calc(100vh - 115px);
+    overflow-y: scroll;
+  }
+  >>> .tree {
+    .tree-list{
+      margin-left:10px;
+
+    }
+    .vtl-caret{
+      padding-right: 2px;
+    }
+    .req-method {
+      display:block;
+      padding: 0px 2px;
+      font-size: 12px;
+      margin-right: 5px;
+      border-radius: 4px;
+
+      text-transform: uppercase;
+    }
+
+    .tree-node {
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+      cursor: pointer;
+      // width:200px;
+      padding: 3px 7px 3px 0;
+    }
+    .node{
+      padding:7px 2px 7px 0px;
+    }
+    .open {
+      // background-color: #fff1ef;
+      font-weight: 500;
+      color: #333;
+    }
+  }
+
+  >>> .vtl-node-main .vtl-operation {
+    position: absolute;
+    right: 20px;
+  }
+
+  >>> .vtl-node-content {
+    width: 100%;
+  }
+
+  .pop-menu {
+    display: flex;
+    justify-content: space-between;
+  }
+
+  >>> .vtl-node-content .add {
+    display: none;
+    margin-right: 10px;
+  }
+
+  >>> .vtl-node-content:hover .add {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    border-radius: 50%;
+    width: 20px;
+    height: 20px;
+  }
+
+  >>> .vtl-node-content:hover .add:hover {
+    background-color: #fff;
+
+    .pop-menu {
+      font-size: 16px;
+    }
+  }
+  >>> .vtl-node-main{
+    padding:0;
+  }
+  >>> .line1 {
+    display: table-caption;
+    white-space: nowrap;
+    width: 120px;
+    overflow: hidden;
+    text-overflow: ellipsis;
+  }
+  >>> .ivu-form-item{
+    margin-bottom: 10px;
+  }
+  .right-card {
+    flex: 1;
+    max-height: calc(100vh - 115px);
+    overflow-y: scroll;
+  }
+
+  .data {
+    flex: 1;
+
+    .req-method {
+      text-transform: uppercase;
+      border-radius: 4px;
+      color: #fff;
+      padding: 3px 7px;
+    }
+
+    .eidt-sub {
+      display: flex;
+      justify-content: space-between;
+
+      .name {
+        font-size: 20px;
+        font-weight: 500;
+      }
+    }
+
+    .title {
+      font-size: 16px;
+      font-weight: 500;
+      margin-bottom: 15px;
+    }
+
+    .perW20 {
+      width: 500px;
+    }
+
+    .text-area {
+      white-space: pre-wrap;
+      word-break: break-word;
+
+    }
+  }
+
+  >>> .ivu-tree-title {
+    width: 100% !important;
+  }
+  >>> .vtl-tree-margin{
+    margin-left: 5px;
+  }
+  >>> .ivu-btn-icon-only.ivu-btn-small {
+    width: 28px;
+  }
+
+  .nothing {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    min-height: 800px;
+
+    .box:hover {
+      border: 1px solid pink;
+    }
+
+    .box {
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      flex-direction: column;
+      width: 150px;
+      height: 200px;
+      margin: 0 20px;
+      border-radius: 10px;
+      cursor: pointer;
+      overflow: hidden;
+      border: 1px solid #fff;
+
+      .icon {
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        width: 100%;
+        height: 150px;
+        font-size: 40px;
+        color: #2d8cf0;
+        background: #f1f1f1;
+      }
+
+      .text {
+        width: 100%;
+        height: 50px;
+        background: #ddd;
+        text-align: center;
+        line-height: 50px;
+        font-size: 14px;
+        font-weight: 500;
+      }
+    }
+  }
+}
+</style>

+ 119 - 0
src/pages/shop_setting/systemOutInterface/request.js

@@ -0,0 +1,119 @@
+import axios from 'axios';
+import Setting from '@/setting';
+import { getCookies, removeCookies } from '@/libs/util';
+
+const service = axios.create({
+  baseURL: Setting.apiBaseURL,
+  timeout: 10000, // 请求超时时间
+});
+axios.defaults.withCredentials = true; // 携带cookie
+
+// 请求拦截器
+service.interceptors.request.use(
+  (config) => {
+    if (config.kefu) {
+      let baseUrl = Setting.apiBaseURL.replace(/adminapi/, 'kefuapi');
+      config.baseURL = baseUrl;
+    } else {
+      config.baseURL = Setting.apiBaseURL;
+    }
+    if (config.file) {
+      config.headers['Content-Type'] = 'multipart/form-data';
+    }
+    try {
+      if (config.headerItem) {
+        for (let i in config.headerItem) {
+          config.headers[i] = config.headerItem[i];
+        }
+      }
+    } catch (error) {
+      console.log(error);
+    }
+
+    const token = getCookies('token');
+    const kefuToken = getCookies('kefu_token');
+    if (token || kefuToken) {
+      config.headers['Authori-zation'] = config.kefu ? 'Bearer ' + kefuToken : 'Bearer ' + token;
+    }
+    return config;
+  },
+  (error) => {
+    // do something with request error
+    return Promise.reject(error);
+  },
+);
+service.interceptors.response.use(
+  (response) => {
+    let obj = {};
+    if (!!response.data) {
+      if (typeof response.data == 'string') {
+        obj = JSON.parse(response.data);
+      } else {
+        obj = response.data;
+      }
+    }
+    let status = response.data ? obj.status : 0;
+    // let status = response.data ? response.data.status : 0;
+    const code = status;
+    switch (code) {
+      case 200:
+        return obj;
+      default:
+        return Promise.reject(obj || { msg: '未知错误' });
+    }
+  },
+  (error) => {
+    return Promise.reject(error);
+  },
+);
+export default service;
+
+// function sendRequest(url, method, params, header) {
+//   const instance = axios.create({
+//     baseURL: Setting.apiBaseURL, // 请求的根域名
+//     timeout: 1000, // 请求超时时间
+//     headers: {
+//       'X-Custom-Header': header, // 自定义头信息
+//     },
+//   });
+
+//   if (method === 'GET') {
+//     instance
+//       .get(url, { params: params })
+//       .then((response) => {
+//         // 处理响应数据
+//       })
+//       .catch((error) => {
+//         // 处理错误
+//       });
+//   } else if (method === 'POST') {
+//     instance
+//       .post(url, params, { headers: header })
+//       .then((response) => {
+//         // 处理响应数据
+//       })
+//       .catch((error) => {
+//         // 处理错误
+//       });
+//   } else if (method === 'PUT') {
+//     instance
+//       .put(url, params, { headers: header })
+//       .then((response) => {
+//         // 处理响应数据
+//       })
+//       .catch((error) => {
+//         // 处理错误
+//       });
+//   } else if (method === 'DELETE') {
+//     instance
+//       .delete(url, { headers: header })
+//       .then((response) => {
+//         // 处理响应数据
+//       })
+//       .catch((error) => {
+//         // 处理错误
+//       });
+//   }
+
+//   return instance;
+// }

+ 382 - 0
src/pages/shop_setting/systemRole/index.vue

@@ -0,0 +1,382 @@
+<template>
+	<div>
+		<Card :bordered="false" dis-hover class="ivu-mt">
+			<Form ref="formValidate" :model="formValidate" :label-width="labelWidth" :label-position="labelPosition"
+				@submit.native.prevent>
+				<Row type="flex" :gutter="24">
+					<Col v-bind="grid">
+					<FormItem label="状态:" label-for="status">
+						<Select v-model="formValidate.status" placeholder="请选择" @on-change="userSearchs" clearable>
+							<Option value="1">显示</Option>
+							<Option value="0">不显示</Option>
+						</Select>
+					</FormItem>
+					</Col>
+					<Col v-bind="grid">
+					<FormItem label="身份昵称:" label-for="role_name">
+						<Input search enter-button placeholder="请输入身份昵称" v-model="formValidate.role_name"
+							@on-search="userSearchs" />
+					</FormItem>
+					</Col>
+				</Row>
+				<Row type="flex">
+					<Col v-bind="grid">
+					<Button v-auth="['setting-system_role-add']" type="primary" icon="md-add"
+						@click="add('添加')">添加身份</Button>
+					</Col>
+				</Row>
+			</Form>
+			<Table :columns="columns1" :data="tableList" ref="table" class="mt25" :loading="loading" highlight-row
+				no-userFrom-text="暂无数据" no-filtered-userFrom-text="暂无筛选结果">
+				<template slot-scope="{ row, index }" slot="is_shows">
+					<i-switch v-model="row.status" :value="row.status" :true-value="1" :false-value="0"
+						@on-change="onchangeIsShow(row)" size="large">
+						<span slot="open">显示</span>
+						<span slot="close">隐藏</span>
+					</i-switch>
+				</template>
+				<template slot-scope="{ row, index }" slot="action">
+					<a @click="edit(row, '编辑')">编辑</a>
+					<Divider type="vertical" />
+					<a @click="del(row, '删除', index)">删除</a>
+				</template>
+			</Table>
+			<div class="acea-row row-right page">
+				<Page :total="total" :current="formValidate.page" show-elevator show-total @on-change="pageChange"
+					:page-size="formValidate.limit" />
+			</div>
+		</Card>
+		<!-- 新增编辑-->
+		<Modal v-model="modals" @on-cancel="onCancel" scrollable footer-hide closable :title="`${modelTit}身份`"
+			:mask-closable="false" width="600">
+			<Form ref="formInline" :model="formInline" :rules="ruleValidate" :label-width="100"
+				:label-position="labelPosition2" @submit.native.prevent>
+				<FormItem label="身份名称:" label-for="role_name" prop="role_name">
+					<Input placeholder="请输入身份昵称" v-model="formInline.role_name" />
+				</FormItem>
+				<FormItem label="是否开启:" prop="status">
+					<RadioGroup v-model="formInline.status">
+						<Radio :label="1">开启</Radio>
+						<Radio :label="0">关闭</Radio>
+					</RadioGroup>
+				</FormItem>
+				<FormItem label="权限:">
+					<div class="trees-coadd">
+						<div class="scollhide">
+							<div class="iconlist">
+								<Tree :data="menusList" show-checkbox ref="tree"></Tree>
+							</div>
+						</div>
+					</div>
+				</FormItem>
+				<Spin size="large" fix v-if="spinShow"></Spin>
+				<Button type="primary" size="large" long @click="handleSubmit('formInline')">提交</Button>
+			</Form>
+		</Modal>
+	</div>
+</template>
+<script>
+	import {
+		mapState
+	} from 'vuex';
+	import {
+		roleListApi,
+		roleSetStatusApi,
+		menusListApi,
+		roleCreatApi,
+		roleInfoApi
+	} from '@/api/setting';
+	export default {
+		name: 'systemrRole',
+		data() {
+			return {
+				spinShow: false,
+				modals: false,
+				total: 0,
+				grid: {
+					xl: 7,
+					lg: 7,
+					md: 12,
+					sm: 24,
+					xs: 24,
+				},
+				loading: false,
+				formValidate: {
+					status: '',
+					role_name: '',
+					page: 1,
+					limit: 20,
+				},
+				columns1: [{
+						title: 'ID',
+						key: 'id',
+						width: 80,
+					},
+					{
+						title: '身份昵称',
+						key: 'role_name',
+						minWidth: 120,
+					},
+					{
+						title: '权限',
+						key: 'rules',
+						tooltip: true,
+						width: 1000,
+					},
+					{
+						title: '状态',
+						slot: 'is_shows',
+						minWidth: 120,
+					},
+					{
+						title: '操作',
+						slot: 'action',
+						fixed: 'right',
+						minWidth: 120,
+					},
+				],
+				tableList: [],
+				formInline: {
+					role_name: '',
+					status: 0,
+					checked_menus: [],
+					id: 0,
+				},
+				menusList: [],
+				modelTit: '',
+				ruleValidate: {
+					role_name: [{
+						required: true,
+						message: '请输入身份昵称',
+						trigger: 'blur'
+					}],
+					status: [{
+						required: true,
+						type: 'number',
+						message: '请选择是否开启',
+						trigger: 'change'
+					}],
+					// checked_menus: [
+					//     { required: true, validator: validateStatus, trigger: 'change' }
+					// ]
+				},
+			};
+		},
+		computed: {
+			...mapState('media', ['isMobile']),
+			labelWidth() {
+				return this.isMobile ? undefined : 75;
+			},
+			labelPosition() {
+				return this.isMobile ? 'top' : 'left';
+			},
+			labelPosition2() {
+				return this.isMobile ? 'top' : 'right';
+			},
+		},
+		created() {
+			this.getList();
+		},
+		methods: {
+			// 添加
+			add(name) {
+				this.formInline.id = 0;
+				this.modelTit = name;
+				this.modals = true;
+				this.getmenusList();
+			},
+			// 删除
+			del(row, tit, num) {
+				let delfromData = {
+					title: tit,
+					num: num,
+					url: `setting/role/${row.id}`,
+					method: 'DELETE',
+					ids: '',
+				};
+				this.$modalSure(delfromData)
+					.then((res) => {
+						this.$Message.success(res.msg);
+						this.tableList.splice(num, 1);
+					})
+					.catch((res) => {
+						this.$Message.error(res.msg);
+					});
+			},
+			// 修改是否显示
+			onchangeIsShow(row) {
+				let data = {
+					id: row.id,
+					status: row.status,
+				};
+				roleSetStatusApi(data)
+					.then(async (res) => {
+						this.$Message.success(res.msg);
+					})
+					.catch((res) => {
+						this.$Message.error(res.msg);
+					});
+			},
+			// 列表
+			getList() {
+				this.loading = true;
+				this.formValidate.status = this.formValidate.status || '';
+				roleListApi(this.formValidate)
+					.then(async (res) => {
+						let data = res.data;
+						this.tableList = data.list;
+						this.total = res.data.count;
+						this.loading = false;
+					})
+					.catch((res) => {
+						this.loading = false;
+						this.$Message.error(res.msg);
+					});
+			},
+			pageChange(index) {
+				this.formValidate.page = index;
+				this.getList();
+			},
+			// 表格搜索
+			userSearchs() {
+				this.formValidate.page = 1;
+				this.getList();
+			},
+			// 编辑
+			edit(row, name) {
+				this.modelTit = name;
+				this.formInline.id = row.id;
+				this.modals = true;
+				this.rows = row;
+				this.getIofo(row);
+			},
+			// 菜单列表
+			getmenusList() {
+				this.spinShow = true;
+				menusListApi()
+					.then(async (res) => {
+						let data = res.data;
+						this.menusList = data.menus;
+						this.menusList.map((item, index) => {
+							if (item.title === '主页') {
+								// item.checked = true;
+								// item.disableCheckbox = true;
+								if (item.children.length) {
+									item.children.map((v) => {
+										// v.checked = true;
+										// v.disableCheckbox = true;
+									});
+								}
+							}
+							item.expand = false;
+						});
+						this.spinShow = false;
+					})
+					.catch((res) => {
+						this.spinShow = false;
+						this.$Message.error(res.msg);
+					});
+			},
+			// 详情
+			getIofo(row) {
+				this.spinShow = true;
+				roleInfoApi(row.id)
+					.then(async (res) => {
+						let data = res.data;
+						this.formInline = data.role || this.formInline;
+						this.formInline.checked_menus = this.formInline.rules;
+						this.tidyRes(data.menus);
+						this.spinShow = false;
+					})
+					.catch((res) => {
+						this.spinShow = false;
+						this.$Message.error(res.msg);
+					});
+			},
+			tidyRes(menus) {
+				let data = [];
+				menus.map((menu) => {
+					if (menu.title === '主页') {
+						menu.checked = true;
+						menu.disableCheckbox = true;
+						if (menu.children.length) {
+							menu.children.map((v) => {
+								v.checked = true;
+								v.disableCheckbox = true;
+							});
+						}
+						data.push(menu);
+					} else {
+						data.push(this.initMenu(menu));
+					}
+				});
+				console.log(data, 'info');
+				this.$set(this, 'menusList', data);
+			},
+			initMenu(menu) {
+				let data = {},
+					checkMenus = ',' + this.formInline.checked_menus + ',';
+				data.title = menu.title;
+				data.id = menu.id;
+				if (menu.children && menu.children.length > 0) {
+					data.children = [];
+					menu.children.map((child) => {
+						data.children.push(this.initMenu(child));
+					});
+				} else {
+					data.checked = checkMenus.indexOf(String(',' + data.id + ',')) !== -1;
+					data.expand = !data.checked;
+				}
+				return data;
+			},
+			// 提交
+			handleSubmit(name) {
+				this.$refs[name].validate((valid) => {
+					if (valid) {
+						this.formInline.checked_menus = [];
+						this.$refs.tree.getCheckedAndIndeterminateNodes().map((node) => {
+							this.formInline.checked_menus.push(node.id);
+						});
+						if (this.formInline.checked_menus.length === 0) return this.$Message.warning('请至少选择一个权限');
+						roleCreatApi(this.formInline)
+							.then(async (res) => {
+								this.$Message.success(res.msg);
+								this.modals = false;
+								this.getList();
+								this.$refs[name].resetFields();
+								this.formInline.checked_menus = [];
+							})
+							.catch((res) => {
+								this.$Message.error(res.msg);
+							});
+					} else {
+						return false;
+					}
+				});
+			},
+			onCancel() {
+				this.$refs['formInline'].resetFields();
+				this.formInline.checked_menus = [];
+			},
+		},
+	};
+</script>
+
+<style scoped lang="stylus">
+	.trees-coadd {
+		width: 100%;
+		height: 385px;
+	}
+
+	.scollhide {
+		width: 100%;
+		height: 100%;
+		overflow-x: hidden;
+		overflow-y: scroll;
+	}
+
+	// margin-left: 18px;
+	.scollhide::-webkit-scrollbar {
+		display: none;
+	}
+</style>

+ 399 - 0
src/pages/shop_setting/systemStore/index.vue

@@ -0,0 +1,399 @@
+<template>
+  <div class="article-manager">
+    <Card :bordered="false" dis-hover class="ivu-mt">
+      <Form
+        ref="formItem"
+        :model="formItem"
+        :label-width="labelWidth"
+        :label-position="labelPosition"
+        :rules="ruleValidate"
+        @submit.native.prevent
+      >
+        <Row type="flex" :gutter="24">
+          <Col span="24">
+            <Col v-bind="grid">
+              <FormItem label="门店名称:" prop="name" label-for="name">
+                <Input v-model="formItem.name" placeholder="请输入门店名称" />
+              </FormItem>
+            </Col>
+          </Col>
+          <Col span="24">
+            <Col v-bind="grid">
+              <FormItem label="门店简介:" label-for="introduction">
+                <Input v-model="formItem.introduction" placeholder="请输入门店简介" />
+              </FormItem>
+            </Col>
+          </Col>
+          <Col span="24">
+            <Col v-bind="grid">
+              <FormItem label="门店手机号:" label-for="phone" prop="phone">
+                <Input v-model="formItem.phone" type="number" placeholder="请输入门店手机号" />
+              </FormItem>
+            </Col>
+          </Col>
+          <Col span="24">
+            <Col v-bind="grid">
+              <FormItem label="门店地址:" label-for="address" prop="address">
+                <Cascader
+                  :data="addresData"
+                  :value="formItem.address"
+                  v-model="formItem.address"
+                  @on-change="handleChange"
+                ></Cascader>
+              </FormItem>
+            </Col>
+          </Col>
+          <Col span="24">
+            <Col v-bind="grid">
+              <FormItem label="详细地址:" label-for="detailed_address" prop="detailed_address">
+                <Input v-model="formItem.detailed_address" placeholder="请输入详细地址" />
+              </FormItem>
+            </Col>
+          </Col>
+          <Col span="24">
+            <Col v-bind="grid">
+              <FormItem label="核销时效:" label-for="valid_time">
+                <DatePicker
+                  :editable="false"
+                  @on-change="onchangeDate"
+                  :value="formItem.valid_time"
+                  v-model="formItem.valid_time"
+                  format="yyyy/MM/dd"
+                  type="daterange"
+                  split-panels
+                  placeholder="请选择核销时效"
+                ></DatePicker>
+              </FormItem>
+            </Col>
+          </Col>
+          <Col span="24">
+            <Col v-bind="grid">
+              <FormItem label="门店营业:" label-for="day_time">
+                <TimePicker
+                  type="timerange"
+                  @on-change="onchangeTime"
+                  v-model="formItem.day_time"
+                  format="HH:mm:ss"
+                  :value="formItem.day_time"
+                  placement="bottom-end"
+                  placeholder="请选择营业时间"
+                ></TimePicker>
+              </FormItem>
+            </Col>
+          </Col>
+          <Col span="24">
+            <Col v-bind="grid">
+              <FormItem label="门店logo:" prop="image">
+                <div class="picBox" @click="modalPicTap('单选')">
+                  <div class="pictrue" v-if="formItem.image"><img v-lazy="formItem.image" /></div>
+                  <div class="upLoad acea-row row-center-wrapper" v-else>
+                    <Icon type="ios-camera-outline" size="26" class="iconfont" />
+                  </div>
+                </div>
+              </FormItem>
+            </Col>
+          </Col>
+          <Col span="24">
+            <Col v-bind="grid">
+              <FormItem label="经纬度:" label-for="status2" prop="latlng">
+                <Tooltip>
+                  <Input
+                    search
+                    enter-button="查找位置"
+                    v-model="formItem.latlng"
+                    style="width: 100%"
+                    placeholder="请查找位置"
+                    @on-search="onSearch"
+                  />
+                  <div slot="content">请点击查找位置选择位置</div>
+                </Tooltip>
+              </FormItem>
+            </Col>
+          </Col>
+        </Row>
+        <Row type="flex">
+          <Col v-bind="grid">
+            <Button type="primary" class="ml20" @click="handleSubmit('formItem')">提交</Button>
+          </Col>
+        </Row>
+        <Spin size="large" fix v-if="spinShow"></Spin>
+      </Form>
+    </Card>
+
+    <Modal
+      v-model="modalPic"
+      width="950px"
+      scrollable
+      footer-hide
+      closable
+      title="上传商品图"
+      :mask-closable="false"
+      :z-index="888"
+    >
+      <uploadPictures
+        :isChoice="isChoice"
+        @getPic="getPic"
+        :gridBtn="gridBtn"
+        :gridPic="gridPic"
+        v-if="modalPic"
+      ></uploadPictures>
+    </Modal>
+
+    <Modal
+      v-model="modalMap"
+      scrollable
+      footer-hide
+      closable
+      title="上传商品图"
+      :mask-closable="false"
+      :z-index="1"
+      class="mapBox"
+    >
+      <iframe id="mapPage" width="100%" height="100%" frameborder="0" v-bind:src="keyUrl"></iframe>
+    </Modal>
+  </div>
+</template>
+
+<script>
+import { storeApi, keyApi, storeAddApi } from '@/api/setting';
+import { mapState } from 'vuex';
+// import city from '@/utils/city';
+import uploadPictures from '@/components/uploadPictures';
+import { cityList } from '@/api/app';
+
+export default {
+  name: 'systemStore',
+  components: { uploadPictures },
+  data() {
+    const validatePhone = (rule, value, callback) => {
+      if (!value) {
+        return callback(new Error('请填写手机号'));
+      } else if (!/^1[3456789]\d{9}$/.test(value)) {
+        callback(new Error('手机号格式不正确!'));
+      } else {
+        callback();
+      }
+    };
+    const validateUpload = (rule, value, callback) => {
+      if (!this.formItem.image) {
+        callback(new Error('请上传门店logo'));
+      } else {
+        callback();
+      }
+    };
+    return {
+      spinShow: false,
+      modalMap: false,
+      addresData: [],
+      formItem: {
+        name: '',
+        introduction: '',
+        phone: '',
+        address: [],
+        address2: [],
+        detailed_address: '',
+        valid_time: [],
+        day_time: [],
+        latlng: '',
+        id: 0,
+      },
+      ruleValidate: {
+        name: [{ required: true, message: '请输入门店名称', trigger: 'blur' }],
+        mail: [
+          { required: true, message: 'Mailbox cannot be empty', trigger: 'blur' },
+          { type: 'email', message: 'Incorrect email format', trigger: 'blur' },
+        ],
+        address: [{ required: true, message: '请选择门店地址', type: 'array', trigger: 'change' }],
+        valid_time: [
+          {
+            required: true,
+            type: 'array',
+            message: '请选择核销时效',
+            trigger: 'change',
+            fields: {
+              0: { type: 'date', required: true, message: '请选择年度范围' },
+              1: { type: 'date', required: true, message: '请选择年度范围' },
+            },
+          },
+        ],
+        day_time: [{ required: true, type: 'array', message: '请选择门店营业时间', trigger: 'change' }],
+        phone: [{ required: true, validator: validatePhone, trigger: 'blur' }],
+        detailed_address: [{ required: true, message: '请输入详细地址', trigger: 'blur' }],
+        image: [{ required: true, validator: validateUpload, trigger: 'change' }],
+        latlng: [{ required: true, message: '请选择经纬度', trigger: 'blur' }],
+      },
+      keyUrl: '',
+      grid: {
+        xl: 10,
+        lg: 16,
+        md: 18,
+        sm: 24,
+        xs: 24,
+      },
+      gridPic: {
+        xl: 6,
+        lg: 8,
+        md: 12,
+        sm: 12,
+        xs: 12,
+      },
+      gridBtn: {
+        xl: 4,
+        lg: 8,
+        md: 8,
+        sm: 8,
+        xs: 8,
+      },
+      modalPic: false,
+      isChoice: '单选',
+    };
+  },
+  created() {
+    this.getCityList();
+    this.getKey();
+    this.getFrom();
+  },
+  computed: {
+    ...mapState('media', ['isMobile']),
+    labelWidth() {
+      return this.isMobile ? undefined : 100;
+    },
+    labelPosition() {
+      return this.isMobile ? 'top' : 'right';
+    },
+  },
+  mounted: function () {
+    window.addEventListener(
+      'message',
+      function (event) {
+        // 接收位置信息,用户选择确认位置点后选点组件会触发该事件,回传用户的位置信息
+        var loc = event.data;
+        if (loc && loc.module === 'locationPicker') {
+          // 防止其他应用也会向该页面post信息,需判断module是否为'locationPicker'
+          window.parent.selectAdderss(loc);
+        }
+      },
+      false,
+    );
+    window.selectAdderss = this.selectAdderss;
+  },
+  methods: {
+    getCityList() {
+      cityList().then((res) => {
+        res.data.map((item) => {
+          item.value = item.label;
+          if (item.children && item.children.length) {
+            item.children.map((j) => {
+              j.value = j.label;
+              if (j.children && j.children.length) {
+                j.children.map((o) => {
+                  o.value = o.label;
+                });
+              }
+            });
+          }
+        });
+        this.addresData = res.data;
+      });
+    },
+    // 选择经纬度
+    selectAdderss(data) {
+      this.formItem.latlng = data.latlng.lat + ',' + data.latlng.lng;
+      this.modalMap = false;
+    },
+    // key值
+    getKey() {
+      keyApi()
+        .then(async (res) => {
+          let keys = res.data.key;
+          this.keyUrl = `https://apis.map.qq.com/tools/locpicker?type=1&key=${keys}&referer=myapp`;
+        })
+        .catch((res) => {
+          this.$Message.error(res.msg);
+        });
+    },
+    // 详情
+    getFrom() {
+      this.spinShow = true;
+      storeApi()
+        .then(async (res) => {
+          let info = res.data.info || null;
+          this.formItem = info || this.formItem;
+          this.formItem.address = info.address2;
+          this.spinShow = false;
+        })
+        .catch((res) => {
+          this.spinShow = false;
+          this.$Message.error(res.msg);
+        });
+    },
+    // 选择图片
+    modalPicTap() {
+      this.modalPic = true;
+    },
+    // 选中图片
+    getPic(pc) {
+      this.formItem.image = pc.att_dir;
+      this.modalPic = false;
+    },
+    // 选择地址
+    handleChange(value, selectedData) {
+      this.formItem.address = selectedData.map((o) => o.label);
+      //  this.formItem.address2 = selectedData.map(o => o.value);
+    },
+    // 核销时效
+    onchangeDate(e) {
+      this.formItem.valid_time = e;
+    },
+    // 营业时间
+    onchangeTime(e) {
+      this.formItem.day_time = e;
+    },
+    onSearch() {
+      this.modalMap = true;
+    },
+    // 提交
+    handleSubmit(name) {
+      this.$refs[name].validate((valid) => {
+        if (valid) {
+          storeAddApi(this.formItem)
+            .then(async (res) => {
+              this.$Message.success(res.msg);
+            })
+            .catch((res) => {
+              this.$Message.error(res.msg);
+            });
+        } else {
+          return false;
+        }
+      });
+    },
+  },
+};
+</script>
+
+<style scoped lang="stylus">
+.picBox
+    display: inline-block;
+    cursor: pointer;
+    .upLoad
+        width: 58px;
+        height: 58px;
+        line-height: 58px;
+        border: 1px dotted rgba(0, 0, 0, 0.1);
+        border-radius: 4px;
+        background: rgba(0, 0, 0, 0.02);
+    .pictrue
+        width: 60px;
+        height: 60px;
+        border: 1px dotted rgba(0, 0, 0, 0.1);
+        margin-right: 10px;
+        img
+           width: 100%;
+           height: 100%;
+    .iconfont
+        color: #898989;
+
+.mapBox >>> .ivu-modal-body
+    height: 640px !important;
+</style>

+ 233 - 0
src/pages/shop_setting/themeStyle/index.vue

@@ -0,0 +1,233 @@
+<template>
+  <div>
+    <div class="i-layout-page-header header-title">
+      <span class="ivu-page-header-title mr20">{{ $route.meta.title }}</span>
+      <div>
+        <div style="float: right">
+          <Button class="bnt" type="primary" @click="submit">保存</Button>
+        </div>
+      </div>
+    </div>
+    <Card :bordered="false" dis-hover class="ivu-mt" :style="'min-height:' + clientHeight + 'px'">
+      <Form :label-width="labelWidth">
+        <FormItem label="选择配色方案:">
+          <RadioGroup v-model="current" @on-change="changeColor">
+            <Radio :label="1" border class="box">天空蓝<i class="iconfont iconxuanzhong6"></i></Radio>
+            <Radio :label="2" border class="box green">生鲜绿<i class="iconfont iconxuanzhong6"></i></Radio>
+            <Radio :label="3" border class="box red">热情红<i class="iconfont iconxuanzhong6"></i></Radio>
+            <Radio :label="4" border class="box pink">魅力粉<i class="iconfont iconxuanzhong6"></i></Radio>
+            <Radio :label="5" border class="box orange">活力橙<i class="iconfont iconxuanzhong6"></i></Radio>
+          </RadioGroup>
+        </FormItem>
+        <FormItem label="当前风格示例:">
+          <div class="acea-row row-top">
+            <div class="pictrue" v-for="(item, index) in picList" :key="index">
+              <img :src="item.image" />
+            </div>
+          </div>
+        </FormItem>
+      </Form>
+    </Card>
+    <!--<div class="footer acea-row row-center-wrapper">-->
+    <!--<Button type="primary" @click="submit">保存</Button>-->
+    <!--</div>-->
+  </div>
+</template>
+
+<script>
+import { mapState } from 'vuex';
+import { colorChange, getColorChange } from '@/api/diy';
+export default {
+  name: 'themeStyle',
+  data() {
+    return {
+      grid: {
+        xl: 7,
+        lg: 7,
+        md: 12,
+        sm: 24,
+        xs: 24,
+      },
+      picList: [],
+      picListBule: [{ image: require('@/assets/images/bule.jpg') }],
+      picListGreen: [{ image: require('@/assets/images/green.jpg') }],
+      picListRed: [{ image: require('@/assets/images/red.jpg') }],
+      picListPink: [{ image: require('@/assets/images/pink.jpg') }],
+      picListOrange: [{ image: require('@/assets/images/orange.jpg') }],
+      current: '',
+      clientHeight: 0,
+      loadingExist: false,
+    };
+  },
+  computed: {
+    ...mapState('admin/layout', ['isMobile']),
+    labelWidth() {
+      return this.isMobile ? undefined : 100;
+    },
+    labelPosition() {
+      return this.isMobile ? 'top' : 'right';
+    },
+  },
+  created() {
+    this.picList = this.picListBule;
+    this.getInfo();
+  },
+  mounted: function () {
+    this.$nextTick(() => {
+      this.clientHeight = `${document.documentElement.clientHeight}` - 250; //获取浏览器可视区域高度
+      let that = this;
+      window.onresize = function () {
+        that.clientHeight = `${document.documentElement.clientHeight}` - 250;
+      };
+    });
+  },
+  methods: {
+    getInfo() {
+      getColorChange('color_change')
+        .then((res) => {
+          this.current = res.data.status ? res.data.status : 3;
+          this.changeColor(this.current);
+        })
+        .catch((err) => {
+          this.$Message.error(err.msg);
+        });
+    },
+    submit() {
+      this.loadingExist = true;
+      colorChange(this.current, 'color_change')
+        .then((res) => {
+          this.loadingExist = false;
+          this.$Message.success(res.msg);
+        })
+        .catch(() => {
+          this.loadingExist = false;
+        });
+    },
+    changeColor(e) {
+      switch (e) {
+        case 1:
+          this.picList = this.picListBule;
+          break;
+        case 2:
+          this.picList = this.picListGreen;
+          break;
+        case 3:
+          this.picList = this.picListRed;
+          break;
+        case 4:
+          this.picList = this.picListPink;
+          break;
+        case 5:
+          this.picList = this.picListOrange;
+          break;
+        default:
+          break;
+      }
+    },
+  },
+};
+</script>
+
+<style scoped lang="stylus">
+.box {
+  height: 40px;
+  width: 100px;
+  line-height: 40px;
+  text-align: center;
+}
+
+.bnt {
+  // width 10px!important;
+}
+
+.pictrue {
+  width: 800px;
+  height: 100%;
+  margin: 10px 24px 0 0;
+
+  img {
+    width: 100%;
+    height: 100%;
+  }
+}
+
+.footer {
+  width: 100%;
+  height: 70px;
+  box-shadow: 0px -2px 4px rgba(0, 0, 0, 0.03);
+  background-color: #fff;
+  position: fixed;
+  bottom: 0;
+  left: 0;
+  z-index: 9;
+}
+
+/deep/.i-layout-content-main {
+  margin-bottom: 0 !important;
+}
+
+/deep/.ivu-card-body {
+  padding-bottom: 0 !important;
+}
+
+/deep/.ivu-radio-inner {
+  background-color: #1db0fc;
+  border: 0;
+  border-radius: 3px;
+  width: 18px;
+  height: 18px;
+}
+
+/deep/.ivu-radio-wrapper-checked .iconfont {
+  display: inline-block;
+}
+
+/deep/.ivu-radio-focus {
+  box-shadow: unset;
+  z-index: unset;
+}
+
+/deep/.ivu-radio-wrapper {
+  margin-right: 18px;
+}
+
+.green /deep/.ivu-radio-inner {
+  background-color: #42CA4D;
+}
+
+.red /deep/.ivu-radio-inner {
+  background-color: #E93323;
+}
+
+.pink/deep/.ivu-radio-inner {
+  background-color: #FF448F;
+}
+
+.orange/deep/.ivu-radio-inner {
+  background-color: #FE5C2D;
+}
+
+/deep/.ivu-radio-border {
+  position: relative;
+}
+
+.iconfont {
+  position: absolute;
+  top: 0px;
+  left: 21px;
+  font-size: 12px;
+  display: none;
+  color: #fff;
+}
+
+/deep/.ivu-radio-inner:after {
+  background-color: unset;
+  transform: unset;
+}
+
+/deep/.i-layout-page-header {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+}
+</style>

+ 120 - 0
src/pages/shop_setting/user/index.vue

@@ -0,0 +1,120 @@
+<template>
+  <div>
+    <Card :bordered="false" dis-hover class="ivu-mt">
+      <Form ref="formValidate" :model="formValidate" :rules="ruleValidate" :label-width="160" label-position="right">
+        <FormItem label="头像">
+          <div class="avatar" @click="avatarMoadl = true">
+            <img v-if="formValidate.head_pic" :src="formValidate.head_pic" alt="" />
+            <img v-else src="../../../assets/images/f.png" alt="" />
+          </div>
+        </FormItem>
+        <FormItem label="账号" prop="">
+          <Input type="text" v-model="account" :disabled="true" class="input"></Input>
+        </FormItem>
+        <FormItem label="姓名" prop="real_name">
+          <Input type="text" v-model="formValidate.real_name" class="input"></Input>
+        </FormItem>
+        <FormItem label="原始密码" prop="pwd">
+          <Input type="password" v-model="formValidate.pwd" class="input"></Input>
+        </FormItem>
+        <FormItem label="新密码" prop="new_pwd">
+          <Input type="password" v-model="formValidate.new_pwd" class="input"></Input>
+        </FormItem>
+        <FormItem label="确认新密码" prop="conf_pwd">
+          <Input type="password" v-model="formValidate.conf_pwd" class="input"></Input>
+        </FormItem>
+        <FormItem>
+          <Button type="primary" @click="handleSubmit('formValidate')">提交</Button>
+        </FormItem>
+      </Form>
+    </Card>
+    <Modal v-model="avatarMoadl" footer-hide title="头像上传" width="700">
+      <CropperImg v-if="avatarMoadl" @uploadImgSuccess="uploadImgSuccess"></CropperImg>
+    </Modal>
+  </div>
+</template>
+
+<script>
+import { updtaeAdmin } from '@/api/user';
+import { mapState } from 'vuex';
+import CropperImg from '@/components/cropperImg';
+export default {
+  name: 'setting_user',
+  components: { CropperImg },
+  computed: {
+    ...mapState('media', ['isMobile']),
+    ...mapState('userLevel', ['categoryId']),
+    labelWidth() {
+      return this.isMobile ? undefined : 75;
+    },
+    labelPosition() {
+      return this.isMobile ? 'top' : 'left';
+    },
+  },
+  data() {
+    return {
+      account: '',
+      avatarMoadl: false,
+      formValidate: {
+        avatar: '',
+        real_name: '',
+        pwd: '',
+        new_pwd: '',
+        conf_pwd: '',
+      },
+      ruleValidate: {
+        real_name: [{ required: true, message: '您的姓名不能为空', trigger: 'blur' }],
+        pwd: [{ required: true, message: '请输入您的原始密码', trigger: 'blur' }],
+        new_pwd: [{ required: true, message: '请输入您的新密码', trigger: 'blur' }],
+        conf_pwd: [{ required: true, message: '请确认您的新密码', trigger: 'blur' }],
+      },
+    };
+  },
+  mounted() {
+    this.account = this.$store.state.userInfo.userInfo.account;
+    this.formValidate.head_pic = this.$store.state.userInfo.userInfo.head_pic;
+    this.formValidate.real_name = this.$store.state.userInfo.userInfo.real_name;
+  },
+  methods: {
+    uploadImgSuccess(data) {
+      this.avatarMoadl = false;
+      this.formValidate.head_pic = data.src;
+    },
+    handleSubmit(name) {
+      this.$refs[name].validate((valid) => {
+        if (valid) {
+          updtaeAdmin(this.formValidate)
+            .then((res) => {
+              this.$store.commit('userInfo/userRealName', this.formValidate.real_name);
+              this.$store.commit('userInfo/userRealHeadPic', this.formValidate.head_pic);
+              this.$Message.success(res.msg);
+            })
+            .catch((res) => {
+              this.$Message.error(res.msg);
+            });
+        } else {
+          if (this.formValidate.new_pwd !== this.formValidate.conf_pwd) {
+            this.$Message.error('您输入的新密码与旧密码不一致');
+          }
+        }
+      });
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+.input {
+  width: 400px;
+}
+.avatar {
+  width: 80px;
+  height: 80px;
+  img {
+    width: 100%;
+    height: 100%;
+    border-radius: 50%;
+    border: 1px solid #f2f2f2;
+  }
+}
+</style>

+ 75 - 0
src/pages/shop_setting/userFile/index.vue

@@ -0,0 +1,75 @@
+<template>
+  <div>
+    <Card :bordered="false" dis-hover class="ivu-mt">
+      <Form ref="formValidate" :model="formValidate" :rules="ruleValidate" :label-width="160" label-position="right">
+        <FormItem label="账号" prop="">
+          <Input type="text" v-model="account" :disabled="true" class="input"></Input>
+        </FormItem>
+        <FormItem label="文件管理新密码" prop="file_pwd">
+          <Input type="password" v-model="formValidate.file_pwd" class="input"></Input>
+        </FormItem>
+        <FormItem label="文件管理确认新密码" prop="conf_file_pwd">
+          <Input type="password" v-model="formValidate.conf_file_pwd" class="input"></Input>
+        </FormItem>
+        <FormItem>
+          <Button type="primary" @click="handleSubmit('formValidate')">提交</Button>
+        </FormItem>
+      </Form>
+    </Card>
+  </div>
+</template>
+
+<script>
+import { setFilePassword } from '@/api/user';
+import { mapState } from 'vuex';
+export default {
+  name: 'setting_files',
+  computed: {
+    ...mapState('media', ['isMobile']),
+    ...mapState('userLevel', ['categoryId']),
+    labelWidth() {
+      return this.isMobile ? undefined : 75;
+    },
+    labelPosition() {
+      return this.isMobile ? 'top' : 'left';
+    },
+  },
+  data() {
+    return {
+      account: '',
+      formValidate: {
+        file_pwd: '',
+        conf_file_pwd: '',
+      },
+      ruleValidate: {
+        file_pwd: [{ required: true, message: '请输入您的文件管理新密码', trigger: 'blur' }],
+        conf_file_pwd: [{ required: true, message: '请确认您的文件管理新密码', trigger: 'blur' }],
+      },
+    };
+  },
+  mounted() {
+    this.account = this.$store.state.userInfo.userInfo.account;
+  },
+  methods: {
+    handleSubmit(name) {
+      this.$refs[name].validate((valid) => {
+        if (valid) {
+          setFilePassword(this.formValidate)
+            .then((res) => {
+              this.$Message.success(res.msg);
+            })
+            .catch((res) => {
+              this.$Message.error(res.msg);
+            });
+        }
+      });
+    },
+  },
+};
+</script>
+
+<style scoped>
+.input {
+  width: 400px;
+}
+</style>

+ 315 - 0
src/pages/shop_setting/verifyOrder/index.vue

@@ -0,0 +1,315 @@
+<template>
+  <div>
+    <Card :bordered="false" dis-hover class="ivu-mt">
+      <Form ref="formValidate" :model="formValidate" :label-width="80" @submit.native.prevent>
+        <Row :gutter="24" type="flex">
+          <Col span="24" class="ivu-text-left">
+            <FormItem label="核销日期:">
+              <RadioGroup
+                v-model="formValidate.data"
+                type="button"
+                class="mr"
+                @on-change="selectChange(formValidate.data)"
+              >
+                <Radio :label="item.val" v-for="(item, i) in fromList.fromTxt" :key="i">{{ item.text }}</Radio>
+              </RadioGroup>
+              <DatePicker
+                :editable="false"
+                @on-change="onchangeTime"
+                :value="timeVal"
+                format="yyyy/MM/dd"
+                type="daterange"
+                placement="bottom-end"
+                placeholder="请选择时间"
+                style="width: 200px"
+              ></DatePicker>
+            </FormItem>
+          </Col>
+          <Col span="12" class="ivu-text-left">
+            <FormItem label="筛选条件:">
+              <Input enter-button placeholder="请输入搜索内容" v-model="formValidate.real_name" style="width: 430px">
+                <Select v-model="field_key" slot="prepend" style="width: 80px">
+                  <Option value="all">全部</Option>
+                  <Option value="order_id">订单号</Option>
+                  <Option value="uid">UID</Option>
+                  <Option value="real_name">用户姓名</Option>
+                  <Option value="user_phone">用户电话</Option>
+                  <Option value="title">商品名称(模糊)</Option>
+                </Select>
+              </Input>
+            </FormItem>
+          </Col>
+          <Col span="12" class="mr">
+            <FormItem label="选择门店:" label-for="store_name">
+              <Select
+                v-model="formValidate.store_id"
+                element-id="store_id"
+                clearable
+                @on-change="userSearchs"
+                style="width: 430px"
+              >
+                <Option v-for="item in storeSelectList" :value="item.id" :key="item.id">{{ item.name }}</Option>
+              </Select>
+            </FormItem>
+          </Col>
+          <Col span="12" class="mr">
+            <FormItem label="" label-for="store_name">
+              <Button type="primary" class="mr15" @click="userSearchs">搜索</Button>
+              <Button class="mr15" @click="refresh">刷新</Button>
+            </FormItem>
+          </Col>
+        </Row>
+      </Form>
+      <Table
+        :columns="columns"
+        :data="orderList"
+        ref="table"
+        :loading="loading"
+        highlight-row
+        no-data-text="暂无数据"
+        no-filtered-data-text="暂无筛选结果"
+        class="orderData mt25"
+      >
+        <template slot-scope="{ row, index }" slot="name"> {{ row.nickname }}/{{ row.uid }} </template>
+        <template slot-scope="{ row, index }" slot="spread_nickname">
+          <a href="javascript:void(0);" @click="referenceInfo(row.spread_uid)">{{ row.spread_nickname }}</a>
+        </template>
+        <template slot-scope="{ row, index }" slot="info">
+          <div class="tabBox" v-for="(val, i) in row._info" :key="i">
+            <div class="tabBox_img">
+              <img
+                v-lazy="
+                  val.cart_info.productInfo.attrInfo
+                    ? val.cart_info.productInfo.attrInfo.image
+                    : val.cart_info.productInfo.image
+                "
+              />
+            </div>
+            <span class="tabBox_tit"
+              >{{ val.cart_info.productInfo.store_name + ' | '
+              }}{{ val.cart_info.productInfo.attrInfo ? val.cart_info.productInfo.attrInfo.suk : '' }}</span
+            >
+            <span class="tabBox_pice">{{ '¥' + val.cart_info.truePrice + ' x ' + val.cart_info.cart_num }}</span>
+          </div>
+        </template>
+        <template slot-scope="{ row, index }" slot="status_name">
+          {{ row.status_name.status_name }}
+        </template>
+      </Table>
+      <div class="acea-row row-right page">
+        <Page
+          :total="total"
+          :current="formValidate.page"
+          show-elevator
+          show-total
+          @on-change="pageChange"
+          :page-size="formValidate.limit"
+        />
+      </div>
+    </Card>
+    <referrer-info ref="info"></referrer-info>
+  </div>
+</template>
+
+<script>
+import { verifyOrderApi, merchantStoreListApi } from '@/api/setting';
+import cardsData from '@/components/cards/cards';
+import referrerInfo from '@/components/referrerInfo/index';
+export default {
+  name: 'setting_order',
+  components: { cardsData, referrerInfo },
+  data() {
+    return {
+      formValidate: {
+        page: 1,
+        limit: 15,
+        data: '',
+        real_name: '',
+        store_id: '',
+        field_key: '',
+      },
+      field_key: '',
+      fromList: {
+        title: '选择时间',
+        custom: true,
+        fromTxt: [
+          { text: '全部', val: '' },
+          { text: '今天', val: 'today' },
+          { text: '昨天', val: 'yesterday' },
+          { text: '最近7天', val: 'lately7' },
+          { text: '最近30天', val: 'lately30' },
+          { text: '本月', val: 'month' },
+          { text: '本年', val: 'year' },
+        ],
+      },
+      timeVal: [],
+      storeSelectList: [],
+      columns: [
+        {
+          title: '订单号',
+          key: 'order_id',
+          minWidth: 180,
+          sortable: true,
+        },
+        {
+          title: '用户信息',
+          slot: 'name',
+          minWidth: 120,
+        },
+        {
+          title: '推荐人信息',
+          slot: 'spread_nickname',
+          minWidth: 120,
+        },
+        {
+          title: '商品信息',
+          slot: 'info',
+          minWidth: 300,
+        },
+        {
+          title: '实际支付',
+          key: 'pay_price',
+          minWidth: 90,
+        },
+        {
+          title: '核销员',
+          key: 'clerk_name',
+          minWidth: 90,
+        },
+        {
+          title: '核销门店',
+          key: 'store_name',
+          minWidth: 120,
+        },
+        {
+          title: '支付状态',
+          key: 'pay_type_name',
+          minWidth: 80,
+        },
+        {
+          title: '订单状态',
+          slot: 'status_name',
+          minWidth: 80,
+        },
+        {
+          title: '下单时间',
+          key: 'add_time',
+          minWidth: 130,
+          sortable: true,
+        },
+      ],
+      orderList: [],
+      loading: false,
+      total: 0,
+    };
+  },
+  mounted() {
+    this.getList();
+    this.storeList();
+  },
+  methods: {
+    getList() {
+      let that = this;
+      that.loading = true;
+      that.formValidate.field_key = this.field_key === 'all' ? '' : this.field_key;
+      verifyOrderApi(that.formValidate)
+        .then((res) => {
+          that.loading = false;
+          that.orderList = res.data.data;
+          that.total = res.data.count;
+        })
+        .catch((res) => {
+          that.$Message.error(res.msg);
+        });
+    },
+    userSearchs() {
+      this.formValidate.page = 1;
+      this.getList();
+    },
+    // 具体日期
+    onchangeTime(e) {
+      this.timeVal = e;
+      this.formValidate.data = this.timeVal.join('-');
+      this.getList();
+    },
+    // 选择时间
+    selectChange(tab) {
+      this.formValidate.page = 1;
+      this.formValidate.data = tab;
+      this.timeVal = [];
+      this.getList();
+    },
+    storeList() {
+      let that = this;
+      merchantStoreListApi()
+        .then((res) => {
+          that.storeSelectList = res.data;
+        })
+        .catch((res) => {
+          that.$Message.error(res.msg);
+        });
+    },
+    pageChange(index) {
+      this.formValidate.page = index;
+      this.getList();
+    },
+    referenceInfo(uid) {
+      this.$refs.info.isTemplate = true;
+      this.$refs.info.verifySpreadInfo(uid);
+    },
+    refresh() {
+      this.formValidate = {
+        page: 1,
+        limit: 15,
+        data: '',
+        real_name: '',
+        store_id: '',
+        field_key: '',
+      };
+      this.field_key = '';
+      this.getList();
+    },
+  },
+};
+</script>
+
+<style scoped lang="stylus">
+img {
+    height: 36px;
+    display: block;
+}
+.tabBox
+    width 100%
+    height 100%
+    display flex
+    align-items: center
+    .tabBox_img
+        width 36px
+        height 36px
+        img
+            width 100%
+            height 100%
+    .tabBox_tit
+        width 60%
+        font-size 12px !important
+        margin 0 2px 0 10px
+        letter-spacing: 1px;
+        padding: 5px 0;
+        box-sizing: border-box;
+.orderData >>>.ivu-table-cell{padding-left: 0 !important;}
+.vertical-center-modal{
+    display: flex;
+    align-items: center;
+    justify-content: center;}
+.ivu-mt{
+  margin-bottom 12px
+}
+.ivu-mt a
+   color #515a6e
+.ivu-mt a:hover
+    color: #2D8cF0;
+.ivu-mt /deep/ .ivu-form-item{
+  padding 7px 0;
+  margin-bottom 0
+}
+</style>

+ 164 - 155
src/router/modules/frameOut.js

@@ -13,158 +13,167 @@ let routePre = setting.routePre;
 const pre = 'kefu_';
 
 export default [
-  // 登录
-  {
-    path: routePre + '/login',
-    name: 'login',
-    meta: {
-      title: '登录',
-      hideInMenu: true,
-    },
-    component: () => import('@/pages/account/login'),
-  },
-  {
-    path: '/kefu',
-    name: `${pre}index`,
-    meta: {
-      auth: true,
-      title: '客服管理',
-      kefu: true,
-    },
-    component: () => import('@/pages/kefu/index'),
-  },
-  // 客服
-  {
-    path: routePre + '/kefu',
-    name: `${pre}index`,
-    meta: {
-      auth: true,
-      title: '客服管理',
-      kefu: true,
-    },
-    redirect: {
-      name: `setting_service`,
-    },
-    component: () => import('@/pages/kefu/index'),
-  },
-  {
-    path: '/kefu/mobile_list',
-    name: `${pre}mobile_list`,
-    meta: {
-      auth: true,
-      title: '消息列表',
-      kefu: true,
-    },
-    component: () => import('@/pages/kefu/mobile/chat_list'),
-  },
-  {
-    path: '/kefu/mobile_chat',
-    name: `${pre}mobile_chat`,
-    meta: {
-      auth: true,
-      title: '对话详情',
-      kefu: true,
-    },
-    component: () => import('@/pages/kefu/mobile/index'),
-  },
-  {
-    path: '/kefu/pc_list',
-    name: `${pre}pc_list`,
-    meta: {
-      auth: true,
-      title: '客服',
-      kefu: true,
-    },
-    component: () => import('@/pages/kefu/pc/index'),
-  },
-  {
-    path: '/kefu/orderList/:type?/:toUid?',
-    name: `${pre}order-list`,
-    meta: {
-      auth: true,
-      title: '订单列表',
-      kefu: true,
-    },
-    component: () => import('@/pages/kefu/mobile/orderList/index'),
-  },
-  {
-    path: '/kefu/orderDetail/:id?/:goname?',
-    name: `${pre}order-detail`,
-    meta: {
-      auth: true,
-      title: '订单详情',
-      kefu: true,
-    },
-    component: () => import('@/pages/kefu/mobile/orderList/orderDetail.vue'),
-  },
-  {
-    path: '/kefu/orderDelivery/:id?/:orderId?',
-    name: `${pre}order-delivery`,
-    meta: {
-      auth: true,
-      title: '发货',
-      kefu: true,
-    },
-    component: () => import('@/pages/kefu/mobile/orderList/orderDelivery.vue'),
-  },
-  {
-    path: '/kefu/user/index/:uid?/:type?',
-    name: `${pre}user-index`,
-    meta: {
-      auth: true,
-      title: '客户信息',
-      kefu: true,
-    },
-    component: () => import('@/pages/kefu/mobile/user/index'),
-  },
-  {
-    path: '/kefu/goods/list',
-    name: `${pre}goods-list`,
-    meta: {
-      auth: true,
-      title: '商品列表',
-      kefu: true,
-    },
-    component: () => import('@/pages/kefu/mobile/goods/list.vue'),
-  },
-  {
-    path: '/kefu/goods/detail',
-    name: `${pre}goods-detail`,
-    meta: {
-      auth: true,
-      title: '商品列表',
-      kefu: true,
-    },
-    component: () => import('@/pages/kefu/mobile/goods/detail.vue'),
-  },
-  {
-    path: '/kefu/appChat',
-    name: `${pre}app-chat`,
-    meta: {
-      auth: true,
-      title: '客服',
-      kefu: true,
-    },
-    component: () => import('@/pages/kefu/appChat/index'),
-  },
-  {
-    path: '/kefu/mobile_user_chat',
-    name: `${pre}app-mobile_user_chat`,
-    meta: {
-      auth: true,
-      title: '用户客服',
-      kefu: true,
-    },
-    component: () => import('@/pages/kefu/appChat/mobile/index'),
-  },
-  {
-    path: '/kefu/mobile_feedback',
-    name: `${pre}app-mobile_feedback`,
-    meta: {
-      auth: true,
-      title: '用户反馈',
-      kefu: true,
-    },
-    component: () => import('@/pages/kefu/appChat/mobile/feedback'),
-  },
-];
+	// 登录
+	{
+		path: routePre + '/login',
+		name: 'login',
+		meta: {
+			title: '登录',
+			hideInMenu: true,
+		},
+		component: () => import('@/pages/account/login'),
+	},
+	{
+		path: routePre + '/shop/login',
+		name: 'shoplogin',
+		meta: {
+			title: '登录',
+			hideInMenu: true,
+		},
+		component: () => import('@/pages/account/shoplogin'),
+	},
+	{
+		path: '/kefu',
+		name: `${pre}index`,
+		meta: {
+			auth: true,
+			title: '客服管理',
+			kefu: true,
+		},
+		component: () => import('@/pages/kefu/index'),
+	},
+	// 客服
+	{
+		path: routePre + '/kefu',
+		name: `${pre}index`,
+		meta: {
+			auth: true,
+			title: '客服管理',
+			kefu: true,
+		},
+		redirect: {
+			name: `setting_service`,
+		},
+		component: () => import('@/pages/kefu/index'),
+	},
+	{
+		path: '/kefu/mobile_list',
+		name: `${pre}mobile_list`,
+		meta: {
+			auth: true,
+			title: '消息列表',
+			kefu: true,
+		},
+		component: () => import('@/pages/kefu/mobile/chat_list'),
+	},
+	{
+		path: '/kefu/mobile_chat',
+		name: `${pre}mobile_chat`,
+		meta: {
+			auth: true,
+			title: '对话详情',
+			kefu: true,
+		},
+		component: () => import('@/pages/kefu/mobile/index'),
+	},
+	{
+		path: '/kefu/pc_list',
+		name: `${pre}pc_list`,
+		meta: {
+			auth: true,
+			title: '客服',
+			kefu: true,
+		},
+		component: () => import('@/pages/kefu/pc/index'),
+	},
+	{
+		path: '/kefu/orderList/:type?/:toUid?',
+		name: `${pre}order-list`,
+		meta: {
+			auth: true,
+			title: '订单列表',
+			kefu: true,
+		},
+		component: () => import('@/pages/kefu/mobile/orderList/index'),
+	},
+	{
+		path: '/kefu/orderDetail/:id?/:goname?',
+		name: `${pre}order-detail`,
+		meta: {
+			auth: true,
+			title: '订单详情',
+			kefu: true,
+		},
+		component: () => import('@/pages/kefu/mobile/orderList/orderDetail.vue'),
+	},
+	{
+		path: '/kefu/orderDelivery/:id?/:orderId?',
+		name: `${pre}order-delivery`,
+		meta: {
+			auth: true,
+			title: '发货',
+			kefu: true,
+		},
+		component: () => import('@/pages/kefu/mobile/orderList/orderDelivery.vue'),
+	},
+	{
+		path: '/kefu/user/index/:uid?/:type?',
+		name: `${pre}user-index`,
+		meta: {
+			auth: true,
+			title: '客户信息',
+			kefu: true,
+		},
+		component: () => import('@/pages/kefu/mobile/user/index'),
+	},
+	{
+		path: '/kefu/goods/list',
+		name: `${pre}goods-list`,
+		meta: {
+			auth: true,
+			title: '商品列表',
+			kefu: true,
+		},
+		component: () => import('@/pages/kefu/mobile/goods/list.vue'),
+	},
+	{
+		path: '/kefu/goods/detail',
+		name: `${pre}goods-detail`,
+		meta: {
+			auth: true,
+			title: '商品列表',
+			kefu: true,
+		},
+		component: () => import('@/pages/kefu/mobile/goods/detail.vue'),
+	},
+	{
+		path: '/kefu/appChat',
+		name: `${pre}app-chat`,
+		meta: {
+			auth: true,
+			title: '客服',
+			kefu: true,
+		},
+		component: () => import('@/pages/kefu/appChat/index'),
+	},
+	{
+		path: '/kefu/mobile_user_chat',
+		name: `${pre}app-mobile_user_chat`,
+		meta: {
+			auth: true,
+			title: '用户客服',
+			kefu: true,
+		},
+		component: () => import('@/pages/kefu/appChat/mobile/index'),
+	},
+	{
+		path: '/kefu/mobile_feedback',
+		name: `${pre}app-mobile_feedback`,
+		meta: {
+			auth: true,
+			title: '用户反馈',
+			kefu: true,
+		},
+		component: () => import('@/pages/kefu/appChat/mobile/feedback'),
+	},
+];

+ 21 - 23
src/router/modules/index.js

@@ -13,31 +13,29 @@ import setting from '@/setting';
 let routePre = setting.routePre;
 
 const meta = {
-  auth: true,
+	auth: true,
 };
 
 const pre = 'home_';
 
 export default {
-  path: routePre + '/home',
-  name: 'home',
-  header: 'home',
-  redirect: {
-    name: `${pre}index`,
-  },
-  meta,
-  component: LayoutMain,
-  children: [
-    {
-      path: routePre + '/index',
-      name: `${pre}index`,
-      header: 'home',
-      meta: {
-        auth: ['admin-index-index'],
-        title: '主页',
-        isAffix: true,
-      },
-      component: () => import('@/pages/index/index'),
-    },
-  ],
-};
+	path: routePre + '/home',
+	name: 'home',
+	header: 'home',
+	redirect: {
+		name: `${pre}index`,
+	},
+	meta,
+	component: LayoutMain,
+	children: [{
+		path: routePre + '/index',
+		name: `${pre}index`,
+		header: 'home',
+		meta: {
+			auth: ['admin-index-index'],
+			title: '主页',
+			isAffix: true,
+		},
+		component: () => import('@/pages/index/index'),
+	}, ],
+};

+ 62 - 0
src/router/modules/shop.js

@@ -0,0 +1,62 @@
+// +---------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +---------------------------------------------------------------------
+// | Copyright (c) 2016~2023 https://www.crmeb.com All rights reserved.
+// +---------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +---------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +---------------------------------------------------------------------
+
+import LayoutMain from '@/layout';
+import setting from '@/setting';
+let routePre = setting.routePre;
+
+const pre = 'shop_';
+
+export default {
+	path: routePre + '/shop',
+	name: 'shop',
+	header: 'shop',
+	redirect: {
+		name: `${pre}list`,
+	},
+	component: LayoutMain,
+	children: [{
+			path: 'list',
+			name: `${pre}list`,
+			meta: {
+				auth: ['admin-shop-storeShop-index'],
+				title: '商户管理',
+			},
+			component: () => import('@/pages/shop/shop'),
+		},
+		{
+			path: 'type',
+			name: `${pre}type`,
+			meta: {
+				auth: ['admin-shop-type'],
+				title: '商户类型',
+			},
+			component: () => import('@/pages/shop/type.vue'),
+		},
+		{
+			path: 'classify',
+			name: `${pre}classify`,
+			meta: {
+				auth: ['admin-shop-classify'],
+				title: '商户分类',
+			},
+			component: () => import('@/pages/shop/classify'),
+		},
+		{
+			path: 'apply',
+			name: `${pre}apply`,
+			meta: {
+				auth: ['admin-shop-apply'],
+				title: '申请商户',
+			},
+			component: () => import('@/pages/shop/apply'),
+		},
+	],
+};

+ 78 - 0
src/router/modules/shop_product.js

@@ -0,0 +1,78 @@
+// +---------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +---------------------------------------------------------------------
+// | Copyright (c) 2016~2023 https://www.crmeb.com All rights reserved.
+// +---------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +---------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +---------------------------------------------------------------------
+
+import LayoutMain from '@/layout';
+import setting from '@/setting';
+let routePre = setting.shoproutePre;
+
+const pre = 'product_';
+
+export default {
+	path: routePre + '/product',
+	name: 'mer_product',
+	header: 'mer_product',
+	meta: {
+		title: '商品',
+		// 授权标识
+		auth: ['mer-store-index'],
+	},
+	redirect: {
+		name: `${pre}productList`,
+	},
+	component: LayoutMain,
+	children: [{
+			path: 'product_list',
+			name: `${pre}productList`,
+			meta: {
+				title: '商品管理',
+				auth: ['mer-store-storeProuduct-index'],
+				keepAlive: true,
+			},
+			component: () => import('@/pages/shop_product/productList'),
+		},
+		{
+			path: 'product_classify',
+			name: `${pre}productClassify`,
+			meta: {
+				title: '商品分类',
+				auth: ['mer-store-storeCategory-index'],
+			},
+			component: () => import('@/pages/shop_product/productClassify'),
+		},
+		{
+			path: 'add_product/:id?',
+			name: `${pre}productAdd`,
+			meta: {
+				auth: ['mer-store-storeProuduct-index'],
+				title: '商品添加',
+				activeMenu: routePre + '/product/product_list',
+			},
+			component: () => import('@/pages/shop_product/productAdd'),
+		},
+		{
+			path: 'product_reply/:id?',
+			name: `${pre}productEvaluate`,
+			meta: {
+				auth: ['mer-store-storeProuduct-index'],
+				title: '商品评论',
+			},
+			component: () => import('@/pages/shop_product/productReply'),
+		},
+		{
+			path: 'product_attr',
+			name: `${pre}productAttr`,
+			meta: {
+				auth: ['mer-store-storeProuduct-index'],
+				title: '商品规格',
+			},
+			component: () => import('@/pages/shop_product/productAttr'),
+		},
+	],
+};

+ 651 - 0
src/router/modules/shop_setting.js

@@ -0,0 +1,651 @@
+// +---------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +---------------------------------------------------------------------
+// | Copyright (c) 2016~2023 https://www.crmeb.com All rights reserved.
+// +---------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +---------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +---------------------------------------------------------------------
+
+import LayoutMain from '@/layout';
+import setting from '@/setting';
+let routePre = setting.shoproutePre;
+
+const meta = {
+	auth: true,
+};
+
+const pre = 'setting_';
+
+export default {
+	path: routePre + '/setting',
+	name: 'setting',
+	header: 'setting',
+	redirect: {
+		name: `${pre}setSystem`,
+	},
+	component: LayoutMain,
+	children: [{
+			path: 'system_role/index',
+			name: `${pre}systemRole`,
+			meta: {
+				auth: ['setting-system-role'],
+				title: '身份管理',
+			},
+			component: () => import('@/pages/shop_setting/systemRole/index'),
+		},
+		{
+			path: 'system_admin/index',
+			name: `${pre}systemAdmin`,
+			meta: {
+				auth: ['setting-system-list'],
+				title: '管理员列表',
+			},
+			component: () => import('@/pages/shop_setting/systemAdmin/index'),
+		},
+		{
+			path: 'system_menus/index',
+			name: `${pre}systemMenus`,
+			meta: {
+				auth: ['setting-system-menus'],
+				title: '权限规则',
+			},
+			component: () => import('@/pages/shop_setting/systemMenus/index'),
+		},
+		{
+			path: 'system_config',
+			name: `${pre}setSystem`,
+			meta: {
+				auth: ['setting-system-config'],
+				title: '系统设置',
+			},
+			component: () => import('@/pages/shop_setting/setSystem/index'),
+		},
+		{
+			path: 'system_config/:type?/:tab_id?',
+			name: `${pre}setApp`,
+			meta: {
+				title: '应用设置',
+			},
+			component: () => import('@/pages/shop_setting/setSystem/index'),
+		},
+		{
+			path: 'system_config_retail/:type?/:tab_id?',
+			name: `${pre}distributionSet`,
+			meta: {
+				...meta,
+				title: '分销配置',
+			},
+			component: () => import('@/pages/shop_setting/setSystem/index'),
+		},
+		{
+			path: 'membership_level/index',
+			name: `${pre}membershipLevel`,
+			meta: {
+				...meta,
+				title: '分销等级',
+			},
+			component: () => import('@/pages/shop_setting/membershipLevel/index'),
+		},
+		{
+			path: 'system_config_message/:type?/:tab_id?',
+			name: `${pre}message`,
+			meta: {
+				auth: ['setting-system-config-message'],
+				title: '短信开关',
+			},
+			component: () => import('@/pages/shop_setting/setSystem/index'),
+		},
+		{
+			path: 'notification/index',
+			name: `${pre}notification`,
+			meta: {
+				auth: ['setting-notification'],
+				title: '消息管理',
+			},
+			component: () => import('@/pages/shop_setting/notification/index'),
+		},
+		{
+			path: 'notification/notificationEdit',
+			name: `${pre}notificationEdit`,
+			meta: {
+				auth: ['setting-notification'],
+				title: '消息编辑',
+			},
+			component: () => import('@/pages/shop_setting/notification/notificationEdit'),
+		},
+		{
+			path: 'system_config_logistics/:type?/:tab_id?',
+			name: `${pre}logistics`,
+			meta: {
+				auth: ['setting-system-config-logistics'],
+				title: '物流配置',
+			},
+			component: () => import('@/pages/shop_setting/setSystem/index'),
+		},
+		{
+			path: 'sms/sms_config/index',
+			name: `${pre}config`,
+			meta: {
+				auth: ['setting-sms-sms-config'],
+				title: '一号通账户',
+			},
+			component: () => import('@/pages/notify/smsConfig/index'),
+		},
+		{
+			path: 'sms/sms_template_apply/index',
+			name: `${pre}smsTemplateApply`,
+			meta: {
+				auth: ['setting-sms-config-template'],
+				title: '短信模板',
+			},
+			component: () => import('@/pages/notify/smsTemplateApply/index'),
+		},
+		{
+			path: 'sms/sms_pay/index',
+			name: `${pre}smsPay`,
+			meta: {
+				auth: ['setting-sms-sms-template'],
+				title: '短信购买',
+			},
+			component: () => import('@/pages/notify/smsPay/index'),
+		},
+		{
+			path: 'sms/sms_template_apply/commons',
+			name: `${pre}commons`,
+			meta: {
+				...meta,
+				title: '公共短信模板',
+			},
+			component: () => import('@/pages/notify/smsTemplateApply/index'),
+		},
+		{
+			path: 'system_group_data/index/:id',
+			name: `${pre}groupDataIndex`,
+			meta: {
+				auth: ['setting-system-group_data-index'],
+				title: '首页导航按钮',
+			},
+			component: () => import('@/pages/system/group/list'),
+		},
+		{
+			path: 'system_group_data/slide/:id',
+			name: `${pre}groupDataSlide`,
+			meta: {
+				auth: ['setting-system-group_data-slide'],
+				title: '首页幻灯片',
+			},
+			component: () => import('@/pages/system/group/list'),
+		},
+		{
+			path: 'system_group_data/sign/:id',
+			name: `${pre}groupDataSign`,
+			meta: {
+				auth: ['setting-system-group_data-sign'],
+				title: '签到天数配置',
+			},
+			component: () => import('@/pages/system/group/list'),
+		},
+		// {
+		//   path: 'system_group_data/order/:id',
+		//   name: `${pre}groupDataOrder`,
+		//   meta: {
+		//     auth: ['setting-system-group_data-order'],
+		//     title: '订单详情动态图'
+		//   },
+		//   component: () => import('@/pages/system/group/list')
+		// },
+		// {
+		//   path: 'system_group_data/user/:id',
+		//   name: `${pre}groupDataUser`,
+		//   meta: {
+		//     auth: ['setting-system-group_data-user'],
+		//     title: '个人中心菜单'
+		//   },
+		//   component: () => import('@/pages/system/group/list')
+		// },
+		{
+			path: 'system_group_data/new/:id',
+			name: `${pre}groupDataNew`,
+			meta: {
+				auth: ['setting-system-group_data-new'],
+				title: '首页滚动新闻',
+			},
+			component: () => import('@/pages/system/group/list'),
+		},
+		{
+			path: 'system_group_data/search/:id',
+			name: `${pre}groupDataNew`,
+			meta: {
+				auth: ['setting-system-group_data-search'],
+				title: '热门搜索',
+			},
+			component: () => import('@/pages/system/group/list'),
+		},
+		{
+			path: 'system_group_data/hot/:id',
+			name: `${pre}groupDataHot`,
+			meta: {
+				auth: ['setting-system-group_data-hot'],
+				title: '热门榜单推荐',
+			},
+			component: () => import('@/pages/system/group/list'),
+		},
+		{
+			path: 'system_group_data/new_product/:id',
+			name: `${pre}groupDataNewProduct`,
+			meta: {
+				auth: ['setting-system-group_data-new_product'],
+				title: '首发新品推荐',
+			},
+			component: () => import('@/pages/system/group/list'),
+		},
+		{
+			path: 'system_group_data/promotion/:id',
+			name: `${pre}groupDataPromotion`,
+			meta: {
+				auth: ['setting-system-group_data-promotion'],
+				title: '促销单品推荐',
+			},
+			component: () => import('@/pages/system/group/list'),
+		},
+		{
+			path: 'system_group_data/poster/:id',
+			name: `${pre}groupDataPoster`,
+			meta: {
+				auth: ['setting-system-group_data-poster'],
+				title: '个人中心分销海报',
+			},
+			component: () => import('@/pages/system/group/list'),
+		},
+		{
+			path: 'system_group_data/best/:id',
+			name: `${pre}groupDataBest`,
+			meta: {
+				auth: ['setting-system-group_data-best'],
+				title: '精品推荐',
+			},
+			component: () => import('@/pages/system/group/list'),
+		},
+		{
+			path: 'system_group_data/activity/:id',
+			name: `${pre}groupDataActivity`,
+			meta: {
+				auth: ['setting-system-group_data-activity'],
+				title: '首页活动区域图片',
+			},
+			component: () => import('@/pages/system/group/list'),
+		},
+		{
+			path: 'system_group_data/system/:id',
+			name: `${pre}groupDataSystem`,
+			meta: {
+				auth: ['setting-system-group_data-system'],
+				title: '首页配置',
+			},
+			component: () => import('@/pages/system/group/list'),
+		},
+		{
+			path: 'system_group_data/hot_money/:id',
+			name: `${pre}groupDataHotMoney`,
+			meta: {
+				auth: ['admin-setting-system_group_data-hot_money'],
+				title: '首页超值爆款',
+			},
+			component: () => import('@/pages/system/group/list'),
+		},
+		{
+			path: 'merchant/system_store/index',
+			name: `${pre}systemStore`,
+			meta: {
+				auth: ['setting-system-config-merchant'],
+				title: '门店设置',
+			},
+			component: () => import('@/pages/setting/systemStore/index'),
+		},
+		{
+			path: 'freight/express/index',
+			name: `${pre}freight`,
+			meta: {
+				auth: ['setting-freight-express'],
+				title: '物流公司',
+			},
+			component: () => import('@/pages/shop_setting/freight/index'),
+		},
+		{
+			path: 'store_service/index',
+			name: `${pre}service`,
+			meta: {
+				auth: ['setting-store-service'],
+				title: '客服管理',
+			},
+			component: () => import('@/pages/shop_setting/storeService/index'),
+		},
+		{
+			path: 'freight/city/list',
+			name: `${pre}dada`,
+			meta: {
+				auth: ['setting-system-city'],
+				title: '城市数据',
+			},
+			component: () => import('@/pages/shop_setting/cityDada/index'),
+		},
+		{
+			path: 'freight/shipping_templates/list',
+			name: `${pre}templates`,
+			meta: {
+				auth: ['setting-shipping-templates'],
+				title: '运费模板',
+			},
+			component: () => import('@/pages/shop_setting/shippingTemplates/index'),
+		},
+		{
+			path: 'merchant/system_store/list',
+			name: `${pre}store`,
+			meta: {
+				auth: ['setting-merchant-system-store'],
+				title: '提货点',
+			},
+			component: () => import('@/pages/shop_setting/storeList/index'),
+		},
+		{
+			path: 'merchant/system_store_staff/index',
+			name: `${pre}staff`,
+			meta: {
+				auth: ['setting-merchant-system-store-staff'],
+				title: '核销员',
+			},
+			component: () => import('@/pages/shop_setting/clerkList/index'),
+		},
+		{
+			path: 'merchant/system_verify_order/index',
+			name: `${pre}order`,
+			meta: {
+				auth: ['setting-merchant-system-verify-order'],
+				title: '核销订单',
+			},
+			component: () => import('@/pages/shop_setting/verifyOrder/index'),
+		},
+		{
+			path: 'theme_style',
+			name: `${pre}themeStyle`,
+			meta: {
+				auth: ['admin-setting-theme_style'],
+				title: '主题风格',
+			},
+			component: () => import('@/pages/shop_setting/themeStyle/index'),
+		},
+		{
+			path: 'pages',
+			name: `${pre}page`,
+			header: 'setting',
+			redirect: {
+				name: `${pre}devise`,
+			},
+		},
+		{
+			path: 'pages/devise',
+			name: `${pre}devise`,
+			meta: {
+				auth: ['admin-setting-pages-devise'],
+				title: '店铺装修',
+			},
+			component: () => import('@/pages/shop_setting/devise/list'),
+		},
+		{
+			path: 'pages/diy',
+			name: `${pre}diy`,
+			meta: {
+				auth: ['admin-setting-pages-diy'],
+				title: '页面设计',
+				activeMenu: routePre + '/setting/pages/devise',
+			},
+			component: () => import('@/pages/shop_setting/devisePage/index'),
+		},
+		{
+			path: 'pages/diy_index',
+			name: `${pre}index_diy`,
+			meta: {
+				auth: ['admin-setting-pages-diy'],
+				title: '首页设计',
+				fullScreen: true, //是否全屏显示main区域
+			},
+			component: () => import('@/pages/shop_setting/devise/diyIndex'),
+		},
+		{
+			path: 'pages/links',
+			name: `${pre}links`,
+			meta: {
+				auth: ['admin-setting-pages-links'],
+				title: '页面链接',
+			},
+			component: () => import('@/pages/shop_setting/devise/links'),
+		},
+		{
+			path: 'store_service/speechcraft',
+			name: `${pre}speechcraft`,
+			meta: {
+				auth: ['admin-setting-store_service-speechcraft'],
+				title: '客服话术',
+			},
+			component: () => import('@/pages/shop_setting/storeService/speechcraft'),
+		},
+		{
+			path: 'store_service/feedback',
+			name: `${pre}feedback`,
+			meta: {
+				auth: ['admin-setting-store_service-feedback'],
+				title: '用户留言',
+			},
+			component: () => import('@/pages/shop_setting/storeService/feedback'),
+		},
+		{
+			path: 'system_group_data/pc/:id',
+			name: `${pre}groupDataPc`,
+			meta: {
+				auth: ['setting-system-group_data-pc'],
+				title: 'PC主页轮播',
+			},
+			component: () => import('@/pages/system/group/list'),
+		},
+		{
+			path: 'system_config_member_right/:type?/:tab_id?',
+			name: `${pre}right`,
+			meta: {
+				auth: ['setting-system-config-member-right'],
+				title: '会员权益',
+			},
+			component: () => import('@/pages/shop_setting/setSystem/index'),
+		},
+		{
+			path: 'delivery_service/index',
+			name: `${pre}deliveryService`,
+			meta: {
+				auth: ['setting-delivery-service'],
+				title: '配送员列表',
+			},
+			component: () => import('@/pages/shop_setting/deliveryService/index'),
+		},
+		{
+			path: 'pc_group_data',
+			name: `${pre}systemGroupData`,
+			meta: {
+				auth: ['setting-system-pc_data'],
+				title: 'PC商城',
+			},
+			component: () => import('@/pages/system/group/pc'),
+		},
+		{
+			path: 'system_visualization_data',
+			name: `${pre}systemGroupData`,
+			meta: {
+				auth: ['admin-setting-system_visualization_data'],
+				title: '数据配置',
+			},
+			component: () => import('@/pages/system/group/visualization'),
+		},
+		{
+			path: 'storage',
+			name: `${pre}storage`,
+			meta: {
+				auth: ['setting-storage'],
+				title: '储存配置',
+			},
+			component: () => import('@/pages/shop_setting/storage'),
+		},
+		{
+			path: 'wechat_config/:type?/:tab_id?',
+			name: `${pre}wechat_config`,
+			meta: {
+				...meta,
+				title: '公众号配置',
+			},
+			component: () => import('@/pages/shop_setting/setSystem/index'),
+		},
+		{
+			path: 'routine_config/:type?/:tab_id?',
+			name: `${pre}routine_config`,
+			meta: {
+				...meta,
+				title: '小程序配置',
+			},
+			component: () => import('@/pages/shop_setting/setSystem/index'),
+		},
+		{
+			path: 'app_config/:type?/:tab_id?',
+			name: `${pre}app_config`,
+			meta: {
+				...meta,
+				title: 'app配置',
+			},
+			component: () => import('@/pages/shop_setting/setSystem/index'),
+		},
+		{
+			path: 'pc_config/:type?/:tab_id?',
+			name: `${pre}pc_config`,
+			meta: {
+				...meta,
+				title: 'PC配置',
+			},
+			component: () => import('@/pages/shop_setting/setSystem/index'),
+		},
+		{
+			path: 'other_config/print/:type?/:tab_id?',
+			name: `${pre}other_print`,
+			meta: {
+				auth: ['setting-other-print'],
+				title: '小票打印配置',
+			},
+			component: () => import('@/pages/shop_setting/setSystem/index'),
+		},
+		{
+			path: 'other_config/copy/:type?/:tab_id?',
+			name: `${pre}other_copy`,
+			meta: {
+				auth: ['setting-other-copy'],
+				title: '商品采集配置',
+			},
+			component: () => import('@/pages/shop_setting/setSystem/index'),
+		},
+		{
+			path: 'other_config/logistics/:type?/:tab_id?',
+			name: `${pre}other_logistics`,
+			meta: {
+				auth: ['setting-other-logistics'],
+				title: '物流查询配置',
+			},
+			component: () => import('@/pages/shop_setting/setSystem/index'),
+		},
+		{
+			path: 'other_config/electronic/:type?/:tab_id?',
+			name: `${pre}other_electronic`,
+			meta: {
+				auth: ['setting-other-electronic'],
+				title: '电子面单配置',
+			},
+			component: () => import('@/pages/shop_setting/setSystem/index'),
+		},
+		{
+			path: 'other_config/sms/:type?/:tab_id?',
+			name: `${pre}other_sms`,
+			meta: {
+				auth: ['setting-other-sms'],
+				title: '短信功能配置',
+			},
+			component: () => import('@/pages/shop_setting/setSystem/index'),
+		},
+		{
+			path: 'other_config/pay/:type?/:tab_id?',
+			name: `${pre}other_pay`,
+			meta: {
+				auth: ['setting-other-sms'],
+				title: '商城支付配置',
+			},
+			component: () => import('@/pages/shop_setting/setSystem/index'),
+		},
+		{
+			path: 'agreement',
+			name: `${pre}notification`,
+			meta: {
+				auth: ['setting-agreement'],
+				title: '协议设置',
+			},
+			component: () => import('@/pages/shop_setting/agreement/index'),
+		},
+		{
+			path: 'other_config/out/:type?/:tab_id?',
+			name: `${pre}other_print`,
+			meta: {
+				auth: ['setting-other-out'],
+				title: '对外接口配置',
+			},
+			component: () => import('@/pages/shop_setting/setSystem/index'),
+		},
+		{
+			path: 'system_out_account/index',
+			name: `${pre}systemOutAccount`,
+			meta: {
+				auth: ['setting-system-out-account-index'],
+				title: '账号列表',
+			},
+			component: () => import('@/pages/shop_setting/systemOutAccount/index'),
+		},
+		{
+			path: 'system_out_interface/index',
+			name: `${pre}systemOutAccount`,
+			meta: {
+				auth: ['setting-system-out-interface-index'],
+				title: '接口文档',
+			},
+			component: () => import('@/pages/shop_setting/systemOutInterface/index'),
+		},
+		{
+			path: 'lang/list',
+			name: `${pre}langList`,
+			meta: {
+				auth: ['admin-lang-list'],
+				title: '语言列表',
+			},
+			component: () => import('@/pages/shop_setting/multiLanguage/list'),
+		},
+		{
+			path: 'lang/info',
+			name: `${pre}langInfo`,
+			meta: {
+				auth: ['admin-lang-info'],
+				title: '语言详情',
+			},
+			component: () => import('@/pages/shop_setting/multiLanguage/langList'),
+		},
+		{
+			path: 'lang/country',
+			name: `${pre}langCountry`,
+			meta: {
+				auth: ['admin-lang-country'],
+				title: '地区关联语言',
+			},
+			component: () => import('@/pages/shop_setting/multiLanguage/country'),
+		},
+	],
+};

+ 163 - 159
src/router/routers.js

@@ -10,6 +10,8 @@
 
 import index from './modules/index';
 import product from './modules/product';
+import shop_product from './modules/shop_product';
+import shop_setting from './modules/shop_setting';
 import order from './modules/order';
 import user from './modules/user';
 // import echarts from './modules/echarts'
@@ -26,14 +28,15 @@ import frameOut from './modules/frameOut';
 import division from './modules/division';
 import settings from '@/setting';
 import crud from './modules/crud';
+import shop from './modules/shop';
 
 const modulesFiles = require.context('./modules/crud', true, /\.js$/);
 
 const routers = [];
 // 将扫描到的路由信息加入路由数组中
 modulesFiles.keys().forEach((modulePath) => {
-  const value = modulesFiles(modulePath);
-  routers.push(value.default);
+	const value = modulesFiles(modulePath);
+	routers.push(value.default);
 });
 
 let routePre = settings.routePre;
@@ -41,137 +44,139 @@ let routePre = settings.routePre;
  * 在主框架内显示
  */
 
-const frameIn = [
-  {
-    path: '/',
-    meta: {
-      title: 'CRMEB',
-    },
-    redirect: {
-      name: 'home_index',
-    },
-    component: LayoutMain,
-    children: [
-      // {
-      //   path: '/admin/system/log',
-      //   name: 'log',
-      //   meta: {
-      //     title: '前端日志',
-      //     auth: true
-      //   },
-      //   component: () => import('@/pages/system/log')
-      // },
-      {
-        path: routePre + '/system/user',
-        name: `systemUser`,
-        meta: {
-          auth: true,
-          title: '个人中心',
-        },
-        component: () => import('@/pages/setting/user/index'),
-      },
-      {
-        path: routePre + '/system/files',
-        name: `systemFiles`,
-        meta: {
-          auth: ['admin-setting-files'],
-          title: '文件管理',
-        },
-        component: () => import('@/pages/setting/userFile/index'),
-      },
-      // 刷新页面 必须保留
-      {
-        path: 'refresh',
-        name: 'refresh',
-        hidden: true,
-        component: {
-          beforeRouteEnter(to, from, next) {
-            next((instance) => instance.$router.replace(from.fullPath));
-          },
-          render: (h) => h(),
-        },
-      },
-      // 页面重定向 必须保留
-      {
-        path: 'redirect/:route*',
-        name: 'redirect',
-        hidden: true,
-        component: {
-          beforeRouteEnter(to, from, next) {
-            next((instance) => instance.$router.replace(JSON.parse(from.params.route)));
-          },
-          render: (h) => h(),
-        },
-      },
-    ],
-  },
-  {
-    path: routePre,
-    meta: {
-      title: 'CRMEB',
-    },
-    redirect: {
-      name: 'home_index',
-    },
-    component: LayoutMain,
-  },
-  {
-    path: routePre + '/widget.images/index.html',
-    name: `images`,
-    meta: {
-      auth: ['admin-user-user-index'],
-      title: '上传图片',
-    },
-    component: () => import('@/components/uploadPictures/widgetImg'),
-  },
-  {
-    path: routePre + '/widget.widgets/icon.html',
-    name: `imagesIcon`,
-    meta: {
-      auth: ['admin-user-user-index'],
-      title: '上传图标',
-    },
-    component: () => import('@/components/iconFrom/index'),
-  },
-  {
-    path: routePre + '/store.StoreProduct/index.html',
-    name: `storeProduct`,
-    meta: {
-      title: '选择商品',
-    },
-    component: () => import('@/components/goodsList/index'),
-  },
-  {
-    path: routePre + '/system.User/list.html',
-    name: `changeUser`,
-    meta: {
-      title: '选择用户',
-    },
-    component: () => import('@/components/customerInfo/index'),
-  },
-  {
-    path: routePre + '/widget.video/index.html',
-    name: `video`,
-    meta: {
-      title: '上传视频',
-    },
-    component: () => import('@/components/uploadVideo/index'),
-  },
-  index,
-  agent,
-  cms,
-  product,
-  marketing,
-  order,
-  user,
-  finance,
-  setting,
-  system,
-  app,
-  statistic,
-  division,
-  ...routers,
-  crud,
+const frameIn = [{
+		path: '/',
+		meta: {
+			title: 'CRMEB',
+		},
+		redirect: {
+			name: 'home_index',
+		},
+		component: LayoutMain,
+		children: [
+			// {
+			//   path: '/admin/system/log',
+			//   name: 'log',
+			//   meta: {
+			//     title: '前端日志',
+			//     auth: true
+			//   },
+			//   component: () => import('@/pages/system/log')
+			// },
+			{
+				path: routePre + '/system/user',
+				name: `systemUser`,
+				meta: {
+					auth: true,
+					title: '个人中心',
+				},
+				component: () => import('@/pages/setting/user/index'),
+			},
+			{
+				path: routePre + '/system/files',
+				name: `systemFiles`,
+				meta: {
+					auth: ['admin-setting-files'],
+					title: '文件管理',
+				},
+				component: () => import('@/pages/setting/userFile/index'),
+			},
+			// 刷新页面 必须保留
+			{
+				path: 'refresh',
+				name: 'refresh',
+				hidden: true,
+				component: {
+					beforeRouteEnter(to, from, next) {
+						next((instance) => instance.$router.replace(from.fullPath));
+					},
+					render: (h) => h(),
+				},
+			},
+			// 页面重定向 必须保留
+			{
+				path: 'redirect/:route*',
+				name: 'redirect',
+				hidden: true,
+				component: {
+					beforeRouteEnter(to, from, next) {
+						next((instance) => instance.$router.replace(JSON.parse(from.params.route)));
+					},
+					render: (h) => h(),
+				},
+			},
+		],
+	},
+	{
+		path: routePre,
+		meta: {
+			title: 'CRMEB',
+		},
+		redirect: {
+			name: 'home_index',
+		},
+		component: LayoutMain,
+	},
+	{
+		path: routePre + '/widget.images/index.html',
+		name: `images`,
+		meta: {
+			auth: ['admin-user-user-index'],
+			title: '上传图片',
+		},
+		component: () => import('@/components/uploadPictures/widgetImg'),
+	},
+	{
+		path: routePre + '/widget.widgets/icon.html',
+		name: `imagesIcon`,
+		meta: {
+			auth: ['admin-user-user-index'],
+			title: '上传图标',
+		},
+		component: () => import('@/components/iconFrom/index'),
+	},
+	{
+		path: routePre + '/store.StoreProduct/index.html',
+		name: `storeProduct`,
+		meta: {
+			title: '选择商品',
+		},
+		component: () => import('@/components/goodsList/index'),
+	},
+	{
+		path: routePre + '/system.User/list.html',
+		name: `changeUser`,
+		meta: {
+			title: '选择用户',
+		},
+		component: () => import('@/components/customerInfo/index'),
+	},
+	{
+		path: routePre + '/widget.video/index.html',
+		name: `video`,
+		meta: {
+			title: '上传视频',
+		},
+		component: () => import('@/components/uploadVideo/index'),
+	},
+	index,
+	agent,
+	cms,
+	product,
+	shop_product,
+	shop_setting,
+	marketing,
+	order,
+	user,
+	shop,
+	finance,
+	setting,
+	system,
+	app,
+	statistic,
+	division,
+	...routers,
+	crud,
 ];
 
 /**
@@ -184,35 +189,34 @@ const frameOuts = frameOut;
  * 错误页面
  */
 
-const errorPage = [
-  {
-    path: routePre + '/403',
-    name: '403',
-    meta: {
-      title: '403',
-    },
-    component: () => import('@/pages/system/error/403'),
-  },
-  {
-    path: routePre + '/500',
-    name: '500',
-    meta: {
-      title: '500',
-    },
-    component: () => import('@/pages/system/error/500'),
-  },
-  {
-    path: routePre + '/*',
-    name: '404',
-    meta: {
-      title: '404',
-    },
-    component: () => import('@/pages/system/error/404'),
-  },
+const errorPage = [{
+		path: routePre + '/403',
+		name: '403',
+		meta: {
+			title: '403',
+		},
+		component: () => import('@/pages/system/error/403'),
+	},
+	{
+		path: routePre + '/500',
+		name: '500',
+		meta: {
+			title: '500',
+		},
+		component: () => import('@/pages/system/error/500'),
+	},
+	{
+		path: routePre + '/*',
+		name: '404',
+		meta: {
+			title: '404',
+		},
+		component: () => import('@/pages/system/error/404'),
+	},
 ];
 
 // 导出需要显示菜单的
 export const frameInRoutes = frameIn;
 
 // 重新组织后导出
-export default [...frameIn, ...frameOuts, ...errorPage];
+export default [...frameIn, ...frameOuts, ...errorPage];

Some files were not shown because too many files changed in this diff