Procházet zdrojové kódy

初始化 船东小程序

wzh před 3 roky
rodič
revize
ff01c41927
56 změnil soubory, kde provedl 2587 přidání a 2 odebrání
  1. 11 2
      README.md
  2. 36 0
      cloudfunctions/api/WXBizDataCrypt.js
  3. 6 0
      cloudfunctions/api/config.json
  4. 117 0
      cloudfunctions/api/index.js
  5. 17 0
      cloudfunctions/api/package.json
  6. 17 0
      miniprogram/apis/api.js
  7. 26 0
      miniprogram/apis/apiConfig.js
  8. 22 0
      miniprogram/apis/cloudApi.js
  9. 57 0
      miniprogram/app.js
  10. 29 0
      miniprogram/app.json
  11. 34 0
      miniprogram/app.wxss
  12. 6 0
      miniprogram/envList.js
  13. binární
      miniprogram/images/index.png
  14. 237 0
      miniprogram/pages/cachePage/cachePage.js
  15. 3 0
      miniprogram/pages/cachePage/cachePage.json
  16. 52 0
      miniprogram/pages/cachePage/cachePage.wxml
  17. 50 0
      miniprogram/pages/cachePage/cachePage.wxss
  18. 67 0
      miniprogram/pages/index/index.js
  19. 3 0
      miniprogram/pages/index/index.json
  20. 3 0
      miniprogram/pages/index/index.wxml
  21. 31 0
      miniprogram/pages/index/index.wxss
  22. 338 0
      miniprogram/pages/newCachePage/newCachePage.js
  23. 3 0
      miniprogram/pages/newCachePage/newCachePage.json
  24. 55 0
      miniprogram/pages/newCachePage/newCachePage.wxml
  25. 50 0
      miniprogram/pages/newCachePage/newCachePage.wxss
  26. 31 0
      miniprogram/pages/share/share.js
  27. 5 0
      miniprogram/pages/share/share.json
  28. 6 0
      miniprogram/pages/share/share.wxml
  29. 34 0
      miniprogram/pages/share/share.wxss
  30. 116 0
      miniprogram/pages/takeBill/canvas/canvas.js
  31. 3 0
      miniprogram/pages/takeBill/canvas/canvas.json
  32. 4 0
      miniprogram/pages/takeBill/canvas/canvas.wxml
  33. 1 0
      miniprogram/pages/takeBill/canvas/canvas.wxss
  34. 30 0
      miniprogram/pages/takeBill/success/success.js
  35. 4 0
      miniprogram/pages/takeBill/success/success.json
  36. 4 0
      miniprogram/pages/takeBill/success/success.wxml
  37. 1 0
      miniprogram/pages/takeBill/success/success.wxss
  38. 125 0
      miniprogram/pages/takeBill/takeBill.js
  39. 4 0
      miniprogram/pages/takeBill/takeBill.json
  40. 13 0
      miniprogram/pages/takeBill/takeBill.wxml
  41. 93 0
      miniprogram/pages/takeBill/takeBill.wxss
  42. 31 0
      miniprogram/pages/takePhoto/success/success.js
  43. 3 0
      miniprogram/pages/takePhoto/success/success.json
  44. 4 0
      miniprogram/pages/takePhoto/success/success.wxml
  45. 48 0
      miniprogram/pages/takePhoto/success/success.wxss
  46. 297 0
      miniprogram/pages/takePhoto/takePhoto.js
  47. 3 0
      miniprogram/pages/takePhoto/takePhoto.json
  48. 35 0
      miniprogram/pages/takePhoto/takePhoto.wxml
  49. 154 0
      miniprogram/pages/takePhoto/takePhoto.wxss
  50. 7 0
      miniprogram/sitemap.json
  51. 22 0
      miniprogram/utils/upload.js
  52. 57 0
      miniprogram/utils/wxUtils.js
  53. 81 0
      project.config.json
  54. 79 0
      project.private.config.json
  55. 1 0
      uploadCloudFunction.sh
  56. 21 0
      隐私协议.txt

+ 11 - 2
README.md

