Browse Source

:update index

0235699曾露 1 week ago
parent
commit
d5febe9be3
4 changed files with 443 additions and 64 deletions
  1. 350 41
      index.js
  2. 9 2
      project.config.json
  3. 17 21
      project.private.config.json
  4. 67 0
      utils/count.js

+ 350 - 41
index.js

@@ -48,12 +48,47 @@ Page({
     });
     });
 
 
     wx.setStorageSync("invite", null);
     wx.setStorageSync("invite", null);
-    let str = decodeURIComponent(options.q); //扫描二维码获得的跳转链接
-    let obj = this.getParaName(str)
-    if (obj && obj.invite) {
-      wx.setStorageSync("invite", obj.invite);
+    
+    // 处理扫码链接(options.q 包含完整的URL或activityId)
+    if (options.q) {
+      let str = decodeURIComponent(options.q); //扫描二维码获得的跳转链接
+      
+      // 检查是否是员工邀请链接(app.fmode.cn/dev/pobingfeng/manager/staff?invite=xxx)
+      if (str.includes('app.fmode.cn/dev/pobingfeng/manager/staff')) {
+        let obj = this.getParaName(str);
+        if (obj && obj.invite) {
+          wx.setStorageSync("invite", obj.invite);
+          console.log('✅ 检测到员工邀请链接,invite:', obj.invite);
+        }
+        // 员工邀请链接不需要跳转到店铺,直接返回
+        this.setData({ options: options });
+        plugin.init(config, wx.getStorageSync('invite'));
+        return;
+      }
+      
+      // 检查是否是活动海报二维码(activityId作为qrCode参数值)
+      // 如果str不包含http/https,且看起来像是一个ID,则可能是activityId
+      if (!str.includes('http://') && !str.includes('https://') && !str.includes('?')) {
+        // 可能是活动ID,尝试作为activityId处理
+        if (str && str.length > 0 && !isNaN(str)) {
+          options.activityId = str;
+          console.log('✅ 检测到活动海报二维码,activityId:', str);
+          // 活动二维码需要特殊处理,先保存activityId
+          wx.setStorageSync("activityId", str);
+        }
+      }
+      
+      // 处理店铺相关的二维码链接(pwa.fmode.cn/gomini/pmd/)
+      // 从完整URL中提取参数
+      if (str.includes('pwa.fmode.cn/gomini/pmd') || str.includes('?')) {
+        let obj = this.getParaName(str);
+        if (obj && obj.invite) {
+          wx.setStorageSync("invite", obj.invite);
+        }
+        // 将所有参数合并到 options 中
+        obj && Object.keys(obj).forEach(key=> options[key] = obj[key]);
+      }
     }
     }
