Просмотр исходного кода

Merge branch 'v4.7.0dev' of https://gitee.com/ZhongBangKeJi/CRMEB into v4.7.0dev

吴昊天 2 лет назад
Родитель
Сommit
dcf1ede517
22 измененных файлов с 900 добавлено и 540 удалено
  1. 280 0
      crmeb/app/services/system/SystemLangServices.php
  2. 16 4
      crmeb/app/services/system/lang/LangCountryServices.php
  3. 6 2
      crmeb/app/services/system/lang/LangTypeServices.php
  4. 7 1
      template/admin/src/components/main/components/header-bar/custom-bread-crumb/custom-bread-crumb.vue
  5. 7 2
      template/admin/src/components/main/components/side-menu/collapsed-menu.vue
  6. 8 4
      template/admin/src/components/main/components/side-menu/side-menu.vue
  7. 2 3
      template/admin/src/components/main/components/tags-nav/tags-nav.less
  8. 3 3
      template/admin/src/components/main/components/tags-nav/tags-nav.vue
  9. 1 4
      template/admin/src/components/main/main.vue
  10. 9 3
      template/admin/src/pages/app/wechat/reply/follow.vue
  11. 1 1
      template/admin/src/pages/kefu/pc/components/rightMenu.vue
  12. 1 1
      template/admin/src/pages/kefu/pc/index.vue
  13. 1 1
      template/admin/src/pages/marketing/storeIntegral/index.vue
  14. 1 0
      template/admin/src/pages/system/group/visualization.vue
  15. 2 3
      template/admin/src/pages/user/label/index.vue
  16. 101 93
      template/admin/src/pages/user/list/index.vue
  17. 6 3
      template/admin/src/router/modules/frameOut.js
  18. 11 3
      template/admin/src/router/modules/setting.js
  19. 4 1
      template/admin/src/styles/style.css
  20. 1 1
      template/uni-app/pages/extension/customer_list/chat.vue
  21. 1 1
      template/uni-app/pages/users/message_center/index.vue
  22. 431 406
      template/uni-app/pages/users/user_goods_collection/index.vue

+ 280 - 0
crmeb/app/services/system/SystemLangServices.php

@@ -0,0 +1,280 @@
+<?php
+// +----------------------------------------------------------------------
+// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
+// +----------------------------------------------------------------------
+// | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
+// +----------------------------------------------------------------------
+// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
+// +----------------------------------------------------------------------
+// | Author: CRMEB Team <admin@crmeb.com>
+// +----------------------------------------------------------------------
+
+namespace app\services\system;
+
+use app\dao\system\SystemMenusDao;
+use app\services\BaseServices;
+use app\services\system\admin\SystemRoleServices;
+use crmeb\exceptions\AdminException;
+use crmeb\services\FormBuilder as Form;
+use crmeb\utils\Arr;
+
+/**
+ * 权限菜单
+ * Class SystemMenusServices
+ * @package app\services\system
+ * @method save(array $data) 保存数据
+ * @method get(int $id, ?array $field = []) 获取数据
+ * @method update($id, array $data, ?string $key = null) 修改数据
+ * @method getSearchList() 主页搜索
+ * @method getColumn(array $where, string $field, ?string $key = '') 主页搜索
+ * @method getVisitName(string $rule) 根据访问地址获得菜单名
+ */
+class SystemLangServices extends BaseServices
+{
+
+    /**
+     * 初始化
+     * SystemMenusServices constructor.
+     * @param SystemMenusDao $dao
+     */
+    public function __construct(SystemMenusDao $dao)
+    {
+        $this->dao = $dao;
+    }
+
+    /**
+     * 获取菜单没有被修改器修改的数据
+     * @param $menusList
+     * @return array
+     */
+    public function getMenusData($menusList)
+    {
+        $data = [];
+        foreach ($menusList as $item) {
+            $data[] = $item->getData();
+        }
+        return $data;
+    }
+
+    /**
+     * 获取后台权限菜单和权限
+     * @param $rouleId
+     * @param int $level
+     * @return array
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     */
+    public function getMenusList($rouleId, int $level)
+    {
+        /** @var SystemRoleServices $systemRoleServices */
+        $systemRoleServices = app()->make(SystemRoleServices::class);
+        $rules = $systemRoleServices->getRoleArray(['status' => 1, 'id' => $rouleId], 'rules');
+        $rulesStr = Arr::unique($rules);
+        $menusList = $this->dao->getMenusRoule(['route' => $level ? $rulesStr : '']);
+        $unique = $this->dao->getMenusUnique(['unique' => $level ? $rulesStr : '']);
+        return [Arr::getMenuIviewList($this->getMenusData($menusList)), $unique];
+    }
+
+    /**
+     * 获取后台菜单树型结构列表
+     * @param array $where
+     * @return array
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     */
+    public function getList(array $where)
+    {
+        $menusList = $this->dao->getMenusList($where);
+        $menusList = $this->getMenusData($menusList);
+        return get_tree_children($menusList);
+    }
+
+    /**
+     * 获取form表单所需要的所要的菜单列表
+     * @return array[]
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     */
+    protected function getFormSelectMenus()
+    {
+        $menuList = $this->dao->getMenusRoule(['is_del' => 0], ['id', 'pid', 'menu_name']);
+        $list = sort_list_tier($this->getMenusData($menuList), '0', 'pid', 'id');
+        $menus = [['value' => 0, 'label' => '顶级按钮']];
+        foreach ($list as $menu) {
+            $menus[] = ['value' => $menu['id'], 'label' => $menu['html'] . $menu['menu_name']];
+        }
+        return $menus;
+    }
+
+    /**
+     * @return array
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     */
+    protected function getFormCascaderMenus(int $value = 0)
+    {
+        $menuList = $this->dao->getMenusRoule(['is_del' => 0], ['id as value', 'pid', 'menu_name as label']);
+        $menuList = $this->getMenusData($menuList);
+        if ($value) {
+            $data = get_tree_value($menuList, $value);
+        } else {
+            $data = [];
+        }
+        return [get_tree_children($menuList, 'children', 'value'), array_reverse($data)];
+    }
+
+    /**
+     * 创建权限规格生表单
+     * @param array $formData
+     * @return mixed
+     * @throws \FormBuilder\Exception\FormBuilderException
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     */
+    public function createMenusForm(array $formData = [])
+    {
+        $field[] = Form::input('menu_name', '按钮名称', $formData['menu_name'] ?? '')->required('按钮名称必填');
+//        $field[] = Form::select('pid', '父级id', $formData['pid'] ?? 0)->setOptions($this->getFormSelectMenus())->filterable(1);
+        $field[] = Form::input('menu_path', '路由名称', $formData['menu_path'] ?? '')->placeholder('请输入前台跳转路由地址')->required('请填写前台路由地址');
+        $field[] = Form::input('unique_auth', '权限标识', $formData['unique_auth'] ?? '')->placeholder('不填写则后台自动生成');
+        $params = $formData['params'] ?? '';
+//        $field[] = Form::input('params', '参数', is_array($params) ? '' : $params)->placeholder('举例:a/123/b/234');
+        $field[] = Form::frameInput('icon', '图标', $this->url('admin/widget.widgets/icon', ['fodder' => 'icon']), $formData['icon'] ?? '')->icon('md-add')->height('505px')->modal(['footer-hide' => true]);
+        $field[] = Form::number('sort', '排序', (int)($formData['sort'] ?? 0))->precision(0);
+        $field[] = Form::radio('auth_type', '类型', $formData['auth_type'] ?? 1)->options([['value' => 2, 'label' => '接口'], ['value' => 1, 'label' => '菜单(包含页面按钮)']]);
+        $field[] = Form::radio('is_show', '状态', $formData['is_show'] ?? 1)->options([['value' => 0, 'label' => '关闭'], ['value' => 1, 'label' => '开启']]);
+        $field[] = Form::radio('is_show_path', '是否为前端隐藏菜单', $formData['is_show_path'] ?? 0)->options([['value' => 1, 'label' => '是'], ['value' => 0, 'label' => '否']]);
+        [$menuList, $data] = $this->getFormCascaderMenus((int)($formData['pid'] ?? 0));
+        $field[] = Form::cascader('menu_list', '父级id', $data)->data($menuList)->filterable(true);
+        return $field;
+    }
+
+    /**
+     * 新增权限表单
+     * @return array
+     * @throws \FormBuilder\Exception\FormBuilderException
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     */
+    public function createMenus()
+    {
+        return create_form('添加权限', $this->createMenusForm(), $this->url('/setting/save'));
+    }
+
+    /**
+     * 修改权限菜单
+     * @param int $id
+     * @return array
+     * @throws \FormBuilder\Exception\FormBuilderException
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     */
+    public function updateMenus(int $id)
+    {
+        $menusInfo = $this->dao->get($id);
+        if (!$menusInfo) {
+            throw new AdminException(100026);
+        }
+        return create_form('修改权限', $this->createMenusForm($menusInfo->getData()), $this->url('/setting/update/' . $id), 'PUT');
+    }
+
+    /**
+     * 获取一条数据
+     * @param int $id
+     * @return mixed
+     */
+    public function find(int $id)
+    {
+        $menusInfo = $this->dao->get($id);
+        if (!$menusInfo) {
+            throw new AdminException(100026);
+        }
+        $menu = $menusInfo->getData();
+        $menu['pid'] = (int)$menu['pid'];
+        $menu['auth_type'] = (int)$menu['auth_type'];
+        $menu['is_header'] = (int)$menu['is_header'];
+        $menu['is_show'] = (int)$menu['is_show'];
+        $menu['is_show_path'] = (int)$menu['is_show_path'];
+        if (!$menu['path']) {
+            [$menuList, $data] = $this->getFormCascaderMenus($menu['pid']);
+            $menu['path'] = $data;
+        } else {
+            $menu['path'] = explode('/', $menu['path']);
+            if (is_array($menu['path'])) {
+                $menu['path'] = array_map(function ($item) {
+                    return (int)$item;
+                }, $menu['path']);
+            }
+        }
+        return $menu;
+    }
+
+    /**
+     * 删除菜单
+     * @param int $id
+     * @return mixed
+     */
+    public function delete(int $id)
+    {
+        if ($this->dao->count(['pid' => $id])) {
+            throw new AdminException(400613);
+        }
+        return $this->dao->delete($id);
+    }
+
+    /**
+     * 获取添加身份规格
+     * @param $roles
+     * @return array
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     */
+    public function getMenus($roles): array
+    {
+        $field = ['menu_name', 'pid', 'id'];
+        $where = ['is_del' => 0];
+        if (!$roles) {
+            $menus = $this->dao->getMenusRoule($where, $field);
+        } else {
+            /** @var SystemRoleServices $service */
+            $service = app()->make(SystemRoleServices::class);
+            $roles = is_string($roles) ? explode(',', $roles) : $roles;
+            $ids = $service->getRoleIds($roles);
+            $menus = $this->dao->getMenusRoule(['rule' => $ids] + $where, $field);
+        }
+        return $this->tidyMenuTier(false, $menus);
+    }
+
+    /**
+     * 组合菜单数据
+     * @param bool $adminFilter
+     * @param $menusList
+     * @param int $pid
+     * @param array $navList
+     * @return array
+     */
+    public function tidyMenuTier(bool $adminFilter = false, $menusList, int $pid = 0, array $navList = []): array
+    {
+        foreach ($menusList as $k => $menu) {
+            $menu = $menu->getData();
+            $menu['title'] = $menu['menu_name'];
+            unset($menu['menu_name']);
+            if ($menu['pid'] == $pid) {
+                unset($menusList[$k]);
+                $menu['children'] = $this->tidyMenuTier($adminFilter, $menusList, $menu['id']);
+                if ($pid == 0 && !count($menu['children'])) continue;
+                if ($menu['children']) $menu['expand'] = true;
+                $navList[] = $menu;
+            }
+        }
+        return $navList;
+    }
+}

