CRM-Star

200 阅读5分钟

一、CRM后台管理系统(PC)

1)简历描述

1、使用Vue.js作为前端框架,实现页面组件化开发和数据的动态绑定。

2、使用Vue-Router进行页面导航和路由管理,实现不同页面之间的切换和参数传递。

3、使用Vuex进行状态管理,确保不同组件之间的数据共享和状态的一致性。

4、使用Element-Plus组件库提供丰富的组件和样式,快速搭建用户界面。

5、使用Echarts进行数据可视化,展示销售订单和物流信息的统计和趋势。

6、使用Axios进行前后端数据交互,发送和接收HTTP请求,与后端API进行通信。

采用技术: Vue,Vue-Router,Vuex,Echarts,Axios,Element-Plus;

项目职责

  • 1、实现首页客户等级、合同成交数量、合同成交金额数据展示。

  • 2、实现线索功能模块,包括线索的创建、编辑和查看详情、分配、模糊搜索等功能。

  • 3、实现公海功能模块,包括公海池的新建、编辑、删除和查看公海成员等功能。

  • 4、优化用户界面的性能和响应速度,提升用户体验。

 

2)解释公海、线索和客户

1. 公海
  • 公海是一个未被分配给特定销售代表或团队的潜在客户资源池。

  • 公海中的潜在客户通常是通过不同渠道获得的,比如网站注册、展会活动、市场活动等。

  • 公海中的潜在客户还没有达到成为正式客户的阶段,通常需要进一步的跟进和开发才能转化为客户。

  • 销售团队可以从公海中领取潜在客户,进行跟进并将其转化为正式客户。

2. 线索  
  • 线索是指表达了对产品或服务感兴趣的个人或组织,但尚未成为正式客户的潜在客户。

  • 线索可以是从各种渠道获得的,比如市场活动、广告、推荐等。

  • 线索通常需要进一步的跟进、沟通和营销活动,以确定其购买意向和能力,并最终转化为客户。

3. 客户
  • 客户是已经购买了产品或服务的个人或组织,与公司建立了正式的业务关系。

  • 客户通常在CRM系统中有着详细的档案记录,包括联系信息、购买历史、交易详情等。

  • 销售团队和客户服务团队会与客户进行持续的沟通和关系维护,以提供支持、满足需求并促进交易。

4.联系:
  • 公海中的潜在客户处于未经处理的状态,等待不同销售团队的领取和跟进。

  • 与公海不同,线索已经被识别并记录在系统中,销售团队可以直接对其进行跟进和处理。

  • 通过有效的跟进和营销活动,线索可以转化为客户,并进入客户管理阶段。

  • 线索是已经记录在系统,直接进行跟进处理,而公海是潜在客户还没有处理,等待不同销售团队领取跟进,进入到线索池发展为客户。

 

3)PC端难点:

1、角色权限功能中对得到的数据进行二次处理。

  • 角色权限用到了Element-Plus里面的Tree树形控件,他里面自带一个方法是getCheckedNodes(ture)获取到的是子节点,但我们想要的是,比如说人员管理:里面有超级管理员、管理员、客户。我们想要一个数组里面有一个对象是超级管理管,他里面有一个属性children,里面包含了超级管理员、管理员与客户。就

需要对数据进行一个二次处理如下:

      // 1.5 获取角色权限
        getCheckedKeys() {
            // console.log(this.$refs.treeRef.getCheckedNodes())
            // console.log(this.$refs.treeRef.getCheckedNodes(true))

            // 1.5.1 存储我们获取到的节点, 但是不符合我们的需求, 所以我们需要 进行一个改造
            const list = this.$refs.treeRef.getCheckedNodes(true);
            // console.log(list)

            // 1.5.2 新建一个数组, 用于存储最终的结果
            const result = [];

            // 1.5.3 新建一个数组, 用于存储选中节点的父级 label 属性, 后续可以利用 这个属性判断我们之前是否选中过这个节点或者之前有没有遇到过这个父级
            const parentLabel = [];

            // 1.5.4 遍历 list 数组, 获取到每一个子节点, 然后寻找这个子节点对应的父级
            list.forEach((item) => {
                // item 就是我们选中的每一个子节点

                // 1.5.4.1 帮助我们的子节点寻找到对应的父节点
                const parent = this.routesList.find((parent) => {
                    return parent.children.some((child) => {
                        return child.label === item.label;
                    });
                });

                if (!parentLabel.includes(parent.label)) {
                    // 第一次遇到这个数据
                    parentLabel.push(parent.label);

                    result.push({
                        label: parent.label,
                        name: parent.name,
                        children: [item],
                    });
                } else {
                    // 之前遇到过这个数据
                    const parentInfo = result.find(
                        (t) => t.label === parent.label
                    );
                    parentInfo.children.push(item);
                }
            });

            // 1.5.5 将我们处理好的数据, 赋值给 我们 form 对象
            this.form.checkedKeys = result;
            console.log(result);
        },

2)大文件进行断点续传(使用axios实现断点续传)

实现文件上传的断点续传通常涉及客户端和服务器端两个方面的工作。在客户端,你需要将文件分块,并在每个块上传完成后记录上传进度。在服务器端,你需要处理每个上传的文件块,并在完成所有块的上传后合并它们。

2-1、客户端实现
    <template>
    <div>
        <!-- 文件选择输入框,当文件选择发生变化时触发 handleFileChange 方法 -->
        <input type="file" @change="handleFileChange" />
        <!-- 上传文件按钮,点击时触发 uploadFile 方法 -->
        <button @click="uploadFile">上传文件</button>
    </div>
