ToB企服应用市场:ToB评测及商务社交产业平台

标题: 粤嵌Linux GEC6818开发板实现电子相册 [打印本页]

作者: 张国伟    时间: 2024-6-21 13:18
标题: 粤嵌Linux GEC6818开发板实现电子相册
前言

最近学校要求使用粤嵌的开发板实现电子相册,具体的功能要有点击特定的区域实现上一张、下一张、自动播放图片、黑屏退出应用步伐、左右滑动切换图片相关功能。其中涉及到的知识点也比较多(文件IO、内存映射、触摸屏、bmp图片格式、进程、线程创建和同步、字符串操纵等)。为理清思路和复习去年学的Linux C应用编程知识,特写下此文举行回顾和总结。
先看看效果
     粤嵌Linux GEC6818开发板实现电子相册
  
整个工程文件和使用到的图片在下方链接
门牙会稍息 / 粤嵌GEC 6818开发板实现简易电子相册和音乐播放器 · GitCode
一:内存映射

存储映射 I/O(memory-mapped I/O)是一种基于内存区域的高级 I/O 操纵,它能将一个文件映射到进程所在空间中的一块内存区域中,当从这段内存中读数据时,就相当于读文件中的数据(对文件举行 read 操纵),将数据写入这段内存时,则相当于将数据直接写入文件中(对文件举行 write 操纵)。用到的两个函数是mmap和munmap,函数原型如下:

简言之addr设置为NULL的话内核会自动找一内存空间,大小就是length,粤嵌的屏是800*480的,以是length就是800*480*4,4代表一个像素点由四字节构成(ARGB),port参数设为PROT_READ、PROT_WRITE就是可读可写,flags形貌的是映射区的属性。

 二:BMP格式图片


 用hexdump检察一下bmp图片的数据(高度和宽度)

LCD屏显示BMP格式图片的函数
  1. /**
  2. *lcd屏显示bmp格式图片函数
  3. *@param     pathname    图片名字
  4. *@param     x0          图片在LCD上显示的x起点坐标
  5. *@param     y0          图片在LCD上显示的y起点坐标
  6. *@return    函数返回值
  7. */
  8. int lcd_show_bmp(char *pathname, int x0, int y0)
  9. {
  10.         //1、打开设备文件
  11.         int lcd = open("/dev/fb0", O_RDWR);
  12.         if(-1 == lcd)
  13.         {
  14.                 printf("lcd open error!\n");
  15.                 return -2;
  16.         }
  17.        
  18.         //2、内存映射
  19.         char *ptr =  (char *)mmap(NULL, 800*480*4, PROT_READ|PROT_WRITE,
  20.                         MAP_SHARED, lcd, 0);
  21.         if(NULL == ptr)
  22.         {
  23.                 printf("mmap error!\n");
  24.                 return -3;
  25.         }
  26.         //清除背景色
  27.         //bzero(ptr, 800*480*4);
  28.        
  29.         //打开图片
  30.         int bmp = open(pathname, O_RDWR);
  31.         if(-1 == bmp)
  32.         {
  33.                 printf("bmp open error!\n");
  34.                 return -2;
  35.         }
  36.        
  37.         //读取图片相关信息
  38.         int bmp_size, bmp_width, bmp_height;
  39.         //大小
  40.         lseek(bmp, 2, SEEK_SET);
  41.         read(bmp, &bmp_size, sizeof(bmp_size));
  42.        
  43.         //宽度和高度
  44.         lseek(bmp, 18, SEEK_SET);
  45.         read(bmp, &bmp_width, sizeof(bmp_width));
  46.         read(bmp, &bmp_height, sizeof(bmp_height));
  47.        
  48.         //读取图片的颜色数据
  49.         lseek(bmp, 54, SEEK_SET);
  50.         char *bmp_buf = malloc(bmp_size);        //申请空间
  51.         read(bmp, bmp_buf, bmp_width*bmp_height*3);
  52.        
  53.         //对颜色数据进行处理(上下颠倒以及数据混乱)
  54.         int bmp_sum = 0;
  55.         int lcd_sum = 0;
  56.         for(int y=0; y+y0<480 && y<bmp_height; y++)
  57.         {
  58.                 for(int x=0; x+x0<800 && x<bmp_width; x++)
  59.                 {
  60.                         bmp_sum = 3*(x+((bmp_height-1-y)*bmp_width));
  61.                         lcd_sum = 4*(800*(y+y0)+x+x0);
  62.                        
  63.                         //等号的坐标属于lcd屏幕, 等号的右边是bmp图像数据
  64.                         ptr[lcd_sum+0] = bmp_buf[bmp_sum+0]; //蓝色数据
  65.                         ptr[lcd_sum+1] = bmp_buf[bmp_sum+1]; //绿色数据
  66.                         ptr[lcd_sum+2] = bmp_buf[bmp_sum+2]; //红色数据
  67.                         ptr[lcd_sum+3] = bmp_buf[bmp_sum+3]; //透明度数据
  68.                 }
  69.                 //usleep(1);
  70.         }
  71.     //释放相关资源
  72.         munmap(ptr, 800*480*4);
  73.         free(bmp_buf);
  74.         //3、关闭文件
  75.         close(lcd);
  76.         close(bmp);
  77. }
