Browse Source

Merge branch 'master' of http://git.shengws.com/zhangbj/scrm-vue

xiaoming_global 4 years ago
parent
commit
9653bfb8a2
36 changed files with 2485 additions and 51 deletions
  1. 2 2
      config/index.js
  2. 2 10
      index.html
  3. 14 0
      src/api/activity/activity.js
  4. 58 1
      src/api/member/member.js
  5. BIN
      src/assets/img/activity_poster_photo_default.png
  6. BIN
      src/assets/img/sa_06.png
  7. BIN
      src/assets/img/sa_13.png
  8. BIN
      src/assets/img/sa_21.png
  9. BIN
      src/assets/img/sa_24.png
  10. BIN
      src/assets/img/sa_25.png
  11. BIN
      src/assets/img/sa_26.png
  12. BIN
      src/assets/img/sa_52.png
  13. BIN
      src/assets/img/sa_7.png
  14. 4 0
      src/lang/en.js
  15. 4 0
      src/lang/zh.js
  16. 3 1
      src/router/index.js
  17. 32 0
      src/router/modules/marketing_tool.js
  18. 7 1
      src/router/modules/member.js
  19. 115 0
      src/scrm_pages/marketing_tool/activity_list.vue
  20. 61 0
      src/scrm_pages/marketing_tool/activity_publish.vue
  21. 123 0
      src/scrm_pages/marketing_tool/components/drafts_cell.vue
  22. 14 0
      src/scrm_pages/marketing_tool/components/edit_activity_edit_form.vue
  23. 206 0
      src/scrm_pages/marketing_tool/components/edit_activity_preview_form.vue
  24. 188 0
      src/scrm_pages/marketing_tool/components/published_cell.vue
  25. 151 0
      src/scrm_pages/marketing_tool/components/unapproved_cell.vue
  26. 128 0
      src/scrm_pages/members/components/AddMembersTagsForm.vue
  27. 348 0
      src/scrm_pages/members/components/CreateMemberForm.vue
  28. 130 0
      src/scrm_pages/members/components/EditMemberCardForm.vue
  29. 351 0
      src/scrm_pages/members/components/EditMemberForm.vue
  30. 128 0
      src/scrm_pages/members/components/EditMemberTagsForm.vue
  31. 263 25
      src/scrm_pages/members/members.vue
  32. 126 0
      src/scrm_pages/members/tags.vue
  33. 3 2
      src/store/getters.js
  34. 8 0
      src/store/modules/members.js
  35. 8 1
      src/utils/tools.js
  36. 8 8
      src/xt_permission.js

+ 2 - 2
config/index.js View File

@@ -19,8 +19,8 @@ module.exports = {
19 19
 
20 20
     // host: 'test1.sgjyun.com',
21 21
     // host: 'jk.kuyicloud.com',
22
-    //host: 'test1.sgjyun.com',
23
-    host:'localhost',
22
+    host: 'test1.sgjyun.com',
23
+    // host:'localhost',
24 24
     port: 8090, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
25 25
     autoOpenBrowser: true,
26 26
     errorOverlay: true,

+ 2 - 10
index.html View File

@@ -9,7 +9,7 @@
9 9
     <title>血透管理-酷医云</title>
10 10
   </head>
11 11
   <body>
12
-    <script src=<%= htmlWebpackPlugin.options.path %>/tinymce4.7.5/tinymce.min.js></script>
12
+    <script src="<%= htmlWebpackPlugin.options.path %>/tinymce4.7.5/tinymce.min.js"></script>
13 13
     <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
14 14
     <script src="<%= htmlWebpackPlugin.options.path %>/neditor/neditor.config.js"></script>
15 15
     <script src="<%= htmlWebpackPlugin.options.path %>/neditor/neditor.all.min.js"></script>
@@ -19,12 +19,4 @@
19 19
     <div id="app"></div>
20 20
     <!-- built files will be auto injected -->
21 21
   </body>
22
-</html>
23
-
24
-
25
-
26
-
27
-
28
-
29
-
30
->>>>>>> .theirs
22
+</html>

+ 14 - 0
src/api/activity/activity.js View File

@@ -0,0 +1,14 @@
1
+import request from "@/utils/request"
2
+
3
+export function fetchActivities(page, keyword, status) {
4
+  const params = {
5
+    page: page,
6
+    keyword: keyword,
7
+    status: status,
8
+  }
9
+  return request({
10
+    url: '/api/activities',
11
+    method: 'get',
12
+    params: params,
13
+  })
14
+}

+ 58 - 1
src/api/member/member.js View File

@@ -6,4 +6,61 @@ export function GetMembers(params) {
6 6
     method: 'get',
7 7
     params: params
8 8
   })
9
-}
9
+}
10
+
11
+export function CreateMember(data) {
12
+  return request({
13
+    url: '/api/member/create',
14
+    method: 'post',
15
+    data: data
16
+  })
17
+}
18
+
19
+export function EditMember(id, data) {
20
+  return request({
21
+    url: '/api/member/edit?id=' + id,
22
+    method: 'put',
23
+    data: data
24
+  })
25
+}
26
+
27
+export function EditMemberTags(id, data) {
28
+  return request({
29
+    url: '/api/member/tag/edit?id=' + id,
30
+    method: 'post',
31
+    data: data
32
+  })
33
+}
34
+
35
+export function AddMembersTags(data) {
36
+  return request({
37
+    url: '/api/members/tags/add',
38
+    method: 'post',
39
+    data: data
40
+  })
41
+}
42
+
43
+export function DeleteMembers(data) {
44
+  return request({
45
+    url: '/api/members/delete',
46
+    method: 'delete',
47
+    data: data
48
+  })
49
+}
50
+
51
+export function EditMemberCard(params) {
52
+  return request({
53
+    url: '/api/member/card/edit',
54
+    method: 'put',
55
+    params: params
56
+  })
57
+}
58
+
59
+export function GetTags() {
60
+  return request({
61
+    url: '/api/members/tags',
62
+    method: 'get',
63
+  })
64
+}
65
+
66
+

BIN
src/assets/img/activity_poster_photo_default.png View File


BIN
src/assets/img/sa_06.png View File


BIN
src/assets/img/sa_13.png View File


BIN
src/assets/img/sa_21.png View File


BIN
src/assets/img/sa_24.png View File


BIN
src/assets/img/sa_25.png View File


BIN
src/assets/img/sa_26.png View File


BIN
src/assets/img/sa_52.png View File


BIN
src/assets/img/sa_7.png View File


+ 4 - 0
src/lang/en.js View File

@@ -110,6 +110,10 @@ export default {
110 110
     special_permission_manage: 'Special Permission Manage',
111 111
     schedule_print: 'Print Schudule',
112 112
     dialysis_batch_print: 'Batch Print Order',
113
+    
114
+    marketingTool: "marketing tools",
115
+    activityList: "activity list",
116
+    activityPublish: "publish activity",
113 117
     systemsetting:'Systemsetting'
114 118
   },