</template>
  
<script>
// 导入 Axios 库,用于发送 HTTP 请求
import axios from 'axios';

export default {
    data() {
        return {
            file: null, // 用于存储选中的文件
        };
    },
    methods: {
        // 文件选择变化事件处理函数
        handleFileChange(event) {
            // 将选中的文件存储到组件的 file 数据中
            this.file = event.target.files[0];
        },
        // 上传文件方法
        async uploadFile() {
            // 定义每个文件块的大小为 1MB
            const chunkSize = 1 * 1024 * 1024;
            // 初始化文件块的起始字节位置
            let start = 0;
            // 初始化文件块的结束字节位置
            let end = Math.min(chunkSize, this.file.size);
            // 初始化文件块的索引
            let index = 0;
            // 用于存储所有的文件块数据
            const chunks = [];


            // 循环直到文件所有字节都处理完毕
            while (start < this.file.size) {
                // 从文件中截取一个文件块
                const chunk = this.file.slice(start, end);
                // 创建一个 FormData 对象,用于将文件块和索引一起发送到服务器
                const formData = new FormData();
                // 将文件块添加到 FormData 对象中
                formData.append('chunk', chunk);
                // 将文件块的索引添加到 FormData 对象中
                formData.append('index', index);

                // 发送文件块到服务器进行上传
                await axios.post('/upload', formData);

                // 将文件块添加到 chunks 数组中
                chunks.push(chunk);
                // 更新文件块的起始字节位置
                start = end;
                // 更新文件块的结束字节位置
                end = Math.min(start + chunkSize, this.file.size);
                // 更新文件块的索引
                index++;
            }
            // 所有文件块上传完毕后,发送请求告知服务器进行文件合并
            await axios.post('/merge', { chunks });
            console.log('上传完成'); // 输出上传完成的提示信息
        },
    },
};
</script>

2-2、nodejs端(服务端)实现
    const express = require('express'); // 导入 Express 框架
const fs = require('fs'); // 导入文件系统模块
const app = express(); // 创建 Express 应用实例
const port = 3000; // 指定服务器运行的端口号

// 使用 express.json 中间件,用于解析请求体中的 JSON 数据
app.use(express.json()); 

// 保存文件块
// 定义 '/upload' POST 路由,用于保存文件块
app.post('/upload', (req, res) => { 
    // 从请求体中获取文件块数据
  const chunk = req.body.chunk; 
  // 从请求体中获取文件块索引
  const index = req.body.index; 
   // 构造文件块临时文件名
  const fileName = `chunk_${index}.tmp`;

  // 将文件块数据写入到临时文件中
  fs.writeFileSync(fileName, chunk); 
  // 输出保存文件块的日志信息
  console.log(`保存文件块 ${index}`); 
  // 响应客户端请求,表示文件块保存成功
  res.send('OK'); 
});

// 合并文件块
// 定义 '/merge' POST 路由,用于合并文件块
app.post('/merge', (req, res) => { 
    // 从请求体中获取所有文件块数据
  const chunks = req.body.chunks; 
  // 创建可写流,用于写入合并后的文件
  const file = fs.createWriteStream('uploaded_file'); 

  for (const chunk of chunks) { // 遍历所有文件块数据
    // 将文件块数据写入到合并后的文件中
    file.write(chunk); 
    // 删除已经合并的文件块临时文件
    fs.unlinkSync(chunk); 
  }

  file.end(); // 关闭可写流
  console.log('文件合并完成'); // 输出文件合并完成的日志信息
  res.send('OK'); // 响应客户端请求,表示文件合并成功
});

// 监听指定端口,启动服务器
app.listen(port, () => {
    // 输出服务器启动成功的日志信息
  console.log(`服务器运行在 http://localhost:${port}`); 
});

2-3、文字总结
  • 大文件断点续传是一种用于上传大型文件的技术,通过将大文件分割成小块,并逐个上传这些小块到服务器,可以实现在上传过程中出现中断或失败后能够恢复上传进度。以下是实现大文件断点续传的基本步骤:
  1. 选择文件:在客户端选择要上传的大文件。

  2. 分割文件:将大文件分割成小块。通常采用固定大小的块,比如1MB或其他合适的大小。这样做有助于管理和处理大文件,并提供更好的上传控制。

  3. 逐个上传:将每个文件块逐个上传到服务器。使用现代的前端技术如Axios 发送 POST 请求来实现。每个文件块上传完成后,服务器会返回一个确认信息,表明文件块上传成功。

  4. 保存上传进度:在上传过程中,客户端需要保存上传进度信息,比如已经上传的文件块索引,以便在上传中断后能够恢复上传。

  5. 处理中断:如果上传过程中出现中断或失败,客户端可以重新启动上传过程,并根据保存的上传进度信息,从上次中断的地方继续上传。

  6. 合并文件块:当所有文件块上传完成后,服务器收到所有文件块后,会将这些文件块按顺序合并成完整的大文件。

  7. 完成上传:一旦文件合并完成,上传过程就算完成了。客户端和服务器都会得到一个上传完成的提示。

总体来说,大文件断点续传技术通过分割文件、逐个上传、保存上传进度和合并文件块等步骤,实现了对大文件的稳定、高效的上传,即使在网络不稳定或上传过程中断的情况下,也能够恢复上传进度,提高了用户体验和上传效率。