复制代码
 三:input_event接收触摸屏上报值


用hexdump下令检察触摸屏上报值


 此实验用到input子体系中的type、code(下面的图片泉源Linux内核中的input.h文件)



获取触摸屏坐标返回值函数
  1. /**
  2. *获取触摸屏坐标返回值函数
  3. *param    NULL
  4. *return   NULL
  5. */
  6. void get_touch()
  7. {
  8.     //打开设备文件
  9.     int touch_fd = open("/dev/input/event0", O_RDONLY);
  10.     if(-1 == touch_fd)
  11.     {
  12.         printf("event0 open error!\n");
  13.     }
  14.     while(1)
  15.     {
  16.         read(touch_fd, &ts, sizeof(ts));
  17.             //获取X、Y坐标
  18.         if(EV_ABS == ts.type) //判断是否为触摸屏事件
  19.         {
  20.             if(ABS_X == ts.code)//判断是否为x轴数据
  21.             {
  22.                 ts_x = ts.value;
  23.                 flag_x = 1;       
  24.             }
  25.             else if(ABS_Y == ts.code) //判断是否为y轴数据
  26.             {
  27.                 ts_y = ts.value;
  28.                 flag_y = 1;
  29.             }
  30.         }
  31.         if(EV_KEY == ts.type)
  32.         {
  33.                 //刚触碰的坐标/长按时
  34.                 if(ts.code == BTN_TOUCH && ts.value == 1)
  35.                 {
  36.                         old_x = ts_x;
  37.                         first_press_flag = 1;
  38.                 }
  39.         }
  40.        
  41.         if(flag_x == 1 && flag_y == 1 && first_press_flag == 1)
  42.         {
  43.                 flag_x = 0;
  44.                 flag_y = 0;
  45.                 pthread_mutex_lock(&mutex);
  46.                 flag_x_y = 1;  
  47.                 //黑色底板才需要执行如下操作
  48.                 ts_x = ts_x*800/1024;
  49.                 ts_y = ts_y*480/600;
  50.                 pthread_mutex_unlock(&mutex);
  51.                 pthread_cond_signal(&cond);
  52.                 //break;                    
  53.         }
  54.     if(EV_KEY == ts.type)
  55.         {
  56.                 //松开
  57.                 if(ts.code == BTN_TOUCH && ts.value == 0)
  58.                 {
  59.                         //从左到右的滑动
  60.                         if(((ts_x > old_x) && (ts_x - old_x > 150) && (ts_x < 600)))
  61.                         {
  62.                                 right_left_slide_flag = 1;
  63.                                 slider_right = 1;                       
  64.                                 old_x = 300;
  65.                         }       
  66.                         //从右到左的滑动
  67.                         else if(((old_x > ts_x) && (old_x - ts_x > 150) && (old_x < 600)))
  68.                         {
  69.                                
  70.                                 right_left_slide_flag = 1;
  71.                                 slider_left = 1;
  72.                                 old_x = 300;
  73.                         }
  74.                 }
  75.         }
  76.     }
  77.     //4、关闭文件
  78.     close(touch_fd);
  79. }
复制代码
四:创建线程,处理惩罚触摸屏坐标数据

