Browse Source

前端页面

armg 1 year ago
parent
commit
bc9b5bb6ae

+ 1 - 1
ruoyi-ui/.env.development

@@ -1,5 +1,5 @@
 # 页面标题
-VUE_APP_TITLE = 爱思系统
+VUE_APP_TITLE = CRM系统
 
 # 开发环境配置
 ENV = 'development'

+ 1 - 1
ruoyi-ui/.env.production

@@ -1,5 +1,5 @@
 # 页面标题
-VUE_APP_TITLE = 爱思系统
+VUE_APP_TITLE = CRM系统
 
 # 生产环境配置
 ENV = 'production'

+ 2 - 0
ruoyi-ui/package.json

@@ -66,6 +66,7 @@
     "quill": "1.3.7",
     "screenfull": "5.0.2",
     "sortablejs": "1.10.2",
+    "vant": "^2.13.2",
     "vconsole": "^3.15.1",
     "vkbeautify": "^0.99.3",
     "vue": "2.6.12",
@@ -75,6 +76,7 @@
     "vue-router": "3.4.9",
     "vuedraggable": "2.24.3",
     "vuex": "3.6.0",
+    "weixin-js-sdk": "^1.6.5",
     "xcrud": "^0.4.19"
   },
   "devDependencies": {

+ 92 - 7
ruoyi-ui/src/App.vue

@@ -8,17 +8,102 @@
 <script>
 import ThemePicker from "@/components/ThemePicker";
 
+import { authToken } from "@/api/login";
+import { openAuth } from "dingtalk-design-libs/biz/openAuth";
+import { setToken } from "@/utils/auth";
+import * as dd from "dingtalk-jsapi"; // 在此引入
 export default {
   name: "App",
   components: { ThemePicker },
-    metaInfo() {
-        return {
-            title: this.$store.state.settings.dynamicTitle && this.$store.state.settings.title,
-            titleTemplate: title => {
-                return title ? `${title} - ${process.env.VUE_APP_TITLE}` : process.env.VUE_APP_TITLE
-            }
-        }
+  created() {
+    let that = this;
+    // 判断是否是移动端
+    let isMobileEnv = this.isMobile();
+    // 储存
+    this.$store.commit("app/SET_IS_MOBILE_ENV", isMobileEnv);
+    // 取值-同步
+    console.log("是否是移动端=", this.$store.state.app.isMobileEnv);
+    if (dd.env.platform !== "notInDingTalk") {
+      dd.ready(function () {
+        // 钉钉免登录认证
+        // dd.getAuthCode({
+        //   corpId: "ding4ab75ecd53106cde4ac5d6980864d335",
+        //   success: (res) => {
+        //     console.log("res=", res);
+        //     avoidLogin(res.code).then((res) => {
+        //       console.log("===avoidLogin_res=",res)
+        //     });
+        //   },
+        //   fail: (err) => {
+        //     console.log("err=", err);
+        //   },
+        //   complete: () => {},
+        // });
+        // 唤起授权
+        openAuth({
+          clientId: "dingwlimimzllguvqf8x", // 应用ID(唯一标识)
+          corpId: "ding4ab75ecd53106cde4ac5d6980864d335", // 当前组织的corpId
+          rpcScope: "Contact.User.Read", //通讯录
+          fieldScope: "Contact.User.mobile", //手机号
+          type: 0, // 0 标识授权个人信息;1 标识授权组织信息
+        }).then((res) => {
+          // 处理返回数据
+          console.log("免登res=", res);
+          authToken(res.result.authCode).then((res) => {
+            let userInfo = res.sysUser;
+            setToken(res.token);
+            that.$store.commit("SET_TOKEN", res.token);
+            console.log("----钉钉环境----");
+            that.toTargetPage();
+
+            // userInfo.nick
+            // userInfo.mobile
+            // userInfo.avatarUrl
+            // openId  unionId
+          });
+        });
+      });
     }
+  },
+  metaInfo() {
+    return {
+      title:
+        this.$store.state.settings.dynamicTitle &&
+        this.$store.state.settings.title,
+      titleTemplate: (title) => {
+        return title
+          ? `${title} - ${process.env.VUE_APP_TITLE}`
+          : process.env.VUE_APP_TITLE;
+      },
+    };
+  },
+  methods: {
+    //判断是否是移动端
+    isMobile() {
+      return (
+        navigator.userAgent.match(
+          /(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i
+        ) !== null
+      );
+    },
+    // 判断是否是移动端跳转
+    toTargetPage() {
+      let that = this;
+      // 判断客户端环境
+      let isMobileEnv = this.$store.state.app.isMobileEnv;
+      console.log("app=====isMobileEnv=", isMobileEnv);
+      if (isMobileEnv) {
+        that.$router.replace({
+          path: that.redirect || "/mobile/crm/index",
+        });
+      } else {
+        that.$router.push({
+          path: that.redirect || "/",
+          query: { type: "admin", title: "爱思系统" },
+        });
+      }
+    },
+  },
 };
 </script>
 <style scoped>

+ 42 - 0
ruoyi-ui/src/api/mobile/crm/index.js

@@ -0,0 +1,42 @@
+import request from '@/utils/request'
+const system = "/system"
+
+// 新增crm
+export function add_customer(data) {
+    return request({
+        url: system + '/customer',
+        method: 'post',
+        data: data
+    })
+}
+// 修改crm
+export function update_customer(data) {
+    return request({
+        url: system + '/customer',
+        method: 'put',
+        data: data
+    })
+}
+// 删除crm
+export function del_customer(id) {
+    return request({
+        url: system + '/customer/' + id,
+        method: 'delete'
+    })
+}
+// 查询crm详情
+export function get_customer(id) {
+    return request({
+        url: system + '/customer/' + id,
+        method: 'get'
+    })
+}
+
+// 查询crm列表
+export function get_customer_list(query) {
+    return request({
+        url: system + '/customer/list',
+        method: 'get',
+        params: query
+    })
+}

+ 44 - 0
ruoyi-ui/src/api/system/customer.js

@@ -0,0 +1,44 @@
+import request from '@/utils/request'
+
+// 查询crm列表
+export function listCustomer(query) {
+  return request({
+    url: '/system/customer/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询crm详细
+export function getCustomer(id) {
+  return request({
+    url: '/system/customer/' + id,
+    method: 'get'
+  })
+}
+
+// 新增crm
+export function addCustomer(data) {
+  return request({
+    url: '/system/customer',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改crm
+export function updateCustomer(data) {
+  return request({
+    url: '/system/customer',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除crm
+export function delCustomer(id) {
+  return request({
+    url: '/system/customer/' + id,
+    method: 'delete'
+  })
+}

+ 17 - 0
ruoyi-ui/src/assets/styles/public.scss

@@ -394,4 +394,21 @@
   left: 0;
   background: rgba(0, 0, 0, 0.7);
   z-index: 4;
+}
+
+.mobileWrapper {
+  position: absolute;
+  width: 100%;
+  height: 100%;
+  top: 0;
+  left: 0;
+  background: #f4f4f4;
+  .van-nav-bar {
+    background: #3f9dfc;
+    .van-nav-bar__title,
+    .van-nav-bar__text,
+    .van-icon {
+      color: white;
+    }
+  }
 }

+ 7 - 2
ruoyi-ui/src/main.js

@@ -16,6 +16,11 @@ import { download } from '@/utils/request'
 // 防止重复点击事件
 import install from '@/utils/preventReClick'
 
+/* 导入第三方vant-ui插件 */
+import Vant from 'vant';
+import 'vant/lib/index.css';
+Vue.use(Vant);
+
 import './assets/icons' // icon
 import './permission' // permission control
 import { getDicts } from "@/api/system/dict/data";
@@ -56,8 +61,8 @@ library.add(fas,)
 library.add(far)
 library.add(fab)
 Vue.component('font-awesome-icon', FontAwesomeIcon)
-import VConsole from "vconsole";
-const vConsole = new VConsole();
+// import VConsole from "vconsole";
+// const vConsole = new VConsole();
 // import * as dd from 'dingtalk-jsapi'
 // 全局方法挂载
 Vue.prototype.getDicts = getDicts

+ 12 - 5
ruoyi-ui/src/permission.js

@@ -27,14 +27,21 @@ router.beforeEach((to, from, next) => {
           store.dispatch('GenerateRoutes').then(accessRoutes => {
             // 根据roles权限生成可访问的路由表
             router.addRoutes(accessRoutes) // 动态添加可访问路由表
-            next({ ...to, replace: true }) // hack方法 确保addRoutes已完成
+            // 新加的路由守卫
+            console.log("=====钉钉手机端-已经登录了的,直接去到crm首页", store.state.app.isMobileEnv)
+            if (store.state.app.isMobileEnv) {
+              next({ path: "/mobile/crm/index" }) // hack方法 确保addRoutes已完成
+            } else {
+              // 原本的路由
+              next({ ...to, replace: true }) // hack方法 确保addRoutes已完成
+            }
           })
         }).catch(err => {
-            store.dispatch('LogOut').then(() => {
-              Message.error(err)
-              next({ path: '/' })
-            })
+          store.dispatch('LogOut').then(() => {
+            Message.error(err)
+            next({ path: '/' })
           })
+        })
       } else {
         next()
       }

+ 26 - 9
ruoyi-ui/src/router/index.js

@@ -61,13 +61,13 @@ export const constantRoutes = [
     component: () => import('@/views/error/401'),
     hidden: true
   },
-  {
-    path: '',
-    component: () => import('@/views/home'),
-    name: "Home",
-    hidden: true
-  },
-  // CRM系统-路由
+  // {
+  //   path: '',
+  //   component: () => import('@/views/home'),
+  //   name: "Home",
+  //   hidden: true
+  // },
+  // PC-CRM系统-路由
   {
     path: '/crmSystem',
     component: Layout,
@@ -114,11 +114,28 @@ export const constantRoutes = [
       }
     ]
   },
+  // mobile - CRM系统-路由
+  {
+    path: "/mobile/crm/index",
+    name: 'MobileCrmIndex',
+    component: () => import('../views/mobile/crm/index.vue')
+  },
+  {
+    path: "/mobile/crm/form",
+    name: 'MobileCrmForm',
+    component: () => import('../views/mobile/crm/form.vue')
+  },
+  {
+    path: "/mobile/crm/detail",
+    name: 'MobileCrmDetail',
+    component: () => import('../views/mobile/crm/detail.vue')
+  },
   {
-    path: '/index',
+    // path: '/index',
+    path: '/',
     component: Layout,
     hidden: true,
-    // redirect: 'index',
+    redirect: 'index',
     children: [
       {
         path: 'index',

+ 1 - 0
ruoyi-ui/src/store/getters.js

@@ -2,6 +2,7 @@ const getters = {
   sidebar: state => state.app.sidebar,
   size: state => state.app.size,
   device: state => state.app.device,
+  isMobileEnv: state => state.app.isMobileEnv,
   dict: state => state.dict.dict,
   visitedViews: state => state.tagsView.visitedViews,
   cachedViews: state => state.tagsView.cachedViews,

+ 5 - 1
ruoyi-ui/src/store/modules/app.js

@@ -7,7 +7,8 @@ const state = {
     hide: false
   },
   device: 'desktop',
-  size: Cookies.get('size') || 'medium'
+  size: Cookies.get('size') || 'medium',
+  isMobileEnv:false,
 }
 
 const mutations = {
@@ -37,6 +38,9 @@ const mutations = {
   },
   SET_SIDEBAR_HIDE: (state, status) => {
     state.sidebar.hide = status
+  },
+  SET_IS_MOBILE_ENV:(state,isMobileEnv) => {
+    state.isMobileEnv = isMobileEnv
   }
 }
 

+ 2 - 0
ruoyi-ui/src/styles/home.scss

@@ -269,3 +269,5 @@ $lighterBlue: #409EFF;
     }
   }
 }
+
+

+ 1 - 1
ruoyi-ui/src/views/crmSystem/myTask/index.vue

@@ -282,7 +282,7 @@ export default {
     };
   },
   created() {
-    this.getList();
+    // this.getList();
   },
   methods: {
     // tab获取列表

+ 3 - 63
ruoyi-ui/src/views/index.vue

@@ -1,66 +1,6 @@
 <template>
   <div class="app-container home">
-    <el-row :gutter="20">
-      <el-col :xs="24" :sm="24" :md="12" :lg="14">
-        <el-card class="update-log">
-          <div slot="header" class="clearfix">
-            <span>联系信息</span>
-          </div>
-          <div class="body">
-            <p>
-              <i class="el-icon-user-solid"></i> QQ群:
-              <a href="https://jq.qq.com/?_wv=1027&k=2zE87c2G" target="_blank"
-              > 782924350</a
-              >
-            </p>
-            <p>
-              <i class="el-icon-chat-dot-round"></i> 微信:<a
-            >Almost-2y</a
-            >
-            </p>
-            <p style="color: #f54a4a;font-size:16px">
-              <i class="el-icon-bell"></i> 说明:<a
-            >技术咨询、业务定制等其它支持可添加 微信: Almost-2y / QQ: 846249920 进行沟通交流</a
-            >
-            </p>
-            <p>
-              <i class="el-icon-shopping-bag-2"></i> 腾讯云秒杀:<a style="color: #365be4" href="https://curl.qcloud.com/W5KFkBG4" target="_blank"
-            >点我进入</a>
-            </p>
-            <p>
-              <i class="el-icon-shopping-bag-2"></i> 腾讯云服务器:<a style="color: #365be4" href="https://curl.qcloud.com/AacfyRxq" target="_blank"
-            >点我进入</a>
-            </p>
-            <p>
-              <i class="el-icon-shopping-bag-2"></i> 阿里云优惠:<a style="color: #365be4" href="https://www.aliyun.com/activity/daily/bestoffer?userCode=q2b8atsa" target="_blank"
-            >点我进入</a>
-            </p>
-            <p>
-              <i class="el-icon-shopping-bag-2"></i> 阿里云服务器:<a style="color: #365be4" href="https://www.aliyun.com/daily-act/ecs/activity_selection?userCode=q2b8atsa" target="_blank"
-            >点我进入</a>
-            </p>
-          </div>
-        </el-card>
-      </el-col>
-      <el-col :xs="24" :sm="24" :md="12" :lg="10">
-        <el-card class="update-log">
-          <div slot="header" class="clearfix">
-            <span>捐赠支持</span>
-          </div>
-          <div class="body">
-            <img
-              src="https://foruda.gitee.com/images/1672215449995765124/596b46c3_2042292.png"
-              alt="donate"
-              width="100%"
-            />
-            <span style="display: inline-block; height: 30px; line-height: 30px"
-            >可以请作者喝杯咖啡以示鼓励!</span
-            >
-          </div>
-        </el-card>
-      </el-col>
-    </el-row>
-    <el-divider />
+    <!-- <el-divider /> -->
     <el-row :gutter="20">
       <el-col :xs="24" :sm="24" :md="12" :lg="8">
         <el-card class="update-log">
@@ -74,14 +14,14 @@
           <p>5.其它模块优化</p>
         </el-card>
       </el-col>
-      <el-col :xs="24" :sm="24" :md="12" :lg="16">
+      <!-- <el-col :xs="24" :sm="24" :md="12" :lg="16">
         <el-card class="update-log">
           <div slot="header" class="clearfix">
             <span>流程演示</span>
           </div>
           <img style="width: 850px" src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f248dea817f74341b70f4087f425975b~tplv-k3u1fbpfcp-watermark.image?"/>
         </el-card>
-      </el-col>
+      </el-col> -->
     </el-row>
   </div>
 </template>

+ 24 - 67
ruoyi-ui/src/views/login.vue

@@ -82,23 +82,6 @@
         <span>Copyright © 2018-2023 ruoyi.vip All Rights Reserved.</span>
       </div>
     </div>
-
-    <div v-else>
-      <el-button
-        type="primary"
-        plain
-        @click="handleModuleJump('myTaskIndex', 'crm', 'CRM系统')"
-      >
-        CRM系统
-      </el-button>
-      <el-button
-        type="primary"
-        plain
-        @click="handleModuleJump('Index', 'admin', '爱思系统')"
-      >
-        系统管理
-      </el-button>
-    </div>
   </div>
 </template>
 
@@ -111,23 +94,14 @@ import Cookies from "js-cookie";
 import { encrypt, decrypt } from "@/utils/jsencrypt";
 import { initDingH5RemoteDebug } from "dingtalk-h5-remote-debug";
 import { openAuth } from "dingtalk-design-libs/biz/openAuth";
-import { getENV } from "dingtalk-jsapi/lib/env";
-import { compareVersion } from "dingtalk-jsapi/lib/sdk/sdkLib";
+import { setToken } from "@/utils/auth";
 
-const { platform, version, appType } = getENV();
-/**
- * 判断当前app版本是否支持使用SDK
- * @return {boolean}
- */
-function isAuthSDKSupport() {
-  return compareVersion(version, "6.3.35");
-}
 initDingH5RemoteDebug();
 export default {
   name: "Login",
   data() {
     return {
-      showLogin: false,
+      showLogin:false,
       codeUrl: "",
       loginForm: {
         username: "admin",
@@ -162,49 +136,15 @@ export default {
     },
   },
   created() {
+    let that = this;
+    // console.log("-------created--------",navigator.userAgent);
     console.log("环境=", dd.env.platform);
-    isAuthSDKSupport();
     // 加上判断条件
-    if (dd.env.platform !== "notInDingTalk") {
-      this.showLogin = false;
-      dd.ready(function () {
-        console.log("-------------000");
-        // 钉钉免登录认证
-        // dd.getAuthCode({
-        //   corpId: "ding4ab75ecd53106cde4ac5d6980864d335",
-        //   success: (res) => {
-        //     console.log("res=", res);
-        //     avoidLogin(res.code).then((res) => {
-        //       console.log("===avoidLogin_res=",res)
-        //     });
-        //   },
-        //   fail: (err) => {
-        //     console.log("err=", err);
-        //   },
-        //   complete: () => {},
-        // });
-        // 唤起授权
-        openAuth({
-          clientId: "dingwlimimzllguvqf8x", // 应用ID(唯一标识)
-          corpId: "ding4ab75ecd53106cde4ac5d6980864d335", // 当前组织的corpId
-          rpcScope: "Contact.User.Read",//通讯录
-          fieldScope: "Contact.User.mobile",//手机号
-          type: 0, // 0 标识授权个人信息;1 标识授权组织信息
-        }).then((res) => {
-          // 处理返回数据
-          console.log("res", res);
-          authToken(res.result.authCode).then((res) => {
-            console.log("===avoidLogin_res=", res);
-          });
-        });
-      });
-    } else {
+    if (dd.env.platform == "notInDingTalk") {
       this.showLogin = true;
       this.getCode();
       this.getCookie();
     }
-
-    console.log("-=====login=====");
   },
   methods: {
     handleModuleJump(name, type, title) {
@@ -261,7 +201,7 @@ export default {
           this.$store
             .dispatch("Login", this.loginForm)
             .then(() => {
-              this.$router.push({ path: this.redirect || "/" }).catch(() => {});
+              this.toTargetPage();
             })
             .catch(() => {
               this.loading = false;
@@ -272,6 +212,23 @@ export default {
         }
       });
     },
+    // 判断是否是移动端跳转
+    toTargetPage() {
+      let that = this;
+      // 判断客户端环境
+      let isMobileEnv = this.$store.state.app.isMobileEnv;
+      console.log("isMobileEnv=", isMobileEnv);
+      if (isMobileEnv) {
+        that.$router.replace({
+          path: that.redirect || "/mobile/crm/index",
+        });
+      } else {
+        that.$router.push({
+          path: that.redirect || "/",
+          query: { type: "admin", title: "爱思系统" },
+        });
+      }
+    },
   },
 };
 </script>
@@ -281,7 +238,7 @@ export default {
   display: flex;
   justify-content: center;
   align-items: center;
-  height: 100%;
+  height: 100vh;
   background-image: url("../assets/images/login-background.jpg");
   background-size: cover;
 }

+ 118 - 0
ruoyi-ui/src/views/mobile/crm/detail.vue

@@ -0,0 +1,118 @@
+<template>
+  <div class="mobileWrapper">
+    <van-nav-bar
+      left-text="返回"
+      left-arrow
+      v-preventReClick
+      @click-left="onClickLeft"
+      title="客户详情"
+    />
+    <van-cell-group>
+      <h5>客户信息</h5>
+      <van-cell title="客户名称" :value="userForm.companyName" />
+      <van-cell title="客户地址" :value="userForm.companyWhere" />
+      <van-cell title="客户企业性质" :value="userForm.companyEnterprisepro" />
+      <van-cell title="客户状态" :value="userForm.companyState" />
+      <van-cell title="注册资本金(万元)" :value="userForm.companyCapital" />
+      <van-cell title="注册年营业额(万元)" :value="userForm.companySales" />
+      <h5>客户联系人</h5>
+      <van-cell title="客户联系人" :value="userForm.userName" />
+      <van-cell title="客户手机" :value="userForm.userPhone" />
+      <van-cell title="客户所属部门" :value="userForm.userDepartment" />
+    </van-cell-group>
+    <div class="public-flex-around btnlist">
+      <van-button type="info" round v-preventReClick @click="toForm"
+        >修改</van-button
+      >
+      <van-button type="danger" round v-preventReClick @click="toDetele"
+        >删除</van-button
+      >
+    </div>
+  </div>
+</template>
+<script>
+import { get_customer, del_customer } from "@/api/mobile/crm/index";
+import { Dialog } from "vant";
+export default {
+  name: "MobileCrmDetail",
+  data() {
+    return {
+      id: "",
+      userForm: {
+        companyName: "",
+        companyWhere: "",
+        companyEnterprisepro: "",
+        companyState: "",
+        companyCapital: "",
+        companySales: "",
+        userName: "",
+        userPhone: "",
+        userDepartment: "",
+      },
+    };
+  },
+  created() {},
+  mounted() {
+    let that = this;
+    this.id = this.$route.query.id ? this.$route.query.id : null;
+    that.$toast.loading({
+      duration: 0,
+      forbidClick: true,
+      message: "加载中...",
+    });
+    get_customer(this.id)
+      .then((response) => {
+        that.$toast.clear();
+        that.userForm = response.data;
+      })
+      .catch((err) => {
+        that.$toast(err.msg);
+      });
+  },
+  methods: {
+    toForm() {
+      this.$router.push({
+        name: "MobileCrmForm",
+        query: { type: 2, id: this.id },
+      });
+    },
+    // 删除
+    toDetele() {
+      let that = this;
+      Dialog.confirm({
+        title: "提示",
+        message: "是否删除该条数据?",
+      })
+        .then(async () => {
+          del_customer(this.id)
+            .then((response) => {
+              if (response.code == 200) {
+                that.$toast.success("删除成功");
+                that.$router.back(-1);
+              }
+            })
+            .catch(() => {
+              that.$toast(err.msg);
+            });
+        })
+        .catch(() => {});
+    },
+    onClickLeft() {
+      this.$router.back(-1);
+    },
+  },
+};
+</script>
+<style lang="scss" scoped>
+h5 {
+  background: #f4f4f4;
+  margin: 0;
+  padding: 10px 5px;
+}
+.btnlist {
+  margin-top: 20px;
+  button {
+    width: 40%;
+  }
+}
+</style>

+ 233 - 0
ruoyi-ui/src/views/mobile/crm/form.vue

@@ -0,0 +1,233 @@
+<template>
+  <div class="mobileWrapper">
+    <van-nav-bar
+      left-text="返回"
+      left-arrow
+      v-preventReClick
+      @click-left="onClickLeft"
+      :title="title"
+    />
+    <van-form ref="userForm" @submit="onSubmit">
+      <h5>客户信息</h5>
+      <van-field
+        v-model="userForm.companyName"
+        name="companyName"
+        label="客户名称"
+        maxlength="40"
+        placeholder="请输入客户名称"
+        :rules="[{ required: true }]"
+      />
+      <van-field
+        v-model="userForm.companyWhere"
+        name="companyWhere"
+        label="客户地址"
+        maxlength="80"
+        placeholder="请输入客户地址"
+        :rules="[{ required: true }]"
+      />
+      <van-field
+        readonly
+        clickable
+        name="companyEnterprisepro"
+        :value="userForm.companyEnterprisepro"
+        label="客户企业性质"
+        placeholder="点击选择客户企业性质"
+        @click="showPicker_nature = true"
+        :rules="[{ required: true }]"
+      />
+      <van-popup v-model="showPicker_nature" position="bottom">
+        <van-picker
+          show-toolbar
+          :columns="columns_nature"
+          value-key="dictLabel"
+          @confirm="onConfirm"
+          @cancel="showPicker_nature = false"
+        />
+      </van-popup>
+      <van-field
+        readonly
+        clickable
+        v-model="userForm.companyState"
+        name="companyState"
+        label="客户状态"
+        placeholder="点击选择客户状态"
+        :rules="[{ required: true }]"
+        @click="showPicker_status = true"
+      />
+      <van-popup v-model="showPicker_status" position="bottom">
+        <van-picker
+          show-toolbar
+          :columns="columns_status"
+          value-key="dictLabel"
+          @confirm="onConfirm1"
+          @cancel="showPicker_status = false"
+        />
+      </van-popup>
+      <van-field
+        v-model="userForm.companyCapital"
+        name="companyCapital"
+        type="number"
+        label="注册资本金(万元)"
+        placeholder="请输入注册资本金(万元)"
+        :rules="[{ required: true }]"
+      />
+      <van-field
+        v-model="userForm.companySales"
+        name="companySales"
+        type="number"
+        label="注册年营业额(万元)"
+        placeholder="请输入年营业额(万元)"
+        :rules="[{ required: true }]"
+      />
+      <h5>客户联系人</h5>
+      <van-field
+        v-model="userForm.userName"
+        name="userName"
+        label="客户联系人"
+        maxlength="10"
+        placeholder="请输入客户联系人"
+        :rules="[{ required: true }]"
+      />
+      <van-field
+        v-model="userForm.userPhone"
+        name="userPhone"
+        type="tel"
+        maxlength="11"
+        label="客户手机"
+        placeholder="请输入客户手机"
+        :rules="[
+          { required: true, message: '请输入客户手机' },
+          { pattern: /^1[3456789]\d{9}$/, message: '手机号码格式错误!' },
+        ]"
+      />
+      <van-field
+        v-model="userForm.userDepartment"
+        name="userDepartment"
+        maxlength="20"
+        label="客户所属部门"
+        placeholder="请输入客户所属部门"
+        :rules="[{ required: true }]"
+      />
+      <div style="margin: 16px">
+        <van-button round block type="info" native-type="submit"
+          >提交</van-button
+        >
+      </div>
+    </van-form>
+  </div>
+</template>
+<script>
+import {
+  add_customer,
+  get_customer,
+  update_customer,
+} from "@/api/mobile/crm/index";
+export default {
+  name: "MobileCrmForm",
+  dicts: [
+    // "CUSTOMER_STATUS", //客户状态
+    // "audit_status", //审核状态
+    // "start_using_yes_no", //是否启用
+    // "CUSTOMER_NATURE", //企业性质
+    // "CUSTOMER_TRADE", //客户行业
+    // "currency_of_registered_capital", //注册资本金币种
+    // "PROJECT_TYPE", //类型
+    // "SUPPLIER_TAXRATE", //税率
+  ],
+  data() {
+    return {
+      columns_nature: [],
+      showPicker_nature: false,
+      columns_status: [],
+      showPicker_status: false,
+      title: "新增客户",
+      id: "",
+      userForm: {
+        companyName: "",
+        companyWhere: "",
+        companyEnterprisepro: "",
+        companyState: "",
+        companyCapital: "",
+        companySales: "",
+        userName: "",
+        userPhone: "",
+        userDepartment: "",
+      },
+    };
+  },
+  created() {},
+  mounted() {
+    this.getDicts("CUSTOMER_NATURE").then((res) => {
+      this.columns_nature = res.data;
+    });
+    this.getDicts("CUSTOMER_STATUS").then((res) => {
+      this.columns_status = res.data;
+    });
+
+    let that = this;
+    this.title = this.$route.query.type == 2 ? "修改客户" : "新增客户";
+    this.id = this.$route.query.id ? this.$route.query.id : null;
+    if (this.id) {
+      get_customer(this.id)
+        .then((response) => {
+          that.userForm = response.data;
+        })
+        .catch((err) => {
+          that.$toast(err.msg);
+        });
+    }
+  },
+  methods: {
+    onConfirm(value) {
+      this.userForm.companyEnterprisepro = value.dictLabel;
+      this.showPicker_nature = false;
+    },
+    onConfirm1(value) {
+      this.userForm.companyState = value.dictLabel;
+      this.showPicker_status = false;
+    },
+    onSubmit(values) {
+      let that = this;
+      // console.log("submit", values);
+      if (that.id) {
+        values.id = that.id;
+        update_customer(values)
+          .then((response) => {
+            if (response.code == 200) {
+              that.$toast.success(response.msg);
+              setTimeout(() => {
+                that.$router.go(-2);
+                that.$toast.clear();
+              }, 1000);
+            }
+          })
+          .catch((err) => {
+            that.$toast(err.msg);
+          });
+      } else {
+        add_customer(values)
+          .then((response) => {
+            if (response.code == 200) {
+              that.$toast.success(response.msg);
+              setTimeout(() => {
+                that.$router.back(-1);
+                that.$toast.clear();
+              }, 1000);
+            }
+          })
+          .catch((err) => {
+            that.$toast(err.msg);
+          });
+      }
+    },
+    onClickLeft() {
+      this.$router.back(-1);
+    },
+  },
+};
+</script>
+<style lang="scss" scoped>
+h5 {
+  margin: 10px 5px;
+}
+</style>

+ 190 - 0
ruoyi-ui/src/views/mobile/crm/index.vue

@@ -0,0 +1,190 @@
+<template>
+  <div class="mobileWrapper">
+    <div class="fixedTop">
+      <van-nav-bar
+        title="重点客户"
+        right-text="新建"
+        v-preventReClick
+        @click-right="onClickRight"
+      />
+      <van-search
+        v-model="queryParams.companyName"
+        show-action
+        label="客户"
+        placeholder="请输入客户名称"
+        @search="onSearch"
+      >
+        <template #action>
+          <div @click="onSearch" v-preventReClick>搜索</div>
+        </template>
+      </van-search>
+    </div>
+
+    <div class="listWrapper">
+      <!-- 内容 -->
+      <van-pull-refresh v-model="refreshing" @refresh="onRefresh">
+        <van-list
+          v-model="loading"
+          :finished="finished"
+          finished-text=""
+          @load="onLoad"
+          class="list"
+        >
+          <div
+            class="item"
+            v-for="(item, index) in list"
+            :key="index"
+            v-preventReClick
+            @click="toDetail(item.id)"
+          >
+            <div>{{ item.companyName }}</div>
+            <div>负责人:{{ item.createBy }}</div>
+            <van-tag class="public-margin-t-10" type="primary" size="large">{{
+              item.companyEnterprisepro
+            }}</van-tag>
+            <van-tag class="public-margin-l-10" type="primary" size="large">{{
+              item.companyState
+            }}</van-tag>
+          </div>
+        </van-list>
+      </van-pull-refresh>
+      <div v-if="noDate" class="noDateWrapper">
+        <div>没有相关数据</div>
+        <div>您可以尝试以下操作</div>
+        <van-button type="info" round v-preventReClick @click="onClickRight"
+          >新建重点客户</van-button
+        >
+      </div>
+    </div>
+  </div>
+</template>
+<script>
+import { get_customer_list } from "@/api/mobile/crm/index";
+export default {
+  name: "MobileCrmIndex",
+  data() {
+    return {
+      list: [],
+      refreshing: false,
+      loading: false,
+      finished: false,
+      noDate: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        companyName: null,
+      },
+    };
+  },
+  created() {},
+  mounted() {},
+  methods: {
+    toDetail(id) {
+      this.$router.push({ path: "detail", query: { id } });
+    },
+    onRefresh() {
+      // 清空列表数据
+      this.finished = false;
+      // 将 loading 设置为 true,表示处于加载状态
+      this.loading = true;
+      this.onLoad();
+    },
+    onClickRight() {
+      this.$router.push({ name: "MobileCrmForm", query: { type: 1 } });
+    },
+    onSearch() {
+      this.getList();
+    },
+    onLoad() {
+      this.getList();
+    },
+    getList() {
+      let that = this;
+      if (this.refreshing) {
+        this.list = [];
+        this.refreshing = false;
+      }
+      that.$toast.loading({
+        duration: 0,
+        forbidClick: true,
+        message: "加载中...",
+      });
+      get_customer_list(that.queryParams)
+        .then((response) => {
+          if (response.code == 200) {
+            that.$toast.clear();
+            let data = response.rows,
+              total = response.total;
+            that.finished = true;
+            that.noDate = false;
+            if (total == 0) {
+              that.list = [];
+              that.noDate = true;
+            } else if (total < 10) {
+              that.list = data;
+            } else {
+              that.finished = false;
+              that.list.push(...data);
+              that.queryParams.page += 1;
+            }
+            that.loading = false;
+          }
+        })
+        .catch((err) => {
+          that.$toast(err.msg);
+        });
+    },
+  },
+};
+</script>
+<style lang="scss">
+.fixedTop{
+  width:100%;
+  position: fixed;
+  top:0;
+  left:0;
+  z-index: 99;
+}
+.listWrapper {
+  margin-top:100px;
+  background: #f4f4f4;
+  // padding-bottom:100px;
+}
+.searchBar {
+  text-align: center;
+  background: #fff;
+  padding: 10px 0;
+}
+.list {
+  width: 100%;
+  .item {
+    margin: 10px 0;
+    padding: 10px 3%;
+    background: #fff;
+    color: #aaa;
+    font-size: 14px;
+    // border: 1px solid #ccc;
+    > div:first-child {
+      font-weight: bold;
+      font-size: 18px;
+      line-height: 30px;
+      color: #333;
+    }
+  }
+}
+.noDateWrapper {
+  width: 100%;
+  text-align: center;
+  position: absolute;
+  top: 50%;
+  left: 50%;
+  transform: translate(-50%, -50%);
+  > div {
+    color: #8a8989;
+  }
+  button {
+    margin-top: 10px;
+  }
+}
+</style>

+ 357 - 0
ruoyi-ui/src/views/system/customer/index.vue

@@ -0,0 +1,357 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="客户名称" prop="companyName">
+        <el-input
+          v-model="queryParams.companyName"
+          placeholder="请输入客户名称"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="客户地址" prop="companyWhere">
+        <el-input
+          v-model="queryParams.companyWhere"
+          placeholder="请输入客户地址"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="客户企业性质" prop="companyEnterprisepro">
+        <el-input
+          v-model="queryParams.companyEnterprisepro"
+          placeholder="请输入客户企业性质"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="客户状态" prop="companyState">
+        <el-input
+          v-model="queryParams.companyState"
+          placeholder="请输入客户状态"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="注册资本金" prop="companyCapital">
+        <el-input
+          v-model="queryParams.companyCapital"
+          placeholder="请输入注册资本金"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="注册年营业额" prop="companySales">
+        <el-input
+          v-model="queryParams.companySales"
+          placeholder="请输入注册年营业额"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="客户联系人" prop="userName">
+        <el-input
+          v-model="queryParams.userName"
+          placeholder="请输入客户联系人"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="客户手机" prop="userPhone">
+        <el-input
+          v-model="queryParams.userPhone"
+          placeholder="请输入客户手机"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="客户所属部门" prop="userDepartment">
+        <el-input
+          v-model="queryParams.userDepartment"
+          placeholder="请输入客户所属部门"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['system:customer:add']"
+        >新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="el-icon-edit"
+          size="mini"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['system:customer:edit']"
+        >修改</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          plain
+          icon="el-icon-delete"
+          size="mini"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['system:customer:remove']"
+        >删除</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="el-icon-download"
+          size="mini"
+          @click="handleExport"
+          v-hasPermi="['system:customer:export']"
+        >导出</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="customerList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="id" align="center" prop="id" />
+      <el-table-column label="客户名称" align="center" prop="companyName" />
+      <el-table-column label="客户地址" align="center" prop="companyWhere" />
+      <el-table-column label="客户企业性质" align="center" prop="companyEnterprisepro" />
+      <el-table-column label="客户状态" align="center" prop="companyState" />
+      <el-table-column label="注册资本金" align="center" prop="companyCapital" />
+      <el-table-column label="注册年营业额" align="center" prop="companySales" />
+      <el-table-column label="客户联系人" align="center" prop="userName" />
+      <el-table-column label="客户手机" align="center" prop="userPhone" />
+      <el-table-column label="客户所属部门" align="center" prop="userDepartment" />
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['system:customer:edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['system:customer:remove']"
+          >删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改crm对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="客户名称" prop="companyName">
+          <el-input v-model="form.companyName" placeholder="请输入客户名称" />
+        </el-form-item>
+        <el-form-item label="客户地址" prop="companyWhere">
+          <el-input v-model="form.companyWhere" placeholder="请输入客户地址" />
+        </el-form-item>
+        <el-form-item label="客户企业性质" prop="companyEnterprisepro">
+          <el-input v-model="form.companyEnterprisepro" placeholder="请输入客户企业性质" />
+        </el-form-item>
+        <el-form-item label="客户状态" prop="companyState">
+          <el-input v-model="form.companyState" placeholder="请输入客户状态" />
+        </el-form-item>
+        <el-form-item label="注册资本金" prop="companyCapital">
+          <el-input v-model="form.companyCapital" placeholder="请输入注册资本金" />
+        </el-form-item>
+        <el-form-item label="注册年营业额" prop="companySales">
+          <el-input v-model="form.companySales" placeholder="请输入注册年营业额" />
+        </el-form-item>
+        <el-form-item label="客户联系人" prop="userName">
+          <el-input v-model="form.userName" placeholder="请输入客户联系人" />
+        </el-form-item>
+        <el-form-item label="客户手机" prop="userPhone">
+          <el-input v-model="form.userPhone" placeholder="请输入客户手机" />
+        </el-form-item>
+        <el-form-item label="客户所属部门" prop="userDepartment">
+          <el-input v-model="form.userDepartment" placeholder="请输入客户所属部门" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">确 定</el-button>
+        <el-button @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listCustomer, getCustomer, delCustomer, addCustomer, updateCustomer } from "@/api/system/customer";
+
+export default {
+  name: "Customer",
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // crm表格数据
+      customerList: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        companyName: null,
+        companyWhere: null,
+        companyEnterprisepro: null,
+        companyState: null,
+        companyCapital: null,
+        companySales: null,
+        userName: null,
+        userPhone: null,
+        userDepartment: null
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+      }
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    /** 查询crm列表 */
+    getList() {
+      this.loading = true;
+      listCustomer(this.queryParams).then(response => {
+        this.customerList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        id: null,
+        companyName: null,
+        companyWhere: null,
+        companyEnterprisepro: null,
+        companyState: null,
+        companyCapital: null,
+        companySales: null,
+        userName: null,
+        userPhone: null,
+        userDepartment: null
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.id)
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加crm";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const id = row.id || this.ids
+      getCustomer(id).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "修改crm";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.id != null) {
+            updateCustomer(this.form).then(response => {
+              this.$modal.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addCustomer(this.form).then(response => {
+              this.$modal.msgSuccess("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ids = row.id || this.ids;
+      this.$modal.confirm('是否确认删除crm编号为"' + ids + '"的数据项?').then(function() {
+        return delCustomer(ids);
+      }).then(() => {
+        this.getList();
+        this.$modal.msgSuccess("删除成功");
+      }).catch(() => {});
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      this.download('system/customer/export', {
+        ...this.queryParams
+      }, `customer_${new Date().getTime()}.xlsx`)
+    }
+  }
+};
+</script>