115 119
   navbar: {

+ 4 - 0
src/lang/zh.js View File

@@ -158,6 +158,10 @@ export default {
158 158
     stockOutDetail: '出库单详情',
159 159
     cancelStockDetail: '退库单详情',
160 160
     stockDetail: '出入库明细查询',
161
+
162
+    marketingTool: "营销工具",
163
+    activityList: "活动列表",
164
+    activityPublish: "发布活动",
161 165
     systemsetting:'系统设置',
162 166
     staffmanagement:'员工管理'
163 167
   },

+ 3 - 1
src/router/index.js View File

@@ -10,7 +10,8 @@ import role from './modules/role'
10 10
 import article from './modules/article'
11 11
 import member from './modules/member'
12 12
 import org from './modules/org'
13
-import system from './modules/system';
13
+import marketing_tool from './modules/marketing_tool'
14
+import system from './modules/system'
14 15
 
15 16
 /** note: submenu only apppear when children.length>=1
16 17
  *   detail see  https://panjiachen.github.io/vue-element-admin-site/guide/essentials/router-and-nav.html
@@ -73,6 +74,7 @@ var _constant_router_map = [{
73 74
 var _asy_router_map = [
74 75
   member,
75 76
   article,
77
+  marketing_tool,
76 78
   org,
77 79
   role,
78 80
   system

+ 32 - 0
src/router/modules/marketing_tool.js View File

@@ -0,0 +1,32 @@
1
+import Layout from '@/views/layout/Layout'
2
+
3
+export default {
4
+  alwaysShow: true,
5
+  path: '/activity',
6
+  component: Layout,
7
+  redirect: 'noredirect',
8
+  name: 'marketingTool',
9
+  meta: {
10
+    title: 'marketingTool',
11
+    icon: 'component'
12
+  },
13
+  children: [{
14
+      path: '/activity/publish',
15
+      component: () => import('@/scrm_pages/marketing_tool/activity_publish'),
16
+      name: 'activityPublish',
17
+      meta: {
18
+        title: 'activityPublish',
19
+        noCache: true
20
+      }
21
+    },
22
+    {
23
+      path: '/activity/list',
24
+      component: () => import('@/scrm_pages/marketing_tool/activity_list'),
25
+      name: 'activityList',
26
+      meta: {
27
+        title: 'activityList',
28
+        noCache: true
29
+      }
30
+    },
31
+  ]
32
+}

+ 7 - 1
src/router/modules/member.js View File

@@ -13,10 +13,16 @@ export default {
13 13
   },
14 14
   children: [
15 15
     {
16
-      path: '/members',
16
+      path: '/member/members',
17 17
       component: () => import('@/scrm_pages/members/members'),
18 18
       name: 'memberslist',
19 19
       meta: { title: '会员管理', noCache: true }
20 20
     },
21
+    {
22
+      path: '/member/tags',
23
+      component: () => import('@/scrm_pages/members/tags'),
24
+      name: 'memberTaglist',
25
+      meta: { title: '标签管理', noCache: true }
26
+    },
21 27
   ]
22 28
 }

+ 115 - 0
src/scrm_pages/marketing_tool/activity_list.vue View File

@@ -0,0 +1,115 @@
1
+<template>
2
+  <div class="main-contain" v-loading="loading_activities">
3
+    <div class="position">
4
+      <bread-crumb :crumbs="crumbs"></bread-crumb>
5
+      <el-button
6
+        :disabled="$store.getters.xt_user.subscibe.state==3?true:false"
7
+        @click="$router.push({path:'/activity/publish'})"
8
+        class="filter-item"
9
+        style="float:right;"
10
+        type="primary"
11
+        icon="el-icon-circle-plus-outline"
12
+        size="small"
13
+      >创建活动</el-button>
14
+    </div>
15
+    <div class="app-container">
16
+      <div class="cell clearfix">
17
+        <el-input v-model="keyword" placeholder="请输入您要搜索的活动" class="keyword_input"></el-input>
18
+        <el-button type="primary" icon="el-icon-search" @click="getActivities()">搜索</el-button>
19
+      </div>
20
+      <div class="cell clearfix">
21
+        <label class="title">
22
+          <span class="name">状态</span> :
23
+        </label>
24
+        <div class="time">
25
+          <ul>
26
+            <li :class="{ active: selecting_status == 0 }" @click="changeSelectingStatus(0)">全部</li>
27
+            <li :class="{ active: selecting_status == 1 }" @click="changeSelectingStatus(1)">已发布</li>
28
+            <li :class="{ active: selecting_status == 2 }" @click="changeSelectingStatus(2)">待发布</li>
29
+            <li :class="{ active: selecting_status == 3 }" @click="changeSelectingStatus(3)">未通过</li>
30
+            <li :class="{ active: selecting_status == 4 }" @click="changeSelectingStatus(4)">已结束</li>
31
+          </ul>
32
+        </div>
33
+      </div>
34
+      <div>
35
+        <template v-for="(activity, index) in activities">
36
+          <published-cell v-if="activity.status == 1 || activity.status == 4" :key="index" :activity="activity"></published-cell>
37
+          <unapproved-cell v-else-if="activity.status == 3" :key="index" :activity="activity"></unapproved-cell>
38
+          <drafts-cell v-else-if="activity.status == 2" :key="index" :activity="activity"></drafts-cell>
39
+        </template>
40
+      </div>
41
+      <div class="cell clearfix" style="padding-top: 15px;">
42
+          <el-pagination :total="activity_total" :current-page.sync="current_page" :page-size="10" layout="total, prev, pager, next" @current-change="getActivities()"></el-pagination>
43
+      </div>
44
+    </div>
45
+  </div>
46
+</template>
47
+
48
+<script>
49
+import BreadCrumb from "@/scrm_pages/components/bread-crumb";
50
+import PublishedCell from "@/scrm_pages/marketing_tool/components/published_cell"
51
+import UnapprovedCell from "@/scrm_pages/marketing_tool/components/unapproved_cell"
52
+import DraftsCell from "@/scrm_pages/marketing_tool/components/drafts_cell"
53
+import { fetchActivities } from "@/api/activity/activity"
54
+
55
+export default {
56
+  name: "ActivityList",
57
+  components: {
58
+    BreadCrumb,
59
+    PublishedCell,
60
+    UnapprovedCell,
61
+    DraftsCell,
62
+  },
63
+  data() {
64
+    return {
65
+      crumbs: [
66
+        { path: false, name: "营销工具" },
67
+        { path: false, name: "活动列表" }
68
+      ],
69
+      keyword: "",
70
+      selecting_status: 0,
71
+      activity_total: 0,
72
+      current_page: 1,
73
+
74
+      loading_activities: false,
75
+      activities: [],
76
+    };
77
+  },
78
+  mounted() {
79
+      this.getActivities()
80
+  },
81
+  methods: {
82
+    changeSelectingStatus(status) {
83
+      this.selecting_status = status
84
+      this.getActivities()
85
+    },
86
+
87
+    getActivities() {
88
+      this.loading_activities = true
89
+      fetchActivities(this.current_page, this.keyword, this.selecting_status).then(rs => {
90
+        this.loading_activities = false
91
+        var resp = rs.data
92
+        if (resp.state == 1) {
93
+          this.activities = resp.data.activities
94
+          this.activity_total = resp.data.total
95
+          console.log(this.activities)
96
+
97
+        } else {
98
+          this.$message.error(resp.msg)
99
+        }
100
+      }).catch(err => {
101
+        this.loading_activities = false
102
+        this.$message.error(err)
103
+      })
104
+    },
105
+  },
106
+};
107
+</script>
108
+
109
+<style scoped>
110
+.keyword_input {
111
+  width: 330px;
112
+}
113
+</style>
114
+
115
+

+ 61 - 0
src/scrm_pages/marketing_tool/activity_publish.vue View File

@@ -0,0 +1,61 @@
1
+<template>
2
+    <div class="main-contain">
3
+        <div class="position">
4
+            <bread-crumb :crumbs="crumbs"></bread-crumb>
5
+        </div>
6
+        <div class="app-container" style="padding: 0 20px; background-color: #f6f8f9;">
7
+            <div class="edit-main">
8
+                <div class="preview-panel">
9
+                    <preview-form></preview-form>
10
+                </div>
11
+                <div class="edit-panel">
12
+                    <edit-form></edit-form>
13
+                </div>
14
+            </div>
15
+        </div>
16
+    </div>
17
+</template>
18
+
19
+<script>
20
+import BreadCrumb from "@/scrm_pages/components/bread-crumb";
21
+import PreviewForm from "@/scrm_pages/marketing_tool/components/edit_activity_preview_form"
22
+import EditForm from "@/scrm_pages/marketing_tool/components/edit_activity_edit_form"
23
+
24
+export default {
25
+    name: "ActivityPublish",
26
+    components: {
27
+        BreadCrumb,
28
+        PreviewForm,
29
+        EditForm,
30
+    },
31
+    data() {
32
+        return {
33
+            crumbs: [
34
+                { path: false, name: "营销工具" },
35
+                { path: false, name: "发布活动" }
36
+            ],
37
+        }
38
+    },
39
+}
40
+</script>
41
+
42
+<style scoped rel="stylesheet/scss" lang="scss">
43
+.edit-main {
44
+    width: 100%;
45
+    display: flex;
46
+    min-height: 600px;
47
+    height: auto;
48
+    box-sizing: border-box;
49
+
50
+    .preview-panel {
51
+        flex: 3;
52
+        margin-right: 1rem;
53
+        background-color: #fff;
54
+    }
55
+    .edit-panel {
56
+        flex: 4;
57
+        padding-bottom: 80px;
58
+        background-color: #fff;
59
+    }
60
+}
61
+</style>

+ 123 - 0
src/scrm_pages/marketing_tool/components/drafts_cell.vue View File

@@ -0,0 +1,123 @@
1
+<template>
2
+<div class="clearfix">
3
+    <div class="drafts-cell">
4
+        <div class="activity-image-panel">
5
+            <span class="status-text">待发布</span>
6
+            <img :src="activity.poster_photo" />
7
+        </div>
8
+        <div class="activity-info-panel">
9
+            <h3 class="title">
10
+                <a href="/">{{ activity.title }}</a>
11
+            </h3>
12
+            <div class="operation">
13
+                <el-button type="primary" size="small" icon="el-icon-edit-outline">编辑</el-button>
14
+                <el-button type="danger" size="small" icon="el-icon-delete">删除</el-button>
15
+            </div>
16
+        </div>
17
+    </div>
18
+</div>
19
+</template>
20
+
21
+<script>
22
+export default {
23
+    name: "DraftsActivityCell",
24
+    props: {
25
+        activity: {
26
+            type: Object,
27
+            required: true,
28
+        }
29
+    },
30
+    data() {
31
+        return {
32
+            
33
+        }
34
+    },
35
+}
36
+</script>
37
+
38
+<style scoped rel="stylesheet/scss" lang="scss">
39
+.drafts-cell {
40
+    padding: 20px 15px;
41
+    border: none;
42
+    border-bottom: 1px solid #e5e8ea;
43
+    float: left;
44
+    margin: 0;
45
+    width: 100%;
46
+    border-radius: 0;
47
+    position: relative;
48
+
49
+    .activity-image-panel {
50
+        width: 155px;
51
+        height: 122px;
52
+        border: 1px #dee2e5 solid;
53
+        display: flex;
54
+        justify-content: center;
55
+        position: relative;
56
+        -webkit-border-radius: 4px;
57
+        -moz-border-radius: 4px;
58
+        border-radius: 4px;
59
+        overflow: hidden;
60
+        float: left;
61
+
62
+        .status-text {
63
+            position: absolute;
64
+            font-size: 12px;
65
+            color: #fff;
66
+            top: 14px;
67
+            left: 3px;
68
+            -webkit-transform: rotate(316deg);
69
+            transform: rotate(316deg);
70
+        }
71
+
72
+        img {
73
+            width: 100%;
74
+            height: 100%;
75
+            object-fit: cover;
76
+            object-position: center;
77
+        }
78
+    }
79
+    .activity-image-panel::before {
80
+        border-top: 28px solid #65d3e3;
81
+        border-right: 28px solid transparent;
82
+        border-bottom: 28px solid transparent;
83
+        border-left: 28px solid #65d3e3;
84
+        position: absolute;
85
+        top: 0;
86
+        left: 0;
87
+        width: 0;
88
+        height: 0;
89
+        display: block;
90
+        content: "";
91
+    }
92
+
93
+    .activity-info-panel {
94
+        padding: 7px 20px;
95
+        width: 60%;
96
+        float: left;
97
+
98
+        .title {
99
+            padding-bottom: 5px;
100
+
101
+            a {
102
+                color: #495060;
103
+                font-size: 20px;
104
+                max-width: 100%;
105
+                font-weight: 500;
106
+                overflow: hidden;
107
+                white-space: nowrap;
108
+                text-overflow: ellipsis;
109
+                display: inline-block;
110
+            }
111
+        }
112
+
113
+        .operation {
114
+            padding: 10px 0 0;
115
+        }
116
+    }
117
+}
118
+</style>
119
+
120
+
121
+
122
+
123
+

+ 14 - 0
src/scrm_pages/marketing_tool/components/edit_activity_edit_form.vue View File

@@ -0,0 +1,14 @@
1
+<template>
2
+    <div></div>
3
+</template>
4
+
5
+<script>
6
+export default {
7
+    name: "EditActivityEditForm",
8
+}
9
+</script>
10
+
11
+<style lang="scss" scoped>
12
+
13
+</style>
14
+

+ 206 - 0
src/scrm_pages/marketing_tool/components/edit_activity_preview_form.vue View File

@@ -0,0 +1,206 @@
1
+<template>
2
+    <div class="preview-main">
3
+        <div class="form-title">
4
+            <img class="icon" src="@/assets/img/sa_06.png" />
5
+            <span>预览</span>
6
+        </div>
7
+        <div class="form-content">
8
+            <div class="preview-cell-poster-photo border">
9
+                <img class="poster-photo" :src="poster_photo" />
10
+                <div class="title-panel">
11
+                    <p class="title">{{ title }}</p>
12
+                    <p class="subtitle">{{ subtitle }}</p>
13
+                </div>
14
+            </div>
15
+            <div class="org-info-cell border">
16
+                <div class="logo">
17
+                    <img :src="poster_photo" />
18
+                </div>
19
+                <div class="text-info">
20
+                    <p class="name">测试机构</p>
21
+                    <p class="address">地址地址地址地址地址地址地址地址地址地址地址地址地址地址地址地址</p>
22
+                </div>
23
+                <div class="arrow-panel">
24
+                    <img src="@/assets/img/sa_52.png" />
25
+                </div>
26
+            </div>
27
+            <div class="simple-cell border">
28
+                <div class="icon">
29
+                    <img src="@/assets/img/sa_21.png" />
30
+                </div>
31
+                <div class="text">
32
+                    <p>2019-01-01</p>
33
+                </div>
34
+                <div class="arrow-panel">
35
+                    <img src="@/assets/img/sa_52.png" />
36
+                </div>
37
+            </div>
38
+            <div class="simple-cell border">
39
+                <div class="icon">
40
+                    <img src="@/assets/img/sa_24.png" />
41
+                </div>
42
+                <div class="text">
43
+                    <p>0755-86879866</p>
44
+                </div>
45
+                <div class="arrow-panel">
46
+                    <img src="@/assets/img/sa_52.png" />
47
+                </div>
48
+            </div>
49
+        </div>
50
+    </div>
51
+</template>
52
+
53
+<script>
54
+export default {
55
+    name: "EditActivityPreviewForm",
56
+    data() {
57
+        return {
58
+            
59
+        }
60
+    },
61
+    computed: {
62
+        poster_photo: function() {
63
+            return require("@/assets/img/activity_poster_photo_default.png")
64
+        },
65
+        title: function() {
66
+            return "与孩子一起挑选采摘新鲜有机马陆葡萄,体验采摘乐趣"
67
+        },
68
+        subtitle: function() {
69
+            return "亲子采摘活动"
70
+        },
71
+    },
72
+}
73
+</script>
74
+
75
+<style lang="scss" scoped>
76
+.preview-main {
77
+    .form-title {
78
+        width: 100%;
79
+        padding: 20px 0 20px 30px;
80
+        border-bottom: 1px #dee2e5 solid;
81
+
82
+        .icon {
83
+            margin-top: -4px;
84
+            vertical-align: middle;
85
+        }
86
+
87
+        span {
88
+            font-size: 18px;
89
+            font-weight: 500;
90
+            color: #485b6d;
91
+            margin-left: 10px;
92
+        }
93
+    }
94
+
95
+    .form-content {
96
+        width: 100%;
97
+        padding: 14px 30px 0 30px;
98
+
99
+        .preview-cell-poster-photo {
100
+            .poster-photo {
101
+                width: 100%;
102
+            }
103
+
104
+            .title-panel {
105
+                padding: 15px 15px 16px 20px;
106
+
107
+                .title {
108
+                    font-size: 18px;
109
+                    color: #485b6d;
110
+                    font-weight: bold;
111
+                    line-height: 28px;
112
+                }
113
+
114
+                .subtitle {
115
+                    margin-top: 6px;
116
+                    color: #a6a6a6;
117
+                    font-size: 14px;
118
+                }
119
+            }
120
+        }
121
+
122
+        .org-info-cell {
123
+            padding: 20px 20px;
124
+            margin-top: 15px;
125
+            position: relative;
126
+            display: flex;
127
+            -webkit-box-align: center;
128
+            align-items: center;
129
+
130
+            .logo {
131
+                img {
132
+                    width: 40px;
133
+                    height: 40px;
134
+                    border-radius: 20px;
135
+                }
136
+            }
137
+            .text-info {
138
+                flex: 1;
139
+                padding-left: 17px;
140
+                color: #485b6d;
141
+
142
+                .name {
143
+                    font-size: 16px;
144
+                    line-height: 22px;
145
+                    font-weight: 500;
146
+                }
147
+                .address {
148
+                    font-size: 14px;
149
+                    line-height: 20px;
150
+                    margin-top: 5px;
151
+                }
152
+            }
153
+            .arrow-panel {
154
+                width: 20px;
155
+                position: relative;
156
+
157
+                img {
158
+                    width: 8px;
159
+                    float: right;
160
+                    vertical-align: middle;
161
+                }
162
+            }
163
+        }
164
+
165
+        .simple-cell {
166
+            padding: 20px 20px;
167
+            margin-top: 15px;
168
+            position: relative;
169
+            display: flex;
170
+            -webkit-box-align: center;
171
+            align-items: center;
172
+
173
+            .icon {
174
+                img {
175
+                    width: 20px;
176
+                    height: 20px;
177
+                    vertical-align: middle;
178
+                }
179
+            }
180
+            .text {
181
+                flex: 1;
182
+                padding-left: 17px;
183
+                color: #485b6d;
184
+                line-height: 20px;
185
+            }
186
+            .arrow-panel {
187
+                width: 20px;
188
+                position: relative;
189
+
190
+                img {
191
+                    width: 8px;
192
+                    float: right;
193
+                    vertical-align: middle;
194
+                }
195
+            }
196
+        }
197
+    }
198
+}
199
+</style>
200
+
201
+<style scoped>
202
+.border {
203
+    border: solid 1px #dee2e5;
204
+    border-radius: 4px;
205
+}
206
+</style>

+ 188 - 0
src/scrm_pages/marketing_tool/components/published_cell.vue View File

@@ -0,0 +1,188 @@
1
+<template>
2
+<div class="clearfix">
3
+    <div class="published-cell">
4
+        <div class="activity-image-panel">
5
+            <span class="status-text">{{ status_text }}</span>
6
+            <img :src="activity.poster_photo" />
7
+        </div>
8
+        <div class="activity-info-panel">
9
+            <h3 class="title">
10
+                <a href="">{{ activity.title }}</a>
11
+            </h3>
12
+            <div class="statistics">
13
+                阅读:{{ activity.read_num }} 丨 评论:{{ activity.comment_num }} 丨 点赞:{{ activity.star_num }}
14
+            </div>
15
+            <div class="progress">
16
+                <div class="progress-bar">
17
+                    <el-progress :percentage="progress_percent" :stroke-width="5" color="#409eff" :show-text="false" ></el-progress>
18
+                </div>
19
+                <span class="progress-text">{{ progress_text }}</span>
20
+            </div>
21
+        </div>
22
+        <div class="activity-time-panel">
23
+            <span class="time">{{ start_time }}</span>
24
+        </div>
25
+    </div>
26
+</div>
27
+</template>
28
+
29
+<script>
30
+import { parseTime } from "@/utils"
31
+
32
+export default {
33
+    name: "PublishedActivityCell",
34
+    props: {
35
+        activity: {
36
+            type: Object,
37
+            required: true,
38
+        }
39
+    },
40
+    data() {
41
+        return {
42
+            
43
+        }
44
+    },
45
+    computed: {
46
+        status_text: function() {
47
+            if (this.activity.status == 4) {
48
+                return "已结束"
49
+            } else if (this.activity.is_recommend == true) {
50
+                return "已推荐"
51
+            } else {
52
+                return "已发布"
53
+            }
54
+        },
55
+        progress_percent: function() {
56
+            if (this.activity.limit_num > 0) {
57
+                return (this.activity.join_num / this.activity.limit_num) * 100
58
+            } else {
59
+                return 100
60
+            }
61
+        },
62
+        progress_text: function() {
63
+            if (this.activity.limit_num > 0) {
64
+                if (this.activity.join_num >= this.activity.limit_num) {
65
+                    return "已报满"
66
+                } else {
67
+                    return this.activity.join_num + " / " + this.activity.limit_num
68
+                }
69
+            } else {
70
+                return "无限制"
71
+            }
72
+        },
73
+        start_time: function() {
74
+            return parseTime(this.activity.start_time, "{y}-{m}-{d}")
75
+        },
76
+    },
77
+}
78
+</script>
79
+
80
+<style scoped rel="stylesheet/scss" lang="scss">
81
+.published-cell {
82
+    padding: 20px 15px;
83
+    border: none;
84
+    border-bottom: 1px solid #e5e8ea;
85
+    float: left;
86
+    margin: 0;
87
+    width: 100%;
88
+    border-radius: 0;
89
+    position: relative;
90
+
91
+    .activity-image-panel {
92
+        width: 155px;
93
+        height: 122px;
94
+        border: 1px #dee2e5 solid;
95
+        display: flex;
96
+        justify-content: center;
97
+        position: relative;
98
+        -webkit-border-radius: 4px;
99
+        -moz-border-radius: 4px;
100
+        border-radius: 4px;
101
+        overflow: hidden;
102
+        float: left;
103
+
104
+        .status-text {
105
+            position: absolute;
106
+            font-size: 12px;
107
+            color: #fff;
108
+            top: 14px;
109
+            left: 3px;
110
+            -webkit-transform: rotate(316deg);
111
+            transform: rotate(316deg);
112
+        }
113
+
114
+        img {
115
+            width: 100%;
116
+            height: 100%;
117
+            object-fit: cover;
118
+            object-position: center;
119
+        }
120
+    }
121
+    .activity-image-panel::before {
122
+        border-top: 28px solid #5bd18b;
123
+        border-right: 28px solid transparent;
124
+        border-bottom: 28px solid transparent;
125
+        border-left: 28px solid #5bd18b;
126
+        position: absolute;
127
+        top: 0;
128
+        left: 0;
129
+        width: 0;
130
+        height: 0;
131
+        display: block;
132
+        content: "";
133
+    }
134
+
135
+    .activity-info-panel {
136
+        padding: 7px 20px;
137
+        width: 60%;
138
+        float: left;
139
+
140
+        .title {
141
+            padding-bottom: 5px;
142
+
143
+            a {
144
+                color: #495060;
145
+                font-size: 20px;
146
+                max-width: 100%;
147
+                font-weight: 500;
148
+                overflow: hidden;
149
+                white-space: nowrap;
150
+                text-overflow: ellipsis;
151
+                display: inline-block;
152
+            }
153
+        }
154
+
155
+        .statistics {
156
+            color: #a8b3ba;
157
+            font-size: 15px;
158
+            justify-content: space-between;
159
+            line-height: 30px;
160
+        }
161
+
162
+        .progress {
163
+            padding: 5px 0;
164
+
165
+            .progress-bar {
166
+                width: 60%;
167
+                display: inline-block;
168
+            }
169
+            .progress-text {
170
+                margin-left: 10px;
171
+                font-size: 15px;
172
+                color: #409eff;
173
+            }
174
+        }
175
+    }
176
+
177
+    .activity-time-panel {
178
+        float: right;
179
+        padding: 7px 0;
180
+
181
+        .time {
182
+            font-size: 15px;
183
+            color: #a8b3ba;
184
+        }
185
+    }
186
+}
187
+</style>
188
+

+ 151 - 0
src/scrm_pages/marketing_tool/components/unapproved_cell.vue View File

@@ -0,0 +1,151 @@
1
+<template>
2
+<div class="clearfix">
3
+    <div class="unapproved-cell">
4
+        <div class="activity-image-panel">
5
+            <span class="status-text">未通过</span>
6
+            <img :src="activity.poster_photo" />
7
+        </div>
8
+        <div class="activity-info-panel">
9
+            <h3 class="title">
10
+                <a href="/">{{ activity.title }}</a>
11
+            </h3>
12
+            <div class="reason">
13
+                审核未通过:{{ activity.reason }}
14
+            </div>
15
+            <div class="operation">
16
+                <el-button type="primary" size="small" icon="el-icon-edit-outline">编辑</el-button>
17
+                <el-button type="danger" size="small" icon="el-icon-delete">删除</el-button>
18
+            </div>
19
+        </div>
20
+        <div class="activity-time-panel">
21
+            <span class="time">{{ start_time }}</span>
22
+        </div>
23
+    </div>
24
+</div>
25
+</template>
26
+
27
+<script>
28
+import { parseTime } from "@/utils"
29
+
30
+export default {
31
+    name: "UnapprovedActivityCell",
32
+    props: {
33
+        activity: {
34
+            type: Object,
35
+            required: true,
36
+        }
37
+    },
38
+    data() {
39
+        return {
40
+            
41
+        }
42
+    },
43
+    computed: {
44
+        start_time: function() {
45
+            return parseTime(this.activity.start_time, "{y}-{m}-{d}")
46
+        },
47
+    },
48
+}
49
+</script>
50
+
51
+<style scoped rel="stylesheet/scss" lang="scss">
52
+.unapproved-cell {
53
+    padding: 20px 15px;
54
+    border: none;
55
+    border-bottom: 1px solid #e5e8ea;
56
+    float: left;
57
+    margin: 0;
58
+    width: 100%;
59
+    border-radius: 0;
60
+    position: relative;
61
+
62
+    .activity-image-panel {
63
+        width: 155px;
64
+        height: 122px;
65
+        border: 1px #dee2e5 solid;
66
+        display: flex;
67
+        justify-content: center;
68
+        position: relative;
69
+        -webkit-border-radius: 4px;
70
+        -moz-border-radius: 4px;
71
+        border-radius: 4px;
72
+        overflow: hidden;
73
+        float: left;
74
+
75
+        .status-text {
76
+            position: absolute;
77
+            font-size: 12px;
78
+            color: #fff;
79
+            top: 14px;
80
+            left: 3px;
81
+            -webkit-transform: rotate(316deg);
82
+            transform: rotate(316deg);
83
+        }
84
+
85
+        img {
86
+            width: 100%;
87
+            height: 100%;
88
+            object-fit: cover;
89
+            object-position: center;
90
+        }
91
+    }
92
+    .activity-image-panel::before {
93
+        border-top: 28px solid #ff7979;
94
+        border-right: 28px solid transparent;
95
+        border-bottom: 28px solid transparent;
96
+        border-left: 28px solid #ff7979;
97
+        position: absolute;
98
+        top: 0;
99
+        left: 0;
100
+        width: 0;
101
+        height: 0;
102
+        display: block;
103
+        content: "";
104
+    }
105
+
106
+    .activity-info-panel {
107
+        padding: 7px 20px;
108
+        width: 60%;
109
+        float: left;
110
+
111
+        .title {
112
+            padding-bottom: 5px;
113
+
114
+            a {
115
+                color: #495060;
116
+                font-size: 20px;
117
+                max-width: 100%;
118
+                font-weight: 500;
119
+                overflow: hidden;
120
+                white-space: nowrap;
121
+                text-overflow: ellipsis;
122
+                display: inline-block;
123
+            }
124
+        }
125
+
126
+        .reason {
127
+            color: #ff7979;
128
+            font-size: 14px;
129
+            justify-content: space-between;
130
+            line-height: 30px;
131
+        }
132
+
133
+        .operation {
134
+            padding: 10px 0 0;
135
+        }
136
+    }
137
+
138
+    .activity-time-panel {
139
+        float: right;
140
+        padding: 7px 0;
141
+
142
+        .time {
143
+            font-size: 15px;
144
+            color: #a8b3ba;
145
+        }
146
+    }
147
+}
148
+</style>
149
+
150
+
151
+

+ 128 - 0
src/scrm_pages/members/components/AddMembersTagsForm.vue View File

@@ -0,0 +1,128 @@
1
+<template>
2
+    <div id="add-members-tags-form-box">
3
+        <el-dialog title="添加标签" :visible.sync="addMembersTagFormVisible" width="800px" >
4
+            <el-form ref="memberTagForm" :rules="tagsRules" :model="form" label-width="90px">
5
+                <el-row>
6
+                    <el-col :span="24">
7
+                        <el-form-item label="标签:"  prop="tags">
8
+                            <el-select
9
+                                v-model="form.tags"
10
+                                multiple
11
+                                style="width:100%"
12
+                                placeholder="请选择标签">
13
+                                <el-option
14
+                                v-for="item in tagOptions"
15
+                                :key="item.id"
16
+                                :label="item.tag_name"
17
+                                :value="item.id">
18
+                                </el-option>
19
+                            </el-select>
20
+                        </el-form-item>
21
+                    </el-col>
22
+                </el-row>
23
+            </el-form>
24
+            <div slot="footer" class="dialog-footer">
25
+                <el-button @click="addMembersTagFormVisible = false">取消</el-button>
26
+                <el-button
27
+                type="primary"
28
+                @click="submitForm('memberTagForm')"
29
+                >保 存
30
+                </el-button>
31
+            </div>
32
+        </el-dialog>  
33
+    </div>
34
+</template>
35
+
36
+<script>
37
+
38
+import {AddMembersTags} from "@/api/member/member";
39
+
40
+export default {
41
+    name:'AddMembersTagsForm',
42
+    props:{
43
+        tagOptions:{
44
+            type: Array,
45
+            default: function () {
46
+                return [];
47
+            }
48
+        },
49
+        form:{
50
+            tags:[],
51
+            ids:[],
52
+        },
53
+        membersData:{
54
+            type: Array,
55
+            default: function () {
56
+                return [];
57
+            }
58
+        },
59
+    },
60
+    data(){
61
+        return {
62
+            addMembersTagFormVisible:false,
63
+            
64
+            tagsRules: {
65
+                tags: [{required: true, message: "请选择标签",},],
66
+            },
67
+        }
68
+    },
69
+    methods:{
70
+        open:function(){
71
+            this.addMembersTagFormVisible = true;
72
+        },
73
+        resetForm(formName) {
74
+            if (typeof(this.$refs[formName]) !='undefined') {
75
+                this.$refs[formName].resetFields();
76
+            }
77
+        },
78
+        submitForm(formName){
79
+            this.$refs[formName].validate((valid) => {
80
+                if (valid) {
81
+                    AddMembersTags({ids:this.form.ids, tags:this.form.tags}).then(response=>{
82
+                        var res = response.data;
83
+                        if(res.state === 1) {
84
+                            var idsMap = {};
85
+                            for (const index in this.form.ids) {
86
+                                idsMap[this.form.ids[index]] = this.form.ids[index];
87
+                            }
88
+                            for (const memberIndex in this.membersData) {
89
+                                if (this.membersData[memberIndex].id in idsMap) {
90
+                                    var tagsMap = {};
91
+                                    for (const index in this.form.tags) {
92
+                                        tagsMap[this.form.tags[index]] = this.form.tags[index];
93
+                                    }
94
+                                    var tags = this.membersData[memberIndex].tags;
95
+                                    if (tags) {
96
+                                        for (const index in tags) {
97
+                                            if(tags[index].id in tagsMap) {
98
+                                                continue;
99
+                                            }
100
+                                            tagsMap[tags[index].id] = tags[index].id;
101
+                                        }
102
+                                    }
103
+                                    var memberTags = [];
104
+                                    for (const index in this.tagOptions) {
105
+                                        if(this.tagOptions[index].id in tagsMap) {
106
+                                            memberTags.push(this.tagOptions[index]);
107
+                                        }
108
+                                    }
109
+                                    this.$set(this.membersData[memberIndex], 'tags', memberTags);
110
+                                }
111
+                            }
112
+                            this.resetForm("memberTagForm");
113
+                            this.addMembersTagFormVisible = false;
114
+                            this.$message.success("编辑会员标签成功");
115
+                        }else {
116
+                            this.$message.error(res.msg);
117
+                        }
118
+                    }).catch(e=>{});
119
+
120
+                } else {
121
+                    return false;
122
+                }
123
+            });
124
+        },
125
+    }
126
+}
127
+</script>
128
+

+ 348 - 0
src/scrm_pages/members/components/CreateMemberForm.vue View File

@@ -0,0 +1,348 @@
1
+<template>
2
+    <div id="create-member-form-box">
3
+        <el-dialog title="添加会员" :visible.sync="createMemberFormVisible" width="800px" >
4
+            <el-form ref="memberForm" :rules="memberRules" :model="form" label-width="90px">
5
+                <el-row>
6
+                    <el-col :span="12">
7
+                        <el-form-item label="姓名:" required prop="name">
8
+                        <el-input v-model="form.name"></el-input>
9
+                        </el-form-item>
10
+                    </el-col>
11
+                    <el-col :span="12">
12
+                        <el-form-item label="手机号:" required prop="mobile">
13
+                        <el-input v-model="form.mobile"></el-input>
14
+                        </el-form-item>
15
+                    </el-col>
16
+                </el-row>
17
+                <el-row>
18
+                    <el-col :span="12">
19
+                        <el-form-item label="性别:" required prop="gender">
20
+                            <el-radio-group v-model="form.gender" @change="selectGender">
21
+                                <el-radio :label="gender.id" :value="gender.id" v-for="(gender, index) in genderOptions" :key="index">{{gender.name}}</el-radio>
22
+                            </el-radio-group>
23
+                        </el-form-item>
24
+                    </el-col>
25
+                    <el-col :span="12">
26
+                        <el-form-item label="生日:" required prop="birthday">
27
+                            <el-date-picker v-model="form.birthday" prefix-icon="el-icon-date" :editable="false" style="width: 100%;" type="date" placeholder="请选择日期" align="right" format="yyyy-MM-dd" value-format="yyyy-MM-dd" ></el-date-picker>
28
+                        </el-form-item>
29
+                    </el-col>
30
+                </el-row>
31
+                <el-row>
32
+                    <el-col :span="12">
33
+                        <el-form-item label="城市:" required prop="city">
34
+                            <el-cascader
35
+                                v-model="form.city"
36
+                                :options="cityOptions"
37
+                                @active-item-change="handleChangeCity"
38
+                                @change="handleSelectedCity"
39
+                                style="width: 100%;" 
40
+                                :props="{
41
+                                    value: 'id',
42
+                                    label: 'name',
43
+                                    children: 'cities'
44
+                                }"
45
+                            ></el-cascader>
46
+                        </el-form-item>
47
+                    </el-col>
48
+                    <el-col :span="12">
49
+                        <el-form-item label="病种:" required prop="illness">
50
+                            <el-select
51
+                                v-model="form.illness"
52
+                                multiple
53
+                                collapse-tags
54
+                                style="width:100%"
55
+                                placeholder="请选择病种">
56
+                                <el-option
57
+                                v-for="item in illnessOptions"
58
+                                :key="item.id"
59
+                                :label="item.illness_name"
60
+                                :value="item.id">
61
+                                </el-option>
62
+                            </el-select>
63
+                        </el-form-item>
64
+                    </el-col>
65
+                </el-row>
66
+                <el-row>
67
+                    <el-col :span="12">
68
+                        <el-form-item label="患病时间:" required prop="ill_date">
69
+                            <el-date-picker v-model="form.ill_date" prefix-icon="el-icon-date" :editable="false" style="width: 100%;" type="date" placeholder="请选择日期" align="right" format="yyyy-MM-dd" value-format="yyyy-MM-dd" ></el-date-picker>
70
+                        </el-form-item>
71
+                    </el-col>
72
+                    <el-col :span="12">
73
+                        <el-form-item label="治疗方式:" required prop="treat_type">
74
+                            <el-select
75
+                                v-model="form.treat_type"
76
+                                style="width:100%"
77
+                                placeholder="请选择治疗方式">
78
+                                <el-option
79
+                                v-for="item in treatTypeOptions"
80
+                                :key="item.id"
81
+                                :label="item.name"
82
+                                :value="item.id">
83
+                                </el-option>
84
+                            </el-select>
85
+                        </el-form-item>
86
+                    </el-col>
87
+                </el-row>
88
+                <el-row>
89
+                    <el-col :span="24">
90
+                        <el-form-item label="标签:"  prop="tags">
91
+                            <el-select
92
+                                v-model="form.tags"
93
+                                multiple
94
+                                style="width:100%"
95
+                                placeholder="请选择标签">
96
+                                <el-option
97
+                                v-for="item in tagOptions"
98
+                                :key="item.id"
99
+                                :label="item.tag_name"
100
+                                :value="item.id">
101
+                                </el-option>
102
+                            </el-select>
103
+                        </el-form-item>
104
+                    </el-col>
105
+                </el-row>
106
+                <el-row>
107
+                    <el-col :span="24">
108
+                        <el-form-item label="备注:"  prop="remark">
109
+                            <el-input type="textarea" :rows="2" placeholder="请输入备注" v-model="form.remark">
110
+                            </el-input>
111
+                        </el-form-item>
112
+                    </el-col>
113
+                </el-row>
114
+            </el-form>
115
+            <div slot="footer" class="dialog-footer">
116
+                <el-button @click="createMemberFormVisible = false">取消</el-button>
117
+                <el-button
118
+                type="primary"
119
+                @click="submitForm('memberForm')"
120
+                >保 存
121
+                </el-button>
122
+            </div>
123
+        </el-dialog>  
124
+    </div>
125
+</template>
126
+
127
+<script>
128
+import {GetDistrictsByUpid} from  "@/api/district";
129
+import {checkMobile} from "@/utils/tools";
130
+import {CreateMember} from "@/api/member/member";
131
+
132
+export default {
133
+    name:'CreateMemberForm',
134
+    props:{
135
+        illnessOptions:{
136
+            type: Array,
137
+            default: function () {
138
+                return [];
139
+            }
140
+        },
141
+        treatTypeOptions:{
142
+            type: Object,
143
+            default: function () {
144
+                return {};
145
+            }
146
+        },
147
+        tagOptions:{
148
+            type: Array,
149
+            default: function () {
150
+                return [];
151
+            }
152
+        },
153
+        levelCards:{
154
+            type: Array,
155
+            default: function () {
156
+                return [];
157
+            }
158
+        },
159
+        membersData:{
160
+            type: Array,
161
+            default: function () {
162
+                return [];
163
+            }
164
+        },
165
+    },
166
+    data(){
167
+        var checkMobileRule = (rule, value, callback) => {
168
+            if (!checkMobile(value)) {
169
+                callback(new Error('请填写正确的手机号'));
170
+            }else {
171
+               callback(); 
172
+            }
173
+        };
174
+        return {
175
+            createMemberFormVisible:false,
176
+            
177
+            memberRules: {
178
+                name: [{required: true, message: "请填写姓名",},],
179
+                mobile: [{required: true, message: "请填写手机号",},{ validator: checkMobileRule}],
180
+                gender: [{required: true, message: "请选择性别",},],
181
+                birthday: [{required: true, message: "请选择生日",},],
182
+                city: [{required: true, message: "请选择城市",},],
183
+                illness: [{required: true, message: "请选择病种",},],
184
+                ill_date: [{required: true, message: "请选择患病时间",},],
185
+                treat_type: [{required: true, message: "请选择治疗方式",},],
186
+                
187
+            },
188
+            genderOptions:[
189
+                {id:1, name:'男'},
190
+                {id:2, name:'女'},
191
+            ],
192
+            cityOptions:[],
193
+            form:{
194
+                name:'',
195
+                mobile:'',
196
+                gender:0,
197
+                birthday:'',
198
+                city:[],
199
+                province_id:0,
200
+                city_id:0,
201
+                district_id:0,
202
+                illness:[],
203
+                ill_date:'',
204
+                treat_type:'',
205
+                tags:[],
206
+                remark:'',
207
+                card:null,
208
+                avatar:'',
209
+            },
210
+            
211
+        }
212
+    },
213
+    methods:{
214
+        open:function(){
215
+            this.GetDistrictsByUpid();
216
+            this.resetForm("memberForm");
217
+            this.createMemberFormVisible = true;
218
+        },
219
+        resetForm(formName) {
220
+            if (typeof(this.$refs[formName]) !='undefined') {
221
+                this.$refs[formName].resetFields();
222
+            }
223
+        },
224
+        submitForm(formName){
225
+            // if (this.levelCards.length>0) {
226
+            //     this.form.card = this.levelCards[0];
227
+            // }
228
+            this.$refs[formName].validate((valid) => {
229
+                if (valid) {
230
+                    CreateMember(this.form).then(response=>{
231
+                        var res = response.data;
232
+                        if(res.state === 1) {
233
+                            var member = res.data.member;
234
+                            if(member.user_tags) {
235
+                                member.tags = [];
236
+                                var userTagsMap = {};
237
+                                for (const index in member.user_tags) {
238
+                                    userTagsMap[member.user_tags[index].tag_id] = 1;
239
+                                }
240
+                                for (const index in this.tagOptions) {
241
+                                    if(this.tagOptions[index].id in userTagsMap) {
242
+                                        member.tags.push(this.tagOptions[index]);
243
+                                    }
244
+                                }
245
+                            }
246
+                            this.membersData.unshift(member);
247
+                            this.resetForm("memberForm");
248
+                            this.createMemberFormVisible = false;
249
+                            this.$message.success("添加会员成功");
250
+                        }else {
251
+                            this.$message.error(res.msg);
252
+                        }
253
+                    }).catch(e=>{});
254
+
255
+                } else {
256
+                    return false;
257
+                }
258
+            });
259
+        },
260
+        selectGender:function(gender) {
261
+            if(gender == 2) {
262
+                this.form.avatar = 'https://images.shengws.com/201809182128222.png';
263
+            }else {
264
+                this.form.avatar = 'https://images.shengws.com/201809182128111.png';
265
+            }
266
+        },
267
+        handleChangeCity:function(val) {
268
+            this.GetDistrictsByUpid(val);
269
+        },
270
+        handleSelectedCity:function(val) {
271
+            this.form.province_id = val[0];
272
+            this.form.city_id = val[1];
273
+            this.form.district_id = val[2];
274
+        },
275
+        GetDistrictsByUpid:function(val) {  
276
+            let idArea
277
+            let sizeArea
278
+            if (!val) {
279
+                idArea = 0
280
+                sizeArea = 0
281
+            } else if (val.length === 1) {
282
+                idArea = val[0]
283
+                sizeArea = val.length // 3:一级 4:二级 6:三级
284
+            } else if (val.length === 2) {
285
+                idArea = val[1]
286
+                sizeArea = val.length // 3:一级 4:二级 6:三级
287
+            }
288
+            
289
+            GetDistrictsByUpid({id:idArea}).then(response=>{
290
+                var res = response.data;
291
+                if (res.state===1) {
292
+                    var citys = res.data.citys;
293
+                    if (sizeArea === 0) { // 初始化 加载一级 省
294
+                        this.cityOptions = citys.map((value, i) => {
295
+                            return {
296
+                                id: value.id,
297
+                                name: value.name,
298
+                                cities: []
299
+                            }
300
+                        })
301
+                    } else if (sizeArea === 1) { // 点击一级 加载二级 市
302
+                        this.cityOptions.map((value, i) => {
303
+                            if (value.id === val[0]) {
304
+                                if (!value.cities.length) {
305
+                                    value.cities = citys.map((value, i) => {
306
+                                        return {
307
+                                            id: value.id,
308
+                                            name: value.name,
309
+                                            cities: []
310
+                                        }
311
+                                    })
312
+                                }
313
+                            }
314
+                        })
315
+                    } else if (sizeArea === 2) { // 点击二级 加载三级 区
316
+                        this.cityOptions.map((value, i) => {
317
+                            if (value.id === val[0]) {
318
+                                value.cities.map((value, i) => {
319
+                                    if (value.id === val[1]) {
320
+                                        if (!value.cities.length) {
321
+                                            if (citys.length) {
322
+                                                value.cities = citys.map((value, i) => {
323
+                                                    return {
324
+                                                        id: value.id,
325
+                                                        name: value.name
326
+                                                    }
327
+                                                })
328
+                                            }else {
329
+                                                value.cities = [
330
+                                                    {id:value.id, name:value.name}
331
+                                                ];
332
+                                            }
333
+                                            
334
+                                        }
335
+                                    }
336
+                                })
337
+                            }
338
+                        })
339
+                    }
340
+                }else {
341
+                    this.$message.error(res.msg);
342
+                }
343
+            }).catch(e=>{});
344
+        },
345
+    }
346
+}
347
+</script>
348
+

+ 130 - 0
src/scrm_pages/members/components/EditMemberCardForm.vue View File

@@ -0,0 +1,130 @@
1
+<template>
2
+    <div id="edit-member-card-form-box">
3
+        <el-dialog title="会员卡设置" :visible.sync="editMemberCardFormVisible" width="700px" >
4
+            <el-form ref="memberCardForm"  :model="form" label-width="60px">
5
+                <el-row>
6
+                    <el-col :span="24">
7
+                        <el-form-item label="会员卡:"  prop="card_id">
8
+                            <el-select
9
+                                v-model="form.card_id"
10
+                                style="width:100%"
11
+                                placeholder="请选择会员卡">
12
+                                 <el-option-group label="无卡">
13
+                                    <el-option
14
+                                        label="普通会员"
15
+                                        value="">
16
+                                    </el-option>
17
+                                </el-option-group>
18
+                                <el-option-group label="选择会员卡">
19
+                                    <el-option
20
+                                        v-for="item in cardOptions"
21
+                                        :key="item.id"
22
+                                        :label="item.card_name"
23
+                                        :value="item.id">
24
+                                    </el-option>
25
+                                </el-option-group>
26
+                            </el-select>
27
+                        </el-form-item>
28
+                    </el-col>
29
+                </el-row>
30
+            </el-form>
31
+            <div slot="footer" class="dialog-footer">
32
+                <el-button @click="editMemberCardFormVisible = false">取消</el-button>
33
+                <el-button
34
+                type="primary"
35
+                @click="submitForm('memberCardForm')"
36
+                >保 存
37
+                </el-button>
38
+            </div>
39
+        </el-dialog>  
40
+    </div>
41
+</template>
42
+
43
+<script>
44
+import {GetDistrictsByUpid} from  "@/api/district";
45
+import {checkMobile} from "@/utils/tools";
46
+import {EditMemberCard} from "@/api/member/member";
47
+
48
+export default {
49
+    name:'EditMemberCardForm',
50
+    props:{
51
+        cardOptions:{
52
+            type: Array,
53
+            default: function () {
54
+                return [];
55
+            }
56
+        },
57
+        memberIndex:{
58
+            type:Number,
59
+            default:-1,
60
+        },
61
+        form:{
62
+            id:0,
63
+            card_id:'',
64
+        },
65
+        membersData:{
66
+            type: Array,
67
+            default: function () {
68
+                return [];
69
+            }
70
+        },
71
+    },
72
+    data(){
73
+        return {
74
+            editMemberCardFormVisible:false,
75
+            cardMap: {},
76
+            oldCardId:0,
77
+        }
78
+    },
79
+    methods:{
80
+        open:function(){
81
+            this.oldCardId = this.form.card_id;
82
+            for (const index in this.cardOptions) {
83
+                this.cardMap[this.cardOptions[index].id] = this.cardOptions[index];
84
+            }
85
+            this.editMemberCardFormVisible = true;
86
+        },
87
+        resetForm(formName) {
88
+            if (typeof(this.$refs[formName]) !='undefined') {
89
+                this.$refs[formName].resetFields();
90
+            }
91
+        },
92
+        submitForm(formName){
93
+            this.$refs[formName].validate((valid) => {
94
+                if (valid) {
95
+                    if (this.oldCardId == this.form.card_id) {
96
+                        this.$message.success("会员卡未变化");
97
+                        this.editMemberCardFormVisible = false;
98
+                        return false;
99
+                    }
100
+                    var card_id = parseInt(this.form.card_id);
101
+                    if (isNaN(card_id) || card_id <0) {
102
+                        card_id = 0;
103
+                    }
104
+                    var form = {id:this.form.id, card_id:card_id};
105
+                    EditMemberCard(form).then(response=>{
106
+                        var res = response.data;
107
+                        if(res.state === 1) {
108
+                            var user_card = res.data.user_card;
109
+                            if (user_card) {
110
+                                user_card["card"] = this.cardMap[card_id];
111
+                            }
112
+                            // this.membersData[this.memberIndex].user_card = user_card; 
113
+                            this.$set(this.membersData[this.memberIndex], 'user_card', user_card);
114
+                            this.resetForm("memberCardForm");
115
+                            this.editMemberCardFormVisible = false;
116
+                            this.$message.success("会员卡设置成功");
117
+                        }else {
118
+                            this.$message.error(res.msg);
119
+                        }
120
+                    }).catch(e=>{});
121
+
122
+                } else {
123
+                    return false;
124
+                }
125
+            });
126
+        },
127
+    }
128
+}
129
+</script>
130
+

+ 351 - 0
src/scrm_pages/members/components/EditMemberForm.vue View File

@@ -0,0 +1,351 @@
1
+<template>
2
+    <div id="edit-member-form-box">
3
+        <el-dialog title="编辑会员" :visible.sync="editMemberFormVisible" width="800px" >
4
+            <el-form ref="memberForm" :rules="memberRules" :model="form" label-width="90px">
5
+                <el-row>
6
+                    <el-col :span="12">
7
+                        <el-form-item label="姓名:" required prop="name">
8
+                        <el-input v-model="form.name"></el-input>
9
+                        </el-form-item>
10
+                    </el-col>
11
+                    <el-col :span="12">
12
+                        <el-form-item label="手机号:" required prop="mobile">
13
+                        <el-input v-model="form.mobile"></el-input>
14
+                        </el-form-item>
15
+                    </el-col>
16
+                </el-row>
17
+                <el-row>
18
+                    <el-col :span="12">
19
+                        <el-form-item label="性别:" required prop="gender">
20
+                            <el-radio-group v-model="form.gender" @change="selectGender">
21
+                                <el-radio :label="gender.id" :value="gender.id" v-for="(gender, index) in genderOptions" :key="index">{{gender.name}}</el-radio>
22
+                            </el-radio-group>
23
+                        </el-form-item>
24
+                    </el-col>
25
+                    <el-col :span="12">
26
+                        <el-form-item label="生日:" required prop="birthday">
27
+                            <el-date-picker v-model="form.birthday" prefix-icon="el-icon-date" :editable="false" style="width: 100%;" type="date" placeholder="请选择日期" align="right" format="yyyy-MM-dd" value-format="yyyy-MM-dd" ></el-date-picker>
28
+                        </el-form-item>
29
+                    </el-col>
30
+                </el-row>
31
+                <el-row>
32
+                    <el-col :span="12">
33
+                        <el-form-item label="城市:" required prop="city">
34
+                            <el-cascader
35
+                                v-model="form.city"
36
+                                :options="cityOptions"
37
+                                @active-item-change="handleChangeCity"
38
+                                @change="handleSelectedCity"
39
+                                style="width: 100%;" 
40
+                                :props="{
41
+                                    value: 'id',
42
+                                    label: 'name',
43
+                                    children: 'cities'
44
+                                }"
45
+                            ></el-cascader>
46
+                        </el-form-item>
47
+                    </el-col>
48
+                    <el-col :span="12">
49
+                        <el-form-item label="病种:" required prop="illness">
50
+                            <el-select
51
+                                v-model="form.illness"
52
+                                multiple
53
+                                collapse-tags
54
+                                style="width:100%"
55
+                                placeholder="请选择病种">
56
+                                <el-option
57
+                                v-for="item in illnessOptions"
58
+                                :key="item.id"
59
+                                :label="item.illness_name"
60
+                                :value="item.id">
61
+                                </el-option>
62
+                            </el-select>
63
+                        </el-form-item>
64
+                    </el-col>
65
+                </el-row>
66
+                <el-row>
67
+                    <el-col :span="12">
68
+                        <el-form-item label="患病时间:" required prop="ill_date">
69
+                            <el-date-picker v-model="form.ill_date" prefix-icon="el-icon-date" :editable="false" style="width: 100%;" type="date" placeholder="请选择日期" align="right" format="yyyy-MM-dd" value-format="yyyy-MM-dd" ></el-date-picker>
70
+                        </el-form-item>
71
+                    </el-col>
72
+                    <el-col :span="12">
73
+                        <el-form-item label="治疗方式:" required prop="treat_type">
74
+                            <el-select
75
+                                v-model="form.treat_type"
76
+                                style="width:100%"
77
+                                placeholder="请选择治疗方式">
78
+                                <el-option
79
+                                v-for="item in treatTypeOptions"
80
+                                :key="item.id"
81
+                                :label="item.name"
82
+                                :value="item.id">
83
+                                </el-option>
84
+                            </el-select>
85
+                        </el-form-item>
86
+                    </el-col>
87
+                </el-row>
88
+                <el-row>
89
+                    <el-col :span="24">
90
+                        <el-form-item label="备注:"  prop="remark">
91
+                            <el-input type="textarea" :rows="2" placeholder="请输入备注" v-model="form.remark">
92
+                            </el-input>
93
+                        </el-form-item>
94
+                    </el-col>
95
+                </el-row>
96
+            </el-form>
97
+            <div slot="footer" class="dialog-footer">
98
+                <el-button @click="editMemberFormVisible = false">取消</el-button>
99
+                <el-button
100
+                type="primary"
101
+                @click="submitForm('memberForm')"
102
+                >保 存
103
+                </el-button>
104
+            </div>
105
+        </el-dialog>  
106
+    </div>
107
+</template>
108
+
109
+<script>
110
+import {GetDistrictsByUpid} from  "@/api/district";
111
+import {checkMobile, uParseTime} from "@/utils/tools";
112
+import {EditMember} from "@/api/member/member";
113
+
114
+export default {
115
+    name:'EditMemberForm',
116
+    props:{
117
+        illnessOptions:{
118
+            type: Array,
119
+            default: function () {
120
+                return [];
121
+            }
122
+        },
123
+        treatTypeOptions:{
124
+            type: Object,
125
+            default: function () {
126
+                return {};
127
+            }
128
+        },
129
+        levelCards:{
130
+            type: Array,
131
+            default: function () {
132
+                return [];
133
+            }
134
+        },
135
+        membersData:{
136
+            type: Array,
137
+            default: function () {
138
+                return [];
139
+            }
140
+        },
141
+        form:{
142
+            name:'',
143
+            mobile:'',
144
+            gender:0,
145
+            birthday:'',
146
+            city:[],
147
+            province_id:0,
148
+            city_id:0,
149
+            district_id:0,
150
+            illness:[],
151
+            ill_date:'',
152
+            treat_type:'',
153
+            tags:[],
154
+            remark:'',
155
+            avatar:'',
156
+            id:0,
157
+        },
158
+        memberIndex:{
159
+            type:Number,
160
+            default:-1,
161
+        },
162
+    },
163
+    data(){
164
+        var checkMobileRule = (rule, value, callback) => {
165
+            if (!checkMobile(value)) {
166
+                callback(new Error('请填写正确的手机号'));
167
+            }else {
168
+               callback(); 
169
+            }
170
+        };
171
+        return {
172
+            editMemberFormVisible:false,
173
+            
174
+            memberRules: {
175
+                name: [{required: true, message: "请填写姓名",},],
176
+                mobile: [{required: true, message: "请填写手机号",},{ validator: checkMobileRule}],
177
+                gender: [{required: true, message: "请选择性别",},],
178
+                birthday: [{required: true, message: "请选择生日",},],
179
+                city: [{required: true, message: "请选择城市",},],
180
+                illness: [{required: true, message: "请选择病种",},],
181
+                ill_date: [{required: true, message: "请选择患病时间",},],
182
+                treat_type: [{required: true, message: "请选择治疗方式",},],
183
+                
184
+            },
185
+            genderOptions:[
186
+                {id:1, name:'男'},
187
+                {id:2, name:'女'},
188
+            ],
189
+            cityOptions:[],
190
+            illnessMap:{},
191
+        }
192
+    },
193
+    methods:{
194
+        open:function(){
195
+            let city = [];
196
+            this.GetDistrictsByUpid();
197
+            if (this.form.province_id>0) {
198
+                city.push(this.form.province_id);
199
+                this.GetDistrictsByUpid(city);
200
+            }
201
+            if (this.form.province_id>0 && this.form.city_id>0) {
202
+                city.push(this.form.city_id);
203
+                this.GetDistrictsByUpid(city);
204
+            }
205
+            this.form.birthday = this.form.birthday?this.form.birthday:'';
206
+            this.form.ill_date = this.form.ill_date?this.form.ill_date:'';
207
+            this.form.treat_type = this.form.treat_type?this.form.treat_type:'';
208
+            this.form.gender = this.form.gender?this.form.gender:'';
209
+            for (const index in this.illnessOptions) {
210
+                this.illnessMap[this.illnessOptions[index].id] = 1;
211
+            }
212
+            var illness = this.form.illness;
213
+            this.form.illness = [];
214
+            for (const index in illness) {
215
+                if (illness[index] in this.illnessMap) {
216
+                    this.form.illness.push(illness[index]);
217
+                }
218
+            }
219
+
220
+            this.editMemberFormVisible = true;
221
+        },
222
+        resetForm(formName) {
223
+            if (typeof(this.$refs[formName]) !='undefined') {
224
+                this.$refs[formName].resetFields();
225
+            }
226
+        },
227
+        submitForm(formName){
228
+            // if (this.levelCards.length>0) {
229
+            //     this.form.card = this.levelCards[0];
230
+            // }
231
+            this.$refs[formName].validate((valid) => {
232
+                if (valid) {
233
+                    EditMember(this.form.id, this.form).then(response=>{
234
+                        var res = response.data;
235
+                        if(res.state === 1) {
236
+                            var member = res.data.member;
237
+                            this.membersData[this.memberIndex].name = member.name;
238
+                            this.membersData[this.memberIndex].avatar = member.avatar;
239
+                            this.membersData[this.memberIndex].mobile = member.mobile;
240
+                            this.membersData[this.memberIndex].gender = member.gender;
241
+                            this.membersData[this.memberIndex].birthday = member.birthday;
242
+                            this.membersData[this.memberIndex].province_id = member.province_id;
243
+                            this.membersData[this.memberIndex].city_id = member.city_id;
244
+                            this.membersData[this.memberIndex].district_id = member.district_id;
245
+                            this.$set(this.membersData[this.memberIndex],'illness', member.illness);
246
+                            this.membersData[this.memberIndex].ill_date = member.ill_date;
247
+                            this.membersData[this.memberIndex].treat_type = member.treat_type;
248
+                            this.membersData[this.memberIndex].remark = member.remark;
249
+                            this.membersData[this.memberIndex].updated_time = member.updated_time;
250
+                            // this.resetForm("memberForm");
251
+                            this.editMemberFormVisible = false;
252
+                            this.$message.success("编辑会员成功");
253
+                        }else {
254
+                            this.$message.error(res.msg);
255
+                        }
256
+                    }).catch(e=>{});
257
+
258
+                } else {
259
+                    return false;
260
+                }
261
+            });
262
+        },
263
+        selectGender:function(gender) {
264
+            if(gender == 2) {
265
+                this.form.avatar = 'https://images.shengws.com/201809182128222.png';
266
+            }else {
267
+                this.form.avatar = 'https://images.shengws.com/201809182128111.png';
268
+            }
269
+        },
270
+        handleChangeCity:function(val) {
271
+            this.GetDistrictsByUpid(val);
272
+        },
273
+        handleSelectedCity:function(val) {
274
+            this.form.province_id = val[0];
275
+            this.form.city_id = val[1];
276
+            this.form.district_id = val[2];
277
+        },
278
+        GetDistrictsByUpid:function(val) {  
279
+            let idArea
280
+            let sizeArea
281
+            if (!val) {
282
+                idArea = 0
283
+                sizeArea = 0
284
+            } else if (val.length === 1) {
285
+                idArea = val[0]
286
+                sizeArea = val.length // 3:一级 4:二级 6:三级
287
+            } else if (val.length === 2) {
288
+                idArea = val[1]
289
+                sizeArea = val.length // 3:一级 4:二级 6:三级
290
+            }
291
+            
292
+            GetDistrictsByUpid({id:idArea}).then(response=>{
293
+                var res = response.data;
294
+                if (res.state===1) {
295
+                    var citys = res.data.citys;
296
+                    if (sizeArea === 0) { // 初始化 加载一级 省
297
+                        this.cityOptions = citys.map((value, i) => {
298
+                            return {
299
+                                id: value.id,
300
+                                name: value.name,
301
+                                cities: []
302
+                            }
303
+                        })
304
+                    } else if (sizeArea === 1) { // 点击一级 加载二级 市
305
+                        this.cityOptions.map((value, i) => {
306
+                            if (value.id === val[0]) {
307
+                                if (!value.cities.length) {
308
+                                    value.cities = citys.map((value, i) => {
309
+                                        return {
310
+                                            id: value.id,
311
+                                            name: value.name,
312
+                                            cities: []
313
+                                        }
314
+                                    })
315
+                                }
316
+                            }
317
+                        })
318
+                    } else if (sizeArea === 2) { // 点击二级 加载三级 区
319
+                        this.cityOptions.map((value, i) => {
320
+                            if (value.id === val[0]) {
321
+                                value.cities.map((value, i) => {
322
+                                    if (value.id === val[1]) {
323
+                                        if (!value.cities.length) {
324
+                                            if (citys.length) {
325
+                                                value.cities = citys.map((value, i) => {
326
+                                                    return {
327
+                                                        id: value.id,
328
+                                                        name: value.name
329
+                                                    }
330
+                                                })
331
+                                            }else {
332
+                                                value.cities = [
333
+                                                    {id:value.id, name:value.name}
334
+                                                ];
335
+                                            }
336
+                                            
337
+                                        }
338
+                                    }
339
+                                })
340
+                            }
341
+                        })
342
+                    }
343
+                }else {
344
+                    this.$message.error(res.msg);
345
+                }
346
+            }).catch(e=>{});
347
+        },
348
+    }
349
+}
350
+</script>
351
+

+ 128 - 0
src/scrm_pages/members/components/EditMemberTagsForm.vue View File

@@ -0,0 +1,128 @@
1
+<template>
2
+    <div id="edit-member-tags-form-box">
3
+        <el-dialog title="编辑标签" :visible.sync="editMemberTagFormVisible" width="800px" >
4
+            <el-form ref="memberTagForm"  :model="form" label-width="90px">
5
+                <el-row>
6
+                    <el-col :span="24">
7
+                        <el-form-item label="标签:"  prop="tags">
8
+                            <el-select
9
+                                v-model="form.tags"
10
+                                multiple
11
+                                style="width:100%"
12
+                                placeholder="请选择标签">
13
+                                <el-option
14
+                                v-for="item in tagOptions"
15
+                                :key="item.id"
16
+                                :label="item.tag_name"
17
+                                :value="item.id">
18
+                                </el-option>
19
+                            </el-select>
20
+                        </el-form-item>
21
+                    </el-col>
22
+                </el-row>
23
+            </el-form>
24
+            <div slot="footer" class="dialog-footer">
25
+                <el-button @click="editMemberTagFormVisible = false">取消</el-button>
26
+                <el-button
27
+                type="primary"
28
+                @click="submitForm('memberTagForm')"
29
+                >保 存
30
+                </el-button>
31
+            </div>
32
+        </el-dialog>  
33
+    </div>
34
+</template>
35
+
36
+<script>
37
+import {GetDistrictsByUpid} from  "@/api/district";
38
+import {checkMobile} from "@/utils/tools";
39
+import {EditMemberTags} from "@/api/member/member";
40
+
41
+export default {
42
+    name:'EditMberTagForm',
43
+    props:{
44
+        tagOptions:{
45
+            type: Array,
46
+            default: function () {
47
+                return [];
48
+            }
49
+        },
50
+        memberIndex:{
51
+            type:Number,
52
+            default:-1,
53
+        },
54
+        form:{
55
+            name:'',
56
+            mobile:'',
57
+            gender:0,
58
+            birthday:'',
59
+            city:[],
60
+            province_id:0,
61
+            city_id:0,
62
+            district_id:0,
63
+            illness:[],
64
+            ill_date:'',
65
+            treat_type:'',
66
+            tags:[],
67
+            remark:'',
68
+            avatar:'',
69
+            id:0,
70
+        },
71
+        membersData:{
72
+            type: Array,
73
+            default: function () {
74
+                return [];
75
+            }
76
+        },
77
+    },
78
+    data(){
79
+        return {
80
+            editMemberTagFormVisible:false,
81
+        }
82
+    },
83
+    methods:{
84
+        open:function(){
85
+            this.editMemberTagFormVisible = true;
86
+        },
87
+        resetForm(formName) {
88
+            if (typeof(this.$refs[formName]) !='undefined') {
89
+                this.$refs[formName].resetFields();
90
+            }
91
+        },
92
+        submitForm(formName){
93
+            this.$refs[formName].validate((valid) => {
94
+                if (valid) {
95
+                    EditMemberTags(this.form.id, {tags:this.form.tags}).then(response=>{
96
+                        var res = response.data;
97
+                        if(res.state === 1) {
98
+                            var tags = res.data.tags;
99
+                            var memberTags = [];
100
+                            if(tags) {
101
+                                var userTagsMap = {};
102
+                                for (const index in tags) {
103
+                                    userTagsMap[tags[index]] = 1;
104
+                                }
105
+                                for (const index in this.tagOptions) {
106
+                                    if(this.tagOptions[index].id in userTagsMap) {
107
+                                        memberTags.push(this.tagOptions[index]);
108
+                                    }
109
+                                }
110
+                            }
111
+                            this.$set(this.membersData[this.memberIndex], 'tags', memberTags);
112
+                            this.resetForm("memberTagForm");
113
+                            this.editMemberTagFormVisible = false;
114
+                            this.$message.success("编辑会员标签成功");
115
+                        }else {
116
+                            this.$message.error(res.msg);
117
+                        }
118
+                    }).catch(e=>{});
119
+
120
+                } else {
121
+                    return false;
122
+                }
123
+            });
124
+        },
125
+    }
126
+}
127
+</script>
128
+

+ 263 - 25
src/scrm_pages/members/members.vue View File

@@ -2,7 +2,7 @@
2 2
   <div class="main-contain">
3 3
     <div class="position">
4 4
       <bread-crumb :crumbs='crumbs'></bread-crumb>
5
-      <el-button  style="float:right;" type="primary" size="small" icon="el-icon-circle-plus-outline">添加会员</el-button>
5
+      <el-button  style="float:right;" type="primary" size="small" icon="el-icon-circle-plus-outline" @click="openCreate">添加会员</el-button>
6 6
     </div>
7 7
     <div class="app-container">
8 8
           <div style="margin-bottom: 10px">
@@ -49,51 +49,62 @@
49 49
              </div>
50 50
           </div>
51 51
           <div class="filter-container" style="margin-top: 10px;margin-left: 5px">
52
-            <el-checkbox style="width: 30px"  >全选</el-checkbox>
53
-            <el-button size="small" icon="el-icon-delete" >删除</el-button>
54
-            <el-button size="small" icon="el-icon-delete" >删除</el-button>
52
+            <el-checkbox style="width: 30px"  @change="changeCheck" v-model="checkAllStatus">全选</el-checkbox>
53
+            <el-button size="small" icon="el-icon-delete" @click="openDeleteMembers">批量删除</el-button>
54
+            <el-button size="small" icon="el-icon-edit" @click="openAddMembersTags">添加标签</el-button>
55
+            <el-button size="small" icon="el-icon-message" @click="openSendMessage">发送短信</el-button>
55 56
           </div>
56
-          <el-table ref="multipleTable" :cell-class-name="cellStyleName" :header-cell-style="{ backgroundColor: 'rgb(245, 247, 250)'}" :data="membersData" border fit highlight-current-row  style="width: 100%;margin-top: 10px;">
57
+          <el-table ref="multipleTable"  @selection-change="handleSelectionChange" :cell-class-name="cellStyleName" :header-cell-style="{ backgroundColor: 'rgb(245, 247, 250)'}" :data="membersData" border fit highlight-current-row  style="width: 100%;margin-top: 10px;">
57 58
              <el-table-column
58 59
                 align="center"
59 60
                 type="selection"
60 61
                 width="55">
61 62
              </el-table-column>
62
-             <el-table-column label="会员" align="center">
63
+             <el-table-column label="会员" align="center" >
63 64
                <template slot-scope="scope">
64
-                   <img :src="memberAvatar(scope.row)" alt="" srcset="" style="width:50px;height:50px; border-radius:50%" >
65
-                   <span>{{scope.row.name}}</span>
65
+                 <div style="display:flex;align-items: center;">
66
+                   <img :src="memberAvatar(scope.row)" alt="" srcset="" style="width:50px;height:50px; border-radius:50%;margin-right:5px;" >
67
+                    <div>
68
+                     <span>{{scope.row.name}}</span>
69
+                    </div>
70
+                 </div>
66 71
                </template>
67 72
              </el-table-column>
68
-            <el-table-column label="文章标题" align="center">
73
+            <el-table-column label="等级" align="center">
69 74
               <template slot-scope="scope">
70
-
75
+                <img v-if="scope.row.user_card && scope.row.user_card.card" :src="vip" alt="" srcset="" style="width:16px;height:16px;margin-bottom: -2px;" >
76
+                <span>{{memberLevel(scope.row)}}</span>
71 77
               </template>
72 78
             </el-table-column>
73
-            <el-table-column label="阅读量" align="center">
79
+            <el-table-column label="标签" align="center">
74 80
               <template slot-scope="scope">
81
+                <el-tag size="small"  v-for="(tag, index) in scope.row.tags" :key="index">{{tag.tag_name}}</el-tag>
75 82
 
76 83
               </template>
77 84
             </el-table-column>
78
-            <el-table-column label="评论数" align="center">
85
+            <el-table-column label="创建时间" align="center">
79 86
               <template slot-scope="scope">
80
-
87
+                <span>{{memberCreateTime(scope.row.created_time)}}</span>
81 88
               </template>
82 89
             </el-table-column>
83
-            <el-table-column label="点赞数" align="center">
90
+            <el-table-column label="来源方式" align="center">
84 91
               <template slot-scope="scope">
85
-
92
+                <span>{{memberSource(scope.row.sources)}}</span>
86 93
               </template>
87 94
             </el-table-column>
88 95
             <el-table-column label="操作" align="center">
89 96
               <template slot-scope="scope">
90 97
                 <el-tooltip class="item" effect="dark" content="编辑" placement="top">
91
-                  <el-button
92
-                    size="mini"
93
-                    type="primary"
94
-                    icon="el-icon-edit-outline"
95
-                    >
96
-                  </el-button>
98
+                  <el-button size="mini" type="primary" icon="el-icon-edit-outline" @click="openEdit(scope.row, scope.$index)" ></el-button>
99
+                </el-tooltip>
100
+                <el-tooltip class="item" effect="dark" content="标签" placement="top">
101
+                  <el-button size="mini" type="warning" icon="el-icon-edit" @click="openTags(scope.row, scope.$index)" ></el-button>
102
+                </el-tooltip>
103
+                <el-tooltip class="item" effect="dark" content="会员卡" placement="top">
104
+                  <el-button size="mini" type="success" icon="el-icon-tickets" @click="openCard(scope.row, scope.$index)" ></el-button>
105
+                </el-tooltip>
106
+                <el-tooltip class="item" effect="dark" content="删除" placement="top">
107
+                  <el-button size="mini" type="danger" icon="el-icon-delete" @click="openDelete(scope.row, scope.$index)" ></el-button>
97 108
                 </el-tooltip>
98 109
               </template>
99 110
             </el-table-column>
@@ -104,21 +115,44 @@
104 115
             :page-sizes="[10,20,50,100]"
105 116
             :page-size="10"
106 117
             background
107
-            style="margin-top:20px;float: right"
118
+            style="margin-top:20px;"
119
+            align="right"
108 120
             layout="total, sizes, prev, pager, next, jumper"
109 121
             :total="total">
110 122
           </el-pagination>
123
+
124
+          <!--create-member-form 添加会员-->
125
+          <create-member-form ref="createMemberForm" :levelCards="levelCards" :membersData="membersData" :illnessOptions="illnessOptions" :treatTypeOptions="treatTypeOptions" :tagOptions="tagOptions"></create-member-form>
126
+          <!--edit-member-form 编辑会员-->
127
+          <edit-member-form ref="editMemberForm" :levelCards="levelCards" :memberIndex="memberIndex" :form="memberData" :membersData="membersData" :illnessOptions="illnessOptions" :treatTypeOptions="treatTypeOptions" :tagOptions="tagOptions"></edit-member-form>
128
+          <!--edit-member-tags-form 为单个会员编辑标签-->
129
+          <edit-member-tags-form ref="editMemberTagsForm" :memberIndex="memberIndex" :form="memberData" :membersData="membersData" :tagOptions="tagOptions"></edit-member-tags-form>
130
+          <!--add-members-tags-form 为所选会员添加标签-->
131
+          <add-members-tags-form ref="addMembersTagsForm" :form="memberData" :membersData="membersData" :tagOptions="tagOptions"></add-members-tags-form>
132
+          <!--edit-member-card-form 为单个会员设置会员卡-->
133
+          <edit-member-card-form ref="editMemberCardForm" :form="cardFormData" :memberIndex="memberIndex" :membersData="membersData" :cardOptions="levelCards"></edit-member-card-form>
111 134
     </div>
112 135
   </div>
113 136
 </template>
114 137
 
115 138
 <script>
116
-  import {GetMembers} from "@/api/member/member";
139
+  import {GetMembers,DeleteMembers} from "@/api/member/member";
117 140
   import BreadCrumb from '../components/bread-crumb'
141
+  import {uParseTime} from "@/utils/tools";
142
+  import CreateMemberForm from "./components/CreateMemberForm";
143
+  import EditMemberForm from "./components/EditMemberForm";
144
+  import EditMemberTagsForm from "./components/EditMemberTagsForm";
145
+  import AddMembersTagsForm from "./components/AddMembersTagsForm";
146
+  import EditMemberCardForm from "./components/EditMemberCardForm";
118 147
   export default {
119 148
     name: 'commentList',
120 149
     components:{
121
-      BreadCrumb
150
+      BreadCrumb,
151
+      CreateMemberForm,
152
+      EditMemberForm,
153
+      EditMemberTagsForm,
154
+      AddMembersTagsForm,
155
+      EditMemberCardForm,
122 156
     },
123 157
     data(){
124 158
       return{
@@ -127,14 +161,42 @@
127 161
           { path: false, name: '会员列表' }
128 162
         ],
129 163
         time: '',
164
+        vip:'https://images.shengws.com/member-ship-card-vip.png',
165
+        checkAllStatus:false,
130 166
         active: true,
131 167
         levelType: 0,
132 168
         levelCards:[],
133 169
         sourceType: 0,
134 170
         sourceOptions:{},
171
+        treatTypeOptions:{},
135 172
         tagType: 0,
136 173
         tagOptions:[],
137 174
         membersData:[],
175
+        illnessOptions:[],
176
+        memberData:{
177
+            name:'',
178
+            mobile:'',
179
+            gender:0,
180
+            birthday:'',
181
+            city:[],
182
+            province_id:0,
183
+            city_id:0,
184
+            district_id:0,
185
+            illness:[],
186
+            ill_date:'',
187
+            treat_type:'',
188
+            tags:[],
189
+            remark:'',
190
+            avatar:'',
191
+            id:0,
192
+            ids:[],
193
+        },
194
+        cardFormData:{
195
+            id:0,
196
+            card_id:''
197
+        },
198
+        selectedMembers:[],
199
+        memberIndex:-1,
138 200
         total:0,
139 201
         listQuery:{
140 202
             page:1,
@@ -163,12 +225,158 @@
163 225
                     if(typeof(res.data.tags) != 'undefined') {
164 226
                         this.tagOptions = res.data.tags;
165 227
                     }
228
+                    if(typeof(res.data.illness) != 'undefined') {
229
+                        this.illnessOptions = res.data.illness;
230
+                    }
166 231
                     this.listQuery.init = 0;
167 232
                 }else {
168 233
                     this.$message.error(res.msg);
169 234
                 }
170 235
             }).catch(e=>{});
171 236
         },
237
+        openSendMessage(){
238
+          
239
+          this.$message.error("功能开发中...");
240
+          return false;
241
+          if (this.selectedMembers.length==0) {
242
+            this.$message.error("请选择要发送短信的会员");
243
+            return false;
244
+          }
245
+          
246
+        },
247
+        openAddMembersTags() {
248
+          if (this.selectedMembers.length==0) {
249
+            this.$message.error("请选择要添加标签的会员");
250
+            return false;
251
+          }
252
+          
253
+          this.memberData.tags = [];
254
+          this.memberData.ids = [];
255
+          for (const index in this.selectedMembers) {
256
+            this.memberData.ids.push(this.selectedMembers[index].id);
257
+          }
258
+          this.$refs.addMembersTagsForm.open();
259
+        },
260
+        openDeleteMembers(){
261
+          if (this.selectedMembers.length==0) {
262
+            this.$message.error("请选择要删除的会员");
263
+            return false;
264
+          }
265
+
266
+          this.$confirm('确认要删除所选的会员吗?<br>删除后,会员信息将无法恢复', '删除提示', {
267
+            dangerouslyUseHTMLString:true,
268
+            confirmButtonText: '确定',
269
+            cancelButtonText: '取消',
270
+            type: 'warning'
271
+          }).then(() => {
272
+            var ids = [];
273
+            var idMap = {};
274
+            for (const index in this.selectedMembers) {
275
+              ids.push(this.selectedMembers[index].id);
276
+              idMap[this.selectedMembers[index].id] = this.selectedMembers[index].id;
277
+            }
278
+            DeleteMembers({ids:ids}).then(response=>{
279
+              var res = response.data;
280
+              if (res.state === 1) {
281
+                var membersDataLength = this.membersData.length;
282
+                for (let index = membersDataLength-1; index >= 0; index--) {
283
+                  if(this.membersData[index].id in idMap) {
284
+                    this.membersData.splice(index, 1);
285
+                  }                  
286
+                }
287
+                this.$message.success("删除会员成功");
288
+              }else {
289
+                this.$message.error(res.msg);
290
+              }
291
+            }).catch(e=>{});
292
+          }).catch(() => {
293
+            return false        
294
+          });
295
+
296
+        },
297
+        openDelete(row, index) {
298
+          this.$confirm('确认要删除该会员吗?<br>删除后,该会员信息将无法恢复', '删除提示', {
299
+            dangerouslyUseHTMLString:true,
300
+            confirmButtonText: '确定',
301
+            cancelButtonText: '取消',
302
+            type: 'warning'
303
+          }).then(() => {
304
+            var ids = [];
305
+            ids.push(row.id);
306
+            DeleteMembers({ids:ids}).then(response=>{
307
+              var res = response.data;
308
+              if (res.state === 1) {
309
+                this.membersData.splice(index, 1);
310
+                this.$message.success("删除会员成功");
311
+              }else {
312
+                this.$message.error(res.msg);
313
+              }
314
+            }).catch(e=>{});
315
+          }).catch(() => {
316
+            return false        
317
+          });
318
+        },
319
+        openCard(row, index){
320
+          this.cardFormData.id = row.id;
321
+          this.cardFormData.card_id = '';
322
+          this.memberIndex = index;
323
+          if (row.user_card && row.user_card.card) {
324
+            this.cardFormData.card_id = row.user_card.card_id;
325
+          }
326
+          this.$refs.editMemberCardForm.open();
327
+        },
328
+        openTags(row, index) {
329
+          this.memberData.tags = [];
330
+          this.memberData.id = row.id;
331
+          let tags = row.tags;
332
+          for (const index in tags) {
333
+              this.memberData.tags.push(tags[index].id);
334
+          }
335
+          
336
+          this.memberIndex = index;
337
+          this.$refs.editMemberTagsForm.open();
338
+        },
339
+        openEdit(row, index){
340
+          this.memberData.illness = [];
341
+          this.memberData.city = [];
342
+          this.memberData.birthday = '';
343
+          this.memberData.ill_date = '';
344
+          this.memberData.treat_type = '';
345
+          for (const key in this.memberData) {
346
+              if (key === "illness" && row.illness) {
347
+                  let illness = row.illness;
348
+                  for (const index in illness) {
349
+                      this.memberData.illness.push(illness[index].illness_id);
350
+                  }
351
+              } else if (key === "tags" && row.tags) {
352
+                  let tags = row.tags;
353
+                  for (const index in tags) {
354
+                      this.memberData.tags.push(tags[index].id);
355
+                  }
356
+              } else if (key === "treat_type" && row.treat_type>0) {
357
+                  this.memberData.treat_type = row.treat_type;
358
+              } else if (key === "city") {
359
+                if (row.province_id > 0) {
360
+                  this.memberData.city.push(row.province_id);
361
+                  this.memberData.city.push(row.city_id);
362
+                  this.memberData.city.push(row.district_id);
363
+                }
364
+              } else if (key === "birthday" && row.birthday!=0) {
365
+                  this.memberData.birthday = uParseTime(row.birthday, "{y}-{m}-{d}");
366
+              } else if (key === "ill_date" && row.ill_date!=0) {
367
+                  this.memberData.ill_date = uParseTime(row.ill_date, "{y}-{m}-{d}");
368
+              } else if (key in row) {
369
+                  this.memberData[key] = row[key];                  
370
+              }
371
+          }
372
+          
373
+          // this.memberData = row;
374
+          this.memberIndex = index;
375
+          this.$refs.editMemberForm.open();
376
+        },
377
+        openCreate(){
378
+          this.$refs.createMemberForm.open();
379
+        },
172 380
         memberAvatar(row) {
173 381
             if(typeof(row.avatar) == "undefined" || !row.avatar || row.avatar.length==0) {
174 382
                 if(row.gender == 2) {
@@ -180,6 +388,32 @@
180 388
                 return row.avatar
181 389
             }
182 390
         },
391
+        memberLevel(row) {
392
+          if(row.user_card && row.user_card.card) {
393
+            return row.user_card.card.card_name;
394
+          } else {
395
+            return '普通会员'
396
+          }
397
+        },
398
+        memberCreateTime(time) {
399
+          return uParseTime(time, "{y}-{m}-{d} {h}:{i}:{s}");
400
+        },
401
+        memberSource(source) {
402
+          if (source in this.sourceOptions) {
403
+            return this.sourceOptions[source].name;
404
+          }else {
405
+            return '--';
406
+          }
407
+        },
408
+        changeCheck(){
409
+          this.$refs.multipleTable.clearSelection();
410
+          if (this.checkAllStatus) {
411
+            this.$refs.multipleTable.toggleAllSelection();
412
+          }
413
+        },
414
+        handleSelectionChange(val){
415
+          this.selectedMembers = val;
416
+        },
183 417
         cellStyleName({row, column, rowIndex, columnIndex}){
184 418
             if (columnIndex===1) {
185 419
                 return 'member-name-box';
@@ -217,13 +451,17 @@
217 451
         }
218 452
     },
219 453
     created(){
220
-        this.sourceOptions = this.$store.getters.sources;
454
+        this.sourceOptions = this.$store.getters.members.sources;
455
+        this.treatTypeOptions = this.$store.getters.members.treat_type;
221 456
         this.GetMembers();
222 457
     }
223 458
   }
224 459
 </script>
225 460
 
226 461
 <style scoped>
462
+  .el-tag {
463
+    margin: 1px;
464
+  }
227 465
   /*.app-container .cell.clearfix .time ul li {*/
228 466
     /*float: left;*/
229 467
     /*list-style: none;*/

+ 126 - 0
src/scrm_pages/members/tags.vue View File

@@ -0,0 +1,126 @@
1
+<template>
2
+  <div class="main-contain">
3
+    <div class="position">
4
+      <bread-crumb :crumbs='crumbs'></bread-crumb>
5
+      <el-button  style="float:right;" type="primary" size="small" icon="el-icon-circle-plus-outline" @click="openCreate">添加标签</el-button>
6
+    </div>
7
+    <div class="app-container">
8
+        <div style="margin-bottom: 10px">
9
+            <el-row :gutter="24">
10
+                <el-col :span="8">
11
+                    <el-input style="width: 300px" v-model="listQuery.search" placeholder="请输入您需要搜索的内容"></el-input>
12
+                    <el-button type="primary"  icon="el-icon-search" @click="changeKey">搜索</el-button>
13
+                </el-col>
14
+            </el-row>
15
+        </div>
16
+        <div class="filter-container" style="margin-top: 10px;margin-left: 5px">
17
+            <el-checkbox style="width: 30px" @change="changeCheck" v-model="checkAllStatus">全选</el-checkbox>
18
+            <el-button size="small" icon="el-icon-delete" >批量删除</el-button>
19
+        </div>
20
+        <el-table ref="multipleTable"  @selection-change="handleSelectionChange"  :header-cell-style="{ backgroundColor: 'rgb(245, 247, 250)'}" :data="tagsData" border fit highlight-current-row  style="width: 100%;margin-top: 10px;">
21
+            <el-table-column
22
+                align="center"
23
+                type="selection"
24
+                width="55">
25
+             </el-table-column>
26
+            <el-table-column label="标签" align="center">
27
+                <template slot-scope="scope">
28
+                    {{scope.row.tag_name}}
29
+                </template>
30
+            </el-table-column>
31
+            <el-table-column label="会员数" align="center">
32
+                <template slot-scope="scope">
33
+                <span>{{scope.row.created_time}}</span>
34
+                </template>
35
+            </el-table-column>
36
+            <el-table-column label="操作" align="center">
37
+                <template slot-scope="scope">
38
+                    <el-tooltip class="item" effect="dark" content="编辑" placement="top">
39
+                        <el-button size="mini" type="primary" icon="el-icon-edit-outline" @click="openEdit(scope.row, scope.$index)" ></el-button>
40
+                    </el-tooltip>
41
+                    <el-tooltip class="item" effect="dark" content="删除" placement="top">
42
+                        <el-button size="mini" type="danger" icon="el-icon-delete" @click="openDelete(scope.row, scope.$index)" ></el-button>
43
+                    </el-tooltip>
44
+                </template>
45
+            </el-table-column>
46
+        </el-table>
47
+    </div>
48
+  </div>
49
+</template>
50
+
51
+<script>
52
+  import {GetTags} from "@/api/member/member";
53
+  import BreadCrumb from '../components/bread-crumb';
54
+  
55
+  export default {
56
+    name: 'memberTagList',
57
+    components:{
58
+      BreadCrumb,
59
+    },
60
+    data(){
61
+      return{
62
+        crumbs: [
63
+          { path: false, name: '会员管理' },
64
+          { path: false, name: '标签列表' }
65
+        ],
66
+        total:0,
67
+        listQuery:{
68
+            page:1,
69
+            limit:10,
70
+            search:'',
71
+        },
72
+        checkAllStatus:false,
73
+       
74
+        tagsData:[],
75
+      }
76
+    },
77
+    methods:{
78
+        openCreate:function(){
79
+            this.tagsData.push({id:1,tag_name:'2'});
80
+        },
81
+        openEdit:function(row,index){},
82
+        openDelete:function(row,index){},
83
+        changeCheck:function(){
84
+
85
+        },
86
+        handleSelectionChange:function (val) {
87
+            
88
+        },
89
+        changeKey(){
90
+            this.GetTags();
91
+        },
92
+        GetTags(){
93
+            GetTags().then(response=>{
94
+                var res = response.data;
95
+                if(res.state===1) {
96
+                    this.tagsData = res.data.tags;
97
+                }
98
+            }).catch(e=>{})
99
+        }
100
+    },
101
+    computed:{
102
+        activeTagsData:function(){
103
+        var tags = [];
104
+        
105
+        return tags;
106
+        }
107
+    },
108
+    created(){
109
+        this.GetTags();
110
+    }
111
+  }
112
+</script>
113
+
114
+<style scoped>
115
+  /*.app-container .cell.clearfix .time ul li {*/
116
+    /*float: left;*/
117
+    /*list-style: none;*/
118
+    /*cursor: pointer;*/
119
+    /*padding: 6px 20px;*/
120
+    /*color: #606266;*/
121
+    /*border-radius: 4px;*/
122
+    /*margin: 0 8px 0 0;*/
123
+    /*font-size: 14px;*/
124
+    /*text-align: center;*/
125
+  /*}*/
126
+</style>

+ 3 - 2
src/store/getters.js View File

@@ -8,8 +8,9 @@ const getters = {
8 8
   addRouters: state => state.xt_permission.addRouters,
9 9
   errorLogs: state => state.errorLog.logs,
10 10
 
11
-  
12
-  sources: state => state.members.sources,
11
+  members: state => state.members,
12
+  // sources: state => state.members.sources,
13
+  // treat_type: state => state.members.treat_type,
13 14
 
14 15
   xt_permission: state => state.xt_permission,
15 16
   xt_user: state => state.xt_user,

+ 8 - 0
src/store/modules/members.js View File

@@ -12,6 +12,14 @@ const members = {
12 12
             10:{id:10, name:"圣卫士"},
13 13
             11:{id:11, name:"血透"},
14 14
         },
15
+        treat_type:{
16
+            1:{id:1, name:'西医治疗'},
17
+            2:{id:2, name:'中医治疗'},
18
+            3:{id:3, name:'血液透析'},
19
+            4:{id:4, name:'腹膜透析'},
20
+            5:{id:5, name:'肾移植'},
21
+            6:{id:6, name:'其他'},
22
+        },
15 23
     },
16 24
     mutations: {
17 25
       

+ 8 - 1
src/utils/tools.js View File

@@ -168,4 +168,11 @@ export function uParseTime(time, cFormat) {
168 168
           return 0
169 169
       }
170 170
       return (shouji + (shichang-t) * weichi).toFixed(1);
171
-  }
171
+  }
172
+
173
+  export function checkMobile(mobile){ 
174
+    if(!(/^1[2-9][0-9]\d{8}$/.test(mobile))){ 
175
+        return false; 
176
+    } 
177
+    return true;
178
+  } 

+ 8 - 8
src/xt_permission.js View File

@@ -10,14 +10,14 @@ const permissionWhiteList = loginWhiteList.concat(['/']) // 权限验证白名
10 10
 
11 11
 router.beforeEach((to, from, next) => {
12 12
   // 线上注释
13
-  if (store.getters.permission_routers === undefined) {
14
-    store.dispatch('xt_GenerateRoutes', []).then(() => {
15
-      next()
16
-    })
17
-  } else {
18
-    next()
19
-  }
20
-  return
13
+  // if (store.getters.permission_routers === undefined) {
14
+  //   store.dispatch('xt_GenerateRoutes', []).then(() => {
15
+  //     next()
16
+  //   })
17
+  // } else {
18
+  //   next()
19
+  // }
20
+  // return
21 21
   // 线上注释
22 22
 
23 23
   NProgress.start()