阻塞式 I/O 的优点在于可以或许提升 CPU 的处理惩罚服从,当自身条件不满足时,进入阻塞状态,交出 CPU资源,将 CPU 资源让给别人使用;而非阻塞式则是抓紧使用 CPU 资源,譬如不断地去轮训,这样就会导致该步伐占用了非常高的 CPU 使用率!我这里是想得到触摸点坐标之后再做相关的操纵,当没有按下触摸屏的时间,相关线程就会阻塞挂起,节约资源,线程同步中使用互斥锁和条件变量就可以实现。
左右滑动线程处理惩罚函数:
  1. void *right_left_slide_func(void *arg)
  2. {
  3.         printf("enter right_left_slide_func\r\n");
  4.         while(1){
  5.                 if(right_left_slide_flag == 1){
  6.                         if(slider_left == 1){
  7.                                 touch_flag--;
  8.                                 if(touch_flag <= 0)
  9.                                         touch_flag = BMP_MAX_NUMBER;
  10.                                 lcd_show_bmp(bmp_path[touch_flag - 1], 0, 0);
  11.                                 slider_left = 0;
  12.                                 right_left_slide_flag == 0;
  13.                         }
  14.                         else if(slider_right == 1){
  15.                                 touch_flag++;
  16.                                 if(touch_flag > BMP_MAX_NUMBER)
  17.                                         touch_flag = 1;
  18.                                 lcd_show_bmp(bmp_path[touch_flag - 1], 0, 0);
  19.                                 slider_right = 0;
  20.                                 right_left_slide_flag == 0;
  21.                         }
  22.                         right_left_slide_flag == 0;
  23.                 }       
  24.         }
  25. }
复制代码
右侧选项框线程处理惩罚函数:
  1. void *area_switch(void *arg)
  2. {
  3.         printf("enter area_switch\r\n");
  4.         while(1){
  5.                 pthread_mutex_lock(&mutex);
  6.                 while(flag_x_y == 0)
  7.                         pthread_cond_wait(&cond, &mutex);
  8.                 while(flag_x_y == 1){
  9.                         //上一张
  10.                         if((ts_y > 0 && ts_y < 120) && (ts_x > 600))
  11.                         {
  12.                                 touch_flag--;
  13.                                 if(touch_flag <= 0)
  14.                                         touch_flag = BMP_MAX_NUMBER;
  15.                
  16.                                 lcd_show_bmp(bmp_path[touch_flag - 1], 0, 0);
  17.                                 ts_x = 0;
  18.                                 ts_y = 0;
  19.                         }
  20.                         //下一张
  21.                         else if((ts_y > 120 && ts_y < 240) && (ts_x > 600))
  22.                         {
  23.                                 touch_flag++;
  24.                                 if(touch_flag > BMP_MAX_NUMBER)
  25.                                         touch_flag = 1;
  26.                
  27.                                 lcd_show_bmp(bmp_path[touch_flag - 1], 0, 0);
  28.                                 ts_x = 0;
  29.                                 ts_y = 0;
  30.                         }
  31.                         //幻灯片
  32.                         else if((ts_y > 240 && ts_y < 360) && (ts_x > 600))
  33.                         {
  34.                                 printf("click slider photo\r\n");
  35.                                 if(slider_flag == 0){
  36.                                         slider_flag = 1;
  37.                                 }
  38.                                 else{
  39.                                         slider_flag = 0;
  40.                                 }
  41.                                 printf("slider_flag = %d\r\n", slider_flag);
  42.                                 ts_x = 0;
  43.                                 ts_y = 0;
  44.                         }
  45.                         //息屏
  46.                         else if((ts_y > 360 && ts_y < 480) && (ts_x > 600))
  47.                         {
  48.                                 char command[] = "kill -9 ";
  49.                                 char str[10];
  50.                                 sprintf(str, "%d", pid);
  51.                                 strcat(command, str);
  52.                                 printf("command = %s\r\n", command);
  53.                                 //方式一:显示一张黑色的图片
  54.                                 lcd_show_bmp("black.bmp", 0, 0);
  55.                                 system(command);
  56.                         }
  57.                         else{
  58.                                 flag_x_y = 0;
  59.                                 break;
  60.                         }
  61.                         flag_x_y = 0;
  62.                 }
  63.                 pthread_mutex_unlock(&mutex);
  64.         }
  65.        
  66. }