+ 16 - 4
crmeb/app/services/system/lang/LangCountryServices.php

@@ -57,8 +57,16 @@ class LangCountryServices extends BaseServices
     {
         if ($id) $info = $this->dao->get($id);
         $field = [];
-        $field[] = Form::input('name', '所属地区', $info['name'] ?? '')->required('请填写所属地区');
-        $field[] = Form::input('code', '语言码', $info['code'] ?? '')->required('请填写语言码');
+        $field[] = Form::input('name', '所属地区', $info['name'] ?? '')->required('请填写所属地区')->appendRule('suffix', [
+            'type' => 'div',
+            'class' => 'tips-info',
+            'domProps' => ['innerHTML' => '例如:中国、香港、德国']
+        ]);
+        $field[] = Form::input('code', '语言识别码', $info['code'] ?? '')->required('请填写浏览器语言识别码')->appendRule('suffix', [
+            'type' => 'div',
+            'class' => 'tips-info',
+            'domProps' => ['innerHTML' => '浏览器语言识别码']
+        ]);
         /** @var LangTypeServices $langTypeServices */
         $langTypeServices = app()->make(LangTypeServices::class);
         $list = $langTypeServices->getColumn(['is_del' => 0, 'status' => 1], 'language_name,file_name,id', 'id');
@@ -69,7 +77,11 @@ class LangCountryServices extends BaseServices
             }
             return $menus;
         };
-        $field[] = Form::select('type_id', '语言类型', $info['type_id'] ?? 0)->setOptions(Form::setOptions($setOption))->filterable(true);
+        $field[] = Form::select('type_id', '关联语言', $info['type_id'] ?? 0)->setOptions(Form::setOptions($setOption))->filterable(true)->appendRule('suffix', [
+            'type' => 'div',
+            'class' => 'tips-info',
+            'domProps' => ['innerHTML' => '请选择关联语言,语言类型是由您自行添加的']
+        ]);
         return create_form($id ? '修改语言地区' : '新增语言地区', $field, Url::buildUrl('/setting/lang_country/save/' . $id), 'POST');
     }
 
@@ -103,4 +115,4 @@ class LangCountryServices extends BaseServices
         $this->cacheDriver()->clear();
         return true;
     }
-}
+}

+ 6 - 2
crmeb/app/services/system/lang/LangTypeServices.php

@@ -46,7 +46,11 @@ class LangTypeServices extends BaseServices
         if ($id) $info = $this->dao->get($id);
         $field = [];
         $field[] = Form::input('language_name', '语言名称', $info['language_name'] ?? '')->required('请填写语言名称');
-        $field[] = Form::input('file_name', '语言标识', $info['file_name'] ?? '')->required('请填写语言标识');
+        $field[] = Form::input('file_name', '语言标识', $info['file_name'] ?? '')->required('请填写语言标识')->appendRule('suffix', [
+            'type' => 'div',
+            'class' => 'tips-info',
+            'domProps' => ['innerHTML' => '请选择或输入浏览器标识']
+        ]);
         $field[] = Form::radio('is_default', '是否默认', $info['is_default'] ?? 0)->options([['label' => '开启', 'value' => 1], ['label' => '关闭', 'value' => 0]]);
         $field[] = Form::radio('status', '状态', $info['status'] ?? 1)->options([['label' => '开启', 'value' => 1], ['label' => '关闭', 'value' => 0]]);
         return create_form($id ? '修改语言类型' : '新增语言类型', $field, Url::buildUrl('/setting/lang_type/save/' . $id), 'POST');
@@ -128,4 +132,4 @@ class LangTypeServices extends BaseServices
         $this->setDefaultLangName();
         return true;
     }
-}
+}

+ 7 - 1
template/admin/src/components/main/components/header-bar/custom-bread-crumb/custom-bread-crumb.vue

@@ -1,7 +1,12 @@
 <template>
   <div class="custom-bread-crumb">
     <Breadcrumb :style="{ fontSize: `${fontSize}px` }">