@@ -1,3 +1,12 @@
-# ShipOwner_WxApp
+# 云开发 quickstart
+
+这是云开发的快速启动指引,其中演示了如何上手使用云开发的三大基础能力:
+
+- 数据库:一个既可在小程序前端操作,也能在云函数中读写的 JSON 文档型数据库
+- 文件存储:在小程序前端直接上传/下载云端文件,在云开发控制台可视化管理
+- 云函数:在云端运行的代码,微信私有协议天然鉴权,开发者只需编写业务逻辑代码
+
+## 参考文档
+
+- [云开发文档](https://developers.weixin.qq.com/miniprogram/dev/wxcloud/basis/getting-started.html)
 
-船东小程序

+ 36 - 0
cloudfunctions/api/WXBizDataCrypt.js

@@ -0,0 +1,36 @@
+var crypto = require('crypto')
+
+function WXBizDataCrypt(appId, sessionKey) {
+  this.appId = appId
+  this.sessionKey = sessionKey
+}
+
+WXBizDataCrypt.prototype.decryptData = function (encryptedData, iv) {
+  // base64 decode
+  var sessionKey = new Buffer(this.sessionKey, 'base64')
+  encryptedData = new Buffer(encryptedData, 'base64')
+  iv = new Buffer(iv, 'base64')
+
+  try {
+    // 解密
+    var decipher = crypto.createDecipheriv('aes-128-cbc', sessionKey, iv)
+    // 设置自动 padding 为 true,删除填充补位
+    decipher.setAutoPadding(true)
+    // var decoded = decipher.update(encryptedData, 'binary', 'utf8')
+    var decoded = decipher.update(encryptedData, '', 'utf8')
+    decoded += decipher.final('utf8')
+
+    decoded = JSON.parse(decoded)
+
+  } catch (err) {
+    throw new Error('Illegal Buffer')
+  }
+
+  if (decoded.watermark.appid !== this.appId) {
+    throw new Error('Illegal Buffer')
+  }
+
+  return decoded
+}
+
+module.exports = WXBizDataCrypt

+ 6 - 0
cloudfunctions/api/config.json

@@ -0,0 +1,6 @@
+{
+  "permissions": {
+    "openapi": [
+    ]
+  }
+}

+ 117 - 0
cloudfunctions/api/index.js

@@ -0,0 +1,117 @@
+// 云函数入口文件
+const cloud = require('wx-server-sdk')
+const TcbRouter = require("tcb-router")
+const got = require('got')
+const md5 = require("md5")
+const APPID = "wxf22759845920b6f3"
+const SECRET = "149873f78958781cd1693c1238deaebc"
+const WXBizDataCrypt = require('./WXBizDataCrypt')
+
+cloud.init()
+
+const db = cloud.database()
+const errorLogs = db.collection("huihenduo_error_log")
+
+// 云函数入口函数
+exports.main = async (event, context) => {
+  const wxContext = cloud.getWXContext()
+  const _openid = wxContext.OPENID
+
+  const app = new TcbRouter({
+    event
+  });
+
+  console.log('Event', event)
+
+  app.use(async (ctx, next) => {
+    ctx.data = {};
+    await next();
+  });
+
+
+  app.router("getWxPhoneNumber", async (ctx, next) => {
+    let {
+      cloudID,
+      encryptedData,
+      errMsg,
+      iv,
+      session_key
+    } = event
+    console.log(event)
+
+    let pc = new WXBizDataCrypt(APPID, session_key)
+
+    let data = pc.decryptData(encryptedData, iv)
+
+    ctx.body = {
+      phone: data.phoneNumber,
+      _openid
+    }
+    await next()
+  })
+
+  app.router("getOpenId", async (ctx, next) => {
+    ctx.body = {
+      openId: _openid
+    }
+    await next()
+  })
+  app.router("sendError", async (ctx, next) => {
+    delete event.$url
+    delete event.userInfo
+    let res = await errorLogs.add({
+      data: {
+        createTime: db.serverDate(),
+        ...event,
+        _openid,
+      }
+    })
+    await next()
+  })
+
+  app.router("base", async (ctx, next) => {
+
+    await next()
+  })
+
+  app.router("code2Session", async (ctx, next) => {
+    let JSCODE = event.JSCODE
+    let url = `https://api.weixin.qq.com/sns/jscode2session?appid=${APPID}&secret=${SECRET}&js_code=${JSCODE}&grant_type=authorization_code`
+
+    let res = await got(url)
+    let result = JSON.parse(res.body)
+    ctx.body = {
+      ...result,
+      _openid
+    }
+
+    await next()
+  })
+
+
+
+  app.router("getAccessToken", async (ctx, next) => {
+    let tokenUrl = `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${APPID}&secret=${SECRET}`
+
+
+    let res = await got(tokenUrl)
+    let {
+      access_token
+    } = JSON.parse(res.body)
+    console.log(access_token)
+    ctx.data = {
+      access_token
+    }
+    await next();
+  });
+
+
+  app.router("getOpenId", async (ctx, next) => {
+    ctx.data = {
+      openId: _openid
+    }
+    await next();
+  });
+
+  return app.serve();
+}

+ 17 - 0
cloudfunctions/api/package.json

@@ -0,0 +1,17 @@
+{
+  "name": "api",
+  "version": "1.0.0",
+  "main": "index.js",
+  "scripts": {
+    "test": "echo \"Error: no test specified\" && exit 1"
+  },
+  "author": "",
+  "license": "ISC",
+  "dependencies": {
+    "wx-server-sdk": "~2.5.3",
+    "md5": "^2.3.0",
+    "got": "^11.8.2",
+    "tcb-router": "^1.1.2"
+  },
+  "description": ""
+}

+ 17 - 0
miniprogram/apis/api.js

@@ -0,0 +1,17 @@
+const {
+  api
+} = require("./apiConfig")
+
+function getApi(url, data) {
+  return api(url, data, "get")
+}
+
+function postApi(url, data) {
+  return api(url, data, "post")
+
+}
+
+module.exports = {
+  getApi,
+  postApi
+}

+ 26 - 0
miniprogram/apis/apiConfig.js

@@ -0,0 +1,26 @@
+let v = wx.getAccountInfoSync()
+let {
+  envVersion
+} = v.miniProgram
+let apiUrl = `${envVersion == 'release'?'https://interface.huihenduo.cc/hhd-ship/':'https://interface.huihenduo.cc/hhd-ship-dev/'}`
+
+function api(url, data, method) {
+  return new Promise((resolve, reject) => {
+    wx.request({
+      url: `${apiUrl}/${url}`,
+      method,
+      data,
+      dataType: 'json',
+      header: {
+        'content-type': 'application/json'
+      },
+      success: resolve,
+      fail: reject
+    })
+  })
+}
+
+module.exports = {
+  apiUrl,
+  api
+}

+ 22 - 0
miniprogram/apis/cloudApi.js

@@ -0,0 +1,22 @@
+module.exports = async function cloudApi($url, data) {
+  if ($url == "sendError") {
+    let res = getCurrentPages()
+    let v = wx.getAccountInfoSync()
+    data.path = res[res.length - 1].route
+    data.env = v.miniProgram.envVersion
+
+    if (data.error) {
+      data.error = data.error.toString()
+    }
+    if (v.miniProgram.version) {
+      data.appVersion = v.miniProgram.version
+    }
+  }
+  return await wx.cloud.callFunction({
+    name: "api",
+    data: {
+      $url,
+      ...data
+    }
+  })
+}

+ 57 - 0
miniprogram/app.js

@@ -0,0 +1,57 @@
+import {
+  wxSetSessionKey,
+  getOpenId
+} from "./utils/wxUtils"
+App({
+  onLaunch: function () {
+    const updateManager = wx.getUpdateManager()
+
+    updateManager.onCheckForUpdate(function (res) {
+      // 请求完新版本信息的回调
+    })
+
+    updateManager.onUpdateReady(function () {
+      wx.showModal({
+        title: '更新提示',
+        content: '新版本已经准备好,是否重启应用?',
+        success: function (res) {
+          if (res.confirm) {
+            // 新的版本已经下载好,调用 applyUpdate 应用新版本并重启
+            updateManager.applyUpdate()
+          }
+        }
+      })
+    })
+
+    updateManager.onUpdateFailed(function () {
+      // 新版本下载失败
+    })
+
+
+    wx.cloud.init({
+      traceUser: true
+    })
+    this.globalData = {}
+  },
+  onShow() {
+    this.checkEnvVersion()
+  },
+  checkEnvVersion() {
+    let v = wx.getAccountInfoSync()
+    let appVersion = wx.getStorageSync('appVersion')
+    let {
+      envVersion
+    } = v.miniProgram
+    if (appVersion != envVersion) {
+      wx.clearStorage({
+        success: (res) => {
+          wx.setStorageSync('appVersion', envVersion)
+          wx.redirectTo({
+            url: '/pages/index/index',
+          })
+        },
+      })
+    }
+    wxSetSessionKey()
+  }
+})

+ 29 - 0
miniprogram/app.json

@@ -0,0 +1,29 @@
+{
+  "pages": [
+    "pages/index/index",
+    "pages/takePhoto/takePhoto",
+    "pages/cachePage/cachePage",
+    "pages/takePhoto/success/success",
+    "pages/share/share",
+    "pages/newCachePage/newCachePage",
+    "pages/takeBill/takeBill",
+    "pages/takeBill/success/success",
+    "pages/takeBill/canvas/canvas"
+  ],
+  "window": {
+    "backgroundColor": "#F6F6F6",
+    "backgroundTextStyle": "light",
+    "navigationBarBackgroundColor": "#F6F6F6",
+    "navigationBarTitleText": "汇很多",
+    "navigationBarTextStyle": "black",
+    "navigationStyle": "custom",
+    "pageOrientation": "portrait"
+  },
+  "permission": {
+    "scope.userLocation": {
+      "desc": "你的位置信息将用于小程序位置接口的效果展示"
+    }
+  },
+  "sitemapLocation": "sitemap.json",
+  "style": "v2"
+}

+ 34 - 0
miniprogram/app.wxss

@@ -0,0 +1,34 @@
+page {
+  width: 100%;
+  height: 100%;
+}
+
+view {
+  box-sizing: border-box
+}
+
+.df {
+  display: flex;
+}
+
+.mt100 {
+  margin-top: 100rpx
+}
+
+.mb30 {
+  margin-bottom: 30rpx;
+}
+
+.line {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+}
+
+.tac {
+  text-align: center;
+}
+
+.aic {
+  align-items: center;
+}

+ 6 - 0
miniprogram/envList.js

@@ -0,0 +1,6 @@
+const envList = [{"envId":"huihenduo-0gwuxs6d1c6824e4","alias":"huihenduo"}]
+const isMac = true
+module.exports = {
+    envList,
+    isMac
+}

binární
miniprogram/images/index.png


+ 237 - 0
miniprogram/pages/cachePage/cachePage.js

@@ -0,0 +1,237 @@
+// pages/cachePage/cachePage.js
+import cloudApi from "../../apis/cloudApi"
+import {
+  postApi
+} from "../../apis/api"
+import {
+  uploadFile
+} from "../../utils/upload"
+
+Page({
+
+  /**
+   * 页面的初始数据
+   */
+  data: {
+    type: "",
+    file: "",
+    latitude: "",
+    longitude: "",
+    shipName: "",
+    shipMmsi: "",
+    agreeModal: false,
+    agreeText: false
+  },
+  goBack() {
+    wx.redirectTo({
+      url: '/pages/index/index',
+    })
+  },
+  checkout() {
+    if (!this.data.shipName) {
+      wx.showToast({
+        title: '请输入船名!',
+        icon: "error"
+      })
+      return
+    }
+
+    if (!this.data.shipMmsi) {
+      wx.showToast({
+        title: '请输入MMSI!',
+        icon: "error"
+      })
+      return
+    }
+
+    return true
+  },
+  agree() {
+    this.setData({
+      agreeText: false,
+    })
+  },
+
+  showAgeeeText() {
+    this.setData({
+      agreeText: true
+    })
+  },
+  hideAgreeText() {
+    this.setData({
+      agreeText: false
+    })
+  },
+  hideAgreeModal() {
+    this.setData({
+      agreeModal: false
+    })
+  },
+  showAgreeModal() {
+    // if (!this.checkout()) return
+    this.setData({
+      agreeModal: true
+    })
+  },
+  async getPhoneNumber(e) {
+    try {
+      if (e.detail.errMsg == "getPhoneNumber:ok") {
+        wx.showLoading({
+          title: '正在登录...',
+          mask: true
+        })
+        let session_key = wx.getStorageSync('session_key')
+        let {
+          result
+        } = await cloudApi("getWxPhoneNumber", {
+          ...e.detail,
+          session_key
+        })
+        let {
+          phone,
+        } = result
+        if (phone) {
+          wx.setStorageSync('phone', phone)
+          let {
+            shipName,
+            shipMmsi
+          } = this.data
+          try {
+            let res = await uploadFile(wx.getStorageSync('file'), {
+              openId: wx.getStorageSync('openId'),
+              phone,
+              shipName,
+              shipMmsi,
+              type: wx.getStorageSync('type'),
+              location: `${this.data.longitude},${this.data.latitude}`
+            }, 1)
+            if (res.status == 0) {
+              wx.setStorageSync('shareImageUrl', res.result.mediaInfo.viewUrl)
+              let {
+                shipInfo,
+                userInfo
+              } = res.result
+
+              let data = {
+                ...shipInfo,
+                ...userInfo
+              }
+              Object.keys(data).forEach(function (key) {
+                wx.setStorageSync(key, data[key])
+              })
+              wx.showToast({
+                title: res.msg,
+              })
+              wx.downloadFile({
+                url: res.result.mediaInfo.viewUrl,
+                success: e => {
+                  console.log("下载调用!", e)
+                  wx.setStorageSync('cacheImage', e.tempFilePath)
+                  wx.saveImageToPhotosAlbum({
+                    filePath: e.tempFilePath,
+                    success: e => {
+                      console.log(5, e)
+
+                      if (e.errMsg == "saveImageToPhotosAlbum:ok") {
+                        wx.showToast({
+                          title: '保存成功!',
+                        })
+                        wx.removeStorageSync('cacheImage')
+                      }
+                    },
+                    fail: async e => {
+                      console.log("6", e)
+                      wx.hideLoading({})
+                      wx.showToast({
+                        title: '保存失败!',
+                        duration: 5000
+                      })
+                      await cloudApi('sendError', {
+                        e,
+                        flag: 4,
+                        msg: "保存失败"
+                      })
+                      this.setData({
+                        authModal: true,
+                        modalText: "文件存储"
+                      })
+                    }
+                  })
+                  wx.navigateTo({
+                    url: '/pages/takePhoto/success/success',
+                  })
+                },
+                fail: async e => {
+                  wx.hideLoading({})
+                  wx.showToast({
+                    title: '下载失败!',
+                    duration: 5000
+                  })
+                  await cloudApi('sendError', {
+                    e,
+                    msg: "下载失败",
+                    flag: 3
+                  })
+                }
+              })
+            } else {
+              wx.hideLoading({})
+              await cloudApi('sendError', {
+                res,
+                flag: 2
+              })
+              wx.showToast({
+                title: res.msg,
+                icon: "error"
+              })
+            }
+          } catch (error) {
+            await cloudApi('sendError', {
+              error,
+              flag: 1
+            })
+          }
+        } else {
+          wx.hideLoading({})
+          wx.showToast({
+            title: '获取手机号失败',
+            duration: 5000
+          })
+          await cloudApi('sendError', {
+            msg: "获取手机号失败"
+          })
+        }
+      } else {
+        wx.showToast({
+          title: '请授权以登录',
+          icon: "error"
+        })
+        await cloudApi('sendError', {
+          msg: "未授权手机号"
+        })
+      }
+    } catch (error) {
+      await cloudApi('sendError', {
+        msg: "全局trycatch",
+        error
+      })
+    }
+
+
+  },
+  /**
+   * 生命周期函数--监听页面加载
+   */
+  onLoad: function (options) {
+    this.setData({
+      type: wx.getStorageSync('type'),
+      file: wx.getStorageSync('file'),
+      latitude: wx.getStorageSync('latitude'),
+      longitude: wx.getStorageSync('longitude')
+    })
+  },
+
+  onShareAppMessage: function () {
+
+  }
+})

+ 3 - 0
miniprogram/pages/cachePage/cachePage.json

@@ -0,0 +1,3 @@
+{
+  "usingComponents": {}
+}

+ 52 - 0
miniprogram/pages/cachePage/cachePage.wxml

@@ -0,0 +1,52 @@
+<view class="main-container">
+  <image class="media-container" mode="aspectFit" wx:if="{{type==1}}" src="{{file}}"> </image>
+  <video class="media-container" autoplay="{{true}}" wx:else src="{{file}}"></video>
+</view>
+<view class="line mb30">
+  <view class="ship-name">船舶名称 : </view><input class="ship-name-ipt" model:value="{{shipName}}" type="text" placeholder="请输入船舶名称" />
+</view>
+<view class="line">
+  <view class="ship-mmsi">MMSI : </view><input class="ship-mmsi-ipt" model:value="{{shipMmsi}}" type="text" placeholder="请输入MMSI" />
+</view>
+<view>
+  <button style="width: 600rpx;height: 90rpx;line-height: 90rpx;background: #3e94f6;border-radius: 45rpx;padding: 0;margin-top: 30rpx;" bindtap="showAgreeModal" type="primary">注册/登录</button>
+  <button style="width: 500rpx;height: 60rpx;line-height: 60rpx;background: #777;border-radius: 30rpx;padding: 0;margin-top: 30rpx;font-size: 24rpx;" bindtap="goBack" type="primary">返回继续体验</button>
+</view>
+<view wx:if="{{agreeText}}" style="position: absolute;top: 0;left: 0;right: 0;bottom: 0;background-color: rgba(000, 000, 000, 0.5);z-index: 10;">
+  <scroll-view style="height: 90vh;width: 90vw;background-color: #fff;margin: 5vh auto;padding: 20rpx;" scroll-y="true">
+    <view style="font-size:large;text-align: center;margin:60rpx;">隐私协议</view>
+    <text space="ensp" decode="true">&nbsp;&nbsp;</text>
+    <text space="ensp" decode="true">&nbsp;&nbsp;本隐私政策介绍本公司的隐私数据相关政策和惯例,包括在使用汇很多小程序时上传至云端的数据将受到保护,防止以及追究某些非法手段获取本公司所保管的关于您的数据资料。请你仔细阅读我们的隐私政策。
+    </text><text space="ensp" decode="true">一、本公司如何收集您的个人信息汇很多小程序以个人电话号码作为唯一身份识别方式,用于个人登录使用以及密码遗忘、找回的唯一途径。当您使用本公司的微信小程序,注册过程中我们将仅收集您的电话号码作为唯一身份识别,使用期间终身有效。
+    </text><text space="ensp" decode="true">二、本公司如何使用您的个人信息
+      1、通过您的手机号码实现密码找回功能。
+      2、本公司不会向任何无关第三方提供、出售、出租、分享或交易您的个人信息,除非事先得到您的许可,或该第三方和本公司单独或共同为您提供服务,且在该服务结束后,其将被禁止访问包括其以前能够访问的所有这些信息。
+    </text><text space="ensp" decode="true">三、个人信息安全
+      保证您的数据的安全对我们来说至关重要。当您在本公司的微信小程序中注册输入个人信息时,我们对这些信息进行加密。
+      在数据传输和数据保管两个阶段里,我们会通过广为接受的行业标准(如防火墙、加密和数据隐私法律要求)来保护您向我们提交的信息。
+      然而,没有任何一种互联网传输或电子存储方法是100%安全的。因此,尽管我们通过商业上可接受的方式来保护您的个人信息,但仍无法保证信息的绝对安全。
+    </text><text space="ensp" decode="true">四、本公司会将个人信息保存多久
+      一般来说,本公司仅在您使用本公司微信小程序期间保留您的个人信息,同时将遵守适用法律规定的数据保留期限。
+    </text><text space="ensp" decode="true">五、法律免责声明
+      在法律要求的情况下(如协助公安机关)或遵守司法程序、法院指令,以及因用户行为而致使本公司的法定权益收到威胁,或适用于本公司的微信小程序的法律程序时,我们有权透露您的个人信息。
+      如果本公司确定为了执行本公司的条款和条件或保护我们的经营,披露是合理必须的,则我们可能会披露与您有关的信息。
+    </text><text space="ensp" decode="true">六、本隐私政策的更改
+      本公司会根据国家法律法规不定时更改本政策协议。修改执行之前,本公司将会在小程序用户协议、以及本公司网站通知本次政策更改,以便您了解我们如何收集、使用您的个人信息,哪些人可以访问这些信息,以及在什么情况下我们会披露这些信息。
+      本公司保留随时修改本政策的权利,因此请经常查看。
+    </text><text space="ensp" decode="true">七、隐私问题
+      如果你对本公司的隐私政策或数据处理有任何问题或顾虑,请通过+86 18049981341与本公司联系。
+    </text>
+
+    <button bindtap="agree" type="primary">确定</button>
+  </scroll-view>
+</view>
+<view style="position: absolute;top: 0;left: 0;right: 0;bottom: 0;background-color: rgba(000, 000, 000, 0.5);z-index: 8;" wx:if="{{agreeModal}}">
+  <view style="width:80vw;height:60vw;background:#fff;border-radius: 50rpx;padding: 50rpx;color: #333;font-size: 30rpx;margin: 60% auto;">
+    <view style="text-align: center;font-size: 36rpx;margin-bottom:20rpx ;">隐私协议提示</view>
+    <view>感谢您的信任并使用汇很多小程序,请务必阅读 <text bindtap="showAgeeeText" style="text-decoration: underline;color: orange;">《隐私协议》</text>各条款,若继续使用请点击下方按钮“同意并继续”。</view>
+    <view style="display: flex;justify-content: space-around;align-items: center;margin-top: 50rpx;">
+      <view style="width: 200rpx;height:80rpx;background: #eee;border-radius: 40rpx;text-align: center;line-height: 80rpx;color: #000;font-size: 28rpx;margin:0" bindtap="hideAgreeModal">取消</view>
+      <button style="    width: 200rpx;height: 80rpx;background: #333;border-radius: 40rpx;text-align: center;line-height: 80rpx;color: #fff;font-size: 28rpx;font-weight: normal;padding: 0;margin: 0;" open-type="getPhoneNumber" bindgetphonenumber="getPhoneNumber">同意并继续</button>
+    </view>
+  </view>
+</view>

+ 50 - 0
miniprogram/pages/cachePage/cachePage.wxss

@@ -0,0 +1,50 @@
+/* pages/cachePage/cachePage.wxss */
+.main-container {
+  height: 55vh;
+  width: 80vw;
+  margin: 0 auto;
+  margin-top: 10vh;
+  margin-bottom: 3vh;
+}
+
+.media-container {
+  width: 100%;
+  height: 100%;
+}
+
+
+
+.ship-name,
+.ship-mmsi {
+  width: 153rpx;
+  height: 36rpx;
+  font-size: 30rpx;
+  font-family: PingFangSC-Regular,
+    PingFang SC;
+  font-weight: 400;
+  color: #333333;
+  line-height: 36rpx;
+  text-align: right;
+  margin-right: 6rpx;
+}
+
+.ship-name-ipt,
+.ship-mmsi-ipt {
+  width: 420rpx;
+  height: 67rpx;
+  border: 1px solid #979797;
+  font-size: 30rpx;
+  padding-left: 20rpx;
+}
+
+.submit {
+  margin-top: 130rpx;
+  height: 80rpx;
+  background: #0094FE;
+  border-radius: 4rpx;
+  font-size: 34rpx;
+  font-family: PingFangSC-Regular,
+    PingFang SC;
+  font-weight: 400;
+  color: #FFFFFF;
+}

+ 67 - 0
miniprogram/pages/index/index.js

@@ -0,0 +1,67 @@
+// pages/index/index.js
+import cloudApi from "../../apis/cloudApi"
+import {
+  postApi
+} from "../../apis/api"
+Page({
+
+  /**
+   * 页面的初始数据
+   */
+  data: {
+    loginStatus: false
+  },
+
+  async login() {
+    if (!wx.getStorageSync('openId')) return
+    let res1 = await postApi("/user/wx/openId/login", {
+      openId: wx.getStorageSync('openId')
+    })
+
+    if (res1.data.status == 0) {
+      let data = {
+        ...res1.data.result.userInfo,
+        ...res1.data.result.shipInfo,
+      }
+      Object.keys(data).forEach(function (key) {
+        wx.setStorageSync(key, data[key])
+      })
+      wx.navigateTo({
+        url: '/pages/takePhoto/takePhoto',
+      })
+    } else {
+      wx.navigateTo({
+        url: '/pages/takePhoto/takePhoto',
+      })
+
+    }
+
+
+  },
+  onLoad: function (options) {
+    if (wx.getStorageSync('userId') && wx.getStorageSync('shipName')) {
+      this.setData({
+        loginStatus: true
+      })
+    }
+  },
+
+  onShow() {
+    let v = wx.getAccountInfoSync()
+
+    if (v.miniProgram.envVersion != "release") {
+      wx.showToast({
+        title: `当前环境:${v.miniProgram.envVersion=="develop"?'开发版':'体验版'}`,
+        icon: 'none',
+        duration: 1000
+      })
+    }
+  },
+
+  /**
+   * 用户点击右上角分享
+   */
+  onShareAppMessage: function () {
+
+  }
+})

+ 3 - 0
miniprogram/pages/index/index.json

@@ -0,0 +1,3 @@
+{
+  "usingComponents": {}
+}

+ 3 - 0
miniprogram/pages/index/index.wxml

@@ -0,0 +1,3 @@
+<image class="main" mode="aspectFit" src="../../images/index.png"></image>
+<view bindtap="login" class="go">{{loginStatus?'去拍照':'去体验'}}</view>
+<!-- <view wx:if="{{!loginStatus}}" class="has-account">已有账号,去登录</view> -->

+ 31 - 0
miniprogram/pages/index/index.wxss

@@ -0,0 +1,31 @@
+/* pages/index/index.wxss */
+.main {
+  display: block;
+  width: 80vw;
+  height: 60vh;
+  margin: 10vh auto;
+}
+
+.go {
+  width: 70vw;
+  height: 12vw;
+  line-height: 12vw;
+  font-size: 5vw;
+  text-align: center;
+  background: #3e94f6;
+  color: #fff;
+  border-radius: 6vw;
+  margin: 0 auto;
+  margin-top: 60rpx;
+}
+
+.has-account {
+  width: 300rpx;
+  height: 70rpx;
+  line-height: 70rpx;
+  color: #888;
+  text-decoration: underline;
+  font-size: 32rpx;
+  text-align: center;
+  margin: 30rpx auto;
+}

+ 338 - 0
miniprogram/pages/newCachePage/newCachePage.js

@@ -0,0 +1,338 @@
+// pages/newCachePage/newCahePage.js
+import cloudApi from "../../apis/cloudApi"
+import {
+  postApi
+} from "../../apis/api"
+import {
+  uploadFile
+} from "../../utils/upload"
+
+Page({
+
+  /**
+   * 页面的初始数据
+   */
+  data: {
+    type: "",
+    file: "",
+    latitude: "",
+    longitude: "",
+    shipName: "",
+    shipMmsi: "",
+    agreeModal: false,
+    agreeText: false,
+    isWxRegister: false
+  },
+  goBack() {
+    wx.redirectTo({
+      url: '/pages/index/index',
+    })
+  },
+  async register() {
+    if (!this.checkout()) return
+    let res = await postApi('/user/wx/register', {
+      userId: wx.getStorageSync('userId'),
+      shipName: this.data.shipName,
+      shipMmsi: this.data.shipMmsi,
+    })
+    console.log(res)
+    if (res.data.status == 0) {
+      let {
+        shipInfo,
+        userInfo
+      } = res.data.result
+
+      let data = {
+        ...shipInfo,
+        ...userInfo
+      }
+      Object.keys(data).forEach(function (key) {
+        wx.setStorageSync(key, data[key])
+      })
+      wx.compressImage({
+        src: wx.getStorageSync('file'),
+        quality: 80, // 压缩质量
+        success: async e => {
+          console.log("图片压缩成功!", e)
+          wx.hideLoading({
+            success: (res) => {},
+          })
+          wx.showLoading({
+            title: '正在上传...',
+          })
+          let res = await uploadFile(e.tempFilePath, {
+            type: 3,
+            userId: wx.getStorageSync('userId'),
+            location: `${this.data.longitude},${this.data.latitude}`
+          })
+          console.log("上传结束", res)
+          if (res.status == 0) {
+            wx.showToast({
+              title: res.msg
+            })
+            wx.setStorageSync('shareImageUrl', res.result.viewUrl)
+            console.log(wx.getStorageSync('shareImageUrl'))
+            wx.downloadFile({
+              url: res.result.viewUrl,
+              success: e => {
+                console.log("下载调用!", e)
+                wx.setStorageSync('cacheImage', e.tempFilePath)
+                wx.saveImageToPhotosAlbum({
+                  filePath: e.tempFilePath,
+                  success: e => {
+                    if (e.errMsg == "saveImageToPhotosAlbum:ok") {
+                      wx.showToast({
+                        title: '保存成功!',
+                      })
+                      wx.removeStorageSync('cacheImage')
+                    }
+                  },
+                  fail: e => {
+                    console.log("失败44", e)
+                    this.setData({
+                      authModal: true,
+                      modalText: "文件存储"
+                    })
+                  }
+                })
+                wx.navigateTo({
+                  url: '/pages/takePhoto/success/success',
+                })
+              },
+              fail: e => {
+                console.log("失败3", e)
+              }
+            })
+
+
+          } else {
+            wx.showToast({
+              title: res.msg
+            })
+          }
+        },
+        fail: e => {
+          console.log("失败22", e)
+        }
+      })
+    } else {
+
+    }
+  },
+  checkout() {
+    if (!this.data.shipName) {
+      wx.showToast({
+        title: '请输入船名!',
+        icon: "error"
+      })
+      return
+    }
+
+    if (!this.data.shipMmsi) {
+      wx.showToast({
+        title: '请输入MMSI!',
+        icon: "error"
+      })
+      return
+    }
+
+    return true
+  },
+  agree() {
+    this.setData({
+      agreeText: false,
+    })
+  },
+
+  showAgeeeText() {
+    this.setData({
+      agreeText: true
+    })
+  },
+  hideAgreeText() {
+    this.setData({
+      agreeText: false
+    })
+  },
+  hideAgreeModal() {
+    this.setData({
+      agreeModal: false
+    })
+  },
+  showAgreeModal() {
+    this.setData({
+      agreeModal: true
+    })
+  },
+  async getPhoneNumber(e) {
+    try {
+      if (e.detail.errMsg == "getPhoneNumber:ok") {
+        wx.showLoading({
+          title: '正在登录...',
+          mask: true
+        })
+        let session_key = wx.getStorageSync('session_key')
+        let {
+          result
+        } = await cloudApi("getWxPhoneNumber", {
+          ...e.detail,
+          session_key
+        })
+        let {
+          phone,
+        } = result
+        if (phone) {
+          wx.setStorageSync('phone', phone)
+          try {
+            let res = await postApi('/user/wx/login', {
+              openId: wx.getStorageSync('openId'),
+              phone
+            })
+            console.log(res)
+            if (res.data.status == 0) {
+              let {
+                shipInfo,
+                userInfo
+              } = res.data.result
+
+              let data = {
+                ...shipInfo,
+                ...userInfo
+              }
+              Object.keys(data).forEach(function (key) {
+                wx.setStorageSync(key, data[key])
+              })
+              wx.compressImage({
+                src: wx.getStorageSync('file'),
+                quality: 80, // 压缩质量
+                success: async e => {
+                  console.log("图片压缩成功!", e)
+                  wx.hideLoading({
+                    success: (res) => {},
+                  })
+                  wx.showLoading({
+                    title: '正在上传...',
+                  })
+                  let res = await uploadFile(e.tempFilePath, {
+                    type: 3,
+                    userId: wx.getStorageSync('userId'),
+                    location: `${this.data.longitude},${this.data.latitude}`
+                  })
+                  console.log("上传结束", res)
+                  if (res.status == 0) {
+                    wx.showToast({
+                      title: res.msg
+                    })
+                    wx.setStorageSync('shareImageUrl', res.result.viewUrl)
+                    console.log(wx.getStorageSync('shareImageUrl'))
+                    wx.downloadFile({
+                      url: res.result.viewUrl,
+                      success: e => {
+                        console.log("下载调用!", e)
+                        wx.setStorageSync('cacheImage', e.tempFilePath)
+                        wx.saveImageToPhotosAlbum({
+                          filePath: e.tempFilePath,
+                          success: e => {
+                            if (e.errMsg == "saveImageToPhotosAlbum:ok") {
+                              wx.showToast({
+                                title: '保存成功!',
+                              })
+                              wx.removeStorageSync('cacheImage')
+                            }
+                          },
+                          fail: e => {
+                            console.log("失败4", e)
+                            this.setData({
+                              authModal: true,
+                              modalText: "文件存储"
+                            })
+                          }
+                        })
+                        wx.navigateTo({
+                          url: '/pages/takePhoto/success/success',
+                        })
+                      },
+                      fail: e => {
+                        console.log("失败33", e)
+                      }
+                    })
+
+
+                  } else {
+                    wx.showToast({
+                      title: res.msg
+                    })
+                  }
+                },
+                fail: e => {
+                  console.log("失败2", e)
+                }
+              })
+            } else {
+              let {
+                userInfo
+              } = res.data.result
+
+              let data = {
+                ...userInfo
+              }
+              Object.keys(data).forEach(function (key) {
+                wx.setStorageSync(key, data[key])
+              })
+              this.setData({
+                isWxRegister: true,
+                agreeModal: false
+              })
+            }
+          } catch (error) {
+            console.log(error)
+          } finally {
+            wx.hideLoading({
+              success: (res) => {},
+            })
+          }
+
+        } else {
+          wx.hideLoading({})
+          wx.showToast({
+            title: '获取手机号失败',
+            duration: 5000
+          })
+          await cloudApi('sendError', {
+            msg: "获取手机号失败"
+          })
+        }
+      } else {
+        wx.showToast({
+          title: '请授权以登录',
+          icon: "error"
+        })
+        await cloudApi('sendError', {
+          msg: "未授权手机号"
+        })
+      }
+    } catch (error) {
+      await cloudApi('sendError', {
+        msg: "全局trycatch",
+        error
+      })
+    }
+
+
+  },
+  /**
+   * 生命周期函数--监听页面加载
+   */
+  onLoad: function (options) {
+    this.setData({
+      type: wx.getStorageSync('type'),
+      file: wx.getStorageSync('file'),
+      latitude: wx.getStorageSync('latitude'),
+      longitude: wx.getStorageSync('longitude')
+    })
+  },
+
+  onShareAppMessage: function () {
+
+  }
+})

+ 3 - 0
miniprogram/pages/newCachePage/newCachePage.json

@@ -0,0 +1,3 @@
+{
+  "usingComponents": {}
+}

+ 55 - 0
miniprogram/pages/newCachePage/newCachePage.wxml

@@ -0,0 +1,55 @@
+<view class="main-container">
+  <image class="media-container" mode="aspectFit" wx:if="{{type==1}}" src="{{file}}"> </image>
+  <video class="media-container" autoplay="{{true}}" wx:else src="{{file}}"></video>
+</view>
+<view wx:if="{{isWxRegister}}">
+  <view class="line mb30">
+    <view class="ship-name">船舶名称 : </view><input class="ship-name-ipt" model:value="{{shipName}}" type="text" placeholder="请输入船舶名称" />
+  </view>
+  <view class="line">
+    <view class="ship-mmsi">MMSI : </view><input class="ship-mmsi-ipt" model:value="{{shipMmsi}}" type="text" placeholder="请输入MMSI" />
+  </view>
+</view>
+<view>
+  <button wx:if="{{isWxRegister}}" style="width: 600rpx;height: 90rpx;line-height: 90rpx;background: #3e94f6;border-radius: 45rpx;padding: 0;margin-top: 30rpx;" bindtap="register" type="primary">完成</button>
+  <button wx:else style="width: 600rpx;height: 90rpx;line-height: 90rpx;background: #3e94f6;border-radius: 45rpx;padding: 0;margin-top: 30rpx;" bindtap="showAgreeModal" type="primary">手机号登录</button>
+  <button style="width: 500rpx;height: 60rpx;line-height: 60rpx;background: #777;border-radius: 30rpx;padding: 0;margin-top: 30rpx;font-size: 24rpx;" bindtap="goBack" type="primary">返回继续体验</button>
+</view>
+<view wx:if="{{agreeText}}" style="position: absolute;top: 0;left: 0;right: 0;bottom: 0;background-color: rgba(000, 000, 000, 0.5);z-index: 10;">
+  <scroll-view style="height: 90vh;width: 90vw;background-color: #fff;margin: 5vh auto;padding: 20rpx;" scroll-y="true">
+    <view style="font-size:large;text-align: center;margin:60rpx;">隐私协议</view>
+    <text space="ensp" decode="true">&nbsp;&nbsp;</text>
+    <text space="ensp" decode="true">&nbsp;&nbsp;本隐私政策介绍本公司的隐私数据相关政策和惯例,包括在使用汇很多小程序时上传至云端的数据将受到保护,防止以及追究某些非法手段获取本公司所保管的关于您的数据资料。请你仔细阅读我们的隐私政策。
+    </text><text space="ensp" decode="true">一、本公司如何收集您的个人信息汇很多小程序以个人电话号码作为唯一身份识别方式,用于个人登录使用以及密码遗忘、找回的唯一途径。当您使用本公司的微信小程序,注册过程中我们将仅收集您的电话号码作为唯一身份识别,使用期间终身有效。
+    </text><text space="ensp" decode="true">二、本公司如何使用您的个人信息
+      1、通过您的手机号码实现密码找回功能。
+      2、本公司不会向任何无关第三方提供、出售、出租、分享或交易您的个人信息,除非事先得到您的许可,或该第三方和本公司单独或共同为您提供服务,且在该服务结束后,其将被禁止访问包括其以前能够访问的所有这些信息。
+    </text><text space="ensp" decode="true">三、个人信息安全
+      保证您的数据的安全对我们来说至关重要。当您在本公司的微信小程序中注册输入个人信息时,我们对这些信息进行加密。
+      在数据传输和数据保管两个阶段里,我们会通过广为接受的行业标准(如防火墙、加密和数据隐私法律要求)来保护您向我们提交的信息。
+      然而,没有任何一种互联网传输或电子存储方法是100%安全的。因此,尽管我们通过商业上可接受的方式来保护您的个人信息,但仍无法保证信息的绝对安全。
+    </text><text space="ensp" decode="true">四、本公司会将个人信息保存多久
+      一般来说,本公司仅在您使用本公司微信小程序期间保留您的个人信息,同时将遵守适用法律规定的数据保留期限。
+    </text><text space="ensp" decode="true">五、法律免责声明
+      在法律要求的情况下(如协助公安机关)或遵守司法程序、法院指令,以及因用户行为而致使本公司的法定权益收到威胁,或适用于本公司的微信小程序的法律程序时,我们有权透露您的个人信息。
+      如果本公司确定为了执行本公司的条款和条件或保护我们的经营,披露是合理必须的,则我们可能会披露与您有关的信息。
+    </text><text space="ensp" decode="true">六、本隐私政策的更改
+      本公司会根据国家法律法规不定时更改本政策协议。修改执行之前,本公司将会在小程序用户协议、以及本公司网站通知本次政策更改,以便您了解我们如何收集、使用您的个人信息,哪些人可以访问这些信息,以及在什么情况下我们会披露这些信息。
+      本公司保留随时修改本政策的权利,因此请经常查看。
+    </text><text space="ensp" decode="true">七、隐私问题
+      如果你对本公司的隐私政策或数据处理有任何问题或顾虑,请通过+86 18049981341与本公司联系。
+    </text>
+
+    <button bindtap="agree" type="primary">确定</button>
+  </scroll-view>
+</view>
+<view style="position: absolute;top: 0;left: 0;right: 0;bottom: 0;background-color: rgba(000, 000, 000, 0.5);z-index: 8;" wx:if="{{agreeModal}}">
+  <view style="width:80vw;height:60vw;background:#fff;border-radius: 50rpx;padding: 50rpx;color: #333;font-size: 30rpx;margin: 60% auto;">
+    <view style="text-align: center;font-size: 36rpx;margin-bottom:20rpx ;">隐私协议提示</view>
+    <view>感谢您的信任并使用汇很多小程序,请务必阅读 <text bindtap="showAgeeeText" style="text-decoration: underline;color: orange;">《隐私协议》</text>各条款,若继续使用请点击下方按钮“同意并继续”。</view>
+    <view style="display: flex;justify-content: space-around;align-items: center;margin-top: 50rpx;">
+      <view style="width: 200rpx;height:80rpx;background: #eee;border-radius: 40rpx;text-align: center;line-height: 80rpx;color: #000;font-size: 28rpx;margin:0" bindtap="hideAgreeModal">取消</view>
+      <button style="    width: 200rpx;height: 80rpx;background: #333;border-radius: 40rpx;text-align: center;line-height: 80rpx;color: #fff;font-size: 28rpx;font-weight: normal;padding: 0;margin: 0;" open-type="getPhoneNumber" bindgetphonenumber="getPhoneNumber">同意并继续</button>
+    </view>
+  </view>
+</view>

+ 50 - 0
miniprogram/pages/newCachePage/newCachePage.wxss

@@ -0,0 +1,50 @@
+/* pages/newCachePage/newCachePage.wxss */
+.main-container {
+  height: 55vh;
+  width: 80vw;
+  margin: 0 auto;
+  margin-top: 10vh;
+  margin-bottom: 3vh;
+}
+
+.media-container {
+  width: 100%;
+  height: 100%;
+}
+
+
+
+.ship-name,
+.ship-mmsi {
+  width: 153rpx;
+  height: 36rpx;
+  font-size: 30rpx;
+  font-family: PingFangSC-Regular,
+    PingFang SC;
+  font-weight: 400;
+  color: #333333;
+  line-height: 36rpx;
+  text-align: right;
+  margin-right: 6rpx;
+}
+
+.ship-name-ipt,
+.ship-mmsi-ipt {
+  width: 420rpx;
+  height: 67rpx;
+  border: 1px solid #979797;
+  font-size: 30rpx;
+  padding-left: 20rpx;
+}
+
+.submit {
+  margin-top: 130rpx;
+  height: 80rpx;
+  background: #0094FE;
+  border-radius: 4rpx;
+  font-size: 34rpx;
+  font-family: PingFangSC-Regular,
+    PingFang SC;
+  font-weight: 400;
+  color: #FFFFFF;
+}

+ 31 - 0
miniprogram/pages/share/share.js

@@ -0,0 +1,31 @@
+// pages/share/share.js
+Page({
+  data: {
+    shareImageUrl: '',
+    markers: [],
+    logoUrl: 'https://6875-huihenduo-2gx127w7f837b584-1255802371.tcb.qcloud.la/miniapp-static/%E6%B1%87%E5%BE%88%E5%A4%9Alogo-%E5%B7%A6%E5%8F%B3.png'
+  },
+  onLoad: function (options) {
+    let {
+      latitude,
+      longitude
+    } = options
+    let markers = [{
+      id: 999,
+      latitude: '32.001233',
+      longitude: '120.5475',
+      iconPath: "https://6875-huihenduo-2gx127w7f837b584-1255802371.tcb.qcloud.la/miniapp-static/red-circle.png?sign=6d208881376358fb4111aa6d7f1a7846&t=1647934972",
+      height: 20,
+      width: 20
+    }]
+    markers[0].latitude = latitude
+    markers[0].longitude = longitude
+
+
+
+    this.setData({
+      markers,
+      shareImageUrl: (options.shareImageUrl.replace(/qwerdfb000mmmccc/g, '?')).replace(/mmmcccqwerdfb/g, '=')
+    })
+  }
+})

+ 5 - 0
miniprogram/pages/share/share.json

@@ -0,0 +1,5 @@
+{
+  "usingComponents": {},
+  "navigationBarTitleText": "汇很多科技",
+  "navigationStyle": "default"
+}

+ 6 - 0
miniprogram/pages/share/share.wxml

@@ -0,0 +1,6 @@
+<view class="df aic" class="header">
+  <image mode="aspectFit" class="logo" mode="aspectFit" src="{{logoUrl}}"></image>
+  <view class="text">航行日志</view>
+</view>
+<image mode="widthFix" src="{{shareImageUrl}}" class="main-image"></image>
+<map enable-zoom="{{false}}" enable-scroll="{{false}}" scale="8" markers="{{markers}}" latitude="{{markers[0].latitude}}" longitude="{{markers[0].longitude}}" class="map" name=""></map>

+ 34 - 0
miniprogram/pages/share/share.wxss

@@ -0,0 +1,34 @@
+/* pages/share/share.wxss */
+.logo {
+  display: block;
+  width: 70px;
+  height: 25px;
+  margin-left: 15px;
+  position: absolute;
+}
+
+.text {
+  font-size: 14px;
+  color: #555;
+  text-align: center;
+  width: 100%;
+  box-sizing: border-box;
+}
+
+.header {
+  margin-top: 2vh;
+  align-items: center;
+  margin-bottom: 3vh;
+}
+
+.main-image {
+  width: 90vw;
+  margin: 0 auto;
+  display: block;
+}
+
+.map {
+  width: 90vw;
+  height: 30vh;
+  margin: 0 auto
+}

+ 116 - 0
miniprogram/pages/takeBill/canvas/canvas.js

@@ -0,0 +1,116 @@
+Page({
+  data: {
+    src: './test-photo.png',
+    cw: 0,
+    ch: 0,
+  },
+  test() {
+    wx.getImageInfo({
+      src: this.data.src,
+      success: e => {
+        console.log(e)
+        let ch = e.height * 2
+        let cw = e.width * 2
+        this.setData({
+          ch,
+          cw
+        })
+        const query = wx.createSelectorQuery();
+        query.select('#myCanvas').node().exec((res) => {
+          const canvas = res[0].node;
+          const ctx = canvas.getContext('2d');
+          const img = canvas.createImage();
+          let h = ch / 2
+          let w = cw / 2
+          canvas.height = h * 0.85
+          canvas.width = w * 0.9
+          img.src = this.data.src
+          img.onload = () => {
+            ctx.drawImage(img, -w * 0.05, -h * 0.05);
+          }
+        })
+      }
+    })
+
+  },
+
+  async saveImg() {
+    const query = wx.createSelectorQuery();
+    const canvas = await new Promise((resolve, reject) => {
+      query.select('#myCanvas')
+        .fields({
+          node: true,
+          size: true
+        })
+        .exec(async (res) => {
+          resolve(res[0].node);
+        })
+    });
+
+    wx.canvasToTempFilePath({
+      canvas,
+      success: (res) => {
+        wx.saveImageToPhotosAlbum({
+          filePath: res.tempFilePath,
+          success: function (data) {
+            wx.showToast({
+              title: '已保存到相册',
+              icon: 'success',
+              duration: 2000
+            })
+          },
+          fail: function (err) {
+            if (err.errMsg === "saveImageToPhotosAlbum:fail:auth denied" || err.errMsg === "saveImageToPhotosAlbum:fail auth deny" || err.errMsg === "saveImageToPhotosAlbum:fail authorize no response") {
+              wx.showModal({
+                title: '提示',
+                content: '需要您授权保存相册',
+                showCancel: false,
+                success: modalSuccess => {
+                  wx.openSetting({
+                    success(settingdata) {
+                      if (settingdata.authSetting['scope.writePhotosAlbum']) {
+                        // wx.showModal({
+                        //   title: '提示',
+                        //   content: '获取权限成功,再次点击图片即可保存',
+                        //   showCancel: false,
+                        // })
+                      } else {
+                        wx.showModal({
+                          title: '提示',
+                          content: '获取权限失败',
+                          showCancel: false,
+                        })
+                      }
+                    },
+                    fail(failData) {
+                      console.log("failData", failData)
+                    },
+                    complete(finishData) {
+                      console.log("finishData", finishData)
+                    }
+                  })
+                }
+              })
+            } else {
+              wx.showToast({
+                title: '请保存图片',
+                icon: 'none',
+                duration: 2000
+              })
+            }
+          },
+        })
+      },
+      fail(res) {
+        console.log('fail');
+      }
+    }, this)
+  },
+
+  onLoad(options) {
+    this.setData({
+      src: options.src
+    })
+    this.test()
+  }
+})

+ 3 - 0
miniprogram/pages/takeBill/canvas/canvas.json

@@ -0,0 +1,3 @@
+{
+  "usingComponents": {}
+}

+ 4 - 0
miniprogram/pages/takeBill/canvas/canvas.wxml

@@ -0,0 +1,4 @@
+<image id="myimage" src="{{src}}" style="width:{{cw}}rpx;height: {{ch}}rpx;"></image>
+<view style="box-sizing: border-box;border: 1rpx solid green;width:{{cw * 0.9}}rpx;;height: {{ch * 0.85}}rpx;position: absolute;top: {{0.05 *0.5* ch}}rpx;left: {{0.075 *0.5* cw}}rpx;"></view>
+<canvas type="2d" id="myCanvas" style="position:fixed;top: -1150rpx;width:{{cw*0.9}}rpx;height: {{ch*0.85}}rpx;box-sizing: border-box"></canvas>
+<button bindtap="saveImg">saveImg</button>

+ 1 - 0
miniprogram/pages/takeBill/canvas/canvas.wxss

@@ -0,0 +1 @@
+/* pages/takeBill/canvas/canvas.wxss */

+ 30 - 0
miniprogram/pages/takeBill/success/success.js

@@ -0,0 +1,30 @@
+Page({
+  data: {
+    src: '',
+    path: ''
+  },
+  onLoad(options) {
+    let {
+      src,
+      path
+    } = options
+    this.setData({
+      src,
+      path
+    })
+    return
+    wx.getImageInfo({
+      src,
+      success: e => {
+        console.log("src", e)
+      }
+    })
+
+    wx.getImageInfo({
+      src: path,
+      success: e => {
+        console.log('path', e)
+      }
+    })
+  }
+})

+ 4 - 0
miniprogram/pages/takeBill/success/success.json

@@ -0,0 +1,4 @@
+{
+  "usingComponents": {},
+  "navigationStyle": "default"
+}

+ 4 - 0
miniprogram/pages/takeBill/success/success.wxml

@@ -0,0 +1,4 @@
+<view style="padding-top: 10vh;">
+  <image mode="aspectFit" style="width: 50vw;border: 1px solid green;" src="{{src}}"></image>
+  <image mode="aspectFit" style="width: 50vw;border: 1px solid blue;" src="{{path}}"></image>
+</view>

+ 1 - 0
miniprogram/pages/takeBill/success/success.wxss

@@ -0,0 +1 @@
+/* pages/takePhoto/success/success.wxss */

+ 125 - 0
miniprogram/pages/takeBill/takeBill.js

@@ -0,0 +1,125 @@
+import {
+  uploadFile
+} from "../../utils/upload"
+Page({
+  data: {
+    avatar: "https://6875-huihenduo-2gx127w7f837b584-1255802371.tcb.qcloud.la/miniapp-static/avatar-icon.jpg?sign=f5c66c94d189436f82353eb48cb01f08&t=1634538864",
+    cameraIcon: "https://6875-huihenduo-2gx127w7f837b584-1255802371.tcb.qcloud.la/miniapp-static/camera-icon.png?sign=11a65871a2800cd04ecaa8991687fccd&t=1634607415",
+    newCameraIcon: "https://6875-huihenduo-2gx127w7f837b584-1255802371.tcb.qcloud.la/miniapp-static/camera.png?sign=ad0fe8bead6a46cb20f45f792d4bed67&t=1645502416",
+    userName: "",
+    phone: "",
+    shipName: "",
+    shipMmsi: "",
+    authModal: false,
+    modalText: "位置",
+    cw: '',
+    ch: '',
+    disabled: false,
+    imgCache:''
+  },
+  takeBill() {
+    if (this.data.disabled) return
+    wx.showLoading({
+      title: '正在上传...',
+    })
+    this.data.disabled = true
+    const ctx = wx.createCameraContext()
+    ctx.takePhoto({
+      quality: 'high',
+      success: (res) => {
+        let src = res.tempImagePath
+        let ch = res.height * 2
+        let cw = res.width * 2
+        wx.getImageInfo({
+          src,
+          success: e => {
+            this.setData({
+              ch,
+              cw
+            })
+            const query = wx.createSelectorQuery();
+            query.select('#myCanvas').node().exec((res) => {
+              const canvas = res[0].node;
+              const ctx = canvas.getContext('2d');
+              const img = canvas.createImage();
+              let h = ch / 2
+              let w = cw / 2
+              canvas.height = h * 0.85
+              canvas.width = w * 0.9
+              img.src = src
+              img.onload = () => {
+                ctx.drawImage(img, -w * 0.05, -h * 0.05);
+              }
+              this.saveImg(src)
+            })
+          }
+        })
+
+      }
+    })
+  },
+  goBack() {
+    wx.redirectTo({
+      url: '/pages/takePhoto/takePhoto',
+    })
+  },
+  async saveImg(src) {
+    const query = wx.createSelectorQuery();
+    const canvas = await new Promise((resolve, reject) => {
+      query.select('#myCanvas')
+        .fields({
+          node: true,
+          size: true
+        })
+        .exec(async (res) => {
+          resolve(res[0].node);
+        })
+    });
+
+    wx.canvasToTempFilePath({
+      canvas,
+      success: async e => {
+        // let path = e.tempFilePath
+        // wx.navigateTo({
+        //   url: `/pages/takeBill/success/success?src=${src}&path=${path}`
+        // })
+        // return
+        this.setData({
+          imgCache:e.tempFilePath
+        })
+        let res = await uploadFile(e.tempFilePath, {
+          type: 0,
+          userId: wx.getStorageSync('userId'),
+          // userId: 89,
+          location: ''
+        })
+        wx.hideLoading({
+          success: (res) => {},
+        })
+        wx.showToast({
+          title: res.msg,
+        })
+        setTimeout(() => {
+          this.data.disabled = false
+          this.goBack()
+        }, 1000)
+      },
+      fail(res) {
+        console.log('fail');
+      }
+    })
+  },
+
+  onLoad() {
+    let userName = wx.getStorageSync('userName')
+    let userId = wx.getStorageSync('userId')
+    let phone = wx.getStorageSync('phone')
+    let shipId = wx.getStorageSync('shipId')
+    this.setData({
+      userName,
+      phone,
+      userId,
+      shipId
+    })
+  }
+})

+ 4 - 0
miniprogram/pages/takeBill/takeBill.json

@@ -0,0 +1,4 @@
+{
+  "usingComponents": {},
+  "pageOrientation": "portrait"
+}

+ 13 - 0
miniprogram/pages/takeBill/takeBill.wxml

@@ -0,0 +1,13 @@
+<camera resolution="high" style="height: 100vh;width: 100vw;"></camera>
+<view class="top back fixed"></view>
+<view class="right back fixed"></view>
+<view class="bottom back fixed"></view>
+<view class="left back fixed"></view>
+<view class="dashed fixed"></view>
+<view class="text fixed">请 将 磅 单 置 于 拍 摄 框 内</view>
+<view class="out fixed" bindtap="takeBill">
+  <view class="in"></view>
+</view>
+<view class="go-back fixed" bindtap="goBack">返 回</view>
+<canvas type="2d" id="myCanvas" style="position:fixed;left: -100vw;width:{{cw*0.9*0.25}}rpx;height: {{ch*0.85*0.25}}rpx;box-sizing: border-box"></canvas>
+<image wx:if="{{imgCache}}" style="position: fixed;width: 100vw;height: 100vh;top: 0;left: 0;z-index: 100;" src="{{imgCache}}"></image>

+ 93 - 0
miniprogram/pages/takeBill/takeBill.wxss

@@ -0,0 +1,93 @@
+/* pages/takeBill/takeBill.wxss */
+page {
+  /* 拍摄框宽度 */
+  --w: 90vw;
+
+  /* 拍摄框高度 */
+  --h: 85vh;
+
+  /* 拍摄框上边距 */
+  --tg: 5vh
+}
+
+.back {
+  background: #000;
+  opacity: 0.5;
+}
+
+.fixed {
+  position: fixed;
+}
+
+
+.top {
+  top: 0;
+  width: 100vw;
+  height: var(--tg);
+}
+
+.right {
+  right: 0;
+  height: var(--h);
+  width: calc((100vw - var(--w)) / 2);
+  top: var(--tg);
+}
+
+.bottom {
+  bottom: 0;
+  width: 100vw;
+  height: calc(100vh - var(--tg) - var(--h));
+}
+
+.left {
+  left: 0;
+  height: var(--h);
+  width: calc((100vw - var(--w)) / 2);
+  top: var(--tg);
+}
+
+.dashed {
+  height: var(--h);
+  width: var(--w);
+  top: var(--tg);
+  left: calc((100vw - var(--w)) / 2);
+  border: 4rpx dashed grey;
+}
+
+.text {
+  top: 22vh;
+  transform: rotate(90deg);
+  transform-origin: left;
+  left: 52vw;
+  color: #fff;
+  opacity: 0.7;
+  font-size: 4vh;
+  white-space: nowrap;
+}
+
+.out {
+  height: calc((100vh - var(--tg) - var(--h)) / 2);
+  width: calc((100vh - var(--tg) - var(--h)) / 2);
+  border: 4rpx solid #fff;
+  bottom: calc((100vh - var(--tg) - var(--h)) / 4);
+  left: calc(50vw - (100vh - var(--tg) - var(--h)) / 4);
+  border-radius: 50%;
+  padding: 2rpx;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+}
+
+.in {
+  width: 90%;
+  height: 90%;
+  background: #fff;
+  border-radius: 50%;
+}
+
+.go-back {
+  font-size: 2vh;
+  color: #fff;
+  bottom: calc((100vh - var(--tg) - var(--h)) / 3);
+  right: calc((100vh - var(--tg) - var(--h)) / 2);
+}

+ 31 - 0
miniprogram/pages/takePhoto/success/success.js

@@ -0,0 +1,31 @@
+Page({
+  data: {
+    shareImageUrl: ''
+  },
+  go() {
+    wx.navigateTo({
+      url: '/pages/takePhoto/takePhoto',
+    })
+  },
+  share() {
+
+  },
+  onLoad() {
+    this.setData({
+      shareImageUrl: wx.getStorageSync('shareImageUrl')
+    })
+  },
+  onShareAppMessage() {
+    let shareImageUrl = wx.getStorageSync('shareImageUrl')
+    let latitude = wx.getStorageSync('latitude')
+    let longitude = wx.getStorageSync('longitude')
+
+
+    return {
+      title: '真实 实时 精准',
+      // 小程序解析带有多个等号的参数时,无法解析等号后面的参数,故=号互相替换%%%%%%
+      path: `/pages/share/share?shareImageUrl=${(shareImageUrl.replace(/\?/g, 'qwerdfb000mmmccc')).replace(/=/g, 'mmmcccqwerdfb')}&latitude=${latitude}&longitude=${longitude}`,
+      imageUrl: shareImageUrl
+    }
+  }
+})

+ 3 - 0
miniprogram/pages/takePhoto/success/success.json

@@ -0,0 +1,3 @@
+{
+  "usingComponents": {}
+}

+ 4 - 0
miniprogram/pages/takePhoto/success/success.wxml

@@ -0,0 +1,4 @@
+<image mode="aspectFit" style="height: 60vh;width: 100vw;display: block;" src="{{shareImageUrl}}"></image>
+<view class="success">图片上传成功</view>
+<view bindtap="go" class="go">继续拍照</view>
+<button open-type="share" bindtap="share" class="share">分享</button>

+ 48 - 0
miniprogram/pages/takePhoto/success/success.wxss

@@ -0,0 +1,48 @@
+/* pages/takePhoto/success/success.wxss */
+page {
+  padding-top: 10vh;
+}
+
+.share {
+  margin: 0 auto;
+  margin-top: 40rpx;
+  width: 90vw !important;
+  height: 80rpx;
+  line-height: 80rpx !important;
+  border-radius: 4rpx;
+  color: #0094FE;
+  text-align: center;
+  font-size: 34rpx;
+  font-family: PingFangSC-Regular, PingFang SC;
+  font-weight: 400;
+  line-height: 80rpx;
+  border: 1px solid #0094FE;
+  padding: 0;
+}
+
+.go {
+  margin: 0 auto;
+  margin-top: 50rpx;
+  width: 90vw;
+  height: 80rpx;
+  background: #0094FE;
+  border-radius: 4rpx;
+  color: #fff;
+  text-align: center;
+  font-size: 34rpx;
+  font-family: PingFangSC-Regular, PingFang SC;
+  font-weight: 400;
+  line-height: 80rpx;
+}
+
+.success {
+  width: 100%;
+  height: 48rpx;
+  text-align: center;
+  font-size: 34rpx;
+  font-family: PingFangSC-Medium, PingFang SC;
+  font-weight: 500;
+  color: #0094FE;
+  line-height: 48rpx;
+  margin-top: 30rpx;
+}

+ 297 - 0
miniprogram/pages/takePhoto/takePhoto.js

@@ -0,0 +1,297 @@
+import {
+  uploadFile
+} from "../../utils/upload"
+import {
+  postApi
+} from "../../apis/api"
+Page({
+  data: {
+    avatar: "https://6875-huihenduo-2gx127w7f837b584-1255802371.tcb.qcloud.la/miniapp-static/avatar-icon.jpg?sign=f5c66c94d189436f82353eb48cb01f08&t=1634538864",
+    cameraIcon: "https://6875-huihenduo-2gx127w7f837b584-1255802371.tcb.qcloud.la/miniapp-static/camera-icon.png?sign=11a65871a2800cd04ecaa8991687fccd&t=1634607415",
+    newCameraIcon: "https://6875-huihenduo-2gx127w7f837b584-1255802371.tcb.qcloud.la/miniapp-static/camera.png?sign=ad0fe8bead6a46cb20f45f792d4bed67&t=1645502416",
+    userName: "",
+    phone: "",
+    shipName: "",
+    shipMmsi: "",
+    authModal: false,
+    modalText: "位置",
+    shipId: ''
+  },
+  openSetting() {
+    this.setData({
+      authModal: false,
+    })
+    wx.openSetting({
+      complete: e => {
+        console.log(e)
+        if (e.authSetting["scope.writePhotosAlbum"]) {
+          if (wx.getStorageSync('cacheImage')) {
+            wx.saveImageToPhotosAlbum({
+              filePath: wx.getStorageSync('cacheImage'),
+              success: e => {
+                wx.showToast({
+                  title: '保存成功!',
+                })
+                wx.removeStorageSync('cacheImage')
+              },
+              complete: e => {
+                console.log(e)
+              }
+            })
+          }
+
+        }
+      }
+    })
+  },
+  takeBill() {
+    wx.redirectTo({
+      url: '/pages/takeBill/takeBill',
+    })
+  },
+  async registerShip() {
+    if (!this.checkout()) return
+    let res = await postApi('/user/wx/register', {
+      userId: wx.getStorageSync('userId'),
+      shipName: this.data.shipName,
+      shipMmsi: this.data.shipMmsi,
+    })
+
+
+    if (res.data.status == 0) {
+      let {
+        shipInfo,
+        userInfo
+      } = res.data.result
+
+      let data = {
+        ...shipInfo,
+        ...userInfo
+      }
+      Object.keys(data).forEach(function (key) {
+        wx.setStorageSync(key, data[key])
+      })
+      wx.showToast({
+        title: res.data.msg,
+      })
+      this.setData({
+        ...data
+      })
+    } else {
+      wx.showToast({
+        title: res.data.msg,
+      })
+    }
+
+
+  },
+
+  checkout() {
+    if (!this.data.shipName) {
+      wx.showToast({
+        title: '请输入船名!',
+        icon: "error"
+      })
+      return
+    }
+
+    if (!this.data.shipMmsi) {
+      wx.showToast({
+        title: '请输入MMSI!',
+        icon: "error"
+      })
+      return
+    }
+
+    return true
+  },
+  takePhoto(e) {
+    let {
+      mediatype
+    } = e.currentTarget.dataset
+    wx.getLocation({
+      type: 'gcj02',
+      isHighAccuracy: true,
+      success: e => {
+        let {
+          latitude,
+          longitude
+        } = e
+        console.log("获取定位成功!", e)
+        this.data.latitude = latitude
+        this.data.longitude = longitude
+        wx.setStorageSync('latitude', latitude)
+        wx.setStorageSync('longitude', longitude)
+        wx.chooseMedia({
+          mediaType: ["image"],
+          sourceType: ["camera"],
+          success: e => {
+            console.log("获取媒体成功!", e)
+            let src = e.tempFiles[0].tempFilePath
+            if (e.type == "video") {
+              wx.showLoading({
+                title: '正在压缩...',
+              })
+              wx.compressVideo({
+                src,
+                quality: "high",
+                bitrate: "",
+                fps: "",
+                resolution: "",
+                success: async e => {
+                  if (wx.getStorageSync('userName')) {
+                    wx.showLoading({
+                      title: '正在上传...',
+                    })
+                    let res = await uploadFile(e.tempFilePath, {
+                      type: 4,
+                      userId: wx.getStorageSync('userId'),
+                      location: `${this.data.longitude},${this.data.latitude}`
+                    })
+                    if (res.status == 0) {
+                      console.log(res)
+                      wx.showToast({
+                        title: res.msg
+                      })
+                      wx.redirectTo({
+                        url: '/pages/takePhoto/success/success',
+                      })
+                    } else {
+                      wx.showToast({
+                        title: res.msg
+                      })
+                    }
+                  } else {
+                    // 新用户视频
+                    wx.hideLoading({
+                      success: (res) => {},
+                    })
+                    console.log("新用户视频", e)
+                    wx.setStorageSync('type', 2)
+                    wx.setStorageSync('file', e.tempFilePath)
+                    wx.redirectTo({
+                      url: `/pages/newCachePage/newCachePage`,
+                    })
+                  }
+
+                },
+                fail: e => {
+                  console.log(e)
+                }
+              })
+            } else {
+              wx.compressImage({
+                src,
+                quality: 80, // 压缩质量
+                success: async e => {
+                  console.log("图片压缩成功!", e)
+                  wx.hideLoading({
+                    success: (res) => {},
+                  })
+                  if (wx.getStorageSync('userName')) {
+                    wx.showLoading({
+                      title: '正在上传...',
+                    })
+                    let postData = {
+                      type: mediatype,
+                      userId: wx.getStorageSync('userId'),
+                    }
+
+                    if (mediatype == 3) {
+                      postData.location = `${this.data.longitude},${this.data.latitude}`
+                    } else {
+                      postData.location = ''
+                    }
+                    let res = await uploadFile(e.tempFilePath, postData)
+                    console.log("上传结束", res)
+                    if (res.status == 0) {
+                      wx.showToast({
+                        title: res.msg
+                      })
+                      wx.setStorageSync('shareImageUrl', res.result.viewUrl)
+                      console.log(wx.getStorageSync('shareImageUrl'))
+                      wx.downloadFile({
+                        url: res.result.viewUrl,
+                        success: e => {
+                          console.log("下载调用!", e)
+                          wx.setStorageSync('cacheImage', e.tempFilePath)
+                          if (mediatype == 3) {
+                            wx.saveImageToPhotosAlbum({
+                              filePath: e.tempFilePath,
+                              success: e => {
+                                if (e.errMsg == "saveImageToPhotosAlbum:ok") {
+                                  wx.showToast({
+                                    title: '保存成功!',
+                                  })
+                                  wx.removeStorageSync('cacheImage')
+                                }
+                              },
+                              fail: e => {
+                                console.log("失败4", e)
+                                this.setData({
+                                  authModal: true,
+                                  modalText: "文件存储"
+                                })
+                              }
+                            })
+                          }
+
+                          wx.redirectTo({
+                            url: '/pages/takePhoto/success/success',
+                          })
+                        },
+                        fail: e => {
+                          console.log("失败3", e)
+                        }
+                      })
+
+
+                    } else {
+                      wx.showToast({
+                        title: res.msg
+                      })
+                    }
+                  } else {
+                    // 新用户图片
+                    console.log("新用户图片", e)
+                    wx.setStorageSync('type', 1)
+                    wx.setStorageSync('file', e.tempFilePath)
+                    wx.redirectTo({
+                      url: `/pages/newCachePage/newCachePage`,
+                    })
+                  }
+                },
+                fail: e => {
+                  console.log("失败2", e)
+                }
+              })
+            }
+          },
+          fail: e => {
+            console.log("失败1", e)
+          }
+        })
+      },
+      fail: e => {
+        this.setData({
+          authModal: true,
+          modalText: "位置信息"
+        })
+      }
+    })
+
+  },
+  onLoad() {
+    let userName = wx.getStorageSync('userName')
+    let userId = wx.getStorageSync('userId')
+    let phone = wx.getStorageSync('phone')
+    let shipId = wx.getStorageSync('shipId')
+
+    this.setData({
+      userName,
+      phone,
+      userId,
+      shipId
+    })
+  }
+})

+ 3 - 0
miniprogram/pages/takePhoto/takePhoto.json

@@ -0,0 +1,3 @@
+{
+  "usingComponents": {}
+}

+ 35 - 0
miniprogram/pages/takePhoto/takePhoto.wxml

@@ -0,0 +1,35 @@
+<view class="top-container">
+  <image class="avatar-icon" src="{{avatar}}"></image>
+  <view class="text" style="text-align: center;">{{userName?"":"体验用户"}}<text wx:if="{{userName}}" class="user-name">{{userName}}</text><text wx:if="{{phone}}" class="phone">{{phone}}</text></view>
+</view>
+<view wx:if="{{userId&&shipId}}">
+  <view class="new-camera camera-cargo">
+    <image class="icon" bindtap="takePhoto" data-mediatype="{{3}}" src="{{newCameraIcon}}"></image>
+    <view bindtap="takePhoto" data-mediatype="{{3}}">拍货物</view>
+
+  </view>
+  <view class="new-camera camera-bill">
+    <image class="icon" data-mediatype="{{0}}" bindtap="takeBill" src="{{newCameraIcon}}"></image>
+    <view data-mediatype="{{0}}" bindtap="takeBill"> 拍单据
+    </view>
+  </view>
+</view>
+<view wx:else>
+  <image wx:if="{{!userId&&!shipId||!userId}}" class="camera-icon" bindtap="takePhoto" data-mediatype="{{3}}" src="{{cameraIcon}}"></image>
+  <view wx:else style="margin-top: 20%;">
+    <view class="line mb30">
+      <view class="ship-name">船舶名称 : </view><input class="ship-name-ipt" model:value="{{shipName}}" type="text" placeholder="请输入船舶名称" />
+    </view>
+    <view class="line">
+      <view class="ship-mmsi">MMSI : </view><input class="ship-mmsi-ipt" model:value="{{shipMmsi}}" type="text" placeholder="请输入MMSI" />
+    </view>
+    <view bindtap="registerShip" class="submit">绑定船舶</view>
+  </view>
+
+</view>
+<view class="auth-modal" wx:if="{{authModal}}">
+  <view class="modal">
+    <view class="service">为了更好的提供服务</view>
+    <view class="auth-btn" bindtap="openSetting">请授权{{modalText}}</view>
+  </view>
+</view>

+ 154 - 0
miniprogram/pages/takePhoto/takePhoto.wxss

@@ -0,0 +1,154 @@
+/* pages/takePhoto/takePhoto.wxss */
+.top-container {
+  position: relative;
+  width: 100%;
+  height: 35vh;
+  padding-top: 154rpx;
+  background-size: contain;
+  background: url(https://6875-huihenduo-2gx127w7f837b584-1255802371.tcb.qcloud.la/miniapp-static/sea-bgd.jpeg?sign=f138978877f53ccdc48937c58811659b&t=1634539269)
+}
+
+.avatar-icon {
+  display: block;
+  width: 110rpx;
+  height: 110rpx;
+  border-radius: 50%;
+  margin: 0 auto;
+}
+
+.user-name {
+  margin-right: 40rpx;
+}
+
+.phone {
+  font-size: 28rpx;
+  font-weight: 400;
+}
+
+.text {
+  font-size: 30rpx;
+  font-family: PingFangSC-Medium,
+    PingFang SC;
+  font-weight: 500;
+  color: #FFFFFF;
+  margin-top: 30rpx;
+}
+
+
+
+.camera-icon {
+  display: block;
+  width: 234rpx;
+  height: 234rpx;
+  position: absolute;
+  top: 50%;
+  left: calc(50% - 117rpx);
+}
+
+.auth-modal {
+  position: absolute;
+  top: 0;
+  right: 0;
+  bottom: 0;
+  left: 0;
+  background-color: rgba(0, 0, 0, 0.7);
+}
+
+.modal {
+  width: 557rpx;
+  height: 274rpx;
+  background: #FFFFFF;
+  border-radius: 16rpx;
+  margin: 548rpx auto;
+  padding-top: 55rpx;
+}
+
+.service {
+  width: 100%;
+  text-align: center;
+  font-size: 36rpx;
+  font-family: PingFangSC-Medium,
+    PingFang SC;
+  font-weight: 500;
+  color: #333333;
+  -webkit-text-stroke: 1rpx #979797;
+}
+
+.auth-btn {
+  width: 350rpx;
+  height: 69rpx;
+  background: #0094FE;
+  border-radius: 8rpx;
+  font-size: 36rpx;
+  font-family: PingFangSC-Regular,
+    PingFang SC;
+  font-weight: 400;
+  color: #FFFFFF;
+  line-height: 69rpx;
+  margin: 0 auto;
+  margin-top: 55rpx;
+  text-align: center;
+}
+
+.icon {
+  width: 160rpx;
+  height: 160rpx;
+}
+
+.camera-cargo {
+  height: 32vh;
+  background: #006ebd;
+}
+
+.camera-bill {
+  height: 33vh;
+  background: #fa283d;
+}
+
+.new-camera {
+  text-align: center;
+  padding-top: 6vh;
+  color: #fff;
+  font-size: 42rpx;
+}
+
+
+.ship-name,
+.ship-mmsi {
+  width: 153rpx;
+  height: 36rpx;
+  font-size: 30rpx;
+  font-family: PingFangSC-Regular,
+    PingFang SC;
+  font-weight: 400;
+  color: #333333;
+  line-height: 36rpx;
+  text-align: right;
+  margin-right: 6rpx;
+}
+
+.ship-name-ipt,
+.ship-mmsi-ipt {
+  width: 420rpx;
+  height: 67rpx;
+  border: 1px solid #979797;
+  font-size: 30rpx;
+  padding-left: 20rpx;
+}
+
+
+.submit {
+  margin: 130rpx auto;
+  width: 80%;
+  height: 80rpx;
+  background: #0094FE;
+  border-radius: 4rpx;
+  font-size: 34rpx;
+  font-family: PingFangSC-Regular,
+    PingFang SC;
+  font-weight: 400;
+  color: #FFFFFF;
+  text-align: center;
+  line-height: 80rpx;
+  border-radius: 40rpx;
+}

+ 7 - 0
miniprogram/sitemap.json

@@ -0,0 +1,7 @@
+{
+  "desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html",
+  "rules": [{
+    "action": "allow",
+    "page": "*"
+  }]
+}

+ 22 - 0
miniprogram/utils/upload.js

@@ -0,0 +1,22 @@
+import {
+  apiUrl
+} from "../apis/apiConfig"
+
+function uploadFile(filePath, formData) {
+  return new Promise((resolve, reject) => {
+    wx.uploadFile({
+      url: `${apiUrl}/cos/upload`,
+      filePath,
+      name: 'file',
+      formData,
+      success: e => {
+        resolve(JSON.parse(e.data))
+      },
+      fail: reject
+    })
+  })
+}
+
+module.exports = {
+  uploadFile
+}

+ 57 - 0
miniprogram/utils/wxUtils.js

@@ -0,0 +1,57 @@
+import cloudApi from "../apis/cloudApi"
+
+function wxSetSessionKey() {
+  return new Promise((resolve, reject) => {
+    wx.login({
+      success: async res => {
+        let res1 = await cloudApi('code2Session', {
+          JSCODE: res.code
+        })
+        wx.setStorageSync('session_key', res1.result.session_key)
+        wx.setStorageSync('openId', res1.result._openid)
+        resolve({
+          session_key: res1.result.session_key,
+          openId: res1.result._openid
+        })
+      }
+    })
+  })
+
+}
+
+function getUserProfile() {
+  return new Promise((resolve, reject) => {
+    wx.getUserProfile({
+      desc: "'用于完善用户信息",
+      success: e => {
+        let {
+          userInfo
+        } = e
+        resolve({
+          status: 0,
+          userInfo
+        })
+      },
+      fail: e => {
+        resolve({
+          errMsg: e.errMsg,
+          status: 1
+        })
+      }
+    })
+  })
+}
+
+function getOpenId() {
+  return new Promise(async (resolve, reject) => {
+    let res1 = await cloudApi('getOpenId')
+    resolve(res1.result.openId)
+  })
+
+}
+
+module.exports = {
+  wxSetSessionKey,
+  getUserProfile,
+  getOpenId
+}

+ 81 - 0
project.config.json

@@ -0,0 +1,81 @@
+{
+  "description": "项目配置文件,详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html",
+  "miniprogramRoot": "miniprogram/",
+  "cloudfunctionRoot": "cloudfunctions/",
+  "setting": {
+    "urlCheck": true,
+    "es6": true,
+    "enhance": true,
+    "postcss": true,
+    "preloadBackgroundData": false,
+    "minified": true,
+    "newFeature": true,
+    "coverView": true,
+    "nodeModules": false,
+    "autoAudits": false,
+    "showShadowRootInWxmlPanel": true,
+    "scopeDataCheck": false,
+    "uglifyFileName": false,
+    "checkInvalidKey": true,
+    "checkSiteMap": true,
+    "uploadWithSourceMap": true,
+    "compileHotReLoad": false,
+    "lazyloadPlaceholderEnable": false,
+    "useMultiFrameRuntime": false,
+    "useApiHook": false,
+    "useApiHostProcess": false,
+    "babelSetting": {
+      "ignore": [],
+      "disablePlugins": [],
+      "outputPath": ""
+    },
+    "useIsolateContext": false,
+    "userConfirmedBundleSwitch": false,
+    "packNpmManually": false,
+    "packNpmRelationList": [],
+    "minifyWXSS": true,
+    "disableUseStrict": false,
+    "minifyWXML": true,
+    "showES6CompileOption": false,
+    "useCompilerPlugins": false,
+    "ignoreUploadUnusedFiles": true,
+    "localPlugins": false
+  },
+  "appid": "wxf22759845920b6f3",
+  "projectname": "船东小程序",
+  "libVersion": "2.19.6",
+  "cloudfunctionTemplateRoot": "cloudfunctionTemplate/",
+  "condition": {
+    "search": {
+      "list": []
+    },
+    "conversation": {
+      "list": []
+    },
+    "plugin": {
+      "list": []
+    },
+    "game": {
+      "list": []
+    },
+    "miniprogram": {
+      "list": [
+        {
+          "id": -1,
+          "name": "db guide",
+          "pathName": "pages/databaseGuide/databaseGuide"
+        }
+      ]
+    }
+  },
+  "compileType": "miniprogram",
+  "packOptions": {
+    "ignore": [],
+    "include": []
+  },
+  "srcMiniprogramRoot": "miniprogram/",
+  "editorSetting": {
+    "tabIndent": "insertSpaces",
+    "tabSize": 2
+  }
+}

+ 79 - 0
project.private.config.json

@@ -0,0 +1,79 @@
+{
+  "condition": {
+    "miniprogram": {
+      "list": [
+        {
+          "name": "pages/test/test",
+          "pathName": "pages/test/test",
+          "query": "",
+          "scene": null
+        },
+        {
+          "name": "缓存注册船舶",
+          "pathName": "pages/cachePage/cachePage",
+          "query": "",
+          "scene": null
+        },
+        {
+          "name": "",
+          "pathName": "pages/takePhoto/success/success",
+          "query": "",
+          "scene": null
+        },
+        {
+          "name": "",
+          "pathName": "pages/takePhoto/success/success",
+          "query": "",
+          "scene": null
+        },
+        {
+          "name": "",
+          "pathName": "pages/share/share",
+          "query": "shareImageUrl=https://hhd-pat-1255802371.cos.ap-shanghai.myqcloud.com/pat/images/%E8%88%B9%E7%8E%8B1647422492928.?sign=q-sign-algorithm%3Dsha1%26q-ak%3DAKID4xb091cy4tRikV0EBrGOGsCF1WkhMlum%26q-sign-time%3D1647422493%3B93158697600%26q-key-time%3D1647422493%3B93158697600%26q-header-list%3Dhost%26q-url-param-list%3D%26q-signature%3D721ca8bebf3e18a92730897ad52b9bf9036e51b9",
+          "launchMode": "default",
+          "scene": 1007
+        },
+        {
+          "name": "",
+          "pathName": "pages/newCachePage/newCachePage",
+          "query": "",
+          "scene": null
+        },
+        {
+          "name": "",
+          "pathName": "pages/takePhoto/takePhoto",
+          "query": "",
+          "launchMode": "default",
+          "scene": null
+        },
+        {
+          "name": "",
+          "pathName": "pages/takeBill/takeBill",
+          "query": "",
+          "launchMode": "default",
+          "scene": null
+        },
+        {
+          "name": "",
+          "pathName": "pages/takeBill/canvas/canvas",
+          "query": "",
+          "launchMode": "default",
+          "scene": null
+        }
+      ]
+    }
+  },
+  "setting": {
+    "urlCheck": true,
+    "preloadBackgroundData": false,
+    "coverView": true,
+    "autoAudits": false,
+    "showShadowRootInWxmlPanel": true,
+    "checkInvalidKey": true,
+    "compileHotReLoad": false,
+    "lazyloadPlaceholderEnable": false,
+    "showES6CompileOption": false,
+    "useStaticServer": true
+  },
+  "description": "项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html"
+}

+ 1 - 0
uploadCloudFunction.sh

@@ -0,0 +1 @@
+"/Applications/wechatwebdevtools.app/Contents/MacOS/cli" cloud functions deploy --e huihenduo-0gwuxs6d1c6824e4 --n quickstartFunctions --r --project "/Users/wangzhihui/Desktop/汇很多/weapp/JiangYunPhotos" --report_first --report

+ 21 - 0
隐私协议.txt

@@ -0,0 +1,21 @@
+本隐私政策介绍本公司的隐私数据相关政策和惯例,包括在使用汇很多小程序时上传至云端的数据将受到保护,防止以及追究某些非法手段获取本公司所保管的关于您的数据资料。请你仔细阅读我们的隐私政策。
+一、本公司如何收集您的个人信息
+汇很多小程序以个人电话号码作为唯一身份识别方式,用于个人登录使用以及密码遗忘、找回的唯一途径。
+当您使用本公司的微信小程序,注册过程中我们将仅收集您的电话号码作为唯一身份识别,使用期间终身有效。
+二、本公司如何使用您的个人信息
+1、通过您的手机号码实现密码找回功能。
+2、本公司不会向任何无关第三方提供、出售、出租、分享或交易您的个人信息,除非事先得到您的许可,或该第三方和本公司单独或共同为您提供服务,且在该服务结束后,其将被禁止访问包括其以前能够访问的所有这些信息。
+三、个人信息安全
+保证您的数据的安全对我们来说至关重要。当您在本公司的微信小程序中注册输入个人信息时,我们对这些信息进行加密。
+在数据传输和数据保管两个阶段里,我们会通过广为接受的行业标准(如防火墙、加密和数据隐私法律要求)来保护您向我们提交的信息。
+然而,没有任何一种互联网传输或电子存储方法是100%安全的。因此,尽管我们通过商业上可接受的方式来保护您的个人信息,但仍无法保证信息的绝对安全。
+四、本公司会将个人信息保存多久
+一般来说,本公司仅在您使用本公司微信小程序期间保留您的个人信息,同时将遵守适用法律规定的数据保留期限。
+五、法律免责声明
+在法律要求的情况下(如协助公安机关)或遵守司法程序、法院指令,以及因用户行为而致使本公司的法定权益收到威胁,或适用于本公司的微信小程序的法律程序时,我们有权透露您的个人信息。
+如果本公司确定为了执行本公司的条款和条件或保护我们的经营,披露是合理必须的,则我们可能会披露与您有关的信息。
+六、本隐私政策的更改
+本公司会根据国家法律法规不定时更改本政策协议。修改执行之前,本公司将会在小程序用户协议、以及本公司网站通知本次政策更改,以便您了解我们如何收集、使用您的个人信息,哪些人可以访问这些信息,以及在什么情况下我们会披露这些信息。
+本公司保留随时修改本政策的权利,因此请经常查看。
+七、隐私问题
+如果你对本公司的隐私政策或数据处理有任何问题或顾虑,请通过+86 18049981341与本公司联系。