复制代码
 自动播放图片线程处理惩罚函数:
  1. void *slider_func(void *arg)
  2. {
  3.         printf("enter slider_func : %d\r\n", pthread_self());
  4.         while(1){
  5.                 if(slider_flag == 1){
  6.                         printf("enter slider_func\r\n");
  7.                         touch_flag++;
  8.                         if(touch_flag > BMP_MAX_NUMBER)
  9.                                 touch_flag = 1;
  10.                         lcd_show_bmp(bmp_path[touch_flag - 1], 0, 0);
  11.                         sleep(1);
  12.                 }
  13.         }
  14. }
复制代码
五:Main函数

main函数就是一些线程、互斥锁、条件变量的创建和接纳
  1. int main()
  2. {
  3.         lcd_show_bmp("choice.bmp", 600, 0);
  4.         lcd_show_bmp(bmp_path[touch_flag - 1], 0, 0);
  5.         pthread_t tid, tid_area_switch, tid_right_left_slide;
  6.         int ret = 0;
  7.        
  8.         pthread_create(&tid, NULL, slider_func, NULL);
  9.         pthread_create(&tid_area_switch, NULL, area_switch, NULL);
  10.         pthread_create(&tid_right_left_slide, NULL, right_left_slide_func, NULL);
  11.         pthread_mutex_init(&mutex, NULL);
  12.         pthread_cond_init(&cond, NULL);
  13.        
  14.         printf("main thread = %ld\r\n", pthread_self());
  15.         pid = getpid();
  16.         printf("pid = %d\r\n", pid);
  17.         while(1){
  18.                 get_touch();
  19.         }
  20.        
  21.        
  22.         pthread_join(tid, NULL);
  23.         pthread_join(tid_area_switch, NULL);
  24.         pthread_join(tid_right_left_slide, NULL);
  25.         pthread_cond_destroy(&cond);
  26.         exit(0);
  27. }