-    obj && Object.keys(obj).forEach(key=> options[key] = obj[key])
     // 兼容从编译参数或页面直达传入的 storeId
     // 兼容从编译参数或页面直达传入的 storeId
     if (options && options.scene && !options.storeId) {
     if (options && options.scene && !options.storeId) {
       try {
       try {
@@ -160,6 +195,12 @@ Page({
         return
         return
       }
       }
       
       
+      // 检查是否需要跳转到活动页面
+      if (wx.getStorageSync('need_activity_redirect') === true) {
+        await this.redirectToActivityPage();
+        return;
+      }
+      
       // 检查是否需要跳转到扫码统计页面
       // 检查是否需要跳转到扫码统计页面
       if (this.shouldRedirectToScanPage()) {
       if (this.shouldRedirectToScanPage()) {
         await this.redirectToScanPage();
         await this.redirectToScanPage();
@@ -259,8 +300,13 @@ Page({
     if (!url || url.indexOf('?') == -1) {
     if (!url || url.indexOf('?') == -1) {
       return
       return
     }
     }
-    let paraname = url.split('?')[1]
-    return this.setObject(paraname) //封装成对象
+    // 提取查询参数部分(去除可能的hash部分)
+    let queryString = url.split('?')[1];
+    // 如果包含 #,只取 # 之前的部分
+    if (queryString.indexOf('#') !== -1) {
+      queryString = queryString.split('#')[0];
+    }
+    return this.setObject(queryString) //封装成对象
   },
   },
   setObject(paraArr) {
   setObject(paraArr) {
     let obj = {}
     let obj = {}
@@ -276,25 +322,99 @@ Page({
 
 
   /**
   /**
    * 检查并处理扫码参数
    * 检查并处理扫码参数
-   * 如果 URL 中包含 scanCount 和 partnerId,保存到临时存储
+   * 支持所有类型的二维码:
+   * 1. 推广员二维码: ?scanCount=0&storeId=xxx&userId=xxx
+   * 2. 产品二维码: ?scanCount=0&storeId=xxx&productId=xxx
+   * 3. 活动海报二维码: activityId作为qrCode参数值
+   * 4. 异业合作伙伴二维码(移动端 / PC端统一): ?scanCount=xxx&storeId=xxx&partnerId=xxx
+   * 5. 员工邀请二维码(移动端): ?scanCount=0&storeId=xxx&employeeId=xxx
+   * 6. 我的二维码(老板): ?scanCount=0&storeId=xxx&ownerId=xxx
+   * 7. 我的二维码(员工): ?scanCount=0&storeId=xxx&employeeId=xxx
    */
    */
   checkAndHandleScan(options) {
   checkAndHandleScan(options) {
-    const { scanCount, partnerId, storeId } = options;
+    const { 
+      scanCount, 
+      ownerId, 
+      employeeId, 
+      partnerId,
+      storeId,
+      productId,
+      userId,  // 推广员二维码使用userId
+      activityId
+    } = options;
     
     
-    // 如果存在 scanCount 和 partnerId,说明是扫码进入
-    if (scanCount !== undefined && partnerId) {
+    // 处理活动海报二维码(activityId作为qrCode参数值)
+    if (activityId && !storeId) {
+      console.log('===========================================');
+      console.log('======= 检测到活动海报二维码 =======');
+      console.log('活动ID (activityId):', activityId);
+      console.log('===========================================');
+      
+      // 活动二维码需要跳转到活动页面,不需要跳转到店铺
+      wx.setStorageSync('scan_activityId', activityId);
+      wx.setStorageSync('need_activity_redirect', true);
+      return;
+    }
+    
+    // 如果存在 storeId,说明是扫码进入具体门店(包括异业分享)
+    if (storeId) {
       console.log('===========================================');
       console.log('===========================================');
       console.log('======= 检测到扫码参数 =======');
       console.log('======= 检测到扫码参数 =======');
-      console.log('partnerId:', partnerId);
-      console.log('storeId:', storeId);
-      console.log('scanCount:', scanCount);
+      console.log('店铺ID (storeId):', storeId);
+      console.log('扫码次数 (scanCount):', scanCount || '0');
+      
+      // 确定来源类型
+      let sourceType = 'unknown';
+      let sourceId = null;
+      
+      if (employeeId) {
+        sourceType = 'employee';
+        sourceId = employeeId;
+        console.log('来源类型: 员工展业');
+        console.log('员工ID (employeeId):', employeeId);
+      } else if (userId) {
+        // 推广员二维码使用userId
+        sourceType = 'promoter';
+        sourceId = userId;
+        console.log('来源类型: 推广员展业');
+        console.log('推广员ID (userId):', userId);
+      } else if (ownerId) {
+        sourceType = 'owner';
+        sourceId = ownerId;
+        console.log('来源类型: 老板展业');
+        console.log('老板ID (ownerId):', ownerId);
+      } else if (partnerId) {
+        sourceType = 'partner';
+        sourceId = partnerId;
+        console.log('来源类型: 异业合作伙伴');
+        console.log('合作伙伴ID (partnerId):', partnerId);
+      } else {
+        sourceType = 'store';
+        console.log('来源类型: 店铺分享');
+      }
+      
+      if (productId) {
+        console.log('产品ID (productId):', productId);
+      }
+      
       console.log('===========================================');
       console.log('===========================================');
       
       
-      // 保存到临时存储,用于后续跳转
-      wx.setStorageSync('scan_partnerId', partnerId);
+      // 保存到临时存储,用于后续跳转和统计
       wx.setStorageSync('scan_storeId', storeId);
       wx.setStorageSync('scan_storeId', storeId);
-      wx.setStorageSync('scan_scanCount', scanCount);
+      wx.setStorageSync('scan_scanCount', scanCount || '0');
+      wx.setStorageSync('scan_sourceType', sourceType);
+      wx.setStorageSync('scan_sourceId', sourceId || '');
+      wx.setStorageSync('scan_ownerId', ownerId || '');
+      wx.setStorageSync('scan_employeeId', employeeId || '');
+      wx.setStorageSync('scan_partnerId', partnerId || '');
+      wx.setStorageSync('scan_userId', userId || '');
+      if (productId) {
+        wx.setStorageSync('scan_productId', productId);
+      }
       wx.setStorageSync('need_scan_redirect', true);
       wx.setStorageSync('need_scan_redirect', true);
+    } else if (partnerId) {
+      // 理论上异业二维码现在也必须带 storeId,这里仅作为兜底保护
+      console.warn('⚠️ 检测到异业合作伙伴二维码缺少 storeId,无法确定门店,请检查二维码生成逻辑');
     }
     }
   },
   },
 
 
@@ -306,59 +426,248 @@ Page({
   },
   },
 
 
   /**
   /**
-   * 跳转到扫码统计页面
-   * 构建完整的 H5 URL 并跳转到 web-view 页面
+   * 跳转到扫码对应的店铺页面
+   * 根据 storeId 跳转到对应店铺,同时记录所有来源信息用于统计
    */
    */
   async redirectToScanPage() {
   async redirectToScanPage() {
     try {
     try {
-      const partnerId = wx.getStorageSync('scan_partnerId');
+      // 获取所有扫码相关参数
       const storeId = wx.getStorageSync('scan_storeId');
       const storeId = wx.getStorageSync('scan_storeId');
       const scanCount = wx.getStorageSync('scan_scanCount');
       const scanCount = wx.getStorageSync('scan_scanCount');
+      const sourceType = wx.getStorageSync('scan_sourceType');
+      const sourceId = wx.getStorageSync('scan_sourceId');
+      const ownerId = wx.getStorageSync('scan_ownerId');
+      const employeeId = wx.getStorageSync('scan_employeeId');
+      const partnerId = wx.getStorageSync('scan_partnerId');
+      const userId = wx.getStorageSync('scan_userId');
+      const productId = wx.getStorageSync('scan_productId');
       
       
       // 清除临时存储
       // 清除临时存储
-      wx.removeStorageSync('scan_partnerId');
       wx.removeStorageSync('scan_storeId');
       wx.removeStorageSync('scan_storeId');
       wx.removeStorageSync('scan_scanCount');
       wx.removeStorageSync('scan_scanCount');
+      wx.removeStorageSync('scan_sourceType');
+      wx.removeStorageSync('scan_sourceId');
+      wx.removeStorageSync('scan_ownerId');
+      wx.removeStorageSync('scan_employeeId');
+      wx.removeStorageSync('scan_partnerId');
+      wx.removeStorageSync('scan_userId');
+      wx.removeStorageSync('scan_productId');
       wx.removeStorageSync('need_scan_redirect');
       wx.removeStorageSync('need_scan_redirect');
       
       
-      if (!partnerId || !storeId) {
-        console.error('❌ 缺少必要参数,无法跳转');
+      if (!storeId) {
+        console.error('❌ 缺少 storeId 参数,无法跳转');
         return;
         return;
       }
       }
       
       
-      // 获取当前用户的 sessionToken
-      const currentUser = Parse.User.current();
-      const token = currentUser ? currentUser.getSessionToken() : '';
+      console.log('===========================================');
+      console.log('======= 扫码进入店铺 =======');
+      console.log('店铺 ID (storeId):', storeId);
+      console.log('来源类型 (sourceType):', sourceType);
+      console.log('来源 ID (sourceId):', sourceId || '无');
+      console.log('扫码次数 (scanCount):', scanCount);
+      if (ownerId) console.log('老板 ID (ownerId):', ownerId);
+      if (employeeId) console.log('员工 ID (employeeId):', employeeId);
+      if (partnerId) console.log('合作伙伴 ID (partnerId):', partnerId);
+      if (userId) console.log('推广员 ID (userId):', userId);
+      if (productId) console.log('产品 ID (productId):', productId);
+      console.log('===========================================');
+      
+      // 设置店铺 ID 到全局和本地存储
+      wx.setStorageSync('storeId', storeId);
+      getApp().globalData.storeId = storeId;
       
       
-      // 构建 H5 URL
-      const h5Url = `https://pwa.fmode.cn/gomini/pmd/`;
+      // 保存来源信息到本地存储(用于后续统计或绑定关系)
+      if (sourceId) {
+        wx.setStorageSync('scan_from_sourceType', sourceType);
+        wx.setStorageSync('scan_from_sourceId', sourceId);
+        console.log('✅ 已记录来源信息:', sourceType, sourceId);
+      }
+      
+      // 记录扫码统计(调用后端接口记录扫码次数)
+      await this.recordScanStatistics({
+        storeId,
+        sourceType,
+        sourceId,
+        ownerId,
+        employeeId,
+        partnerId,
+        userId,
+        productId,
+        scanCount
+      });
       
       
-      // 手动构建查询参数(兼容小程序环境)
-      const params = [];
-      params.push(`scanCount=${scanCount || '1'}`);
-      params.push(`storeId=${storeId}`);
-      params.push(`partnerId=${partnerId}`);
+      // 获取默认首页路径并跳转
+      let url = getApp().globalData.rootPage || getApp().globalData.defaultTabBar.list[0].pagePath;
+      url += `?storeId=${storeId}`;
       
       
-      if (token) {
-        params.push(`token=${encodeURIComponent(token)}`);
+      // 如果有产品ID,添加到URL参数中
+      if (productId) {
+        url += `&productId=${productId}`;
       }
       }
       
       
-      const fullUrl = `${h5Url}?${params.join('&')}`;
+      console.log('✅ 跳转到店铺页面:', url);
+      
+      wx.redirectTo({
+        url: url,
+        fail: (err) => {
+          console.error('❌ 跳转失败:', err);
+          // 如果 redirectTo 失败,尝试 reLaunch
+          wx.reLaunch({
+            url: url,
+            fail: (err2) => {
+              console.error('❌ reLaunch 也失败:', err2);
+            }
+          });
+        }
+      });
+    } catch (error) {
+      console.error('❌ 跳转到店铺页面失败:', error);
+    }
+  },
+  
+  /**
+   * 跳转到活动页面
+   */
+  async redirectToActivityPage() {
+    try {
+      const activityId = wx.getStorageSync('scan_activityId');
+      
+      // 清除临时存储
+      wx.removeStorageSync('scan_activityId');
+      wx.removeStorageSync('need_activity_redirect');
+      
+      if (!activityId) {
+        console.error('❌ 缺少 activityId 参数,无法跳转');
+        return;
+      }
       
       
       console.log('===========================================');
       console.log('===========================================');
-      console.log('======= 跳转到扫码统计页面 =======');
-      console.log('完整 URL:', fullUrl);
+      console.log('======= 扫码进入活动页面 =======');
+      console.log('活动 ID (activityId):', activityId);
       console.log('===========================================');
       console.log('===========================================');
       
       
-      // 跳转到 web-view 页面
+      // 保存活动ID
+      wx.setStorageSync('activityId', activityId);
+      
+      // 获取默认首页路径并跳转(活动页面可能需要根据实际路由调整)
+      let url = getApp().globalData.rootPage || getApp().globalData.defaultTabBar.list[0].pagePath;
+      url += `?activityId=${activityId}`;
+      
+      console.log('✅ 跳转到活动页面:', url);
+      
       wx.redirectTo({
       wx.redirectTo({
-        url: `/common-page/pages/web-view/index?path=${encodeURIComponent(fullUrl)}`,
+        url: url,
         fail: (err) => {
         fail: (err) => {
           console.error('❌ 跳转失败:', err);
           console.error('❌ 跳转失败:', err);
+          wx.reLaunch({
+            url: url,
+            fail: (err2) => {
+              console.error('❌ reLaunch 也失败:', err2);
+            }
+          });
         }
         }
       });
       });
     } catch (error) {
     } catch (error) {
-      console.error('❌ 跳转到扫码页面失败:', error);
+      console.error('❌ 跳转到活动页面失败:', error);
+    }
+  },
+  
+  /**
+   * 记录扫码统计信息
+   * @param {Object} params - 扫码参数对象
+   * @param {string} params.storeId - 店铺 ID
+   * @param {string} params.sourceType - 来源类型 (employee/owner/partner/promoter/store)
+   * @param {string} params.sourceId - 来源 ID
+   * @param {string} params.ownerId - 老板 ID
+   * @param {string} params.employeeId - 员工 ID
+   * @param {string} params.partnerId - 合作伙伴 ID
+   * @param {string} params.userId - 推广员 ID
+   * @param {string} params.productId - 产品 ID
+   * @param {string} params.scanCount - 扫码次数
+   */
+  async recordScanStatistics(params) {
+    try {
+      const {
+        storeId,
+        sourceType,
+        sourceId,
+        ownerId,
+        employeeId,
+        partnerId,
+        userId,
+        productId,
+        scanCount
+      } = params;
+      
+      // 如果没有来源信息,不记录统计
+      if (!sourceId && !ownerId && !employeeId && !partnerId && !userId) {
+        console.log('ℹ️ 无来源信息,跳过统计记录');
+        return;
+      }
+      
+      // 创建扫码记录
+      const ScanRecord = Parse.Object.extend('ScanRecord');
+      const record = new ScanRecord();
+      
+      record.set('company', {
+        __type: 'Pointer',
+        className: 'Company',
+        objectId: getApp().globalData.company
+      });
+      record.set('storeId', storeId);
+      record.set('sourceType', sourceType || 'unknown');
+      record.set('scanCount', parseInt(scanCount) || 0);
+      record.set('scanTime', new Date());
+      
+      // 根据来源类型设置对应的ID
+      if (ownerId) {
+        record.set('ownerId', ownerId);
+      }
+      if (employeeId) {
+        record.set('employeeId', employeeId);
+      }
+      if (partnerId) {
+        record.set('partnerId', partnerId);
+      }
+      if (userId) {
+        record.set('userId', userId);
+      }
+      if (productId) {
+        record.set('productId', productId);
+      }
+      
+      // 如果用户已登录,记录扫码用户
+      const currentUser = Parse.User.current();
+      if (currentUser) {
+        record.set('user', {
+          __type: 'Pointer',
+          className: '_User',
+          objectId: currentUser.id
+        });
+      }
+      
+      await record.save();
+      console.log('✅ 扫码记录已保存');
+
+      // 如果存在异业合作伙伴ID,则在其 scanCount 字段上自增 1(数据库中的 Partner 表)
+      if (partnerId) {
+        try {
+          const Partner = Parse.Object.extend('Partner');
+          const partnerQuery = new Parse.Query(Partner);
+          const partnerObj = await partnerQuery.get(partnerId);
+
+          if (partnerObj) {
+            partnerObj.increment('scanCount', 1);
+            await partnerObj.save();
+            console.log('✅ 已为异业合作伙伴累加一次扫码次数,partnerId:', partnerId);
+          }
+        } catch (e) {
+          console.warn('⚠️ 更新异业合作伙伴扫码次数失败:', e);
+        }
+      }
+    } catch (error) {
+      console.warn('⚠️ 保存扫码记录失败:', error);
+      // 不影响主流程
     }
     }
   }
   }
 });
 });

+ 9 - 2
project.config.json

@@ -36,7 +36,12 @@
     "showES6CompileOption": false,
     "showES6CompileOption": false,
     "useCompilerPlugins": false,
     "useCompilerPlugins": false,
     "ignoreUploadUnusedFiles": true,
     "ignoreUploadUnusedFiles": true,
-    "useApiHostProcess": false
+    "useApiHostProcess": false,
+    "compileWorklet": false,
+    "localPlugins": false,
+    "condition": false,
+    "swc": false,
+    "disableSWC": true
   },
   },
   "compileType": "miniprogram",
   "compileType": "miniprogram",
   "cloudfunctionTemplateRoot": "",
   "cloudfunctionTemplateRoot": "",
@@ -67,5 +72,7 @@
     ],
     ],
     "include": []
     "include": []
   },
   },