-      <BreadcrumbItem v-for="(item,index) in list" :key="`${item.path}`" :to="index !== 1 ? item.path : ''" v-if="listLast[0].path !== homePath">
+      <BreadcrumbItem
+        v-for="(item, index) in list"
+        :key="`${item.path}`"
+        :to="index !== 1 ? item.path : ''"
+        v-if="listLast[0].path !== homePath"
+      >
         <common-icon style="margin-right: 4px" :type="item.icon || ''" />
         {{ item.title }}
       </BreadcrumbItem>
@@ -65,6 +70,7 @@ export default {
 </script>
 <style lang="less">
 .ivu-breadcrumb-item-link {
+  font-weight: 400;
   .ivu-icon {
     line-height: 14px;
   }

+ 7 - 2
template/admin/src/components/main/components/side-menu/collapsed-menu.vue

@@ -43,6 +43,7 @@
 import mixin from './mixin';
 import itemMixin from './item-mixin';
 import { findNodeUpperByClasses } from '@/libs/util';
+import settings from '@/setting';
 
 export default {
   name: 'CollapsedMenu',
@@ -72,7 +73,12 @@ export default {
       this.$emit('on-click', name, this.activeMenuPath);
     },
     handClick(name) {
+      console.log(name, this.activeMenuPath);
       this.$emit('on-click', name, this.activeMenuPath);
+
+      // if (name == settings.routePre + '/home/') {
+      //   this.$emit('on-click', name, this.activeMenuPath);
+      // }
     },
     handleMousemove(event, children) {
       const { pageY } = event;
@@ -91,7 +97,7 @@ export default {
 @import './side-menu.less';
 
 /deep/ .collased-menu-dropdown {
-  width: 100%;
+  width: @side-width;
 }
 
 .child-menu {
@@ -108,7 +114,6 @@ export default {
   font-size: 14px;
   line-height: 14px;
   padding: 14px 20px;
-
 }
 .ivu-dropdown-menu /deep/ .ivu-dropdown-item {
   width: 140px !important;

+ 8 - 4
template/admin/src/components/main/components/side-menu/side-menu.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="side-menu-wrapper">
     <!-- <sider-trigger :collapsed="collapsed" @on-change="handleCollpasedChange"></sider-trigger> -->
-    <div class="side-menu-box" v-show="!collapsed">
+    <div class="side-menu-box" v-if="!collapsed">
       <div class="parent-menu">
         <slot></slot>
         <Menu
@@ -23,7 +23,7 @@
           </template>
         </Menu>
       </div>
-      <div class="child-menu" v-show="sider.length">
+      <div class="child-menu"  v-if="sider.length">
         <div class="cat-name">{{ oneMenuName }}</div>
         <Menu
           ref="childMenu"
@@ -63,7 +63,7 @@
       </div>
     </div>
 
-    <div class="menu-collapsed" v-show="collapsed">
+    <div class="menu-collapsed" v-if="collapsed">
       <slot></slot>
       <template v-for="item in menusName">
         <collapsed-menu
@@ -229,6 +229,7 @@ export default {
 @import './side-menu.less';
 .ivu-layout-sider {
   overflow: unset !important;
+  transition: all 0.3s ease !important;
 }
 .ivu-menu {
   .side-menu-wrapper {
@@ -350,8 +351,10 @@ export default {
     }
   }
   .child-menu {
-    z-index: 999;
+    z-index: 9;
     box-shadow: 2px 0px 4px 0px rgba(0, 0, 0, 0.06);
+    transition: width .2s ease .2s;
+    overflow: hidden;
     .child-menus {
       width: @side-child-width !important;
     }
@@ -415,6 +418,7 @@ export default {
   left: 95px !important;
 }
 .menu-collapsed {
+  width: @side-width;
   .side-menu-wrapper a.drop-menu-a {
     display: flex;
     align-items: center;

+ 2 - 3
template/admin/src/components/main/components/tags-nav/tags-nav.less

@@ -11,16 +11,15 @@
   height: 100%;
 }
 .tag-nav-wrapper {
-  // height: 10px;
   background: unset;
   width: 100%;
-  margin: 0 15px 0 0px;
+  margin: 0px;
   //overflow: hidden;
   padding: 0;
   height: 42px;
-  margin-bottom: 14px;
   background-color: #fff;
   box-shadow: 0px 2px 4px 0px rgba(0, 0, 0, 0.06);
+  z-index: 8;
 }
 .tags-nav {
   position: relative;

+ 3 - 3
template/admin/src/components/main/components/tags-nav/tags-nav.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="tags-nav">
     <div class="close-con">
-      <Dropdown transfer @on-click="handleTagsOption" style="margin-top: 7px">
+      <Dropdown transfer @on-click="handleTagsOption" style="margin-top: 10px">
         <Button size="small" type="text">
           <Icon :size="18" type="ios-close-circle-outline" />
         </Button>
@@ -184,8 +184,8 @@ export default {
       }
       this.visible = true;
       const offsetLeft = this.$el.getBoundingClientRect().left;
-      this.contextMenuLeft = e.clientX - offsetLeft + 10;
-      this.contextMenuTop = e.clientY - 64;
+      this.contextMenuLeft = e.clientX - offsetLeft;
+      this.contextMenuTop = e.clientY - 34;
     },
     closeMenu() {
       this.visible = false;

+ 1 - 4
template/admin/src/components/main/main.vue

@@ -303,7 +303,7 @@ export default {
   }
 }
 .main-warper {
-  min-height: calc(~'100vh - 166px');
+  min-height: calc(~'100vh - 196px');
 }
 .all-desk {
   height: 100vh !important;
@@ -314,8 +314,5 @@ export default {
   .content-wrapper {
     height: 100vh !important;
   }
-  .content-wrapper {
-    padding: 0;
-  }
 }
 </style>

+ 9 - 3
template/admin/src/pages/app/wechat/reply/follow.vue

@@ -92,11 +92,13 @@
                       </Select>
                     </FormItem>
                     <FormItem label="消息内容:" prop="content" v-if="formValidate.type === 'text'">
-                      <textarea
+                      <Input
                         v-model="formValidate.data.content"
                         placeholder="请填写消息内容"
                         style="width: 90%"
-                      ></textarea>
+                        type="textarea"
+                        :rows="4"
+                      ></Input>
                     </FormItem>
                     <FormItem label="选取图文:" v-if="formValidate.type === 'news'">
                       <Button type="info" @click="changePic">选择图文消息</Button>
@@ -208,7 +210,7 @@ export default {
       formatVoice: ['mp3', 'wma', 'wav', 'amr'],
       header: {},
       formValidate: {
-        status: 1,
+        status: -1,
         type: '',
         key: this.$route.params.key || '',
         data: {
@@ -285,6 +287,10 @@ export default {
       }
       keywordsinfoApi(url, data)
         .then(async (res) => {
+          if (res.data.info.data instanceof Array) {
+            this.formValidate.status = 0;
+            return;
+          }
           let info = res.data.info || {};
           let data = info.data || {};
           this.formValidate = {

+ 1 - 1
template/admin/src/pages/kefu/pc/components/rightMenu.vue

@@ -156,7 +156,7 @@
                     type="info"
                     ghost
                     style="color: #1890ff; border-color: #1890ff"
-                    v-if="item.refund_type == 1 || item.refund_type == 5"
+                    v-if="item.refund_status == 1"
                     @click.stop="orderRecord(item.id)"
                     >退款</Button
                   >

+ 1 - 1
template/admin/src/pages/kefu/pc/index.vue

@@ -457,7 +457,7 @@ export default {
     },
     // 聊天表情转换
     replace_em(str) {
-      str = str.replace(/\[em-([\s\S]*)\]/g, "<span class='em em-$1'/></span>");
+      str = str.replace(/\[([^\[\]]+)\]/g, "<span class='em $1'/></span>");
       return str;
     },
     // 获取是否游客

+ 1 - 1
template/admin/src/pages/marketing/storeIntegral/index.vue

@@ -30,7 +30,7 @@
               <Select
                 placeholder="请选择"
                 clearable
-                style="width: 150px"
+                style="width: 200px"
                 v-model="tableFrom.is_show"
                 @on-change="userSearchs"
               >

+ 1 - 0
template/admin/src/pages/system/group/visualization.vue

@@ -1792,6 +1792,7 @@ export default {
   padding: 20px;
   background-color: #fff;
   border-radius: 5px;
+  min-height: 600px;
 }
 
 .iview-video-style {

+ 2 - 3
template/admin/src/pages/user/label/index.vue

@@ -69,7 +69,7 @@
             </template>
           </Table>
           <div class="acea-row row-right page">
-            <Page :total="total" show-elevator show-total @on-change="pageChange" :page-size="labelFrom.limit" />
+            <Page :total="total" :model-value="labelFrom.page" show-elevator show-total @on-change="pageChange" :page-size="labelFrom.limit" />
           </div>
         </Card>
       </Col>
@@ -191,7 +191,6 @@ export default {
         .then((res) => {
           this.$Message.success(res.msg);
           this.labelLists.splice(num, 1);
-          this.labelFrom.page = 1;
           this.getList();
         })
         .catch((res) => {
@@ -283,7 +282,7 @@ export default {
 }
 
 .left-wrapper {
-  height: 904px;
+  height: 920px;
   background: #fff;
   border-right: 1px solid #f2f2f2;
 }

+ 101 - 93
template/admin/src/pages/user/list/index.vue

@@ -1,7 +1,7 @@
 <template>
   <div>
     <Card :bordered="false" dis-hover class="ivu-mt listbox">
-      <Tabs @on-click="onClickTab" class="mb20">
+      <Tabs @on-click="onClickTab" class="mb30">
         <TabPane :label="item.name" :name="item.type" v-for="(item, index) in headeNum" :key="index" />
       </Tabs>
       <Form
@@ -12,53 +12,41 @@
         @submit.native.prevent
       >
         <Row :gutter="16">
-          <Col span="18">
-            <Col span="24">
-              <Col span="20">
-                <FormItem label="用户搜索:" label-for="nickname">
-                  <Input v-model="userFrom.nickname" placeholder="请输入用户" element-id="nickname" clearable>
-                    <Select v-model="field_key" slot="prepend" style="width: 80px">
-                      <Option value="all">全部</Option>
-                      <Option value="uid">UID</Option>
-                      <Option value="phone">手机号</Option>
-                      <Option value="nickname">用户昵称</Option>
-                    </Select>
-                  </Input>
-                </FormItem>
-              </Col>
-            </Col>
+          <Col v-bind="grid">
+              <FormItem label="用户搜索:" label-for="nickname">
+                <Input v-model="userFrom.nickname" placeholder="请输入用户" element-id="nickname" clearable>
+                  <Select v-model="field_key" slot="prepend" style="width: 80px">
+                    <Option value="all">全部</Option>
+                    <Option value="uid">UID</Option>
+                    <Option value="phone">手机号</Option>
+                    <Option value="nickname">用户昵称</Option>
+                  </Select>
+                </Input>
+              </FormItem>
+          </Col>
+          <Col span="12" class="ivu-text-left userFrom" v-if="!collapse">
+            <FormItem>
+              <Button type="primary" icon="ios-search" label="default" class="mr15" @click="userSearchs">搜索</Button>
+              <Button class="ResetSearch" @click="reset('userFrom')">重置</Button>
+              <a class="ivu-ml-8 font14 ml10" @click="collapse = !collapse">
+                <template v-if="!collapse"> 展开 <Icon type="ios-arrow-down" /> </template>
+                <template v-else> 收起 <Icon type="ios-arrow-up" /> </template>
+              </a>
+            </FormItem>
           </Col>
           <template v-if="collapse">
             <Col span="18">
-              <Col v-bind="grid">
-                <FormItem label="用户等级:" label-for="level">
-                  <Select v-model="level" placeholder="请选择用户等级" element-id="level" clearable>
-                    <Option value="all">全部</Option>
-                    <Option :value="item.id" v-for="(item, index) in levelList" :key="index">{{ item.name }}</Option>
-                  </Select>
-                </FormItem>
-              </Col>
-              <Col v-bind="grid">
-                <FormItem label="用户分组:" label-for="group_id">
-                  <Select v-model="group_id" placeholder="请选择用户分组" element-id="group_id" clearable>
-                    <Option value="all">全部</Option>
-                    <Option :value="item.id" v-for="(item, index) in groupList" :key="index">{{
-                      item.group_name
-                    }}</Option>
-                  </Select>
-                </FormItem>
-              </Col>
               <Col v-bind="grid">
                 <FormItem label="用户标签:" label-for="label_id">
                   <div class="labelInput acea-row row-between-wrapper" @click="openSelectLabel">
                     <div style="width: 90%">
                       <div v-if="selectDataLabel.length">
                         <Tag
-                          :closable="false"
-                          v-for="(item, index) in selectDataLabel"
-                          @on-close="closeLabel(item)"
-                          :key="index"
-                          >{{ item.label_name }}</Tag
+                            :closable="false"
+                            v-for="(item, index) in selectDataLabel"
+                            @on-close="closeLabel(item)"
+                            :key="index"
+                        >{{ item.label_name }}</Tag
                         >
                       </div>
                       <span class="span" v-else>选择用户关联标签</span>
@@ -67,50 +55,37 @@
                   </div>
                 </FormItem>
               </Col>
-            </Col>
-            <Col span="18">
               <Col v-bind="grid">
-                <FormItem label="付费会员:" label-for="isMember">
-                  <!-- <Select
-                    v-model="userFrom.isMember"
-                    placeholder="请选择付费会员"
-                    element-id="isMember"
-                    clearable
-                    @on-change="changeMember"
-                  >
-                    <Option :value="1">是</Option>
-                    <Option :value="0">否</Option>
-                  </Select> -->
-                  <RadioGroup v-model="userFrom.isMember" type="button">
-                    <Radio label="">
-                      <span>全部</span>
-                    </Radio>
-                    <Radio label="1">
-                      <span>是</span>
-                    </Radio>
-                    <Radio label="0">
-                      <span>否</span>
-                    </Radio>
-                  </RadioGroup>
+                <FormItem label="下单次数:" label-for="pay_count">
+                  <Select v-model="pay_count" placeholder="请选择下单次数" element-id="pay_count" clearable>
+                    <Option value="all">全部</Option>
+                    <Option value="-1">0次</Option>
+                    <Option value="0">1次以上</Option>
+                    <Option value="1">2次以上</Option>
+                    <Option value="2">3次以上</Option>
+                    <Option value="3">4次以上</Option>
+                    <Option value="4">5次以上</Option>
+                  </Select>
                 </FormItem>
               </Col>
+            </Col>
+            <Col span="18">
               <Col v-bind="grid">
-                <FormItem label="国家:" label-for="country">
-                  <Select
-                    v-model="userFrom.country"
-                    placeholder="请选择国家"
-                    element-id="country"
-                    clearable
-                    @on-change="changeCountry"
-                  >
-                    <Option value="domestic">中国</Option>
-                    <Option value="abroad">外国</Option>
+                <FormItem label="用户分组:" label-for="group_id">
+                  <Select v-model="group_id" placeholder="请选择用户分组" element-id="group_id" clearable>
+                    <Option value="all">全部</Option>
+                    <Option :value="item.id" v-for="(item, index) in groupList" :key="index">{{
+                        item.group_name
+                      }}</Option>
                   </Select>
                 </FormItem>
               </Col>
-              <Col v-bind="grid" v-if="userFrom.country === 'domestic'">
-                <FormItem label="省份:">
-                  <Cascader :data="addresData" :value="address" v-model="address" @on-change="handleChange"></Cascader>
+              <Col v-bind="grid">
+                <FormItem label="用户等级:" label-for="level">
+                  <Select v-model="level" placeholder="请选择用户等级" element-id="level" clearable>
+                    <Option value="all">全部</Option>
+                    <Option :value="item.id" v-for="(item, index) in levelList" :key="index">{{ item.name }}</Option>
+                  </Select>
                 </FormItem>
               </Col>
             </Col>
@@ -148,6 +123,31 @@
                   </RadioGroup>
                 </FormItem>
               </Col>
+              <Col v-bind="grid">
+                <FormItem label="付费会员:" label-for="isMember">
+                  <!-- <Select
+                    v-model="userFrom.isMember"
+                    placeholder="请选择付费会员"
+                    element-id="isMember"
+                    clearable
+                    @on-change="changeMember"
+                  >
+                    <Option :value="1">是</Option>
+                    <Option :value="0">否</Option>
+                  </Select> -->
+                  <RadioGroup v-model="userFrom.isMember" type="button">
+                    <Radio label="">
+                      <span>全部</span>
+                    </Radio>
+                    <Radio label="1">
+                      <span>是</span>
+                    </Radio>
+                    <Radio label="0">
+                      <span>否</span>
+                    </Radio>
+                  </RadioGroup>
+                </FormItem>
+              </Col>
             </Col>
             <Col span="18">
               <Col v-bind="grid">
@@ -180,21 +180,29 @@
             </Col>
             <Col span="18">
               <Col v-bind="grid">
-                <FormItem label="下单次数:" label-for="pay_count">
-                  <Select v-model="pay_count" placeholder="请选择下单次数" element-id="pay_count" clearable>
-                    <Option value="all">全部</Option>
-                    <Option value="-1">0次</Option>
-                    <Option value="0">1次以上</Option>
-                    <Option value="1">2次以上</Option>
-                    <Option value="2">3次以上</Option>
-                    <Option value="3">4次以上</Option>
-                    <Option value="4">5次以上</Option>
+                <FormItem label="地区:" label-for="country">
+                  <Select
+                      v-model="userFrom.country"
+                      placeholder="请选择国家"
+                      element-id="country"
+                      clearable
+                      @on-change="changeCountry"
+                  >
+                    <Option value="domestic">中国</Option>
+                    <Option value="abroad">外国</Option>
                   </Select>
                 </FormItem>
               </Col>
+              <Col v-bind="grid" v-if="userFrom.country === 'domestic'">
+                <FormItem label="省份:">
+                  <Cascader :data="addresData" :value="address" v-model="address" @on-change="handleChange"></Cascader>
+                </FormItem>
+              </Col>
             </Col>
           </template>
-          <Col span="6" class="ivu-text-right userFrom">
+        </Row>
+        <Row v-if="collapse">
+          <Col span="13" class="ivu-text-right userFrom">
             <FormItem>
               <Button type="primary" icon="ios-search" label="default" class="mr15" @click="userSearchs">搜索</Button>
               <Button class="ResetSearch" @click="reset('userFrom')">重置</Button>
@@ -209,11 +217,11 @@
       <Divider dashed />
       <Row type="flex" justify="space-between" class="mt20">
         <Col span="24">
-          <Button v-auth="['admin-user-save']" type="primary" class="mr20" @click="edit({ uid: 0 })">添加用户</Button>
-          <Button v-auth="['admin-user-coupon']" class="mr20" @click="onSend">发送优惠券</Button>
+          <Button v-auth="['admin-user-save']" type="primary" class="mr10" @click="edit({ uid: 0 })">添加用户</Button>
+          <Button v-auth="['admin-user-coupon']" class="mr10" @click="onSend">发送优惠券</Button>
           <Button
             v-auth="['admin-wechat-news']"
-            class="greens mr20"
+            class="greens mr10"
             size="default"
             @click="onSendPic"
             v-if="userFrom.user_type === 'wechat'"
@@ -221,9 +229,9 @@
             <Icon type="md-list"></Icon>
             发送图文消息
           </Button>
-          <Button v-auth="['admin-user-group_set']" class="mr20" @click="setGroup">批量设置分组</Button>
-          <Button v-auth="['admin-user-set_label']" class="mr20" @click="setLabel">批量设置标签</Button>
-          <Button class="mr20" icon="ios-share-outline" @click="exportList">导出</Button>
+          <Button v-auth="['admin-user-group_set']" class="mr10" @click="setGroup">批量设置分组</Button>
+          <Button v-auth="['admin-user-set_label']" class="mr10" @click="setLabel">批量设置标签</Button>
+          <Button class="mr10" icon="ios-share-outline" @click="exportList">导出</Button>
 
           <!-- <Button v-auth="['admin-user-synchro']" class="mr20" @click="synchro">同步公众号用户</Button> -->
         </Col>
@@ -236,7 +244,7 @@
       <Table
         :columns="columns"
         :data="userLists"
-        class="mt25"
+        class="mt10"
         ref="table"
         highlight-row
         :loading="loading"

+ 6 - 3
template/admin/src/router/modules/frameOut.js

@@ -8,14 +8,14 @@
 // | Author: CRMEB Team <admin@crmeb.com>
 // +---------------------------------------------------------------------
 
-import setting  from '@/setting'
+import setting from '@/setting';
 let routePre = setting.routePre;
 const pre = 'kefu_';
 
 export default [
   // 登录
   {
-    path: routePre+'/login',
+    path: routePre + '/login',
     name: 'login',
     meta: {
       title: '登录',
@@ -25,13 +25,16 @@ export default [
   },
   // 客服
   {
-    path: '/kefu',
+    path: routePre + '/kefu',
     name: `${pre}index`,
     meta: {
       auth: true,
       title: '客服管理',
       kefu: true,
     },
+    redirect: {
+      name: `setting_service`,
+    },
     component: () => import('@/pages/kefu/index'),
   },
   {

+ 11 - 3
template/admin/src/router/modules/setting.js

@@ -9,7 +9,7 @@
 // +---------------------------------------------------------------------
 
 import BasicLayout from '@/components/main';
-import setting  from '@/setting'
+import setting from '@/setting';
 let routePre = setting.routePre;
 
 const meta = {
@@ -19,11 +19,11 @@ const meta = {
 const pre = 'setting_';
 
 export default {
-  path: routePre+'/setting',
+  path: routePre + '/setting',
   name: 'setting',
   header: 'setting',
   redirect: {
-    name: `${pre}systemRole`,
+    name: `${pre}setSystem`,
   },
   component: BasicLayout,
   children: [
@@ -385,6 +385,14 @@ export default {
       },
       component: () => import('@/pages/setting/themeStyle/index'),
     },
+    {
+      path: 'pages',
+      name: `${pre}page`,
+      header: 'setting',
+      redirect: {
+        name: `${pre}devise`,
+      },
+    },
     {
       path: 'pages/devise',
       name: `${pre}devise`,

+ 4 - 1
template/admin/src/styles/style.css

@@ -537,7 +537,10 @@ body {
   font-size: 20px;
 }
 .main .content-wrapper {
-  padding-top: 0;
+  padding: 16px;
+  height: calc(100% - 80px);
+  overflow: auto;
+  background-color: #f5f7f9;
 }
 .left-wrapper{
   height: calc(100vh - 120px);

+ 1 - 1
template/uni-app/pages/extension/customer_list/chat.vue

@@ -416,7 +416,7 @@
 			},
 			// 聊天表情转换
 			replace_em(str) {
-				str = str.replace(/\[em-([\s\S]*)\]/g, "<span class='em em-$1' style='background-image:url(" + this
+				str = str.replace(/\[([^\[\]]+)\]/g, "<span class='em $1' style='background-image:url(" + this
 					.httpUrl + ")'></span>");
 				return str;
 			},

+ 1 - 1
template/uni-app/pages/users/message_center/index.vue

@@ -320,7 +320,7 @@
 					})
 			},
 			replace_em(str) {
-				str = str.replace(/\[em-([a-z_]*)\]/g, "<span class='em em-$1'/></span>");
+				str = str.replace(/\[([^\[\]]+)\]/g, "<span class='em $1'/></span>");
 				return str;
 			},
 			goChat(id) {

+ 431 - 406
template/uni-app/pages/users/user_goods_collection/index.vue

@@ -1,408 +1,433 @@
-<template>
-	<view :style="colorStyle">
-		<view class='collectionGoods' v-if="collectProductList.length">
-			<view class="title-admin">
-				<view>{{$t(`当前共`)}} <text class="text"> {{count}} </text> {{$t(`件商品`)}}</view>
-				<view class="admin" @click="showRadio">{{checkbox_show?$t(`取消`):$t(`管理`)}}</view>
-			</view>
-			<checkbox-group @change="checkboxChange">
-				<view class='item acea-row' v-for="(item,index) in collectProductList" :key="index">
-					<view class="left">
-						<checkbox v-show="checkbox_show" :value="item.pid.toString()" :checked="item.checked" />
-						<view class='pictrue'>
-							<image :src="item.image"></image>
-						</view>
-					</view>
-					<view class='text acea-row row-column-between' @click="jump(item)">
-						<view class='name line2'>{{item.store_name}}</view>
-						<view class='acea-row row-between-wrapper'>
-							<view class='money font-color'>{{$t(`¥`)}}{{item.price}}</view>
-							<!-- <view class='delete' @click.stop='delCollection(item.pid,index)'>删除</view> -->
-						</view>
-					</view>
-				</view>
-				<view class='loadingicon acea-row row-center-wrapper'>
-					<text class='loading iconfont icon-jiazai' :hidden='loading==false'></text>{{loadTitle}}
-				</view>
-			</checkbox-group>
-		</view>
-
-		<view class='noCommodity' v-else-if="!collectProductList.length && page > 1">
-			<view class='pictrue'>
-				<image :src="imgHost + '/statics/images/noCollection.png'"></image>
-			</view>
-			<recommend :hostProduct="hostProduct"></recommend>
-		</view>
-		<view class='footer acea-row row-between-wrapper' v-if="checkbox_show && collectProductList.length">
-			<view>
-				<checkbox-group @change="checkboxAllChange">
-					<checkbox value="all" :checked="!!isAllSelect" />
-					<text class='checkAll'>{{$t(`全选`)}}({{ids.length}})</text>
-				</checkbox-group>
-			</view>
-			<view class='button acea-row row-middle'>
-				<button class='bnt' formType="submit" @click="subDel">{{$t(`取关`)}}</button>
-			</view>
-		</view>
-		<!-- #ifdef MP -->
-		<!-- <authorize @onLoadFun="onLoadFun" :isAuto="isAuto" :isShowAuth="isShowAuth" @authColse="authColse"></authorize> -->
-		<!-- #endif -->
-		<!-- #ifndef MP -->
-		<home></home>
-		<!-- #endif -->
-	</view>
-</template>
-
-<script>
-	import {
-		getCollectUserList,
-		getProductHot,
-		collectDel
-	} from '@/api/store.js';
-	import {
-		mapGetters
-	} from "vuex";
-	import {
-		toLogin
-	} from '@/libs/login.js';
-	import recommend from '@/components/recommend';
-	// #ifdef MP
-	import authorize from '@/components/Authorize';
-	// #endif
-	import home from '@/components/home';
-	import colors from '@/mixins/color.js';
-	import {HTTP_REQUEST_URL} from '@/config/app';
-	export default {
-		components: {
-			recommend,
-			// #ifdef MP
-			authorize,
-			// #endif
-			home
-		},
-		mixins: [colors],
-		data() {
-			return {
-				imgHost:HTTP_REQUEST_URL,
-				ids: [],
-				hostProduct: [],
-				checkbox_show: false,
-				loadTitle: this.$t(`加载更多`),
-				loading: false,
-				loadend: false,
-				collectProductList: [],
-				count: 0,
-				limit: 15,
-				page: 1,
-				isAuto: false, //没有授权的不会自动授权
-				isShowAuth: false, //是否隐藏授权
-				hotScroll: false,
-				hotPage: 1,
-				hotLimit: 10,
-				isAllSelect: false, //全选
-			};
-		},
-		computed: mapGetters(['isLogin']),
-		onLoad() {
-			if (this.isLogin) {
-				this.loadend = false;
-				this.page = 1;
-				this.collectProductList = [];
-				this.getUserCollectProduct();
-			} else {
-				toLogin();
-			}
-		},
-		onShow() {
-			this.loadend = false;
-			this.page = 1;
-			this.$set(this, 'collectProductList', []);
-			this.getUserCollectProduct();
-		},
-		/**
-		 * 页面上拉触底事件的处理函数
-		 */
-		onReachBottom: function() {
-			this.getUserCollectProduct();
-		},
-		methods: {
-			showRadio() {
-				this.checkbox_show = !this.checkbox_show
-			},
-			checkboxChange(e) {
-				if (e.detail.value.length < this.ids.length) {
-					this.$set(this, 'isAllSelect', false);
-				} else if (e.detail.value.length === this.collectProductList.length) {
-					this.$set(this, 'isAllSelect', true);
-				}
-				this.$set(this, 'ids', e.detail.value);
-			},
-			subDel() {
-				let that = this
-				if (this.ids.length) {
-					collectDel(that.ids).then(res => {
-						that.loadend = false;
-						that.$util.Tips({
-							title: res.msg
-						});
-						that.page = 1;
-						that.collectProductList = [];
-						this.getUserCollectProduct();
-						this.ids.length = '';
-					});
-				} else {
-					return that.$util.Tips({
-						title: that.$t(`请选择商品`)
-					});
-				}
-
-			},
-			checkboxAllChange(event) {
-				let value = event.detail.value;
-				if (value.length > 0) {
-					this.setAllSelectValue(1)
-				} else {
-					this.setAllSelectValue(0)
-				}
-			},
-			setAllSelectValue(status) {
-				let that = this;
-				let selectValue = [];
-				let valid = that.collectProductList;
-				if (valid.length > 0) {
-					let newValid = valid.map(item => {
-						if (status) {
-							item.checked = true;
-							selectValue.push(item.pid);
-							that.isAllSelect = true;
-						} else {
-							item.checked = false;
-							that.isAllSelect = false;
-						}
-						return item;
-					});
-					that.$set(that, 'collectProductList', newValid);
-					that.$set(that, 'ids', selectValue);
-				}
-			},
-			jump(item) {
-				uni.navigateTo({
-					url: "/pages/goods_details/index?id=" + item.pid
-				})
-			},
-			/**
-			 * 授权回调
-			 */
-			onLoadFun: function() {
-				this.loadend = false;
-				this.page = 1;
-				this.$set(this, 'collectProductList', []);
-				this.getUserCollectProduct();
-				// this.get_host_product();
-			},
-			// 授权关闭
-			authColse(e) {
-				this.isShowAuth = e
-			},
-			/**
-			 * 获取收藏产品
-			 */
-			getUserCollectProduct() {
-				let that = this;
-				if (this.loading) return;
-				if (this.loadend) return;
-				that.loading = true;
-				that.loadTitle = "";
-				getCollectUserList({
-					page: that.page,
-					limit: that.limit
-				}).then(res => {
-					this.count = res.data.count;
-					let collectProductList = res.data.list;
-					collectProductList.map(e => {
-						e.checked = false
-					})
-
-					let loadend = collectProductList.length < that.limit;
-					that.collectProductList = that.$util.SplitArray(collectProductList, that
-						.collectProductList);
-					that.$set(that, 'collectProductList', that.collectProductList);
-					that.loadend = loadend;
-					that.loadTitle = loadend ? that.$t(`我也是有底线的`) : that.$t(`加载更多`);
-					if (!that.collectProductList.length && that.page == 1) this.get_host_product();
-					that.page = that.page + 1;
-					that.loading = false;
-				}).catch(err => {
-					that.loading = false;
-					that.loadTitle = that.$t(`加载更多`);
-				});
-			},
-			/**
-			 * 获取我的推荐
-			 */
-			get_host_product() {
-				let that = this;
-				if (that.hotScroll) return
-				getProductHot(
-					that.hotPage,
-					that.hotLimit,
-				).then(res => {
-					that.hotPage++
-					that.hotScroll = res.data.length < that.hotLimit
-					that.hostProduct = that.hostProduct.concat(res.data)
-				});
-			}
-		},
-		onReachBottom() {
-			this.getUserCollectProduct();
-		},
-		// 滚动监听
-		onPageScroll(e) {
-			// 传入scrollTop值并触发所有easy-loadimage组件下的滚动监听事件
-			uni.$emit('scroll');
-		},
-	}
-</script>
-
-<style scoped lang="scss">
-	.collectionGoods {
-		background-color: #fff;
-		border-top: 1rpx solid #eee;
-	}
-
-	.collectionGoods .item {
-		margin-left: 30rpx;
-		border-bottom: 1rpx solid #eee;
-		height: 180rpx;
-		display: flex;
-		align-items: center;
-		flex-wrap: nowrap;
-	}
-
-	.left {
-		display: flex;
-		align-items: center;
-		margin-right: 20rpx;
-	}
-
-	.collectionGoods .item .pictrue {
-		width: 130rpx;
-		height: 130rpx;
-		margin-left: 20rpx;
-
-	}
-
-	.collectionGoods .item .pictrue image {
-		width: 100%;
-		height: 100%;
-		border-radius: 6rpx;
-	}
-
-	.collectionGoods .item .text {
-		height: 130rpx;
-		flex: 1;
-		font-size: 28rpx;
+<template>
+	<view :style="colorStyle">
+		<view class='collectionGoods' v-if="collectProductList.length">
+			<view class="title-admin">
+				<view>{{$t(`当前共`)}} <text class="text"> {{count}} </text> {{$t(`件商品`)}}</view>
+				<view class="admin" @click="showRadio">{{checkbox_show?$t(`取消`):$t(`管理`)}}</view>
+			</view>
+			<checkbox-group @change="checkboxChange">
+				<view class='item acea-row' v-for="(item,index) in collectProductList" :key="index">
+					<view class="left">
+						<checkbox v-show="checkbox_show" :value="item.pid.toString()" :checked="item.checked" />
+						<view class='pictrue'>
+							<image :src="item.image"></image>
+							<view class="invalid acea-row row-center-wrapper" v-if="!item.is_show">
+								已下架
+							</view>
+						</view>
+					</view>
+					<view class='text acea-row row-column-between' @click="jump(item)">
+						<view class='name line2'>{{item.store_name}}</view>
+						<view class='acea-row row-between-wrapper'>
+							<view class='money font-color'>{{$t(`¥`)}}{{item.price}}</view>
+							<!-- <view class='delete' @click.stop='delCollection(item.pid,index)'>删除</view> -->
+						</view>
+					</view>
+				</view>
+				<view class='loadingicon acea-row row-center-wrapper'>
+					<text class='loading iconfont icon-jiazai' :hidden='loading==false'></text>{{loadTitle}}
+				</view>
+			</checkbox-group>
+		</view>
+
+		<view class='noCommodity' v-else-if="!collectProductList.length && page > 1">
+			<view class='pictrue'>
+				<image :src="imgHost + '/statics/images/noCollection.png'"></image>
+			</view>
+			<recommend :hostProduct="hostProduct"></recommend>
+		</view>
+		<view class='footer acea-row row-between-wrapper' v-if="checkbox_show && collectProductList.length">
+			<view>
+				<checkbox-group @change="checkboxAllChange">
+					<checkbox value="all" :checked="!!isAllSelect" />
+					<text class='checkAll'>{{$t(`全选`)}}({{ids.length}})</text>
+				</checkbox-group>
+			</view>
+			<view class='button acea-row row-middle'>
+				<button class='bnt' formType="submit" @click="subDel">{{$t(`取关`)}}</button>
+			</view>
+		</view>
+		<!-- #ifdef MP -->
+		<!-- <authorize @onLoadFun="onLoadFun" :isAuto="isAuto" :isShowAuth="isShowAuth" @authColse="authColse"></authorize> -->
+		<!-- #endif -->
+		<!-- #ifndef MP -->
+		<home></home>
+		<!-- #endif -->
+	</view>
+</template>
+
+<script>
+	import {
+		getCollectUserList,
+		getProductHot,
+		collectDel
+	} from '@/api/store.js';
+	import {
+		mapGetters
+	} from "vuex";
+	import {
+		toLogin
+	} from '@/libs/login.js';
+	import recommend from '@/components/recommend';
+	// #ifdef MP
+	import authorize from '@/components/Authorize';
+	// #endif
+	import home from '@/components/home';
+	import colors from '@/mixins/color.js';
+	import {
+		HTTP_REQUEST_URL
+	} from '@/config/app';
+	export default {
+		components: {
+			recommend,
+			// #ifdef MP
+			authorize,
+			// #endif
+			home
+		},
+		mixins: [colors],
+		data() {
+			return {
+				imgHost: HTTP_REQUEST_URL,
+				ids: [],
+				hostProduct: [],
+				checkbox_show: false,
+				loadTitle: this.$t(`加载更多`),
+				loading: false,
+				loadend: false,
+				collectProductList: [],
+				count: 0,
+				limit: 15,
+				page: 1,
+				isAuto: false, //没有授权的不会自动授权
+				isShowAuth: false, //是否隐藏授权
+				hotScroll: false,
+				hotPage: 1,
+				hotLimit: 10,
+				isAllSelect: false, //全选
+			};
+		},
+		computed: mapGetters(['isLogin']),
+		onLoad() {
+			if (this.isLogin) {
+				this.loadend = false;
+				this.page = 1;
+				this.collectProductList = [];
+				this.getUserCollectProduct();
+			} else {
+				toLogin();
+			}
+		},
+		onShow() {
+			this.loadend = false;
+			this.page = 1;
+			this.$set(this, 'collectProductList', []);
+			this.getUserCollectProduct();
+		},
+		/**
+		 * 页面上拉触底事件的处理函数
+		 */
+		onReachBottom: function() {
+			this.getUserCollectProduct();
+		},
+		methods: {
+			showRadio() {
+				this.checkbox_show = !this.checkbox_show
+			},
+			checkboxChange(e) {
+				if (e.detail.value.length < this.ids.length) {
+					this.$set(this, 'isAllSelect', false);
+				} else if (e.detail.value.length === this.collectProductList.length) {
+					this.$set(this, 'isAllSelect', true);
+				}
+				this.$set(this, 'ids', e.detail.value);
+			},
+			subDel() {
+				let that = this
+				if (this.ids.length) {
+					collectDel(that.ids).then(res => {
+						that.loadend = false;
+						that.$util.Tips({
+							title: res.msg
+						});
+						that.page = 1;
+						that.collectProductList = [];
+						this.getUserCollectProduct();
+						this.ids.length = '';
+					});
+				} else {
+					return that.$util.Tips({
+						title: that.$t(`请选择商品`)
+					});
+				}
+
+			},
+			checkboxAllChange(event) {
+				let value = event.detail.value;
+				if (value.length > 0) {
+					this.setAllSelectValue(1)
+				} else {
+					this.setAllSelectValue(0)
+				}
+			},
+			setAllSelectValue(status) {
+				let that = this;
+				let selectValue = [];
+				let valid = that.collectProductList;
+				if (valid.length > 0) {
+					let newValid = valid.map(item => {
+						if (status) {
+							item.checked = true;
+							selectValue.push(item.pid);
+							that.isAllSelect = true;
+						} else {
+							item.checked = false;
+							that.isAllSelect = false;
+						}
+						return item;
+					});
+					that.$set(that, 'collectProductList', newValid);
+					that.$set(that, 'ids', selectValue);
+				}
+			},
+			jump(item) {
+				if (item.is_show) {
+					uni.navigateTo({
+						url: "/pages/goods_details/index?id=" + item.pid
+					})
+				} else {
+					this.$util.Tips({
+						title: that.$t(`该商品已下架`)
+					})
+				}
+
+			},
+			/**
+			 * 授权回调
+			 */
+			onLoadFun: function() {
+				this.loadend = false;
+				this.page = 1;
+				this.$set(this, 'collectProductList', []);
+				this.getUserCollectProduct();
+				// this.get_host_product();
+			},
+			// 授权关闭
+			authColse(e) {
+				this.isShowAuth = e
+			},
+			/**
+			 * 获取收藏产品
+			 */
+			getUserCollectProduct() {
+				let that = this;
+				if (this.loading) return;
+				if (this.loadend) return;
+				that.loading = true;
+				that.loadTitle = "";
+				getCollectUserList({
+					page: that.page,
+					limit: that.limit
+				}).then(res => {
+					this.count = res.data.count;
+					let collectProductList = res.data.list;
+					collectProductList.map(e => {
+						e.checked = false
+					})
+
+					let loadend = collectProductList.length < that.limit;
+					that.collectProductList = that.$util.SplitArray(collectProductList, that
+						.collectProductList);
+					that.$set(that, 'collectProductList', that.collectProductList);
+					that.loadend = loadend;
+					that.loadTitle = loadend ? that.$t(`我也是有底线的`) : that.$t(`加载更多`);
+					if (!that.collectProductList.length && that.page == 1) this.get_host_product();
+					that.page = that.page + 1;
+					that.loading = false;
+				}).catch(err => {
+					that.loading = false;
+					that.loadTitle = that.$t(`加载更多`);
+				});
+			},
+			/**
+			 * 获取我的推荐
+			 */
+			get_host_product() {
+				let that = this;
+				if (that.hotScroll) return
+				getProductHot(
+					that.hotPage,
+					that.hotLimit,
+				).then(res => {
+					that.hotPage++
+					that.hotScroll = res.data.length < that.hotLimit
+					that.hostProduct = that.hostProduct.concat(res.data)
+				});
+			}
+		},
+		onReachBottom() {
+			this.getUserCollectProduct();
+		},
+		// 滚动监听
+		onPageScroll(e) {
+			// 传入scrollTop值并触发所有easy-loadimage组件下的滚动监听事件
+			uni.$emit('scroll');
+		},
+	}
+</script>
+
+<style scoped lang="scss">
+	.collectionGoods {
+		background-color: #fff;
+		border-top: 1rpx solid #eee;
+	}
+
+	.collectionGoods .item {
+		margin-left: 30rpx;
+		border-bottom: 1rpx solid #eee;
+		height: 180rpx;
+		display: flex;
+		align-items: center;
+		flex-wrap: nowrap;
+	}
+
+	.left {
+		display: flex;
+		align-items: center;
+		margin-right: 20rpx;
+	}
+
+	.collectionGoods .item .pictrue {
+		width: 130rpx;
+		height: 130rpx;
+		margin-left: 20rpx;
+		position: relative;
+
+		.invalid {
+			position: absolute;
+			width: 100%;
+			height: 100%;
+			top: 0;
+			left: 0;
+			background-color: rgba(0, 0, 0, 0.4);
+			backdrop-filter: blur(3px);
+			color: #fff;
+		}
+
+	}
+
+	.collectionGoods .item .pictrue image {
+		width: 100%;
+		height: 100%;
+		border-radius: 6rpx;
+	}
+
+	.collectionGoods .item .text {
+		height: 130rpx;
+		flex: 1;
+		font-size: 28rpx;
 		color: #282828;
-	}
-
-	.collectionGoods .item .text .name {
-		width: max-contnet;
-	}
-
-	.collectionGoods .item .text .money {
-		font-size: 26rpx;
-	}
-
-	.collectionGoods .item .text .delete {
-		font-size: 26rpx;
-		color: #282828;
-		width: 144rpx;
-		height: 46rpx;
-		border: 1px solid #bbb;
-		border-radius: 4rpx;
-		text-align: center;
-		line-height: 46rpx;
-	}
-
-	.noCommodity {
-		background-color: #fff;
-		padding-top: 1rpx;
-		border-top: 0;
-	}
-
-	.title-admin {
-		display: flex;
-		justify-content: space-between;
-		align-items: center;
-		padding: 20rpx;
-		border-bottom: 1px solid #f2f2f2;
-
-		.text {
-			color: var(--view-theme);
-		}
-
-		.admin {
-			color: var(--view-theme);
-		}
-	}
-
-	.footer {
-		z-index: 999;
-		width: 100%;
-		height: 96rpx;
-		background-color: #fafafa;
-		position: fixed;
-		padding: 0 30rpx;
-		box-sizing: border-box;
-		border-top: 1rpx solid #eee;
-		bottom: 0;
-	}
-
-	.footer.on {
-		// #ifndef H5
-		bottom: 0rpx;
-		// #endif
-		// #ifdef MP || APP-PLUS
-		bottom: 100rpx;
-		bottom: calc(100rpx + constant(safe-area-inset-bottom)); ///兼容 IOS<11.2/
-		bottom: calc(100rpx + env(safe-area-inset-bottom)); ///兼容 IOS>11.2/
-		// #endif
-	}
-
-	.footer .checkAll {
-		font-size: 28rpx;
-		color: #282828;
-		margin-left: 16rpx;
-	}
-
-	// .shoppingCart .footer checkbox .wx-checkbox-input{background-color:#fafafa;}
-	.footer .money {
-		font-size: 30rpx;
-	}
-
-	.footer .placeOrder {
-		color: #fff;
-		font-size: 30rpx;
-		width: 226rpx;
-		height: 70rpx;
-		border-radius: 50rpx;
-		text-align: center;
-		line-height: 70rpx;
-		margin-left: 22rpx;
-	}
-
-	.footer .button .bnt {
-		font-size: 28rpx;
-		color: #999;
-		border-radius: 50rpx;
-		border: 1px solid #999;
-		width: 160rpx;
-		height: 60rpx;
-		text-align: center;
-		line-height: 60rpx;
-	}
-
-	.footer .button form~form {
-		margin-left: 17rpx;
-	}
+		padding-right: 20rpx;
+	}
+
+	.collectionGoods .item .text .name {
+		width: max-contnet;
+	}
+
+	.collectionGoods .item .text .money {
+		font-size: 26rpx;
+	}
+
+	.collectionGoods .item .text .delete {
+		font-size: 26rpx;
+		color: #282828;
+		width: 144rpx;
+		height: 46rpx;
+		border: 1px solid #bbb;
+		border-radius: 4rpx;
+		text-align: center;
+		line-height: 46rpx;
+	}
+
+	.noCommodity {
+		background-color: #fff;
+		padding-top: 1rpx;
+		border-top: 0;
+	}
+
+	.title-admin {
+		display: flex;
+		justify-content: space-between;
+		align-items: center;
+		padding: 20rpx;
+		border-bottom: 1px solid #f2f2f2;
+
+		.text {
+			color: var(--view-theme);
+		}
+
+		.admin {
+			color: var(--view-theme);
+		}
+	}
+
+	.footer {
+		z-index: 999;
+		width: 100%;
+		height: 96rpx;
+		background-color: #fafafa;
+		position: fixed;
+		padding: 0 30rpx;
+		box-sizing: border-box;
+		border-top: 1rpx solid #eee;
+		bottom: 0;
+	}
+
+	.footer.on {
+		// #ifndef H5
+		bottom: 0rpx;
+		// #endif
+		// #ifdef MP || APP-PLUS
+		bottom: 100rpx;
+		bottom: calc(100rpx + constant(safe-area-inset-bottom)); ///兼容 IOS<11.2/
+		bottom: calc(100rpx + env(safe-area-inset-bottom)); ///兼容 IOS>11.2/
+		// #endif
+	}
+
+	.footer .checkAll {
+		font-size: 28rpx;
+		color: #282828;
+		margin-left: 16rpx;
+	}
+
+	// .shoppingCart .footer checkbox .wx-checkbox-input{background-color:#fafafa;}
+	.footer .money {
+		font-size: 30rpx;
+	}
+
+	.footer .placeOrder {
+		color: #fff;
+		font-size: 30rpx;
+		width: 226rpx;
+		height: 70rpx;
+		border-radius: 50rpx;
+		text-align: center;
+		line-height: 70rpx;
+		margin-left: 22rpx;
+	}
+
+	.footer .button .bnt {
+		font-size: 28rpx;
+		color: #999;
+		border-radius: 50rpx;
+		border: 1px solid #999;
+		width: 160rpx;
+		height: 60rpx;
+		text-align: center;
+		line-height: 60rpx;
+	}
+
+	.footer .button form~form {
+		margin-left: 17rpx;
+	}
 </style>