复制代码
六:完整代码

  1. #include <stdio.h>#include <fcntl.h>#include <sys/stat.h>#include <sys/types.h>#include <unistd.h>#include <string.h>#include <sys/mman.h>#include <stdlib.h>#include <linux/input.h>#include <pthread.h>#include <unistd.h>#define BMP_MAX_NUMBER 4char bmp_path[4][100] = {"1.1.bmp", "1.2.bmp", "1.3.bmp", "1.4.bmp"};int slider_flag = 0;pid_t pid;pthread_mutex_t mutex;pthread_cond_t cond;//自界说函数:LCD屏幕显示bmp图片//pathname:必要打开的图片路径//x0:存放图片显示的x轴出发点//y0:存放图片显示的y轴出发点int lcd_show_bmp(char *pathname, int x0, int y0){        //1、打开装备文件        int lcd = open("/dev/fb0", O_RDWR);        if(-1 == lcd)        {                printf("lcd open error!\n");                return -2;        }                //2、内存映射        char *ptr =  (char *)mmap(NULL, 800*480*4, PROT_READ|PROT_WRITE,                         MAP_SHARED, lcd, 0);        if(NULL == ptr)        {                printf("mmap error!\n");                return -3;        }        //清除背景致        //bzero(ptr, 800*480*4);                //打开图片        int bmp = open(pathname, O_RDWR);        if(-1 == bmp)        {                printf("bmp open error!\n");                return -2;        }                //读取图片相关信息        int bmp_size, bmp_width, bmp_height;        //大小        lseek(bmp, 2, SEEK_SET);        read(bmp, &bmp_size, sizeof(bmp_size));                //宽度和高度        lseek(bmp, 18, SEEK_SET);        read(bmp, &bmp_width, sizeof(bmp_width));        read(bmp, &bmp_height, sizeof(bmp_height));                //读取图片的颜色数据        lseek(bmp, 54, SEEK_SET);        char *bmp_buf = malloc(bmp_size);        //申请空间        read(bmp, bmp_buf, bmp_width*bmp_height*3);                //对颜色数据举行处理惩罚(上下颠倒以及数据混乱)        int bmp_sum = 0;        int lcd_sum = 0;        for(int y=0; y+y0<480 && y<bmp_height; y++)        {                for(int x=0; x+x0<800 && x<bmp_width; x++)                {                        bmp_sum = 3*(x+((bmp_height-1-y)*bmp_width));                        lcd_sum = 4*(800*(y+y0)+x+x0);                                                //等号的坐标属于lcd屏幕, 等号的右边是bmp图像数据                        ptr[lcd_sum+0] = bmp_buf[bmp_sum+0]; //蓝色数据                        ptr[lcd_sum+1] = bmp_buf[bmp_sum+1]; //绿色数据                        ptr[lcd_sum+2] = bmp_buf[bmp_sum+2]; //红色数据                        ptr[lcd_sum+3] = bmp_buf[bmp_sum+3]; //透明度数据                }                //usleep(1);        }        munmap(ptr, 800*480*4);        free(bmp_buf);        //3、关闭文件        close(lcd);        close(bmp);}int touch_flag = 1;int ts_x, ts_y;int old_x = 300;int slider_left = 0;int slider_right = 0;int flag_x_y = 0;int right_left_slide_flag = 0;struct input_event ts;int flag_x = 0, flag_y = 0, first_press_flag = 0;//获取触摸屏坐标//自界说函数:获取触摸屏的坐标void get_touch(){    //1、打开装备文件    int touch_fd = open("/dev/input/event0", O_RDONLY);    if(-1 == touch_fd)    {        printf("event0 open error!\n");    }    while(1)    {        read(touch_fd, &ts, sizeof(ts));        //3、分析数据        if(EV_ABS == ts.type) //判断是否为触摸屏变乱        {            if(ABS_X == ts.code)//判断是否为x轴数据            {                ts_x = ts.value;                flag_x = 1;                    }            else if(ABS_Y == ts.code) //判断是否为y轴数据            {                ts_y = ts.value;                flag_y = 1;            }        }        if(EV_KEY == ts.type)        {                //刚触碰的坐标/长按时                if(ts.code == BTN_TOUCH && ts.value == 1)                {                        old_x = ts_x;                        first_press_flag = 1;                }        }                if(flag_x == 1 && flag_y == 1 && first_press_flag == 1)         {                flag_x = 0;                flag_y = 0;                pthread_mutex_lock(&mutex);                flag_x_y = 1;                  //黑色底板才必要执行如下操纵                ts_x = ts_x*800/1024;                ts_y = ts_y*480/600;                 pthread_mutex_unlock(&mutex);                pthread_cond_signal(&cond);                //break;                            }    if(EV_KEY == ts.type)        {                //松开                if(ts.code == BTN_TOUCH && ts.value == 0)                {                        //从左到右的滑动                        if(((ts_x > old_x) && (ts_x - old_x > 150) && (ts_x < 600)))                        {                                right_left_slide_flag = 1;                                slider_right = 1;                                                        old_x = 300;                        }                                //从右到左的滑动                        else if(((old_x > ts_x) && (old_x - ts_x > 150) && (old_x < 600)))                        {                                                                right_left_slide_flag = 1;                                slider_left = 1;                                old_x = 300;                        }                }        }    }    //4、关闭文件    close(touch_fd);}void *right_left_slide_func(void *arg)
  2. {
  3.         printf("enter right_left_slide_func\r\n");
  4.         while(1){
  5.                 if(right_left_slide_flag == 1){
  6.                         if(slider_left == 1){
  7.                                 touch_flag--;
  8.                                 if(touch_flag <= 0)
  9.                                         touch_flag = BMP_MAX_NUMBER;
  10.                                 lcd_show_bmp(bmp_path[touch_flag - 1], 0, 0);
  11.                                 slider_left = 0;
  12.                                 right_left_slide_flag == 0;
  13.                         }
  14.                         else if(slider_right == 1){
  15.                                 touch_flag++;
  16.                                 if(touch_flag > BMP_MAX_NUMBER)
  17.                                         touch_flag = 1;
  18.                                 lcd_show_bmp(bmp_path[touch_flag - 1], 0, 0);
  19.                                 slider_right = 0;
  20.                                 right_left_slide_flag == 0;
  21.                         }
  22.                         right_left_slide_flag == 0;
  23.                 }       
  24.         }
  25. }void *area_switch(void *arg)
  26. {
  27.         printf("enter area_switch\r\n");
  28.         while(1){
  29.                 pthread_mutex_lock(&mutex);
  30.                 while(flag_x_y == 0)
  31.                         pthread_cond_wait(&cond, &mutex);
  32.                 while(flag_x_y == 1){
  33.                         //上一张
  34.                         if((ts_y > 0 && ts_y < 120) && (ts_x > 600))
  35.                         {
  36.                                 touch_flag--;
  37.                                 if(touch_flag <= 0)
  38.                                         touch_flag = BMP_MAX_NUMBER;
  39.                
  40.                                 lcd_show_bmp(bmp_path[touch_flag - 1], 0, 0);
  41.                                 ts_x = 0;
  42.                                 ts_y = 0;
  43.                         }
  44.                         //下一张
  45.                         else if((ts_y > 120 && ts_y < 240) && (ts_x > 600))
  46.                         {
  47.                                 touch_flag++;
  48.                                 if(touch_flag > BMP_MAX_NUMBER)
  49.                                         touch_flag = 1;
  50.                
  51.                                 lcd_show_bmp(bmp_path[touch_flag - 1], 0, 0);
  52.                                 ts_x = 0;
  53.                                 ts_y = 0;
  54.                         }
  55.                         //幻灯片
  56.                         else if((ts_y > 240 && ts_y < 360) && (ts_x > 600))
  57.                         {
  58.                                 printf("click slider photo\r\n");
  59.                                 if(slider_flag == 0){
  60.                                         slider_flag = 1;
  61.                                 }
  62.                                 else{
  63.                                         slider_flag = 0;
  64.                                 }
  65.                                 printf("slider_flag = %d\r\n", slider_flag);
  66.                                 ts_x = 0;
  67.                                 ts_y = 0;
  68.                         }
  69.                         //息屏
  70.                         else if((ts_y > 360 && ts_y < 480) && (ts_x > 600))
  71.                         {
  72.                                 char command[] = "kill -9 ";
  73.                                 char str[10];
  74.                                 sprintf(str, "%d", pid);
  75.                                 strcat(command, str);
  76.                                 printf("command = %s\r\n", command);
  77.                                 //方式一:显示一张黑色的图片
  78.                                 lcd_show_bmp("black.bmp", 0, 0);
  79.                                 system(command);
  80.                         }
  81.                         else{
  82.                                 flag_x_y = 0;
  83.                                 break;
  84.                         }
  85.                         flag_x_y = 0;
  86.                 }
  87.                 pthread_mutex_unlock(&mutex);
  88.         }
  89.        
  90. }void *slider_func(void *arg)
  91. {
  92.         printf("enter slider_func : %d\r\n", pthread_self());
  93.         while(1){
  94.                 if(slider_flag == 1){
  95.                         printf("enter slider_func\r\n");
  96.                         touch_flag++;
  97.                         if(touch_flag > BMP_MAX_NUMBER)
  98.                                 touch_flag = 1;
  99.                         lcd_show_bmp(bmp_path[touch_flag - 1], 0, 0);
  100.                         sleep(1);
  101.                 }
  102.         }
  103. }int main()
  104. {
  105.         lcd_show_bmp("choice.bmp", 600, 0);
  106.         lcd_show_bmp(bmp_path[touch_flag - 1], 0, 0);
  107.         pthread_t tid, tid_area_switch, tid_right_left_slide;
  108.         int ret = 0;
  109.        
  110.         pthread_create(&tid, NULL, slider_func, NULL);
  111.         pthread_create(&tid_area_switch, NULL, area_switch, NULL);
  112.         pthread_create(&tid_right_left_slide, NULL, right_left_slide_func, NULL);
  113.         pthread_mutex_init(&mutex, NULL);
  114.         pthread_cond_init(&cond, NULL);
  115.        
  116.         printf("main thread = %ld\r\n", pthread_self());
  117.         pid = getpid();
  118.         printf("pid = %d\r\n", pid);
  119.         while(1){
  120.                 get_touch();
  121.         }
  122.        
  123.        
  124.         pthread_join(tid, NULL);
  125.         pthread_join(tid_area_switch, NULL);
  126.         pthread_join(tid_right_left_slide, NULL);
  127.         pthread_cond_destroy(&cond);
  128.         exit(0);
  129. }
复制代码
总结

以上就是本文的全部内容, 希望可以或许帮助到你。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4