-  "appid": "wxbb048b80cd2a14b9"
+  "appid": "wxbb048b80cd2a14b9",
+  "libVersion": "3.6.6",
+  "simulatorPluginLibVersion": {}
 }
 }

+ 17 - 21
project.private.config.json

@@ -1,9 +1,23 @@
 {
 {
   "description": "项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html",
   "description": "项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html",
   "setting": {
   "setting": {
-    "compileHotReLoad": false,
+    "compileHotReLoad": true,
     "urlCheck": true,
     "urlCheck": true,
-    "preloadBackgroundData": false
+    "preloadBackgroundData": false,
+    "coverView": true,
+    "lazyloadPlaceholderEnable": false,
+    "skylineRenderEnable": false,
+    "autoAudits": false,
+    "useApiHook": true,
+    "useApiHostProcess": false,
+    "showShadowRootInWxmlPanel": true,
+    "useStaticServer": false,
+    "useLanDebug": false,
+    "showES6CompileOption": false,
+    "checkInvalidKey": true,
+    "ignoreDevUnusedFiles": true,
+    "bigPackageSizeSupport": false,
+    "useIsolateContext": true
   },
   },
   "game": {
   "game": {
     "list": []
     "list": []
@@ -16,23 +30,5 @@
   },
   },
   "libVersion": "3.6.6",
   "libVersion": "3.6.6",
   "projectname": "nova-wapp",
   "projectname": "nova-wapp",
-  "condition": {
-    "miniprogram": {
-      "list": [
-        {
-          "name": "nova-pbf/pages/index/index",
-          "pathName": "nova-pbf/pages/index/index",
-          "query": "storeId=ARhMGM5Y1W",
-          "launchMode": "default",
-          "scene": null
-        },
-        {
-          "name": "nova-vbank/pages/home/activity/index",
-          "pathName": "nova-vbank/pages/home/activity/index",
-          "query": "regid=A2Y8jMWLjN",
-          "scene": null
-        }
-      ]
-    }
-  }
+  "condition": {}
 }
 }

