YY 2 tahun lalu
induk
melakukan
71bac7c36f

+ 5 - 0
src/components/orderParts/card/parts/detail-1.vue

@@ -23,6 +23,7 @@
             :total="total"
             @detail="toDetail"
             @sales="toSales"
+            @message="toMessage"
           >
             <template #is_afterSale="{ row }">
               <span :style="{ color: row.is_afterSale === true ? 'red' : '' }"> {{ row.is_afterSale === true ? '该订单有商品申请售后' : '未申请售后' }}</span>
@@ -54,6 +55,7 @@ export default {
       opera: [
         { label: '详情', method: 'detail' },
         { label: '售后', method: 'sales', type: 'danger' },
+        { label: '联系', method: 'message', type: 'warning' },
       ],
       fields: [
         { label: '订单号', model: 'no', showTip: false },
@@ -119,6 +121,9 @@ export default {
     toSales({ data }) {
       this.$emit('toSaless', { id: data._id, status: '1' });
     },
+    toMessage({ data }) {
+      this.$router.push({ path: `/selfShop/message`, query: { customer_id: data.customer._id, address_id: data.address._id } });
+    },
     toClose() {
       this.searchForm = {};
       this.search();

+ 42 - 36
src/router/module/selfShop.js

@@ -1,56 +1,62 @@
 export default [
   {
-    path: "/selfShop/info",
-    name: "selfShop_info",
-    meta: { title: "自营店铺-信息" },
-    component: () => import("@/views/selfShop/info/index.vue"),
+    path: '/selfShop/info',
+    name: 'selfShop_info',
+    meta: { title: '自营店铺-信息' },
+    component: () => import('@/views/selfShop/info/index.vue'),
   },
   {
-    path: "/selfShop/goods",
-    name: "selfShop_goods",
-    meta: { title: "自营店铺-商品管理" },
-    component: () => import("@/views/selfShop/goods/index.vue"),
+    path: '/selfShop/goods',
+    name: 'selfShop_goods',
+    meta: { title: '自营店铺-商品管理' },
+    component: () => import('@/views/selfShop/goods/index.vue'),
   },
   {
-    path: "/selfShop/spec/:id",
-    name: "selfShop_spec",
-    meta: { title: "自营店铺-商品管理-库存管理" },
-    component: () => import("@/views/selfShop/goods/spec.vue"),
+    path: '/selfShop/spec/:id',
+    name: 'selfShop_spec',
+    meta: { title: '自营店铺-商品管理-库存管理' },
+    component: () => import('@/views/selfShop/goods/spec.vue'),
   },
   {
-    path: "/selfShop/goodsSet",
-    name: "selfShop_goodsSet",
-    meta: { title: "自营店铺-套装管理" },
-    component: () => import("@/views/selfShop/goodsSet/index.vue"),
+    path: '/selfShop/goodsSet',
+    name: 'selfShop_goodsSet',
+    meta: { title: '自营店铺-套装管理' },
+    component: () => import('@/views/selfShop/goodsSet/index.vue'),
   },
   {
-    path: "/selfShop/order",
-    name: "selfShop_order",
-    meta: { title: "自营店铺-订单管理" },
-    component: () => import("@/views/selfShop/order/index.vue"),
+    path: '/selfShop/order',
+    name: 'selfShop_order',
+    meta: { title: '自营店铺-订单管理' },
+    component: () => import('@/views/selfShop/order/index.vue'),
   },
   {
-    path: "/selfShop/sales",
-    name: "selfShop_sales",
-    meta: { title: "自营店铺-售后管理" },
-    component: () => import("@/views/selfShop/sales/index.vue"),
+    path: '/selfShop/sales',
+    name: 'selfShop_sales',
+    meta: { title: '自营店铺-售后管理' },
+    component: () => import('@/views/selfShop/sales/index.vue'),
   },
   {
-    path: "/selfShop/goodsRate",
-    name: "selfShop_goodsRate",
-    meta: { title: "自营店铺-商品评价" },
-    component: () => import("@/views/selfShop/goodsRate/index.vue"),
+    path: '/selfShop/goodsRate',
+    name: 'selfShop_goodsRate',
+    meta: { title: '自营店铺-商品评价' },
+    component: () => import('@/views/selfShop/goodsRate/index.vue'),
   },
   {
-    path: "/selfShop/bill",
-    name: "selfShop_bill",
-    meta: { title: "自营店铺-账单管理" },
-    component: () => import("@/views/selfShop/bill/index.vue"),
+    path: '/selfShop/bill',
+    name: 'selfShop_bill',
+    meta: { title: '自营店铺-账单管理' },
+    component: () => import('@/views/selfShop/bill/index.vue'),
   },
   {
-    path: "/selfShop/notice",
-    name: "selfShop_notice",
-    meta: { title: "自营店铺-消息管理" },
-    component: () => import("@/views/selfShop/notice/index.vue"),
+    path: '/selfShop/message',
+    name: 'selfShop_message',
+    meta: { title: '自营店铺-消息管理' },
+    component: () => import('@/views/selfShop/message/index.vue'),
+  },
+  {
+    path: '/selfShop/notice',
+    name: 'selfShop_notice',
+    meta: { title: '自营店铺-系统通知' },
+    component: () => import('@/views/selfShop/notice/index.vue'),
   },
 ];

+ 10 - 0
src/store/index.js

@@ -8,6 +8,7 @@ import users from './module/user/users';
 // 系统消息
 import notice from './module/user/notice';
 import msgList from './module/user/msgList';
+import address from './module/user/address';
 
 import todo from './module/statistics/todo';
 import sellTotal from './module/statistics/sellTotal';
@@ -72,6 +73,12 @@ import group from './module/group/group';
 import groupTransport from './module/group/groupTransport';
 import salesTransport from './module/group/salesTransport';
 
+// 聊天
+// 聊天记录
+import chatRecord from './module/message/chatRecord';
+// 房间表
+import room from './module/message/room';
+
 Vue.use(Vuex);
 
 export default new Vuex.Store({
@@ -82,6 +89,7 @@ export default new Vuex.Store({
     users,
     admin,
     shop,
+    address,
     goods,
     dictIndex,
     dictData,
@@ -124,5 +132,7 @@ export default new Vuex.Store({
     getBill,
     shopNotice,
     goodsSet,
+    chatRecord,
+    room,
   },
 });

+ 44 - 0
src/store/module/message/chatRecord.js

@@ -0,0 +1,44 @@
+import Vue from 'vue';
+import Vuex from 'vuex';
+const _ = require('lodash');
+Vue.use(Vuex);
+const api = {
+  url: '/point/v1/api/chatRecord',
+};
+
+const state = () => ({});
+const mutations = {};
+
+const actions = {
+  async query({ commit }, { skip = 0, limit, ...info } = {}) {
+    const res = await this.$axios.$get(`${api.url}`, {
+      skip,
+      limit,
+      ...info,
+    });
+    return res;
+  },
+  async create({ commit }, payload) {
+    const res = await this.$axios.$post(`${api.url}`, payload);
+    return res;
+  },
+  async fetch({ commit }, payload) {
+    const res = await this.$axios.$get(`${api.url}/${payload}`);
+    return res;
+  },
+  async update({ commit }, payload) {
+    const id = _.get(payload, 'id', _.get(payload, '_id'));
+    const res = await this.$axios.$post(`${api.url}/${id}`, payload);
+    return res;
+  },
+  async delete({ commit }, payload) {
+    const res = await this.$axios.$delete(`${api.url}/${payload}`);
+    return res;
+  },
+};
+export default {
+  namespaced: true,
+  state,
+  mutations,
+  actions,
+};

+ 44 - 0
src/store/module/message/room.js

@@ -0,0 +1,44 @@
+import Vue from 'vue';
+import Vuex from 'vuex';
+const _ = require('lodash');
+Vue.use(Vuex);
+const api = {
+  url: '/point/v1/api/room',
+};
+
+const state = () => ({});
+const mutations = {};
+
+const actions = {
+  async query({ commit }, { skip = 0, limit, ...info } = {}) {
+    const res = await this.$axios.$get(`${api.url}`, {
+      skip,
+      limit,
+      ...info,
+    });
+    return res;
+  },
+  async create({ commit }, payload) {
+    const res = await this.$axios.$post(`${api.url}`, payload);
+    return res;
+  },
+  async fetch({ commit }, payload) {
+    const res = await this.$axios.$get(`${api.url}/${payload}`);
+    return res;
+  },
+  async update({ commit }, payload) {
+    const id = _.get(payload, 'id', _.get(payload, '_id'));
+    const res = await this.$axios.$post(`${api.url}/${id}`, payload);
+    return res;
+  },
+  async delete({ commit }, payload) {
+    const res = await this.$axios.$delete(`${api.url}/${payload}`);
+    return res;
+  },
+};
+export default {
+  namespaced: true,
+  state,
+  mutations,
+  actions,
+};

+ 44 - 0
src/store/module/user/address.js

@@ -0,0 +1,44 @@
+import Vue from 'vue';
+import Vuex from 'vuex';
+const _ = require('lodash');
+Vue.use(Vuex);
+const api = {
+  url: '/point/v1/api/address',
+};
+
+const state = () => ({});
+const mutations = {};
+
+const actions = {
+  async query({ commit }, { skip = 0, limit, ...info } = {}) {
+    const res = await this.$axios.$get(`${api.url}`, {
+      skip,
+      limit,
+      ...info,
+    });
+    return res;
+  },
+  async create({ commit }, payload) {
+    const res = await this.$axios.$post(`${api.url}`, payload);
+    return res;
+  },
+  async fetch({ commit }, payload) {
+    const res = await this.$axios.$get(`${api.url}/${payload}`);
+    return res;
+  },
+  async update({ commit }, payload) {
+    const id = _.get(payload, 'id', _.get(payload, '_id'));
+    const res = await this.$axios.$post(`${api.url}/${id}`, payload);
+    return res;
+  },
+  async delete({ commit }, payload) {
+    const res = await this.$axios.$delete(`${api.url}/${payload}`);
+    return res;
+  },
+};
+export default {
+  namespaced: true,
+  state,
+  mutations,
+  actions,
+};

File diff ditekan karena terlalu besar
+ 397 - 0
src/views/selfShop/message/index.vue


+ 104 - 0
src/views/selfShop/message/parts/left-1.vue

@@ -0,0 +1,104 @@
+<template>
+  <div id="left-1">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="left_one">
+          <el-input placeholder="请输入名称" v-model="searchName" size="medium">
+            <el-button slot="append" icon="el-icon-search" @click="toSearch()"></el-button>
+          </el-input>
+        </el-col>
+        <el-col :span="24" class="left_two">
+          <el-col :span="24" v-for="item in list" :key="item._id" @click.native="toView(item)">
+            <el-col :span="24" class="left_two_1">
+              <el-col :span="4" class="left_image">
+                <el-image :src="item.speaker.icon[0].url" class="left_icon"> </el-image>
+              </el-col>
+              <el-col :span="20">
+                <el-col :span="24" class="left_time">
+                  <el-col :span="12" style="text-align: left">{{ item.speaker.name }}</el-col>
+                  <el-col :span="12" style="text-align: right">{{ item.time }}</el-col>
+                </el-col>
+                <el-col :span="20" class="left_content">
+                  <p class="left_content_test">{{ item.content }}</p>
+                </el-col>
+                <el-col :span="4" class="left_badge"> <el-badge :value="200" :max="99" class="left_item"> </el-badge></el-col>
+              </el-col>
+            </el-col>
+          </el-col>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'left-1',
+  props: {
+    list: { type: Array },
+    searchName: { type: String },
+  },
+  components: {},
+  data: function () {
+    return {};
+  },
+  created() {},
+  methods: {
+    toSearch() {
+      this.$emit('toSearch');
+    },
+    toView(data) {
+      this.$emit('toView', data);
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.left_one {
+  margin: 5px 0;
+}
+.left_two {
+  overflow-y: auto;
+  height: 75vh;
+  .left_two_1 {
+    border-bottom: 1px solid #ccc;
+    padding: 7px 0 5px 0;
+    .left_image {
+      width: 70px;
+      .left_icon {
+        border-radius: 5px;
+        width: 60px;
+        height: 60px;
+      }
+    }
+    .left_content_test {
+      margin: 4px 0;
+      overflow: hidden;
+      text-overflow: ellipsis;
+      display: -webkit-box;
+      -webkit-line-clamp: 1;
+      -webkit-box-orient: vertical;
+      color: #666;
+    }
+
+    .left_badge {
+      text-align: right;
+    }
+  }
+}
+</style>

+ 177 - 0
src/views/selfShop/message/parts/right-1.vue

@@ -0,0 +1,177 @@
+<template>
+  <div id="right-1">
+    <el-row>
+      <el-col :span="24" class="main">
+        <el-col :span="24" class="right_one">
+          <p class="right_one_name">{{ customer.name }}</p>
+          <p class="right_one_address">
+            {{ address.name }},{{ address.phone }},{{ address.province }},{{ address.city }},{{ address.area }},{{ address.address }}
+          </p>
+        </el-col>
+        <el-col :span="24" class="right_two">
+          <el-col :span="24" v-for="item in list" :key="item._id">
+            <el-col :span="24" class="right_time">{{ item.time }}</el-col>
+            <el-col :span="24" class="right_left" v-if="item.speaker._id != user._id">
+              <el-col :span="24">
+                <el-col :span="2" class="right_image">
+                  <el-image :src="item.speaker.icon[0].url" class="right_icon"> </el-image>
+                </el-col>
+                <el-col :span="20" class="right_left_cont">
+                  <p class="test">{{ item.content }}</p>
+                </el-col>
+              </el-col>
+            </el-col>
+            <el-col :span="24" class="right_right" v-else-if="item.speaker._id == user._id">
+              <el-col :span="24">
+                <el-col :span="20" class="right_right_cont">
+                  <p class="test">{{ item.content }}</p>
+                </el-col>
+                <el-col :span="2" class="right_image">
+                  <el-image :src="item.speaker.icon[0].url" class="right_icon"> </el-image>
+                </el-col>
+              </el-col>
+            </el-col>
+          </el-col>
+        </el-col>
+        <el-col :span="24" class="right_thr">
+          <el-col :span="20" class="right_thr_1">
+            <!-- <el-input v-model="message" :autosize="{ minRows: 5, maxRows: 7 }" maxlength="-1" placeholder="消息" type="textarea" size="small"></el-input> -->
+            <el-form ref="form" :model="form" label-width="80px">
+              <el-input v-model="form.message" :autosize="{ minRows: 5, maxRows: 7 }" maxlength="-1" placeholder="消息" type="textarea" size="small"></el-input>
+            </el-form>
+          </el-col>
+          <el-col :span="4" class="right_thr_2">
+            <el-col :span="12" class="btn"><el-button type="success" size="mini" @click="onSubmit('content')">发送</el-button></el-col>
+            <el-col :span="12" class="icon">
+              <i class="el-icon-circle-plus-outline" style="color: #666; font-size: 50px" @click="toUp()"></i>
+            </el-col>
+          </el-col>
+        </el-col>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import { mapState, createNamespacedHelpers } from 'vuex';
+export default {
+  name: 'right-1',
+  props: {
+    list: { type: Array },
+    address: { type: Object },
+    customer: { type: Object },
+    form: { type: Object },
+  },
+  components: {},
+  data: function () {
+    return {};
+  },
+  created() {},
+  methods: {
+    toUp() {
+      this.$emit('toUp');
+    },
+    onSubmit(data) {
+      this.$emit('onSubmit', data);
+    },
+  },
+  computed: {
+    ...mapState(['user']),
+  },
+  metaInfo() {
+    return { title: this.$route.meta.title };
+  },
+  watch: {
+    test: {
+      deep: true,
+      immediate: true,
+      handler(val) {},
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.right_one {
+  text-align: center;
+  line-height: 30px;
+  padding: 5px;
+  .right_one_name {
+    font-size: 22px;
+  }
+  .right_one_address {
+    overflow: hidden;
+    text-overflow: ellipsis;
+    display: -webkit-box;
+    -webkit-line-clamp: 1;
+    -webkit-box-orient: vertical;
+    color: #666;
+  }
+}
+
+.right_two {
+  background: rgb(246, 246, 246);
+  height: 62vh;
+  overflow-y: auto;
+  .right_icon {
+    border-radius: 10px;
+    width: 50px;
+    height: 50px;
+  }
+  .right_time {
+    text-align: center;
+    padding: 10px 0;
+    color: #666;
+  }
+  .right_left {
+    text-align: left;
+    padding: 0 30px;
+
+    .right_image {
+      padding: 10px 15px;
+    }
+
+    .right_left_cont {
+      padding: 10px 10px;
+      .test {
+        border-radius: 8px;
+        border: 1px #ccc solid;
+        background: rgb(235, 249, 162);
+        padding: 10px;
+      }
+    }
+  }
+  .right_right {
+    text-align: right;
+    padding: 0 30px;
+    .right_image {
+      padding: 10px 15px;
+    }
+    .right_time {
+      padding: 10px 0;
+    }
+    .right_right_cont {
+      margin: 0 0 0 8.3%;
+      padding: 10px 10px;
+      text-align: left;
+      .test {
+        border-radius: 8px;
+        border: 1px #ccc solid;
+        background: rgb(174, 254, 149);
+        padding: 10px;
+      }
+    }
+  }
+}
+.right_thr {
+  position: relative;
+  bottom: 0;
+  padding: 3px 5px;
+  .right_thr_2 {
+    padding: 20px;
+    .btn {
+      margin: 20px 0 0 0;
+    }
+  }
+}
+</style>

+ 1 - 1
src/views/selfShop/notice/index.vue

@@ -8,7 +8,7 @@
         element-loading-text="拼命加载中"
         element-loading-spinner="el-icon-loading"
       >
-        <el-col :span="24" class="one"> <span>消息管理</span> </el-col>
+        <el-col :span="24" class="one"> <span>系统通知</span> </el-col>
         <el-col :span="24">
           <data-search :fields="searchFields" v-model="searchInfo" @query="search">
             <template #source>

+ 1 - 0
src/views/selfShop/order/index.vue

@@ -91,6 +91,7 @@ export default {
       opera: [
         { label: '详情', method: 'detail' },
         { label: '售后', method: 'sales', type: 'danger', display: (i) => i.status == '1' || i.status == '2' || i.status == '2-' || i.status == '3' },
+        // { label: '联系', method: 'message', type: 'warning' },
       ],
       fields: [
         { label: '订单号', model: 'no', showTip: false },