+ 67 - 0
utils/count.js

@@ -1,3 +1,69 @@
+/**
+ * 处理扫描的二维码链接
+ * @param {string} qrUrl - 扫描到的二维码链接
+ * @returns {Object} 解析后的二维码信息
+ */
+function processQRCode(qrUrl) {
+  // 解析URL参数
+  const parseUrlParams = (url) => {
+    try {
+      const query = url.split('?')[1];
+      if (!query) return {};
+      
+      return query.split('&').reduce((params, param) => {
+        const [key, value] = param.split('=');
+        if (key && value !== undefined) {
+          params[key] = decodeURIComponent(value);
+        }
+        return params;
+      }, {});
+    } catch (e) {
+      console.error('解析二维码链接失败:', e);
+      return {};
+    }
+  };
+
+  // 更新扫码次数(加1)
+  const updateScanCount = (params) => {
+    if (params.scanCount !== undefined) {
+      params.scanCount = parseInt(params.scanCount || '0', 10) + 1;
+    }
+    return params;
+  };
+
+  // 确定来源类型和ID
+  const determineSource = (params) => {
+    if (params.employeeId) {
+      return { type: 'employee', id: params.employeeId };
+    } else if (params.ownerId) {
+      return { type: 'owner', id: params.ownerId };
+    } else if (params.partnerId) {
+      return { type: 'partner', id: params.partnerId };
+    }
+    return { type: 'unknown', id: null };
+  };
+
+  // 主处理逻辑
+  const params = parseUrlParams(qrUrl);
+  if (!params.storeId) {
+    throw new Error('无效的二维码:缺少店铺ID');
+  }
+
+  // 更新扫码次数
+  const updatedParams = updateScanCount(params);
+  
+  // 确定来源
+  const source = determineSource(updatedParams);
+
+  return {
+    storeId: updatedParams.storeId,
+    sourceType: source.type,
+    sourceId: source.id,
+    scanCount: updatedParams.scanCount || 1,
+    rawParams: updatedParams
+  };
+}
+
 //加法
 //加法
 function addNum(arg1, arg2) {
 function addNum(arg1, arg2) {
   arg1 = arg1 ? arg1 : 0
   arg1 = arg1 ? arg1 : 0
@@ -82,6 +148,7 @@ function multiply(arg1, arg2) {
 }
 }
 
 
 module.exports = {
 module.exports = {
+  processQRCode,
   addNum,
   addNum,
   subtraction,
   subtraction,
   multiply
   multiply