From cf1972fe1e1ec70717d3a9edd63d906090d33e09 Mon Sep 17 00:00:00 2001
From: MrShi <1878285526@qq.com>
Date: 星期五, 08 三月 2024 14:34:25 +0800
Subject: [PATCH] mrshi

---
 admin/src/components/business/OperaVisitsDesWindow.vue                                 |    6 
 h5/main.js                                                                             |    2 
 admin/src/views/business/empower.vue                                                   |    8 
 admin/src/views/business/visits.vue                                                    |   11 
 admin/src/views/business/deletePersonnel.vue                                           |   60 
 admin/vue.config.js                                                                    |    2 
 h5/uni_modules/bt-cropper/components/bt-cropper/utils/tools.js                         |   43 
 h5/store/index.js                                                                      |   11 
 h5/uni_modules/bt-cropper/changelog.md                                                 |   29 
 h5/uni_modules/bt-cropper/components/bt-cropper/bt-cropper.vue                         | 1095 +++++++++++
 h5/uni_modules/bt-cropper/readme.md                                                    |  108 +
 h5/uni_modules/bt-cropper/components/bt-cropper/iconfont.css                           |   22 
 h5/uni_modules/bt-cropper/package.json                                                 |   81 
 admin/src/components/business/OperaDeviceRoleWindow.vue                                |   22 
 h5/package.json                                                                        |   22 
 h5/uni_modules/bt-cropper/components/bt-cropper/js/touchs.js                           |  253 ++
 h5/uni_modules/qf-image-cropper/components/qf-image-cropper/qf-image-cropper.vue       |  692 +++++++
 h5/uni_modules/qf-image-cropper/readme.md                                              |   83 
 admin/src/api/business/member.js                                                       |    5 
 h5/uni_modules/qf-image-cropper/package.json                                           |   81 
 h5/components/tly-picture-cut/tlyPictureCut.vue                                        |  413 ++++
 h5/components/keyboard-input/keyboard-input.vue                                        |  463 ++++
 admin/src/views/business/deviceRole.vue                                                |   14 
 admin/src/views/business/interfaceLog.vue                                              |    2 
 h5/pages/userinfo/userinfo.vue                                                         |  111 
 h5/pages/visitorApplication/visitorApplication.vue                                     |   85 
 h5/uni_modules/qf-image-cropper/changelog.md                                           |   34 
 h5/uni_modules/qf-image-cropper/components/qf-image-cropper/qf-image-cropper.render.js |  628 ++++++
 h5/uni_modules/qf-image-cropper/components/qf-image-cropper/qf-image-cropper.wxs       |  543 +++++
 admin/src/views/business/device.vue                                                    |   30 
 h5/redirect.html                                                                       |    2 
 h5/App.vue                                                                             |    3 
 h5/components/cropping/cropping.vue                                                    |  700 +++++++
 admin/src/views/business/internalMember.vue                                            |   38 
 34 files changed, 5,551 insertions(+), 151 deletions(-)

diff --git a/admin/src/api/business/member.js b/admin/src/api/business/member.js
index 0238bdf..fd4665e 100644
--- a/admin/src/api/business/member.js
+++ b/admin/src/api/business/member.js
@@ -36,6 +36,11 @@
   return request.get(`/business/member/batchBlock?ids=${ids}`)
 }
 
+// 閲嶆柊鎺堟潈
+export function roleAuth (id) {
+  return request.get(`/business/member/roleAuth/${id}`)
+}
+
 // 鍒犻櫎
 export function deleteById (id) {
   return request.get(`/business/member/delete/${id}`)
diff --git a/admin/src/components/business/OperaDeviceRoleWindow.vue b/admin/src/components/business/OperaDeviceRoleWindow.vue
index 7b425b1..211f896 100644
--- a/admin/src/components/business/OperaDeviceRoleWindow.vue
+++ b/admin/src/components/business/OperaDeviceRoleWindow.vue
@@ -2,15 +2,15 @@
     <GlobalWindow
         :title="title"
         :visible.sync="visible"
-        width="50%"
+        width="900px"
         :confirm-working="isWorking"
         @confirm="confirm"
     >
         <el-form :model="form" ref="form" :rules="rules">
-            <el-form-item label="闂ㄧ缁勫悕绉�" prop="name">
+            <el-form-item label="闂ㄧ鐐瑰垎缁勫悕绉�" prop="name">
                 <el-input v-model="form.name" placeholder="璇疯緭鍏ュ悕绉�" v-trim/>
             </el-form-item>
-            <el-form-item label="榛樿闂ㄧ缁�" prop="isDefault">
+            <el-form-item label="榛樿闂ㄧ鐐瑰垎缁�" prop="isDefault">
                 <el-switch
                     v-model="form.isDefault"
                     active-color="#13ce66"
@@ -27,9 +27,10 @@
                 <el-transfer
                     v-if="form.radio === 1"
                     style="margin-top: 15px;"
-                    :titles="['鏈�夐棬绂佺粍', '宸查�夐棬绂佺粍']"
+                    :titles="['鏈�夐棬绂佺偣', '宸查�夐棬绂佺偣']"
                     filterable
-                    filter-placeholder="璇疯緭鍏ラ棬绂佺粍鍚嶇О"
+                    :filter-method="filterMethod"
+                    filter-placeholder="璇疯緭鍏ラ棬绂佺偣鎴栧尯鍩熷悕绉�"
                     v-model="form.doorIds"
                     :data="device">
                 </el-transfer>
@@ -54,7 +55,7 @@
         }
       }
       callback()
-    }
+    };
     return {
       // 琛ㄥ崟鏁版嵁
       form: {
@@ -66,6 +67,10 @@
         radio: 0
       },
       device: [],
+      filterMethod(query, item) {
+        if (!query) return item;
+        return item.label.indexOf(query) > -1 || item.area.indexOf(query) > -1;
+      },
       // 楠岃瘉瑙勫垯
       rules: {
         name: [
@@ -157,7 +162,8 @@
         .then(res => {
           this.device = res.map(item => {
             return {
-              label: item.name,
+              label: item.doorName,
+              area: item.regionPathName,
               key: item.id
             }
           })
@@ -192,6 +198,6 @@
 
 <style>
     .el-transfer-panel {
-        width: 350px;
+        width: 350px !important;
     }
 </style>
diff --git a/admin/src/components/business/OperaVisitsDesWindow.vue b/admin/src/components/business/OperaVisitsDesWindow.vue
index abe4ef6..45149da 100644
--- a/admin/src/components/business/OperaVisitsDesWindow.vue
+++ b/admin/src/components/business/OperaVisitsDesWindow.vue
@@ -12,10 +12,12 @@
                 <div class="list_item_label">鎷滆淇℃伅</div>
                 <div class="list_item_val" v-if="info" style="display: inline-block">
                     <div class="list_item_val_item">鎷滆瀵规柟锛歿{info.receptMemberName}} - {{info.receptMemberDepartment}}</div>
-                    <div class="list_item_val_item">鎷滆鏃堕棿锛歿{info.starttime}} 鑷� {{info.endtime}}</div>
+                    <div class="list_item_val_item">棰勭害鏃堕棿锛歿{info.starttime}} 鑷� {{info.endtime}}</div>
+                    <div class="list_item_val_item" v-if="info.inDate && info.outDate">绛惧埌鏃堕棿锛歿{info.inDate}} 鑷� {{info.outDate}}</div>
+                    <div class="list_item_val_item" v-else>绛惧埌鏃堕棿锛�-</div>
                     <div class="list_item_val_item">鎷滆浜嬬敱锛歿{info.reason}}</div>
                     <div class="list_item_val_item">鐢宠浜哄憳锛歿{info.name}} {{info.companyName}}</div>
-                    <div class="list_item_val_item">鐢宠闂ㄧ锛歿{info.deviceRoleList ? info.deviceRoleList.map(item => item.name).join(' | ') : ''}}</div>
+                    <div class="list_item_val_item">鐢宠闂ㄧ锛歿{info.deviceRoleList ? info.deviceRoleList.map(item => item.name).join(' | ') : '-'}}</div>
                     <div class="list_item_val_item">鍒涘缓鏃堕棿锛歿{info.createDate}}</div>
                 </div>
                 <div class="list_item_val" v-if="info" style="display: inline-block;float: right">
diff --git a/admin/src/views/business/deletePersonnel.vue b/admin/src/views/business/deletePersonnel.vue
index dd2ed88..c933e02 100644
--- a/admin/src/views/business/deletePersonnel.vue
+++ b/admin/src/views/business/deletePersonnel.vue
@@ -19,10 +19,10 @@
             <!--                <li><el-button type="primary" v-permissions="['business:member:create']" @click="thaws">绂诲満</el-button></li>-->
             <!--            </ul>-->
             <el-table
-                    v-loading="isWorking.search"
-                    :data="tableData.list"
-                    stripe
-                    @selection-change="handleSelectionChange"
+                v-loading="isWorking.search"
+                :data="tableData.list"
+                stripe
+                @selection-change="handleSelectionChange"
             >
                 <!--                <el-table-column type="selection" width="55"></el-table-column>-->
                 <el-table-column prop="name" label="濮撳悕" min-width="100px"></el-table-column>
@@ -35,36 +35,38 @@
                         <span v-if="row.type === 2">鍐呴儴浜哄憳</span>
                     </template>
                 </el-table-column>
-                <el-table-column prop="inDate" label="鍏ュ満鏃堕棿" min-width="100px"></el-table-column>
-                <el-table-column prop="outDate" label="鎺堟潈鍒版湡鏃堕棿" min-width="100px"></el-table-column>
-                <el-table-column label="瓒呮椂鏃堕暱" min-width="100px">
-                    <template slot-scope="{row}">
-                        <span v-if="row.outStatus === 1">{{row.timeOut.toString().replace('-', '')}}鍒嗛挓</span>
-                        <span v-else>-</span>
-                    </template>
-                </el-table-column>
+<!--                <el-table-column prop="inDate" label="鍏ュ満鏃堕棿" min-width="100px"></el-table-column>-->
+<!--                <el-table-column prop="outDate" label="鎺堟潈鍒版湡鏃堕棿" min-width="100px"></el-table-column>-->
+<!--                <el-table-column label="瓒呮椂鏃堕暱" min-width="100px">-->
+<!--                    <template slot-scope="{row}">-->
+<!--                        <span v-if="row.outStatus === 1">{{row.timeOut.toString().replace('-', '')}}鍒嗛挓</span>-->
+<!--                        <span v-else>-</span>-->
+<!--                    </template>-->
+<!--                </el-table-column>-->
                 <el-table-column label="鐘舵��" min-width="100px">
                     <template slot-scope="{row}">
-                        <span v-if="row.outStatus === 0">鏈秴鏃�</span>
-                        <span style="color: red;" v-else-if="row.outStatus === 1">宸茶秴鏃�</span>
-                        <span v-else-if="row.outStatus === 2">鍗冲皢瓒呮椂</span>
+                        <span v-if="row.hkStatus === 0">鏈悓姝�</span>
+                        <span v-else-if="row.hkStatus === 1">宸插悓姝�</span>
+                        <span v-else-if="row.hkStatus === 2">鍚屾澶辫触</span>
+                        <span v-else-if="row.hkStatus === 3">涓嶇鍚堜笅鍙戞潯浠�</span>
+                        <span v-else-if="row.hkStatus === 4">绛夊緟鍒犻櫎鏉冮檺</span>
                     </template>
                 </el-table-column>
-                <el-table-column
-                        v-if="containPermissions(['business:member:update', 'business:member:delete'])"
-                        label="鎿嶄綔"
-                        min-width="120"
-                        fixed="right"
-                >
-                    <template slot-scope="{row}">
-                        <el-button type="text" icon="el-icon-edit" v-permissions="['business:member:update']" @click="departure(row.id)">绂诲巶</el-button>
-                    </template>
-                </el-table-column>
+<!--                <el-table-column-->
+<!--                        v-if="containPermissions(['business:member:update', 'business:member:delete'])"-->
+<!--                        label="鎿嶄綔"-->
+<!--                        min-width="120"-->
+<!--                        fixed="right"-->
+<!--                >-->
+<!--                    <template slot-scope="{row}">-->
+<!--                        <el-button type="text" icon="el-icon-edit" v-permissions="['business:member:update']" @click="departure(row.id)">绂诲巶</el-button>-->
+<!--                    </template>-->
+<!--                </el-table-column>-->
             </el-table>
             <pagination
-                    @size-change="handleSizeChange"
-                    @current-change="handlePageChange"
-                    :pagination="tableData.pagination"
+                @size-change="handleSizeChange"
+                @current-change="handlePageChange"
+                :pagination="tableData.pagination"
             >
             </pagination>
         </template>
@@ -95,7 +97,7 @@
     created () {
       this.config({
         module: '浜哄憳淇℃伅琛�',
-        api: '/business/strandedPersonnel',
+        api: '/business/member',
         'field.id': 'id',
         'field.main': 'id'
       })
diff --git a/admin/src/views/business/device.vue b/admin/src/views/business/device.vue
index 585e035..cd26382 100644
--- a/admin/src/views/business/device.vue
+++ b/admin/src/views/business/device.vue
@@ -2,15 +2,11 @@
     <TableLayout :permissions="['business:device:query']">
         <!-- 鎼滅储琛ㄥ崟 -->
         <el-form ref="searchForm" slot="search-form" :model="searchForm" label-width="100px" inline>
-            <el-form-item label="闂ㄧ鍚嶇О" prop="name">
-                <el-input v-model="searchForm.name" placeholder="璇疯緭鍏ラ棬绂佸悕绉�" @keypress.enter.native="search"></el-input>
+            <el-form-item label="闂ㄧ鐐瑰悕绉�" prop="doorName">
+                <el-input v-model="searchForm.doorName" placeholder="璇疯緭鍏ラ棬绂佺偣鍚嶇О" @keypress.enter.native="search"></el-input>
             </el-form-item>
-            <el-form-item label="闂ㄧ绛夌骇" prop="level">
-                <el-select v-model="searchForm.level" placeholder="璇烽�夋嫨闂ㄧ绛夌骇" @keypress.enter.native="search">
-                    <el-option label="涓�绾ч棬绂�" value="1"></el-option>
-                    <el-option label="浜岀骇闂ㄧ" value="2"></el-option>
-                    <el-option label="涓夌骇闂ㄧ" value="3"></el-option>
-                </el-select>
+            <el-form-item label="鍖哄煙鍚嶇О" prop="regionPathName">
+                <el-input v-model="searchForm.regionPathName" placeholder="璇疯緭鍏ュ尯鍩熷悕绉�" @keypress.enter.native="search"></el-input>
             </el-form-item>
             <section>
                 <el-button type="primary" @click="search">鎼滅储</el-button>
@@ -27,16 +23,12 @@
                 :data="tableData.list"
                 stripe
             >
+                <el-table-column prop="name" label="璁惧鍚嶇О" min-width="100px"></el-table-column>
+                <el-table-column prop="doorName" label="闂ㄧ鐐瑰悕绉�" min-width="100px"></el-table-column>
+                <el-table-column prop="regionPathName" label="鍖哄煙鍚嶇О" min-width="100px"></el-table-column>
+                <el-table-column prop="doorNo" label="闂ㄧ鐐圭紪鍙�" min-width="100px"></el-table-column>
                 <el-table-column prop="manufature" label="鍘傚晢" min-width="100px"></el-table-column>
-                <el-table-column prop="no" label="璁惧缂栧彿" min-width="100px"></el-table-column>
-                <el-table-column prop="name" label="闂ㄧ鍚嶇О" min-width="100px"></el-table-column>
-                <el-table-column prop="level" label="闂ㄧ绛夌骇" min-width="100px"></el-table-column>
-                <el-table-column prop="status" label="璁惧鐘舵��" min-width="100px">
-                    <template slot-scope="{row}">
-                        <span v-if="row.status === 0">绂佺敤</span>
-                        <span v-if="row.status === 1">鍚敤</span>
-                    </template>
-                </el-table-column>
+                <el-table-column prop="no" label="璁惧鍙�" min-width="100px"></el-table-column>
 <!--                <el-table-column-->
 <!--                    v-if="containPermissions(['business:device:update'])"-->
 <!--                    label="鎿嶄綔"-->
@@ -75,8 +67,8 @@
     return {
       // 鎼滅储
       searchForm: {
-        name: '',
-        level: ''
+        doorName: '',
+        regionPathName: ''
       },
       options: []
     }
diff --git a/admin/src/views/business/deviceRole.vue b/admin/src/views/business/deviceRole.vue
index 776c49d..c2c96cb 100644
--- a/admin/src/views/business/deviceRole.vue
+++ b/admin/src/views/business/deviceRole.vue
@@ -1,9 +1,9 @@
 <template>
     <TableLayout :permissions="['business:devicerole:query']">
         <!-- 鎼滅储琛ㄥ崟 -->
-        <el-form ref="searchForm" slot="search-form" :model="searchForm" label-width="100px" inline>
-            <el-form-item label="闂ㄧ缁勫悕绉�" prop="name">
-                <el-input v-model="searchForm.name" placeholder="璇疯緭鍏ラ棬绂佺粍鍚嶇О" @keypress.enter.native="search"></el-input>
+        <el-form ref="searchForm" slot="search-form" :model="searchForm" label-width="110px" inline>
+            <el-form-item label="闂ㄧ鐐瑰垎缁勫悕绉�" prop="name">
+                <el-input v-model="searchForm.name" placeholder="璇疯緭鍏ラ棬绂佺偣鍒嗙粍鍚嶇О" @keypress.enter.native="search"></el-input>
             </el-form-item>
             <section>
                 <el-button type="primary" @click="search">鎼滅储</el-button>
@@ -13,7 +13,7 @@
         <!-- 琛ㄦ牸鍜屽垎椤� -->
         <template v-slot:table-wrap>
             <ul class="toolbar" v-permissions="['business:devicerole:create', 'business:devicerole:delete']">
-                <li><el-button type="primary" @click="$refs.operaDeviceRoleWindow.open('鏂板缓闂ㄧ瑙掕壊')" icon="el-icon-plus" v-permissions="['business:devicerole:create']">鏂板缓</el-button></li>
+                <li><el-button type="primary" @click="$refs.operaDeviceRoleWindow.open('鏂板缓闂ㄧ鐐瑰垎缁�')" icon="el-icon-plus" v-permissions="['business:devicerole:create']">鏂板缓</el-button></li>
                 <li><el-button @click="deleteByIdInBatch" icon="el-icon-delete" v-permissions="['business:devicerole:delete']">鍒犻櫎</el-button></li>
             </ul>
             <el-table
@@ -23,7 +23,7 @@
                 @selection-change="handleSelectionChange"
             >
                 <el-table-column type="selection" width="55"></el-table-column>
-                <el-table-column prop="name" label="闂ㄧ缁勫悕绉�" min-width="100px"></el-table-column>
+                <el-table-column prop="name" label="闂ㄧ鐐瑰垎缁�" min-width="100px"></el-table-column>
                 <el-table-column prop="memberNum" label="浣跨敤浜烘暟" min-width="100px"></el-table-column>
                 <el-table-column prop="isDefault" label="鏄惁榛樿" min-width="100px">
                     <template slot-scope="{row}">
@@ -83,7 +83,7 @@
   },
   created () {
     this.config({
-      module: '闂ㄧ瑙掕壊',
+      module: '闂ㄧ鐐瑰垎缁�',
       api: '/business/deviceRole',
       'field.id': 'id',
       'field.main': 'name'
@@ -108,7 +108,7 @@
         row.radio = 0
         row.doorIds = []
       }
-      this.$refs.operaDeviceRoleWindow.open('缂栬緫闂ㄧ瑙掕壊', row)
+      this.$refs.operaDeviceRoleWindow.open('缂栬緫闂ㄧ鐐瑰垎缁�', row)
     }
   }
 }
diff --git a/admin/src/views/business/empower.vue b/admin/src/views/business/empower.vue
index bf8eb75..b0e7e3d 100644
--- a/admin/src/views/business/empower.vue
+++ b/admin/src/views/business/empower.vue
@@ -60,10 +60,14 @@
                 <el-table-column prop="memberPhone" label="鎵嬫満鍙�" min-width="120px"></el-table-column>
                 <el-table-column prop="memberidCard" label="韬唤璇佸彿鐮�" min-width="130px"></el-table-column>
                 <el-table-column prop="companyName" label="鎵�灞炲叕鍙�" min-width="150px"></el-table-column>
+                <el-table-column prop="deviceName" label="璁惧鍚嶇О" min-width="150px"></el-table-column>
                 <el-table-column label="闂ㄧ鏈夋晥鏈�" min-width="170px">
                     <template slot-scope="{row}">
-                        <span>璧凤細{{row.startTime}}</span><br />
-                        <span>姝細{{row.endTime}}</span>
+                        <span v-if="!row.startTime || !row.endTime">闀挎湡</span>
+                        <div v-else>
+                            <span>璧凤細{{row.startTime}}</span><br />
+                            <span>姝細{{row.endTime}}</span>
+                        </div>
                     </template>
                 </el-table-column>
                 <el-table-column prop="sendDate" label="鍒涘缓鏃堕棿" min-width="150px"></el-table-column>
diff --git a/admin/src/views/business/interfaceLog.vue b/admin/src/views/business/interfaceLog.vue
index 89642cd..e9d457e 100644
--- a/admin/src/views/business/interfaceLog.vue
+++ b/admin/src/views/business/interfaceLog.vue
@@ -40,7 +40,7 @@
                 <el-table-column label="绫诲瀷" min-width="100px">
                     <template slot-scope="{row}">
                         <span v-if="row.type == 0">璋冪敤</span>
-                        <span v-if="row.type == 1">鎺ㄩ�佹帴鍙�</span>
+                        <span v-if="row.type == 1">鎺ㄩ�佹帴鏀�</span>
                     </template>
                 </el-table-column>
                 <el-table-column label="骞冲彴" min-width="100px">
diff --git a/admin/src/views/business/internalMember.vue b/admin/src/views/business/internalMember.vue
index 21cc600..24f5473 100644
--- a/admin/src/views/business/internalMember.vue
+++ b/admin/src/views/business/internalMember.vue
@@ -107,17 +107,16 @@
                         <el-button @click="$refs.cardOpeningRecord.open('寮�鍗¤褰�', row.id)" type="text">{{row.memberCardCount || '0'}}</el-button>
                     </template>
                 </el-table-column>
-<!--                <el-table-column-->
-<!--                    v-if="containPermissions(['business:member:update', 'business:member:delete'])"-->
-<!--                    label="鎿嶄綔"-->
-<!--                    min-width="120"-->
-<!--                    fixed="right"-->
-<!--                >-->
-<!--                    <template slot-scope="{row}">-->
-<!--                        <el-button type="text" @click="$refs.operaMemberWindow.open('缂栬緫浜哄憳淇℃伅琛�', row)" icon="el-icon-edit" v-permissions="['business:member:update']">缂栬緫</el-button>-->
-<!--                        <el-button type="text" @click="deleteById(row)" icon="el-icon-delete" v-permissions="['business:member:delete']">鍒犻櫎</el-button>-->
-<!--                    </template>-->
-<!--                </el-table-column>-->
+                <el-table-column
+                    v-if="containPermissions(['business:member:update', 'business:member:delete'])"
+                    label="鎿嶄綔"
+                    min-width="120"
+                    fixed="right"
+                >
+                    <template slot-scope="{row}">
+                        <el-button type="text" @click="empower(row.id)" v-permissions="['business:empower:create']">閲嶆柊鎺堟潈</el-button>
+                    </template>
+                </el-table-column>
             </el-table>
             <pagination
                 @size-change="handleSizeChange"
@@ -138,7 +137,7 @@
 import cardOpeningRecord from '@/components/business/cardOpeningRecord'
 import Tree from '@/components/common/Tree'
 import { fetchList } from '@/api/business/company'
-import { memberSync } from '@/api/business/member'
+import { memberSync, roleAuth } from '@/api/business/member'
 export default {
   name: 'internalMember',
   extends: BaseTable,
@@ -173,6 +172,21 @@
     this.getfindCompanyTreePage()
   },
   methods: {
+    empower(id) {
+      var that = this
+      this.$confirm('纭畾閲嶆柊鎺堟潈鍚�?', '鎻愮ず', {
+        confirmButtonText: '纭畾',
+        cancelButtonText: '鍙栨秷',
+        type: 'warning'
+      }).then(() => {
+        roleAuth(id)
+          .then(res => {
+            that.search()
+          })
+      }).catch(() => {
+
+      });
+    },
     // 鑾峰彇缁勭粐鏍�
     getfindCompanyTreePage () {
       fetchList(1)
diff --git a/admin/src/views/business/visits.vue b/admin/src/views/business/visits.vue
index 34e4ca2..2c4ea45 100644
--- a/admin/src/views/business/visits.vue
+++ b/admin/src/views/business/visits.vue
@@ -49,12 +49,21 @@
                 <el-table-column prop="companyName" label="鍏徃鍚嶇О" min-width="100px"></el-table-column>
                 <el-table-column prop="receptMemberName" label="琚浜�" min-width="100px"></el-table-column>
                 <el-table-column prop="reason" label="鎷滆浜嬬敱" min-width="100px"></el-table-column>
-                <el-table-column label="鎷滆鏃堕棿" min-width="170px">
+                <el-table-column label="棰勭害鏃堕棿" min-width="170px">
                     <template slot-scope="{row}">
                         <span>璧凤細{{row.starttime}}</span><br/>
                         <span>姝細{{row.endtime}}</span>
                     </template>
                 </el-table-column>
+                <el-table-column label="绛惧埌鏃堕棿" min-width="170px">
+                    <template slot-scope="{row}">
+                        <div v-if="row.inDate && row.outDate">
+                            <span>璧凤細{{row.inDate}}</span><br/>
+                            <span>姝細{{row.outDate}}</span>
+                        </div>
+                        <span v-else>-</span>
+                    </template>
+                </el-table-column>
                 <el-table-column label="闅忚浜哄憳" min-width="100px">
                     <template slot-scope="{row}">
                         <span>{{row.memberNum || '-'}}</span>
diff --git a/admin/vue.config.js b/admin/vue.config.js
index ec8fd81..e5bba52 100644
--- a/admin/vue.config.js
+++ b/admin/vue.config.js
@@ -13,7 +13,7 @@
         // http://192.168.0.134:10028   浠诲悍
         // http://192.168.0.110:10013   纾婄
         // http://192.168.0.132:10013   甯呭摜
-        // http://192.168.0.126:10033   钀嶅
+        // http://192.168.0.176:10028   钀嶅
         // http://192.168.0.186:10028   浠诲悍
         // https://dmtest.ahapp.net/admin_api   娴嬭瘯鏈�
         // http://10.10.99.63/admin_interface/  鏈�鏂版祴璇曟湇锛堝唴缃戯級
diff --git a/h5/App.vue b/h5/App.vue
index 76fce77..b69017c 100644
--- a/h5/App.vue
+++ b/h5/App.vue
@@ -18,6 +18,9 @@
 					}).then(res => {
 						if (res.code === 200) {
 							that.$store.commit('setOpenId', res.data.openid)
+							if (res.data.member) {
+								that.$store.commit('setMember', res.data.member)
+							}
 						}
 					})
 				}
diff --git a/h5/components/cropping/cropping.vue b/h5/components/cropping/cropping.vue
new file mode 100644
index 0000000..15de5cc
--- /dev/null
+++ b/h5/components/cropping/cropping.vue
@@ -0,0 +1,700 @@
+<template name="yq-avatar">
+	<view class="croppage">
+		<canvas canvas-id="avatar-canvas" id="avatar-canvas" class="my-canvas" :style="{top: sT, height: csH}"
+			:disable-scroll="false"></canvas>
+		<canvas canvas-id="oper-canvas" id="oper-canvas" class="oper-canvas" :style="{top: sT1, height: csH1}"
+			:disable-scroll="false" @touchstart="fStart" @touchmove="fMove" @touchend="fEnd">
+		</canvas>
+		<canvas canvas-id="prv-canvas" id="prv-canvas" class="prv-canvas" :disable-scroll="false" @touchstart="fHideImg"
+			:style="{ height: csH, top: pT }">
+		</canvas>
+		<view class="oper-wrapper" :style="{top:tp}">
+			<view class="oper">
+				<view class="btn-wrapper">
+					<view @click="rechoose" hover-class="hover" :style="{width: bW}"><text>閲嶉��</text></view>
+					<view @click="fUpload" hover-class="hover" :style="{width: bW}"><text>纭畾</text></view>
+				</view>
+			</view>
+		</view>
+	</view>
+</template>
+ 
+<script>
+	const tH = 50;
+	export default {
+		data() {
+			return {
+				sT1num: 0,
+				csH1: '0px',
+				sT1: 0,
+				csH: '0px',
+				sD: 'none',
+				sT: '-10000px',
+				pT: '-10000px',
+				iS: {},
+				sS: {},
+				bW: '19%',
+				bD: 'flex',
+				tp: 0,
+			};
+		},
+		props: {
+			avatarSrc: '',
+			avatarStyle: '',
+			selWidth: '',
+			selHeight: '',
+			expWidth: '',
+			expHeight: '',
+			minScale: '',
+			maxScale: '',
+			canScale: '',
+			canRotate: '',
+			lockWidth: '',
+			lockHeight: '',
+			stretch: '',
+			lock: '',
+			fileType: '',
+			noTab: '',
+			inner: '',
+			quality: '',
+			index: '',
+			bgImage: '',
+		},
+		created() {
+			this.cc = uni.createCanvasContext('avatar-canvas', this);
+			this.cco = uni.createCanvasContext('oper-canvas', this);
+			this.ccp = uni.createCanvasContext('prv-canvas', this);
+			this.qlty = parseFloat(this.quality) || 1; //鐢昏川
+			this.letRotate = (this.canRotate === false || this.inner === true || this.inner === 'true' || this
+				.canRotate === 'false') ? 0 : 1; //鏄惁鏃嬭浆
+			this.letScale = (this.canScale === false || this.canScale === 'false') ? 0 : 1; //鏄惁鏀惧ぇ
+			this.isin = (this.inner === true || this.inner === 'true') ? 1 : 0;
+			this.indx = this.index || undefined; //绂佹鏃嬭浆骞跺湪鍥剧墖鑼冨洿鍐呯Щ鍔�
+			this.mnScale = parseFloat(this.minScale) || 0.3; //缂╁皬姣斾緥
+			this.mxScale = parseFloat(this.maxScale) || 4; //鏀惧ぇ姣斿垪
+			this.noBar = (this.noTab === true || this.noTab === 'true') ? 1 : 0; //鏄惁瀛樺湪nobar
+			this.stc = this.stretch; //鑷姩閾烘弧
+			this.lck = this.lock; //閿佸畾鍥炬柟鍚� x y long short longSel shortSel
+			this.fType = this.fileType === 'jpg' ? 'jpg' : 'png';
+			if (this.isin || !this.letRotate) {
+				this.bW = '24%';
+				this.bD = 'none';
+			} else {
+				this.bW = '19%';
+				this.bD = 'flex';
+			}
+			if (this.noBar) {
+				this.fWindowResize();
+			} else {
+				uni.showTabBar({
+					fail: () => {
+						this.noBar = 1;
+					},
+					success: () => {
+						this.noBar = 0;
+					},
+					complete: (res) => {
+						this.fWindowResize();
+					}
+				});
+			}
+		},
+		methods: {
+			//閲嶉��
+			rechoose() {
+				const that = this
+				uni.chooseImage({
+					count: 1,
+					sizeType: ['original', 'compressed'],
+					sourceType: ["album"],
+					success: (res) => {
+						that.sT1 = that.sT
+						that.csH1 = that.csH
+						that.fSelect(res.tempFilePaths[0])
+					}
+				});
+			},
+			//鍒濆鍖栧悇绉嶆暟鎹�
+			fWindowResize() {
+				let sysInfo = uni.getSystemInfoSync();
+				this.platform = sysInfo.platform;
+				this.wW = sysInfo.windowWidth;
+				// #ifndef H5
+				let phone = uni.getSystemInfoSync().platform
+				console.log(uni.getSystemInfoSync().platform)
+				if (phone == 'ios') {
+					let h = uni.upx2px(60); //灏唕px鍗曚綅鍊艰浆鎹㈡垚px 瑁佸壀妗嗚嚜宸�
+					let b = uni.upx2px(100); //搴曢儴鎸夐挳
+					this.sT1 = (sysInfo.windowHeight - h - b) / 2 + 'px' //瑁佸壀妗嗚窛绂婚《閮�+px
+					this.sT1num = (sysInfo.windowHeight - h - b) / 2 //瑁佸壀妗嗚窛绂婚《閮ㄤ笉+px
+				} else {
+					this.drawTop = 0;
+				}
+				// #endif
+				// #ifndef MP-ALIPAY
+				let phone = uni.getSystemInfoSync().platform
+				this.wH = sysInfo.windowHeight; //璁惧楂�
+				if (!this.noBar) this.wH += tH; //th=50
+				this.csH = this.wH - tH + 'px'; //楂�=璁惧楂�-50(瀵艰埅)
+				if (phone == 'ios') { //閫傞厤ios
+					this.csH1 = (this.wH - 50) / 2 + 'px'
+				} else {
+					this.csH1 = this.wH - tH + 'px';
+				}
+				// #endif
+				this.tp = this.csH;
+				this.pxRatio = this.wW / 750; //璁惧瀹�/750  姣斿垪
+				this.expWidth && (this.eW = this.expWidth.toString().indexOf('upx') >= 0 ? parseInt(this.expWidth) * this
+					.pxRatio : parseInt(this.expWidth));
+				this.expHeight && (this.eH = this.expHeight.toString().indexOf('upx') >= 0 ? parseInt(this.expHeight) *
+					this.pxRatio : parseInt(this.expHeight));
+				this.fHideImg();
+			},
+			fSelect(r) {
+				if (this.fSelecting) return;
+				this.fSelecting = true;
+				setTimeout(() => {
+					this.fSelecting = false;
+				}, 500); //闃叉姈
+				let path = this.imgPath = r; //闇�瑕佸壀瑁佺殑鍥剧墖璺緞
+				// 鑾峰彇鍥剧墖淇℃伅
+				uni.getImageInfo({
+					src: path,
+					success: r => {
+						this.imgWidth = r.width;
+						this.imgHeight = r.height;
+						this.path = path;
+						if (!this.hasSel) {
+							let style = this.sS || {};
+							if (this.selWidth && this.selHeight) { //璁剧疆鐨勫壀瑁佸尯鍩熷楂�
+								let sW = this.selWidth.toString().indexOf('upx') >= 0 ?
+									parseInt(this.selWidth) * this.pxRatio : parseInt(
+										this.selWidth),
+									sH = this.selHeight.toString().indexOf('upx') >= 0 ?
+									parseInt(this.selHeight) * this.pxRatio : parseInt(
+										this.selHeight);
+								style.width = sW + 'px';
+								style.height = sH + 'px';
+								style.top = ((this.wH - sH - tH) | 0) / 2 + 'px';
+								style.left = ((this.wW - sW) | 0) / 2 + 'px';
+								// }
+							} else {
+								uni.showModal({
+									title: '瑁佸壀妗嗙殑瀹芥垨楂樻病鏈夎缃�',
+									showCancel: false
+								})
+								return;
+							}
+							this.sS = style;
+						}
+						if (this.noBar) {
+							setTimeout(() => {
+								this.fDrawInit(true);
+							}, 200)
+						} else {
+							uni.hideTabBar({
+								complete: () => {
+									setTimeout(() => {
+										this.fDrawInit(true);
+									}, 200)
+								}
+							});
+						}
+					},
+					fail: () => {
+						uni.showToast({
+							title: "璇烽�夋嫨姝g‘鍥剧墖",
+							duration: 2000,
+						})
+					},
+					complete() {
+						uni.hideLoading();
+					}
+				});
+			},
+			//鍓纭畾
+			fUpload() {
+				uni.showLoading({
+					title: '鍥剧墖涓婁紶涓�...',
+					mask: true
+				});
+				if (this.fUploading) return;
+				this.fUploading = true;
+				setTimeout(() => {
+					this.fUploading = false;
+				}, 1000)
+				let style = this.sS,
+					x = parseInt(style.left),
+					y = parseInt(style.top),
+					width = parseInt(style.width),
+					height = parseInt(style.height),
+					expWidth = this.eW || (width * this.pixelRatio),
+					expHeight = this.eH || (height * this.pixelRatio);
+				this.fHideImg();
+				// #ifndef MP-ALIPAY
+				let phone = uni.getSystemInfoSync().platform
+				if (phone == 'ios') {
+					y = this.sT1num
+				}
+				uni.canvasToTempFilePath({
+					x: x,
+					y: y,
+					width: width,
+					height: height,
+					destWidth: expWidth,
+					destHeight: expHeight,
+					canvasId: 'avatar-canvas',
+					fileType: this.fType,
+					quality: this.qlty,
+					success: (r) => {
+						r = r.tempFilePath;
+						// #ifndef H5
+						this.$emit("upload", {
+							avatar: this.imgSrc,
+							path: r,
+							index: this.indx,
+							data: this.rtn,
+							base64: this.base64 || null
+						});
+						// #endif
+					},
+					fail: (res) => {
+						uni.showToast({
+							title: "error1",
+							duration: 2000,
+						})
+					},
+					complete: () => {
+						uni.hideLoading();
+						this.noBar || uni.showTabBar();
+						this.$emit("end");
+					}
+				}, this);
+				// #endif
+			},
+			fDrawInit(ini = false) {
+				let allWidth = this.wW, //璁惧瀹�
+					allHeight = this.wH, //璁惧楂�
+					imgWidth = this.imgWidth, //鍥惧
+					imgHeight = this.imgHeight, //鍥鹃珮
+					imgRadio = imgWidth / imgHeight, //鍥炬瘮
+					useWidth = allWidth - 40, //璁惧瀹�-40
+					useHeight = allHeight - tH - 80, //璁惧楂�-80
+					useRadio = useWidth / useHeight,
+					sW = parseInt(this.sS.width), //鍥剧墖淇℃伅
+					sH = parseInt(this.sS.height);
+				this.fixWidth = 0;
+				this.fixHeight = 0;
+				this.lckWidth = 0;
+				this.lckHeight = 0;
+				switch (this.stc) { //浠ヤ笅鏄嚜鍔ㄩ摵婊$殑绠楁硶
+					case 'x':
+						this.fixWidth = 1;
+						break;
+					case 'y':
+						this.fixHeight = 1;
+						break;
+					case 'long':
+						if (imgRadio > 1) this.fixWidth = 1;
+						else this.fixHeight = 1;
+						break;
+					case 'short':
+						if (imgRadio > 1) this.fixHeight = 1;
+						else this.fixWidth = 1;
+						break;
+					case 'longSel':
+						if (sW > sH) this.fixWidth = 1;
+						else this.fixHeight = 1;
+						break;
+					case 'shortSel':
+						if (sW > sH) this.fixHeight = 1;
+						else this.fixWidth = 1;
+						break;
+				}
+				switch (this.lck) { //浠ヤ笅閿佸畾灞忓箷鐨勭Щ鍔ㄦ柟鍚�
+					case 'x':
+						this.lckWidth = 1;
+						break;
+					case 'y':
+						this.lckHeight = 1;
+						break;
+					case 'long':
+						if (imgRadio > 1) this.lckWidth = 1;
+						else this.lckHeight = 1;
+						break;
+					case 'short':
+						if (imgRadio > 1) this.lckHeight = 1;
+						else this.lckWidth = 1;
+						break;
+					case 'longSel':
+						if (sW > sH) this.lckWidth = 1;
+						else this.lckHeight = 1;
+						break;
+					case 'shortSel':
+						if (sW > sH) this.lckHeight = 1;
+						else this.lckWidth = 1;
+						break;
+				}
+				if (this.fixWidth) {
+					useWidth = sW;
+					useHeight = useWidth / imgRadio;
+				} else if (this.fixHeight) {
+					useHeight = sH;
+					useWidth = useHeight * imgRadio;
+				} else if (imgRadio < useRadio) {
+					if (imgHeight < useHeight) {
+						useWidth = imgWidth;
+						useHeight = imgHeight;
+					} else {
+						useWidth = useHeight * imgRadio;
+					}
+				} else {
+					if (imgWidth < useWidth) {
+						useWidth = imgWidth;
+						useHeight = imgHeight;
+					} else {
+						useHeight = useWidth / imgRadio;
+					}
+				}
+				if (this.isin) {
+					if (useWidth < sW) {
+						useWidth = sW;
+						useHeight = useWidth / imgRadio;
+						this.lckHeight = 0;
+					}
+					if (useHeight < sH) {
+						useHeight = sH;
+						useWidth = useHeight * imgRadio;
+						this.lckWidth = 0;
+					}
+				}
+				this.scaleSize = 1;
+				this.rotateDeg = 0;
+				this.posWidth = (allWidth - useWidth) / 2 | 0;
+				this.posHeight = (allHeight - useHeight - tH) / 2 | 0;
+				this.useWidth = useWidth | 0;
+				this.useHeight = useHeight | 0;
+				this.centerX = this.posWidth + useWidth / 2;
+				this.centerY = this.posHeight + useHeight / 2;
+				this.focusX = 0;
+				this.focusY = 0;
+				let style = this.sS,
+					left = parseInt(style.left),
+					top = parseInt(style.top),
+					width = parseInt(style.width),
+					height = parseInt(style.height),
+					canvas = this.canvas,
+					canvasOper = this.canvasOper,
+					cc = this.cc, //avatar-canvas
+					cco = this.cco; //oper-canvas  瑁佸壀
+				cco.beginPath(); //寮�濮嬪垱寤轰竴涓矾寰�
+				cco.setLineWidth(3); //璁剧疆绾挎潯鐨勫搴�  px
+				cco.setGlobalAlpha(1); //璁剧疆鍏ㄥ眬鐢荤瑪閫忔槑搴︺��
+				cco.setStrokeStyle('white'); //璁剧疆杈规棰滆壊銆傚鏋滄病鏈夎缃� fillStyle锛岄粯璁ら鑹蹭负 black銆�
+				cco.strokeRect(left, top, width, height); //鐢讳竴涓煩褰�(闈炲~鍏�)銆傜敤 setFillStroke() 璁剧疆杈规棰滆壊锛屽鏋滄病璁剧疆榛樿鏄粦鑹层��
+				cco.setFillStyle('black');
+				cco.setGlobalAlpha(0.5);
+				cco.fillRect(0, 0, this.wW, top); //濉厖涓�涓煩褰�
+				cco.fillRect(0, top, left, height);
+				cco.fillRect(0, top + height, this.wW, this.wH - height - top - tH);
+				cco.fillRect(left + width, top, this.wW - width - left, height);
+				cco.setGlobalAlpha(1);
+				cco.setStrokeStyle('red');
+				cco.moveTo(left + 15, top); //鎶婅矾寰勭Щ鍔ㄥ埌鐢诲竷涓殑鎸囧畾鐐癸紝涓嶅垱寤虹嚎鏉°�傜敤 stroke() 鏂规硶鏉ョ敾绾挎潯銆�
+				cco.lineTo(left, top); //澧炲姞涓�涓柊鐐癸紝鐒跺悗鍒涘缓涓�鏉′粠涓婃鎸囧畾鐐瑰埌鐩爣鐐圭殑绾裤��
+				cco.lineTo(left, top + 15);
+				cco.moveTo(left + width - 15, top);
+				cco.lineTo(left + width, top);
+				cco.lineTo(left + width, top + 15);
+				cco.moveTo(left + 15, top + height);
+				cco.lineTo(left, top + height);
+				cco.lineTo(left, top + height - 15);
+				cco.moveTo(left + width - 15, top + height);
+				cco.lineTo(left + width, top + height);
+				cco.lineTo(left + width, top + height - 15);
+				cco.stroke(); //鐢荤嚎鏉�
+				cco.draw(false, () => { //灏嗕箣鍓嶅湪缁樺浘涓婁笅鏂囦腑鐨勬弿杩帮紙璺緞銆佸彉褰€�佹牱寮忥級鐢诲埌 canvas 涓��
+					if (ini) {
+						this.sT = this.drawTop + 'px';
+						this.fDrawImage(true); //缁樺埗鑳屾櫙鑹�
+					}
+				});
+				this.$emit("init");
+			},
+			//缁樺埗鑳屾櫙鑹�
+			fDrawImage(ini = false) {
+				let tm_now = Date.now(); //褰撳墠鏃堕棿
+				if (tm_now - this.drawTm < 20) return;
+				this.drawTm = tm_now;
+				let cc = this.cc,
+					imgWidth = this.useWidth * this.scaleSize,
+					imgHeight = this.useHeight * this.scaleSize;
+				if (this.bgImage) { //濡傛灉鑳屾櫙鍥�
+					// #ifndef MP-ALIPAY
+					cc.drawImage(this.bgImage, 0, 0, this.wW, this.wH - tH); //缁樺埗鍥惧儚鍒扮敾甯冦��
+					// #endif
+				} else {
+					cc.fillRect(0, 0, this.wW, this.wH - tH); //濉厖涓�涓煩褰�
+				}
+				if (this.isin) { //绂佹鏃嬭浆骞跺湪鍥剧墖鑼冨洿鍐呯Щ鍔�
+					let cx = this.focusX * (this.scaleSize - 1),
+						cy = this.focusY * (this.scaleSize - 1);
+					cc.translate(this.centerX, this.centerY);
+					cc.rotate(this.rotateDeg * Math.PI / 180);
+					cc.drawImage(this.imgPath, this.posWidth - this.centerX - cx, this.posHeight - this.centerY - cy,
+						imgWidth, imgHeight);
+				} else {
+					cc.translate(this.posWidth + imgWidth / 2, this.posHeight + imgHeight / 2);
+					cc.rotate(this.rotateDeg * Math.PI / 180);
+					cc.drawImage(this.imgPath, -imgWidth / 2, -imgHeight / 2, imgWidth, imgHeight);
+				}
+				cc.draw(false);
+			},
+			//鏃嬭浆
+			fRotate() {
+				this.rotateDeg += 90 - this.rotateDeg % 90;
+				this.fDrawImage();
+			},
+			//鎵嬫寚瑙︽懜寮�濮�
+			fStart(e) {
+				let touches = e.touches,
+					touch0 = touches[0],
+					touch1 = touches[1];
+				this.touch0 = touch0;
+				this.touch1 = touch1;
+				if (touch1) {
+					let x = touch1.x - touch0.x,
+						y = touch1.y - touch0.y;
+					this.fgDistance = Math.sqrt(x * x + y * y);
+				}
+			},
+			//鎵嬫寚瑙︽懜鍚庣Щ鍔�
+			fMove(e) {
+				let touches = e.touches,
+					touch0 = touches[0],
+					touch1 = touches[1];
+				if (touch1) {
+					let x = touch1.x - touch0.x,
+						y = touch1.y - touch0.y,
+						fgDistance = Math.sqrt(x * x + y * y),
+						scaleSize = 0.005 * (fgDistance - this.fgDistance),
+						beScaleSize = this.scaleSize + scaleSize;
+					do {
+						if (!this.letScale) break;
+						if (beScaleSize < this.mnScale) break;
+						if (beScaleSize > this.mxScale) break;
+						let growX = this.useWidth * scaleSize / 2,
+							growY = this.useHeight * scaleSize / 2;
+						if (this.isin) {
+							let imgWidth = this.useWidth * beScaleSize,
+								imgHeight = this.useHeight * beScaleSize,
+								l = this.posWidth - growX,
+								t = this.posHeight - growY,
+								r = l + imgWidth,
+								b = t + imgHeight,
+								left = parseInt(this.sS.left),
+								top = parseInt(this.sS.top),
+								width = parseInt(this.sS.width),
+								height = parseInt(this.sS.height),
+								right = left + width,
+								bottom = top + height,
+								cx, cy;
+							if (imgWidth <= width || imgHeight <= height) break;
+							this.cx = cx = this.focusX * beScaleSize - this.focusX,
+								this.cy = cy = this.focusY * beScaleSize - this.focusY;
+							this.posWidth -= growX;
+							this.posHeight -= growY;
+							if (this.posWidth - cx > left) {
+								this.posWidth = left + cx;
+							}
+							if (this.posWidth + imgWidth - cx < right) {
+								this.posWidth = right - imgWidth + cx;
+							}
+							if (this.posHeight - cy > top) {
+								this.posHeight = top + cy;
+							}
+							if (this.posHeight + imgHeight - cy < bottom) {
+								this.posHeight = bottom - imgHeight + cy;
+							}
+						} else {
+							this.posWidth -= growX;
+							this.posHeight -= growY;
+						}
+						this.scaleSize = beScaleSize;
+					} while (0);
+					this.fgDistance = fgDistance;
+					if (touch1.x !== touch0.x && this.letRotate) {
+						x = (this.touch1.y - this.touch0.y) / (this.touch1.x - this.touch0.x);
+						y = (touch1.y - touch0.y) / (touch1.x - touch0.x);
+						this.rotateDeg += Math.atan((y - x) / (1 + x * y)) * 180 / Math.PI;
+						this.touch0 = touch0;
+						this.touch1 = touch1;
+					}
+					this.fDrawImage();
+				} else if (this.touch0) {
+					let x = touch0.x - this.touch0.x,
+						y = touch0.y - this.touch0.y,
+						beX = this.posWidth + x,
+						beY = this.posHeight + y;
+					if (this.isin) {
+						let imgWidth = this.useWidth * this.scaleSize,
+							imgHeight = this.useHeight * this.scaleSize,
+							l = beX,
+							t = beY,
+							r = l + imgWidth,
+							b = t + imgHeight,
+							left = parseInt(this.sS.left),
+							top = parseInt(this.sS.top),
+							right = left + parseInt(this.sS.width),
+							bottom = top + parseInt(this.sS.height),
+							cx, cy;
+						this.cx = cx = this.focusX * this.scaleSize - this.focusX;
+						this.cy = cy = this.focusY * this.scaleSize - this.focusY;
+						if (!this.lckWidth && Math.abs(x) < 100) {
+							if (left < l - cx) {
+								this.posWidth = left + cx;
+							} else if (right > r - cx) {
+								this.posWidth = right - imgWidth + cx;
+							} else {
+								this.posWidth = beX;
+								this.focusX -= x;
+							}
+						}
+						if (!this.lckHeight && Math.abs(y) < 100) {
+							if (top < t - cy) {
+								this.focusY -= (top + cy - this.posHeight);
+								this.posHeight = top + cy;
+							} else if (bottom > b - cy) {
+								this.focusY -= (bottom + cy - (this.posHeight + imgHeight));
+								this.posHeight = bottom - imgHeight + cy;
+							} else {
+								this.posHeight = beY;
+								this.focusY -= y;
+							}
+						}
+					} else {
+						if (Math.abs(x) < 100 && !this.lckWidth) this.posWidth = beX;
+						if (Math.abs(y) < 100 && !this.lckHeight) this.posHeight = beY;
+						this.focusX -= x;
+						this.focusY -= y;
+					}
+					this.touch0 = touch0;
+					this.fDrawImage();
+				}
+			},
+			//鎵嬫寚瑙︽懜鍔ㄤ綔缁撴潫
+			fEnd(e) {
+				let touches = e.touches,
+					touch0 = touches && touches[0],
+					touch1 = touches && touches[1];
+				if (touch0) {
+					this.touch0 = touch0;
+				} else {
+					this.touch0 = null;
+					this.touch1 = null;
+				}
+			},
+			fHideImg() {
+				this.prvImg = '';
+				this.pT = '-10000px';
+				this.prvImgData = null;
+				this.target = null;
+			},
+		}
+	}
+</script>
+<style>
+	.croppage {
+		width: 100%;
+		height: 100%;
+		box-sizing: border-box;
+		background-color: #000000;
+		position: relative;
+	}
+	.my-canvas {
+		/* display: flex; */
+		position: absolute !important;
+		left: 0;
+		z-index: 100000;
+		width: 100%;
+	}
+	.my-avatar {
+		width: 150upx;
+		height: 150upx;
+		border-radius: 100%;
+	}
+	.oper-canvas {
+		/* display: flex; */
+		position: absolute !important;
+		left: 0;
+		z-index: 100000;
+		width: 100%;
+	}
+	.prv-canvas {
+		display: flex;
+		position: fixed !important;
+		background: #000000;
+		left: 0;
+		z-index: 200000;
+		width: 100%;
+	}
+	.oper-wrapper {
+		height: 100rpx;
+		position: fixed !important;
+		box-sizing: border-box;
+		border: 1px solid #F1F1F1;
+		background: #ffffff;
+		width: 100%;
+		left: 0;
+		bottom: 0;
+		z-index: 99999999;
+		flex-direction: row;
+	}
+	.oper {
+		display: flex;
+		flex-direction: column;
+		justify-content: center;
+		padding: 10upx 20upx;
+		width: 100%;
+		height: 100%;
+		box-sizing: border-box;
+		align-self: center;
+	}
+	.btn-wrapper {
+		display: flex;
+		flex-direction: row;
+		flex-grow: 1;
+		height: 50px;
+		justify-content: space-between;
+	}
+ 
+	.btn-wrapper view {
+		display: flex;
+		align-items: center;
+		justify-content: center;
+		font-size: 16px;
+		color: #3b7ffb;
+		border-radius: 6%;
+	}
+	.hover {
+		background: #f1f1f1;
+		border-radius: 6%;
+	}
+	.clr-wrapper {
+		display: flex;
+		flex-direction: row;
+		flex-grow: 1;
+	}
+	.clr-wrapper view {
+		display: flex;
+		align-items: center;
+		justify-content: center;
+		font-size: 16px;
+		color: #333;
+		border: 1px solid #f1f1f1;
+		border-radius: 6%;
+	}
+	.my-slider {
+		flex-grow: 1;
+	}
+</style>
\ No newline at end of file
diff --git a/h5/components/keyboard-input/keyboard-input.vue b/h5/components/keyboard-input/keyboard-input.vue
new file mode 100644
index 0000000..e8af5fc
--- /dev/null
+++ b/h5/components/keyboard-input/keyboard-input.vue
@@ -0,0 +1,463 @@
+ <template>
+	<view class="so-mask" v-if="show">
+		<view style="height: 100%" @tap="$emit('close')" />
+		<view class="so-plate animation-scale-up">
+			<view class="so-plate-head">
+				<view class="so-plate-type">
+					<radio-group @change="typeChange">
+						<label>
+							<radio value="1" :checked="type===1" />
+							鏅�氳溅鐗�
+						</label>
+						<label>
+							<radio value="2" :checked="type===2" />
+							鏂拌兘婧愯溅鐗�
+						</label>
+					</radio-group>
+				</view>
+			</view>
+			<view class="so-plate-body">
+				<view class="so-plate-word" :class="{ active: currentInputIndex == 0 }" @tap="inputSwitch"
+					data-index="0">
+					<text>{{ currentInputValue[0] }}</text>
+				</view>
+				<view class="so-plate-word" :class="{ active: currentInputIndex == 1 }" @tap="inputSwitch"
+					data-index="1">
+					<text>{{ currentInputValue[1] }}</text>
+				</view>
+				<view class="so-plate-dot"></view>
+				<view class="so-plate-word" :class="{ active: currentInputIndex == 2 }" @tap="inputSwitch"
+					data-index="2">
+					<text>{{ currentInputValue[2] }}</text>
+				</view>
+				<view class="so-plate-word" :class="{ active: currentInputIndex == 3 }" @tap="inputSwitch"
+					data-index="3">
+					<text>{{ currentInputValue[3] }}</text>
+				</view>
+				<view class="so-plate-word" :class="{ active: currentInputIndex == 4 }" @tap="inputSwitch"
+					data-index="4">
+					<text>{{ currentInputValue[4] }}</text>
+				</view>
+				<view class="so-plate-word" :class="{ active: currentInputIndex == 5 }" @tap="inputSwitch"
+					data-index="5">
+					<text>{{ currentInputValue[5] }}</text>
+				</view>
+				<view class="so-plate-word" :class="{ active: currentInputIndex == 6 }" @tap="inputSwitch"
+					data-index="6">
+					<text>{{ currentInputValue[6] }}</text>
+				</view>
+				<view class="so-plate-word" :class="{ active: currentInputIndex == 7 }" @tap="inputSwitch"
+					v-if="type == 2" data-index="7">
+					<text>{{ currentInputValue[7] }}</text>
+				</view>
+			</view>
+			<view class="so-plate-foot">
+				<view class="so-plate-keyboard" :style="{height:keyboardHeight}">
+					<view id="keyboard">
+						<block v-if="inputType == 1">
+							<view hover-class="hover" class="so-plate-key" v-for="el of provinceText" :key="el"
+								:data-value="el" @tap="chooseKey">{{ el }}</view>
+						</block>
+						<block v-if="inputType == 1">
+							<text class="so-plate-key fill-block"></text>
+						</block>
+						<block v-if="inputType >= 3">
+							<view hover-class="hover" class="so-plate-key" v-for="el of numberText" :key="el"
+								:data-value="el" @tap="chooseKey">{{ el }}</view>
+						</block>
+						<block v-if="inputType >= 2">
+							<view hover-class="hover" class="so-plate-key" v-for="el of wordText" :key="el"
+								:data-value="el" @tap="chooseKey">{{ el }}</view>
+						</block>
+						<block v-if="inputType == 3">
+							<text v-for="el of fillBlock" :key="el.num" class="so-plate-key fill-block"></text>
+						</block>
+						<block v-if="inputType == 4">
+							<view hover-class="hover" class="so-plate-key" v-for="el of lastWordText" :key="el"
+								:data-value="el" @tap="chooseKey">{{ el }}</view>
+						</block>
+						<text v-if="inputType == 4" class="so-plate-key fill-block"></text>
+					</view>
+				</view>
+				<view class="so-plate-btn-group">
+					<view>
+						<button class="so-plate-btn so-plate-btn--cancel" @tap="$emit('close')">鍙栨秷</button>
+					</view>
+					<view>
+						<button class="so-plate-btn so-plate-btn--delete" @tap="deleteKey">鍒犻櫎</button>
+						<button class="so-plate-btn so-plate-btn--submit" @tap="exportPlate">瀹屾垚</button>
+ 
+					</view>
+ 
+				</view>
+			</view>
+		</view>
+	</view>
+	<view v-else></view>
+</template>
+<script>
+	export default {
+		name: 'uni-plate-input',
+		data() {
+			return {
+				show: false,
+				type: 1, //杞︾墝绫诲瀷
+				currentInputIndex: 0, //褰撳墠缂栬緫鐨勮緭鍏ユ
+				currentInputValue: ['', '', '', '', '', '', ''],
+				fillBlock: [{
+					num: 11
+				}, {
+					num: 12
+				}, {
+					num: 13
+				}, {
+					num: 14
+				}, {
+					num: 15
+				}, {
+					num: 16
+				}], //閬垮厤:key鎶ラ敊
+				keyboardHeightInit: false,
+				keyboardHeight: 'auto',
+				provinceText: [
+					'绮�',
+					'浜�',
+					'鍐�',
+					'娌�',
+					'娲�',
+					'鏅�',
+					'钂�',
+					'杈�',
+					'鍚�',
+					'榛�',
+					'鑻�',
+					'娴�',
+					'鐨�',
+					'闂�',
+					'璧�',
+					'椴�',
+					'璞�',
+					'閯�',
+					'婀�',
+					'妗�',
+					'鐞�',
+					'娓�',
+					'宸�',
+					'璐�',
+					'浜�',
+					'钘�',
+					'闄�',
+					'鐢�',
+					'闈�',
+					'瀹�',
+					'鏂�'
+				],
+				numberText: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'],
+				wordText: ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U',
+					'V', 'W', 'X', 'Y', 'Z'
+				],
+				lastWordText: ['鎸�', '娓�', '瀛�', '棰�', '璀�']
+			};
+		},
+		props: {
+			plate: {
+				type: String
+			}
+		},
+		computed: {
+			//杈撳叆妗嗙被鍨�
+			inputType() {
+				switch (this.currentInputIndex) {
+					case 0:
+						return 1;
+						break;
+					case 1:
+						return 2;
+						break;
+					case 2:
+						return 3;
+						break;
+					case 3:
+						return 3;
+						break;
+					case 4:
+						return 3;
+						break;
+					case 5:
+						return 3;
+						break;
+					case 6:
+						return this.type == 2 ? 3 : 4;
+						break;
+					case 7:
+						return 4;
+						break;
+					default:
+						return 1;
+						break;
+				}
+			}
+		},
+		watch: {
+			currentInputIndex: function(n, o) {
+				if (!this.keyboardHeightInit) return
+				this.$nextTick(() => {
+					this.changeKeyboardHeight()
+				})
+			}
+		},
+		methods: {
+			open() {
+				this.type = 1
+				this.currentInputIndex = 0
+				this.currentInputValue = ['', '', '', '', '', '', '']
+				this.show = true
+				setTimeout(() => { //鍦ㄥ姩鐢荤粨鏉熶箣鍚庢墠寮�濮嬭幏鍙�
+					this.$nextTick(() => {
+						this.changeKeyboardHeight()
+					})
+				}, 500);
+			},
+			close() {
+				this.show = false
+			},
+			//杞︾墝绫诲瀷鍒囨崲
+			typeChange(e) {
+				this.$emit("typeChange", e.detail.value);
+				const {
+					value
+				} = e.detail;
+				this.type = parseInt(value)
+				this.currentInputIndex = 0
+				if (value == 1) {
+					this.currentInputValue = ['', '', '', '', '', '', '']
+				} else {
+					this.currentInputValue = ['', '', '', '', '', '', '', '']
+				}
+			},
+			inputSwitch(e) {
+				const {
+					index
+				} = e.currentTarget.dataset;
+				this.currentInputIndex = parseInt(index);
+			},
+			chooseKey(e) {
+				const {
+					value
+				} = e.currentTarget.dataset;
+				this.$set(this.currentInputValue, this.currentInputIndex, value);
+				if (this.type == 1 && this.currentInputIndex < 6) {
+					this.currentInputIndex++
+				}
+				if (this.type == 2 && this.currentInputIndex < 7) {
+					this.currentInputIndex++
+				}
+			},
+			deleteKey() {
+				this.$set(this.currentInputValue, this.currentInputIndex, '')
+				if (this.currentInputIndex != 0) this.currentInputIndex--
+			},
+			exportPlate() {
+				const plate = this.currentInputValue.join('')
+				let err = false
+				if (this.type === 1 && plate.length != 7) {
+					err = true
+				} else if (this.type === 2 && plate.length != 8) {
+					err = true
+				}
+				if (err) return uni.showToast({
+					title: '璇疯緭鍏ュ畬鏁寸殑杞︾墝鍙风爜',
+					icon: 'none'
+				})
+ 
+				this.$emit('export', plate)
+			},
+			changeKeyboardHeight() {
+				const that = this
+				const query = uni.createSelectorQuery().in(this);
+				query.select('#keyboard').boundingClientRect();
+				query.exec(function(res) {
+					if (res && res[0]) {
+						that.keyboardHeight = res[0].height + uni.upx2px(30) + 'px'
+						that.keyboardHeightInit = true
+					}
+				});
+			}
+		},
+		mounted() {
+			// console.log(this.plate);
+	// 		const plateKey = this.plate.split('')
+	// 		if (plateKey.length === 7) {
+	// 			this.type = 1
+	// 		} else if (plateKey.length === 8) {
+	// 			this.type = 2
+	// 		}
+	// 		if (plateKey.length === 7 || plateKey.length === 8) {
+	// 			this.currentInputValue = plateKey
+	// 			this.currentInputIndex = plateKey.length - 1
+	// 		}
+ 
+	// 		setTimeout(() => { //鍦ㄥ姩鐢荤粨鏉熶箣鍚庢墠寮�濮嬭幏鍙�
+	// 			this.$nextTick(() => {
+	// 				this.changeKeyboardHeight()
+	// 			})
+	// 		}, 500);
+		}
+	};
+</script>
+<style scoped lang="less">
+	.so-mask {
+		position: fixed;
+		top: 0;
+		bottom: 0;
+		right: 0;
+		left: 0;
+		background: rgba(0, 0, 0, 0.5);
+		z-index: 99999;
+	}
+	.so-plate {
+		box-sizing: border-box;
+		position: absolute;
+		bottom: 0;
+		width: 100%;
+		left: 0;
+		background: #fff;
+		padding: 25upx 25upx 0 25upx;
+		&-head {
+			display: flex;
+			justify-content: space-between;
+			align-items: center;
+		}
+		&-type {			
+			flex:1;
+			display:block;
+			label {
+				display: inline-block;
+				min-height: 32upx;
+				font-size: 26upx;
+				margin-right: 10upx;
+			}
+		}
+		&-body {
+			box-sizing: border-box;
+			padding: 30upx 0;
+			display: flex;
+			justify-content: space-between;
+			align-items: center;
+		}
+		&-word {
+			border: 1upx solid #ccc;
+			border-radius: 10upx;
+			height: 0;
+			margin: 0 5upx;
+			box-sizing: border-box;
+			padding-bottom: calc((100% - 70upx) / 7);
+			width: calc((100% - 70upx) / 7);
+			position: relative;
+			&.active {
+				border-color: #007aff;
+				box-shadow: 0 0 15upx 0 #007aff;
+			}
+			text {
+				position: absolute;
+				top: 50%;
+				left: 50%;
+				transform: translateX(-50%) translateY(-50%);
+				font-weight: 700;
+				font-size: 32upx;
+			}
+		}
+		&-dot {
+			width: 15upx;
+			height: 15upx;
+			background: #ccc;
+			border-radius: 50%;
+			margin: 0 5upx;
+		}
+		&-keyboard {
+			background: #eee;
+			margin-left: -25upx;
+			margin-right: -25upx;
+			padding: 20upx 25upx 10upx 25upx;
+			box-sizing: border-box;
+			transition: all .3s;
+			&>view{
+				display: flex;
+				flex-wrap: wrap;
+				justify-content: space-between;
+			}
+		}
+		&-key {
+			display: block;
+			background: #fff;
+			border-radius: 10upx;
+			box-shadow: 0 0 8upx 0 #bbb;
+			width: 80upx;
+			height: 80upx;
+			margin: 5upx 0;
+			font-size: 32upx;
+			text-align: center;
+			display: flex;
+			align-items: center;
+			justify-content: center;
+			position: relative;
+			&.hover {
+				background: #efefef;
+			}
+			&.fill-block {
+				width: 80upx;
+				height: 80upx;
+				background: none;
+				box-shadow: none;
+			}
+		}
+		&-btn {
+			display: inline-block;
+			background: #fff;
+			border-radius: 10upx;
+			box-shadow: 0 0 10upx 0 #bbb;
+			font-size: 28upx;
+			text-align: center;
+			margin:0 0 0 10upx;
+			padding:0 25upx;
+			&-group{
+				display: flex;
+				justify-content: space-between;
+				background: #eee;
+				margin-left: -25upx;
+				margin-right: -25upx;
+				box-sizing: border-box;
+				padding: 0 25upx 10upx 25upx;
+			}
+			&--cancel{
+				margin:0;
+			}
+			&--submit{
+				background:#5773f9;
+				color:#fff;
+			}
+			&--delete{
+				color:#fd6b6d;
+			}
+		}
+	}
+	 
+	 
+	.animation-scale-up {
+		animation-duration: .2s;
+		animation-timing-function: ease-out;
+		animation-fill-mode: both;
+	    animation-name: scale-up
+	}
+	@keyframes scale-up {
+	    0% {
+	        opacity: .8;
+	        transform: scale(.8)
+	    }
+	 
+	    100% {
+	        opacity: 1;
+	        transform: scale(1)
+	    }
+	}
+</style>
\ No newline at end of file
diff --git a/h5/components/tly-picture-cut/tlyPictureCut.vue b/h5/components/tly-picture-cut/tlyPictureCut.vue
new file mode 100644
index 0000000..81e2151
--- /dev/null
+++ b/h5/components/tly-picture-cut/tlyPictureCut.vue
@@ -0,0 +1,413 @@
+<template>
+	<view class="picture-cut" :class="{'picture-cut-show':isShow}">
+		
+		 <!-- :style="{width:choosePictureWidth+'px',height:choosePictureHeight+'px',top:choosePictureTop+'px',left:choosePictureLeft+'px'}" -->
+		<view class="select-box" :style="{width: '70%', height: '250px', top:choosePictureTop+'px',left: '15%'}">
+			<view class="horn">
+				<!-- <view class="lt" data-drag="leftTop"  @touchstart.stop="dragStart" @touchmove.stop.prevent="dragMove" ></view>
+				<view class="rt"  data-drag="topTight" @touchstart.stop="dragStart" @touchmove.stop.prevent="dragMove" ></view>
+				<view class="rb" data-drag="rightBottom" @touchstart.stop="dragStart" @touchmove.stop.prevent="dragMove"></view>
+				<view class="lb" data-drag="bottomLeft"  @touchstart.stop="dragStart" @touchmove.stop.prevent="dragMove"></view> -->
+			</view>
+		</view>
+		
+		
+		<movable-area class="picture-area" :style="{width:areaWidth+'px',height:areaHeight+'px',top:areaHeightTop+'px',left:areaWidthLeft+'px'}">
+			<movable-view class="picture-view" :style="{width:img_width/img_scaling+'px',height:img_height/img_scaling+'px'}"
+			 direction="all" :x="offsetX" :y="offsetY" scale="true" :scale-min="scaleMin" @change="movableChange" @scale="movableScale">
+				<image :style="{width:img_width/img_scaling+'px',height:img_height/img_scaling+'px'}" :src="pictureSrc"></image>
+			</movable-view>
+		</movable-area>
+		<view class="area-bottom">
+			<view class="area-bottom-box">
+				<view @click="cancelArea">鍙栨秷</view>
+				<!-- <view @click="changeImg">鎹釜鍥剧墖</view> -->
+				<view @click="createImg">瀹屾垚</view>
+			</view>
+	
+		</view>
+		<canvas canvas-id="picture-canvas" :style="'position:absolute;border: 1px solid red; width:'+canvasWidth+'px;height:'+canvasHeight+'px;top:-9999px;left:-9999px;'" class="canvas-view"></canvas>
+	</view>
+</template>
+
+<script>
+	
+	let tailorSize = 240; // 闇�瑕佹埅鍙栫殑灏哄240x240px锛屾鍙橀噺瑕佸拰鏍峰紡涓殑240px鍜�120px鐩稿搴旓紝120px涓烘鍙橀噺鐨勪竴鍗婏紝鑻ヨ淇敼鎴愬叾浠栧�间竴瀹氳涓�涓�瀵瑰簲
+	let tailorWidth = 0;
+	let tailorHeight = 0;
+	let	newOffsetX = 0; // 鎷栧姩缂╂斁瀹屾垚鍚庣殑X杞村亸绉婚噺
+	let newOffsetY = 0; // 鎷栧姩缂╂斁瀹屾垚鍚庣殑Y杞村亸绉婚噺
+	let T_PAGE_X, // 鎵嬬Щ鍔ㄧ殑鏃跺�檟鐨勪綅缃�
+	    T_PAGE_Y, // 鎵嬬Щ鍔ㄧ殑鏃跺�橸鐨勪綅缃�
+		area_x,
+		area_y
+	let [choosePictureMinWidth,choosePictureMinHeight] = [50,50];
+	export default {
+		name: "tly-picture-cut",
+		props: {
+			// 鍥剧墖璺緞
+			pictureSrc: {
+				type: String,
+				required: true
+			}
+		},
+		data() {
+			return {
+				offsetX: 0, // 鍥惧儚鍒濆鍖栫殑X杞村亸绉婚噺
+				offsetY: 0, // 鍥惧儚鍒濆鍖栫殑Y杞村亸绉婚噺
+				img_width: 0, // 鍥剧墖鐪熷疄瀹藉害
+				img_height: 0, // 鍥剧墖鐪熷疄楂樺害
+				img_scaling: 1, //鍥剧墖鍒濆鍖栫缉鏀炬瘮渚�
+				scale: 1, // 鎷栧姩缂╂斁瀹屾垚鍚庣殑鍥剧墖缂╂斁姣斾緥
+				scaleMin: 0.5, // 鏈�灏忕缉鏀惧��
+				isShow: false,
+				choosePictureWidth:0,
+				choosePictureHeight:0,
+				choosePictureTop:0,
+				choosePictureLeft:0,
+				chooseVisible:0.5,
+				areaWidth:0,
+				areaHeight:0,
+				movableViewTop:0,
+				movableViewLeft:0,
+				areaWidthLeft:0,
+				areaHeightTop:0,
+				canvasWidth:0,
+				canvasHeight:0,
+				
+			};
+		},
+		watch: {
+			pictureSrc() {
+				this.getImgInfo();
+			}
+		},
+		methods: {
+			changeImg(){
+				this.$emit('changeImg')
+			},
+			cancelArea(){
+				this.hidePop();
+			},
+			// 璁剧疆澶у皬鐨勬椂鍊欒Е鍙戠殑touchStart浜嬩欢
+			dragStart(e) {
+			    T_PAGE_X = e.touches[0].pageX
+			    T_PAGE_Y = e.touches[0].pageY
+			},
+			 
+			// 璁剧疆澶у皬鐨勬椂鍊欒Е鍙戠殑touchMove浜嬩欢
+			dragMove(e) {
+			    var _this = this
+			    var dragType = e.target.dataset.drag
+				var dragLengthX = (T_PAGE_X - e.touches[0].pageX);
+				var dragLengthY = (T_PAGE_Y - e.touches[0].pageY);
+					switch (dragType) {
+					    case 'leftTop':
+							this.choosePictureWidth += dragLengthX;
+							this.choosePictureLeft  -= dragLengthX;
+							this.choosePictureTop  -= dragLengthY;
+							this.choosePictureHeight += dragLengthY;
+							this.canvasY -= dragLengthY
+							this.canvasX -= dragLengthX
+					        break;
+					    case 'topTight':
+							this.choosePictureWidth -= dragLengthX;
+							this.choosePictureHeight += dragLengthY;
+							this.choosePictureTop  -= dragLengthY;
+							this.canvasY -= dragLengthY
+					        break;
+					    case 'bottomLeft':
+							this.choosePictureWidth += dragLengthX;
+							this.choosePictureLeft  -= dragLengthX;
+							this.choosePictureHeight -= dragLengthY;
+							this.canvasX  -= dragLengthX
+							
+					        break;
+					    case 'rightBottom':
+							this.choosePictureWidth -= dragLengthX;
+							this.choosePictureHeight -= dragLengthY;
+					        break;
+					    default:
+					        break;
+					}
+					T_PAGE_Y -= dragLengthY;
+					T_PAGE_X -= dragLengthX;
+			},
+			// 鏄剧ず缁勪欢
+			showPop() {
+				this.isShow = true;
+			},
+			// 闅愯棌缁勪欢
+			hidePop() {
+				this.isShow = false;
+			},
+			// 鍒濆鍖栧浘鐗�
+			getImgInfo() {
+				uni.getImageInfo({
+					src: this.pictureSrc,
+					success: (res) => {
+						
+						// 灞忓箷鍙敤瀹介珮
+						let sysInfo = uni.getSystemInfoSync();
+						let windowWidth = sysInfo.windowWidth;
+						let windowHeight = sysInfo.windowHeight;
+						// 鍥剧墖瀹介珮
+						// 绛夋瘮缂╂斁
+						this.img_width = windowWidth*0.8;
+						this.img_height = res.height*(this.img_width/res.width);
+						this.canvasWidth = this.img_width;
+						this.canvasHeight = this.img_height;
+						//鎴浘瀹�
+						this.choosePictureWidth = this.img_width*this.chooseVisible;
+						//鎴浘楂�
+						this.choosePictureHeight = this.img_height*this.chooseVisible;
+						
+						this.canvasX = (this.img_width - this.choosePictureWidth) /2;
+						this.canvasY = (this.img_height - this.choosePictureHeight) /2;
+						area_x = this.canvasX ;
+						area_y = this.canvasY ;
+						this.choosePictureTop = windowHeight/2-this.choosePictureHeight/2;
+						this.choosePictureLeft = windowWidth/2-this.choosePictureWidth/2;
+						// 璁$畻鍒濆缂╂斁姣斿拰鏈�灏忕缉鏀惧��
+						if (this.img_width < this.choosePictureWidth || this.img_height < this.choosePictureHeight) { // 褰撳浘鐗囧鎴栭珮灏忎簬240px鏃�
+							let count = this.img_width <= this.img_height ? this.img_width : this.img_height;
+							let check = this.choosePictureWidth <= this.choosePictureHeight ? this.choosePictureWidth : this.choosePictureHeight;
+							this.img_scaling = count / check;
+							this.scaleMin = 1;
+						} else if (this.img_width > windowWidth && this.img_width <= this.img_height) { // 褰撳浘鐗囧搴﹀ぇ浜庡睆骞曞搴﹀苟涓斿浘鐗囧搴﹀皬浜庡浘鐗囬珮搴︽椂
+							this.img_scaling = this.img_width / windowWidth;
+							this.scaleMin = tailorSize / windowWidth;
+						} else {
+							this.img_scaling  = 1;
+							//this.img_scaling = count / check;
+							let count = this.img_width <= this.img_height ? this.img_width : this.img_height;
+							let check = this.choosePictureWidth <= this.choosePictureHeight ? this.choosePictureWidth : this.choosePictureHeight;
+							this.scaleMin = check / count;
+						}
+						//澶栧潡瀹介珮
+						this.areaWidth = this.choosePictureWidth*3;
+						this.areaHeight = this.choosePictureHeight*3;
+						//澶栧潡鍋忕Щ閲�
+						this.areaHeightTop = -((this.areaHeight - windowHeight)/2);
+						this.areaWidthLeft = -((this.areaWidth - windowWidth)/2);
+
+						this.offsetX = this.areaWidth/2-(this.img_width/this.img_scaling)/2;
+						this.offsetY = this.areaHeight/2-(this.img_height/this.img_scaling)/2;
+
+						// 鑾峰彇鏂扮殑鍋忕Щ閲�
+						newOffsetX = this.offsetX;
+						newOffsetY = this.offsetY;
+					}
+				})
+			},
+			// 璁$畻鎷栧姩鍋忕Щ閲�
+			movableChange(e) {
+			
+				this.canvasX = this.canvasX-(e.detail.x-area_x);
+				area_x = e.detail.x;
+				this.canvasY = this.canvasY-(e.detail.y-area_y)
+				if(this.canvasY<0){
+					this.canvasY = 0;
+				}
+				area_y = e.detail.y;
+				
+			},
+			// 璁$畻缂╂斁姣斾緥鍜屽亸绉婚噺
+			movableScale(e) {
+				newOffsetX = e.detail.x
+				newOffsetY = e.detail.y
+				this.canvasWidth = this.canvasWidth*e.detail.scale;
+				this.canvasHeight = this.canvasHeight*e.detail.scale;
+				this.scale = e.detail.scale;
+			},
+			// 鎴彇鍥剧墖
+			createImg() {
+				var that = this;
+				let ctx = uni.createCanvasContext("picture-canvas",this);
+				ctx.drawImage(this.pictureSrc, 0, 0, this.img_width*this.scale,this.img_height*this.scale );
+					// ctx.draw();
+				ctx.draw(false, () => {
+					
+					uni.canvasToTempFilePath({
+					    x: this.canvasX,
+					    y: this.canvasY,
+					    width: this.choosePictureWidth,
+					    height: this.choosePictureHeight,
+					    destWidth: this.choosePictureWidth,
+					    destHeight: this.choosePictureHeight,
+					    quality: 0.9,
+					    canvasId: 'picture-canvas',
+					    success: function (res) {
+					
+							  //#ifdef H5
+							  that.hidePop();
+							  that.$emit("createImg",res.tempFilePath)
+							  //#endif
+							  //#ifdef MP-WEIXIN || APP
+							   uni.getFileSystemManager().readFile({
+							   	filePath: res.tempFilePath,
+							   	encoding: 'base64',
+							   	success: res => {
+							   		let base64 = 'data:image/png;base64,' + res.data;
+							   	
+							   		that.hidePop();
+							   		that.$emit("createImg",base64)
+							   	}
+							   })
+							    //#endif
+
+
+					    }
+					},this);
+					
+					
+		
+				});
+			}
+		}
+	}
+</script>
+
+<style>
+	.picture-cut {
+		position: fixed;
+		top: 0;
+		left: 0;
+		bottom: 0;
+		right: 0;
+		width: 100%;
+		height: 100%;
+		
+		z-index: 999999;
+		
+		transform: translateX(100%);
+		transition: all 200ms ease;
+		visibility: hidden;
+	}
+
+	.picture-cut-show {
+		transform: translateY(0) !important;
+		visibility: visible;
+		
+		
+	}
+
+	/* 鎷栧姩鍩熺殑浣嶇疆鍜屽ぇ灏� */
+	.picture-cut .picture-area {
+
+		position: absolute;
+		/* 浣垮叾灞呬腑瀹氫綅 */
+		
+		
+
+	}
+
+	/* 鎷栧姩鎺т欢鐨勫ぇ灏� */
+	.picture-area {
+		
+		pointer-events: none;
+		z-index: 998;
+		
+	}
+
+	.picture-view {
+			
+		pointer-events: auto;
+			
+	}
+		
+	/* 涓棿閫夋嫨妗嗙殑澶у皬锛屾湰鎰忔槸瑙嗚涓婃ā鎷熸嫋鍔ㄥ煙 */
+	.select-box {
+	
+		position: absolute;
+		/* top: calc(50% - 120px);
+		left: calc(50% - 120px); */
+/* 		width: 240px;
+		height: 240px; */
+		box-sizing: border-box;
+	/* 	border-radius: 50%; */
+
+
+		box-shadow: 0px 0px 0px 2005px rgba(0, 0, 0, 0.7) ;   
+		z-index: 999;  
+		pointer-events: none;
+	/* 	min-width: 50px;
+		min-height: 50px; */
+	}
+	.horn{
+		position: absolute;
+		width: 100%;
+		height: 100%;
+		/* border:1rpx solid #ff0000; */
+
+	}
+	.horn>view{
+		width: 15px;
+		height: 15px;
+		position:absolute;
+	}
+	.horn .lt{
+		pointer-events: auto;
+		/* border-top: 3px solid #ff0000;
+		border-left: 3px solid #ff0000; */
+		left: -4px;
+		top: -4px;
+	}
+	.horn .rt{
+		pointer-events: auto;
+		/* border-top: 3px solid #ff0000;
+		border-right: 3px solid #ff0000; */
+		right: -2px;
+		top: -2px;
+	}
+	.horn .rb{
+		pointer-events: auto;
+		/* border-bottom:3px solid #ff0000;
+		border-right: 3px solid #ff0000; */
+		right: -2px;
+		bottom: -2px;
+	}
+	.horn .lb{
+		pointer-events: auto;
+		/* border-bottom:3px solid #ff0000;
+		border-left: 3px solid #ff0000; */
+		left: -2px;
+		bottom: -2px;
+	}
+	.area-bottom{
+		position: absolute;
+		width:100%;
+		height:75px;
+
+		bottom: 0;
+		z-index:999;
+		box-shadow: 0 -8px 12px -5px  #ffffff;
+		background-color: rgba(66, 66, 66, 0.4);
+	}
+	.area-bottom-box{
+		
+		display: flex;
+		justify-content: space-between;
+		width:86%;
+		height:50px;
+		line-height: 60px;
+		color:#FFFFFF;
+		margin:0 auto;
+	}
+	.button-view {
+		position: absolute;
+		bottom: 20px;
+		right: 20px;
+		width: 60px;
+		background-color: #007AFF;
+		font-size: 14px;
+		color: #FFFFFF;
+		z-index:101;
+	}
+
+	/* 鐢诲竷澶у皬锛岀敾甯冨ぇ灏忓氨鏄埅鍙栫殑鍘熷澶у皬 */
+	.canvas-view {
+		position: absolute;
+	/* 	visibility: hidden; */
+	}
+</style>
diff --git a/h5/main.js b/h5/main.js
index 881da17..0990e1e 100644
--- a/h5/main.js
+++ b/h5/main.js
@@ -9,7 +9,7 @@
 
 // Vue.prototype.$baseUrl = 'http://192.168.0.186:10027/';
 // Vue.prototype.$baseUrl = 'https://dmtest.ahapp.net/h5_api/';
-Vue.prototype.$baseUrl = 'http://218.23.218.228:8018/web_interface/';
+Vue.prototype.$baseUrl = 'http://facepay.huasunsolar.com/web_interface/';
 Vue.prototype.$store = store;
 
 App.mpType = 'app'
diff --git a/h5/package.json b/h5/package.json
index dcafdae..eb44b0f 100644
--- a/h5/package.json
+++ b/h5/package.json
@@ -1,24 +1,16 @@
 {
-    "id": "stephenzhou-picker",
-    "name": "鏀寔鍒嗛〉Picker",
-    "displayName": "鏀寔鍒嗛〉Picker",
-    "version": "1.0",
-    "description": "Popup寮瑰嚭妗嗭紝鍙粴鍔ㄥ垎椤碉紝鏀寔鍗曢�夈�佸閫夊姛鑳界殑picker绛涢�夌粍浠�",
+    "id": "tly-picture-cut",
+    "name": "鍥剧墖瑁佸壀 鍥涜鎷栧姩 鍥剧墖缂╂斁绉诲姩",
+    "displayName": "鍥剧墖瑁佸壀 鍥涜鎷栧姩 鍥剧墖缂╂斁绉诲姩",
+    "version": "1.0.0",
+    "description": "鍥剧墖瑁佸壀缁勪欢 鏀寔鎷栧姩鍥涜 宸蹭娇鐢ㄥ井淇″皬绋嬪簭銆丠5 骞冲彴",
     "keywords": [
-        "绛涢��",
-        "鍒嗛〉",
-        "鎼滅储",
-        "澶氶��",
-        "鍗曢��"
+        "鍥剧墖瑁佸壀"
     ],
     "dcloudext": {
         "category": [
             "鍓嶇缁勪欢",
             "閫氱敤缁勪欢"
         ]
-    },
-    "dependencies": {
-        "qrcodejs2": "0.0.2",
-        "uniapp-qrcode": "^1.0.2"
     }
-}
+}
\ No newline at end of file
diff --git a/h5/pages/userinfo/userinfo.vue b/h5/pages/userinfo/userinfo.vue
index cc59728..fc49bd6 100644
--- a/h5/pages/userinfo/userinfo.vue
+++ b/h5/pages/userinfo/userinfo.vue
@@ -63,14 +63,20 @@
 		<view class="footer-box">
 			<view class="submit-button" @click="submit">涓嬩竴姝�</view>
 		</view>
-		<u-picker keyName="name" :show="show" :columns="columns" @confirm="confirm" @cancel="show = false"></u-picker>
+		<!-- <tly-picture-cut ref="tlyPictureCut" :pictureSrc="photoSrc" @createImg="uploadImg"></tly-picture-cut> -->
+		<u-picker :show="show" :columns="columns" keyName="name" @cancel="show = false" @confirm="confirm"></u-picker>
+		<qf-image-cropper ref="cropper" :width="280" :height="280" :radius="30" @crop="uploadImg"></qf-image-cropper>
 	</view>
 </template>
 
 <script>
+	import tlyPictureCut from "@/components/tly-picture-cut/tlyPictureCut.vue";
+	import QfImageCropper from '@/uni_modules/qf-image-cropper/components/qf-image-cropper/qf-image-cropper.vue';
+	import { mapState } from 'vuex'
 	export default {
 		data() {
 			return {
+				photoSrc: "",
 				show: false,
 				visit: '',
 				type: '',
@@ -86,17 +92,46 @@
 					faceImg: '',
 					faceImgUrl: '',
 					imgurl: '',
-					imgurlUrl: ''
+					imgurlUrl: '',
+					companyName: ''
 				}
 			}
 		},
 		
+		computed: {
+			...mapState(['member'])
+		},
+		
+		components: { tlyPictureCut, QfImageCropper },
+		
 		onLoad(option) {
+			if (this.member) {
+				this.visitorData.name = this.member.name
+				this.visitorData.phone = this.member.phone
+				this.visitorData.idcardNo = this.member.idcardDecode
+				this.visitorData.companyName = this.member.visitCompanyName
+				this.visitorData.faceImg = this.member.faceImg
+				if (this.member.faceImg) {
+					this.visitorData.faceImgUrl = this.member.prefixUrl + this.member.faceImg
+				}
+				this.visitorData.imgurl = this.member.imgurl
+				if (this.member.imgurl) {
+					this.visitorData.imgurlUrl = this.member.prefixUrl + this.member.imgurl
+				}
+				this.visitorData.idcardType = this.member.idcardType
+				if (this.member.idcardType === 0) {
+					this.visitorData.idcardTypeName = '韬唤璇�'
+				} else if (this.member.idcardType === 1) {
+					this.visitorData.idcardTypeName = '娓境璇佷欢'
+				} else if (this.member.idcardType === 2) {
+					this.visitorData.idcardTypeName = '鎶ょ収'
+				}
+			}
 			this.visitorData.userAnswerId = option.userAnswerId
 			this.getVisit()
-			uni.$on('update', (data) => {
-				this.uploadImg(data.tempFilePath)
-			})
+			// uni.$on('update', (data) => {
+			// 	this.uploadImg(data.tempFilePath)
+			// })
 		},
 
 		methods: {
@@ -159,23 +194,23 @@
 				})
 			},
 			uploadImg(file) {
+				var that = this
+				that.$refs.cropper.close()
 				uni.showLoading({ title: '涓婁紶涓�', mask: true });
 				uni.uploadFile({
 					url: `${this.$baseUrl}public/api/uploadFtp.do`,
-					filePath: file,
+					filePath: file.tempFilePath,
 					name: 'file',
 					formData: {
 						folderCode: 'MEMBER_IMG'
 					},
 					success: (uploadFileRes) => {
 						let res = JSON.parse(uploadFileRes.data)
-						if (this.type === 'faceImg') {
-							this.visitorData.faceImg = res.data.halfPath
-							this.visitorData.faceImgUrl = res.data.prefixPath + res.data.folder + res.data.halfPath
-						} else {
-							this.visitorData.imgurl = res.data.halfPath
-							this.visitorData.imgurlUrl = res.data.prefixPath + res.data.folder + res.data.halfPath
-						}
+						this.visitorData.faceImg = res.data.halfPath
+						this.visitorData.faceImgUrl = res.data.prefixPath + res.data.folder + res.data.halfPath
+					},
+					fail(err) {
+						alert('澶辫触')
 					},
 					complete() {
 						uni.hideLoading();
@@ -183,42 +218,42 @@
 				});
 			},
 			upload(type) {
-				this.type = type
+				var that = this
+				that.type = type
+				if (type === 'faceImg') {
+					that.$refs.cropper.open()
+					return
+				}
 				uni.chooseImage({
 					count: 1,
 					success: (chooseImageRes) => {
-						if (type === 'faceImg') {
-							uni.navigateTo({
-								url: `/pages/cropping/cropping?item=${JSON.stringify({ tempFilePath: chooseImageRes.tempFilePaths[0] })}`
-							})
-							return
-						}
-						uni.showLoading({ title: '涓婁紶涓�', mask: true });
-						for (let i = 0; i < chooseImageRes.tempFilePaths.length; i++) {
+						// if (type === 'faceImg') {
+						// 	that.photoSrc = chooseImageRes.tempFilePaths[0];
+						// 	that.$refs.tlyPictureCut.showPop();
+						// }
+						if (type === 'imgurl') {
+							uni.showLoading({ title: '涓婁紶涓�', mask: true });
 							uni.uploadFile({
-								url: `${this.$baseUrl}public/api/uploadFtp.do`,
-								filePath: chooseImageRes.tempFilePaths[i],
+								url: `${that.$baseUrl}public/api/uploadFtp.do`,
+								filePath: chooseImageRes.tempFilePaths[0],
 								name: 'file',
 								formData: {
 									folderCode: 'MEMBER_IMG'
 								},
-								success: (uploadFileRes) => {	
+								timeout: 60000,
+								success: (uploadFileRes) => {
 									let res = JSON.parse(uploadFileRes.data)
-									if (type === 'faceImg') {
-										this.visitorData.faceImg = res.data.halfPath
-										this.visitorData.faceImgUrl = res.data.prefixPath + res.data.folder + res.data.halfPath
-									} else {
-										this.visitorData.imgurl = res.data.halfPath
-										this.visitorData.imgurlUrl = res.data.prefixPath + res.data.folder + res.data.halfPath
-									}
+									that.visitorData.imgurl = res.data.halfPath
+									that.visitorData.imgurlUrl = res.data.prefixPath + res.data.folder + res.data.halfPath
 								},
 								complete() {
-									if (i === chooseImageRes.tempFilePaths.length - 1) {
-										uni.hideLoading();
-									}
+									uni.hideLoading();
 								}
 							});
 						}
+					},
+					fail(err) {
+						alert('api鎶ラ敊')
 					}
 				});
 			},
@@ -231,7 +266,7 @@
 	}
 </script>
 
-<style>
+<style lang="scss">
 	page {
 		background-color: #F7F7F7 !important;
 	}
@@ -268,7 +303,7 @@
 		display: flex;
 		flex-direction: column;
 		.title1_a {
-			font-size: 30rpx;
+			font-size: 30rpx !important;
 			font-weight: 400;
 			color: #222222;
 			display: flex;
@@ -280,7 +315,7 @@
 			}
 		}
 		.title1_b {
-			font-size: 24rpx;
+			font-size: 24rpx !important;
 			font-weight: 400;
 			color: #999999;
 		}
diff --git a/h5/pages/visitorApplication/visitorApplication.vue b/h5/pages/visitorApplication/visitorApplication.vue
index 4b65e9c..927e769 100644
--- a/h5/pages/visitorApplication/visitorApplication.vue
+++ b/h5/pages/visitorApplication/visitorApplication.vue
@@ -45,6 +45,7 @@
 					<text>璁块棶闂ㄧ</text>
 					<text>*</text>
 				</view>
+				 <!-- @click="show6 = true" -->
 				<view class="list_item_content">
 					<text :style="{color: form1.doorSelectName ? '#000000' : ''}">{{form1.doorSelectName ? form1.doorSelectName : '璇烽�夋嫨'}}</text>
 					<u-icon name="arrow-right" color="#CCCCCC" size="20"></u-icon>
@@ -64,8 +65,9 @@
 					<text>闅忚杞﹁締</text>
 					<text></text>
 				</view>
-				<view class="list_item_content">
-					<input type="text" placeholder="璇疯緭鍏ヨ溅鐗屽彿" v-model="form1.carNos" maxlength="8" placeholder-style="color: #999999;" />
+				<view class="list_item_content" @click="openInput(1)">
+					<text :style="{color: form1.carNos ? '#000000' : ''}">{{form1.carNos ? form1.carNos : '璇疯緭鍏ヨ溅鐗屽彿鐮�'}}</text>
+					<!-- <input type="text" placeholder="璇疯緭鍏ヨ溅鐗屽彿" v-model="form1.carNos" maxlength="8" placeholder-style="color: #999999;" /> -->
 				</view>
 			</view>
 		</view>
@@ -226,7 +228,7 @@
 					<view class="adduser_list_item">
 						<view class="adduser_list_item_label">
 							<text>鍏徃</text>
-							<text></text>
+							<text>*</text>
 						</view>
 						<view class="adduser_list_item_ipt">
 							<input type="text" v-model="withUserList.companyName" placeholder-style="color: #999999;font-size: 28rpx;" placeholder="璇疯緭鍏ュ叕鍙稿悕绉�" />
@@ -237,8 +239,9 @@
 							<text>闅忚杞﹁締</text>
 							<text></text>
 						</view>
-						<view class="adduser_list_item_ipt">
-							<input type="text" v-model="withUserList.carNos" placeholder-style="color: #999999;font-size: 28rpx;" placeholder="璇疯緭鍏ヨ溅鐗屽彿" />
+						<view class="adduser_list_item_ipt" @click="openInput(2)">
+							<text :style="{color: withUserList.carNos ? '#000000' : ''}">{{withUserList.carNos ? withUserList.carNos : '璇疯緭鍏ヨ溅鐗屽彿鐮�'}}</text>
+							<!-- <input type="text" v-model="withUserList.carNos" disabled placeholder-style="color: #999999;font-size: 28rpx;" placeholder="璇疯緭鍏ヨ溅鐗屽彿" /> -->
 						</view>
 					</view>
 					<view class="adduser_list_item">
@@ -278,13 +281,22 @@
 			</view>
 		</u-popup>
 		<u-picker keyName="name" :show="show6" :columns="columns1" @confirm="seleIdcard" @cancel="show6 = false"></u-picker>
+		<!-- <tly-picture-cut ref="tlyPictureCut" :pictureSrc="photoSrc" @createImg="uploadImg"></tly-picture-cut> -->
+		<keyboardInput ref="keyboard" @export="setPlate" @close="closeInput" />
+		<qf-image-cropper ref="cropper" :width="280" :height="280" :radius="30" @crop="uploadImg"></qf-image-cropper>
 	</view>
 </template>
 
 <script>
+	import tlyPictureCut from "@/components/tly-picture-cut/tlyPictureCut.vue";
+	import keyboardInput from "@/components/keyboard-input/keyboard-input.vue";
+	import QfImageCropper from '@/uni_modules/qf-image-cropper/components/qf-image-cropper/qf-image-cropper.vue';
 	export default {
 		data() {
 			return {
+				photoSrc: '',
+				type: '',
+				inputType: '',
 				show: false,
 				show1: false,
 				show2: false,
@@ -292,6 +304,7 @@
 				show4: false,
 				show5: false,
 				show6: false,
+				show7: false,
 				fileList: [],
 				columns1: [[{name: '韬唤璇�', id: 0}, {name: '娓境璇佷欢', id: 1},{name: '鎶ょ収', id: 2}]],
 				columns: [],
@@ -328,13 +341,52 @@
 				verify: ''
 			};
 		},
+		components: { tlyPictureCut, keyboardInput, QfImageCropper },
 		onLoad(options) {
-			this.form = JSON.parse(options.data)
+			if (options.data) {
+				this.form = JSON.parse(options.data)
+			}
 			this.getvisit()
 			this.getVisit1()
 			this.getUserValid()
 		},
 		methods: {
+			openInput(type) {
+				this.inputType = type
+				this.$refs.keyboard.open()
+			},
+			setPlate(e) {
+				if (this.inputType === 1) {
+					this.form1.carNos = e
+				} else if (this.inputType === 2) {
+					this.withUserList.carNos = e
+				}
+				this.$forceUpdate()
+				this.closeInput()
+			},
+			closeInput() {
+				this.$refs.keyboard.close()
+			},
+			uploadImg(file) {
+				this.$refs.cropper.close()
+				uni.showLoading({ title: '涓婁紶涓�', mask: true });
+				uni.uploadFile({
+					url: `${this.$baseUrl}public/api/uploadFtp.do`,
+					filePath: file.tempFilePath,
+					name: 'file',
+					formData: {
+						folderCode: 'MEMBER_IMG'
+					},
+					success: (uploadFileRes) => {
+						let res = JSON.parse(uploadFileRes.data)
+						this.withUserList.faceImg = res.data.halfPath
+						this.withUserList.faceImgUrl = res.data.prefixPath + res.data.folder + res.data.halfPath
+					},
+					complete() {
+						uni.hideLoading();
+					}
+				});
+			},
 			closeMJ() {
 				this.show = false
 				this.columns.forEach(item => {
@@ -354,7 +406,7 @@
 					title: '绂诲満鏃堕棿涓嶈兘涓虹┖',
 					icon: 'none'
 				})
-				if (!this.form1.doorSelectName) return uni.showToast({
+				if (!this.form1.doorSelectName && this.accessControl == 1) return uni.showToast({
 					title: '璁块棶闂ㄧ涓嶈兘涓虹┖',
 					icon: 'none'
 				})
@@ -374,7 +426,6 @@
 					withUserList: this.personnel
 				}).then(res => {
 					if (res.code === 200) {
-						console.log(res)
 						uni.reLaunch({
 							url: `/pages/appointmentDetails/appointmentDetails?id=${res.data}`
 						})
@@ -424,6 +475,10 @@
 						icon: 'none'
 					})
 				}
+				if (!this.withUserList.companyName) return uni.showToast({
+					title: '鍏徃涓嶈兘涓虹┖',
+					icon: 'none'
+				})
 				if (!this.withUserList.faceImg) return uni.showToast({
 					title: '浜鸿劯鐓х墖涓嶈兘涓虹┖',
 					icon: 'none'
@@ -449,8 +504,18 @@
 				this.withUserList.imgurlUrl = ''
 			},
 			upload(type) {
+				this.type = type
+				if (type === 'faceImg') {
+					this.$refs.cropper.open()
+					return
+				}
 				uni.chooseImage({
 					success: (chooseImageRes) => {
+						// if (type === 'faceImg') {
+						// 	this.photoSrc = chooseImageRes.tempFilePaths[0];
+						// 	this.$refs.tlyPictureCut.showPop();
+						// 	return
+						// }
 						uni.showLoading({ title: '涓婁紶涓�', mask: true });
 						for (let i = 0; i < chooseImageRes.tempFilePaths.length; i++) {
 							uni.uploadFile({
@@ -533,9 +598,6 @@
 			},
 			// 鏌ヨ鐢ㄦ埛
 			getUser() {
-				console.log(this.verify)
-				console.log(this.form1.phone1)
-				console.log(this.form1.receptMemberName)
 				if (this.verify === '0') {
 					if (this.form1.phone1) {
 						this.$u.api.getVisitedMember({
@@ -568,7 +630,6 @@
 					label: 'BEVISITED_USER_VALID'
 				}).then(res => {
 					if (res.code === 200) {
-						console.log(res)
 						this.verify = res.data.code
 					}
 				})
diff --git a/h5/redirect.html b/h5/redirect.html
index 07eb389..e445f88 100644
--- a/h5/redirect.html
+++ b/h5/redirect.html
@@ -6,7 +6,7 @@
   <script>
     var p = location.href.split("?")
     // window.location.href = 'https://dmtest.ahapp.net/hsvisit_h5/#/pages/notice/notice?' + p[1]
-	window.location.href = 'http://218.23.218.228:8018/h5/#/pages/notice/notice?' + p[1]
+	window.location.href = 'http://facepay.huasunsolar.com/h5/#/pages/notice/notice?' + p[1]
   </script>
 </head>
 <body>
diff --git a/h5/store/index.js b/h5/store/index.js
index 9ebd456..a1dfad7 100644
--- a/h5/store/index.js
+++ b/h5/store/index.js
@@ -4,18 +4,25 @@
 Vue.use(Vuex)
 
 const openId = uni.getStorageSync('openId');
+const member = uni.getStorageSync('member');
 
 const store = new Vuex.Store({
 	
 	state: {
-		openId: openId || ''
+		openId: openId || '',
+		member: member || null
 	},
 	
 	mutations: {
-		// 璁剧疆鍩庡競
+		// 璁剧疆openId
 		setOpenId(state, val) {
 			state.openId = val
 			uni.setStorageSync('openId', val);
+		},
+		// 璁剧疆鐢ㄦ埛淇℃伅
+		setMember(state, val) {
+			state.member = val
+			uni.setStorageSync('member', val);
 		}
 	}
 	
diff --git a/h5/uni_modules/bt-cropper/changelog.md b/h5/uni_modules/bt-cropper/changelog.md
new file mode 100644
index 0000000..eab9155
--- /dev/null
+++ b/h5/uni_modules/bt-cropper/changelog.md
@@ -0,0 +1,29 @@
+## 3.0.2锛�2023-06-06锛�
+鏇存柊浜嗘枃妗�
+
+## 3.0.1锛�2022-11-03锛�
+淇 鎾ら攢鍜岄噸鍋氫笉鐢熸晥鐨勯棶棰�
+## 3.0.0锛�2022-11-03锛�
+浣跨敤wxs閲嶆瀯浠g爜锛屾�ц兘澶ф彁鍗�
+鏂板 鏀寔钂欑増瑁佸壀锛屽彲浠ヨ鍓换浣曞舰鐘剁殑鍥惧舰锛堣鎯呰demo绀轰緥锛�
+鏂板 鏀寔鍦ㄥ脊绐椾腑浣跨敤锛堣鎯呰demo绀轰緥锛�
+绉婚櫎 鐢变簬鎻掓Ы浼氬鑷磋澶氶棶棰橈紝瀹為檯涓婂紑鍙戣�呰嚜宸卞皝瑁呯粍浠跺弽鑰屾洿绠�鍗曪紝鎵�浠�3.0鐗堟湰浠ュ悗绉婚櫎鎻掓Ы锛�2.0杩佺Щ鏁欑▼瑙� demo:鍏ㄥ睆瑁佸壀
+## 2.0.3锛�2022-08-21锛�
+淇 鍦╲ue3 绋嬪簭涓姤閿欑殑闂
+鏂板 鏂板浜嗗浘鐗囧垵濮嬪寲瀹屾垚鍜屽姞杞藉け璐ョ殑浜嬩欢
+## 2.0.2锛�2022-08-18锛�
+鏂板 澧炲姞浜嗗師鍍忕礌瑁佸壀鍔熻兘锛屽嵆浣跨敤鐢ㄦ埛鍦ㄨ鍓鍙栨櫙鐨勫ぇ灏忎綔涓鸿緭鍑哄儚绱狅紝鎹㈠彞璇濊锛岃緭鍑虹殑鍥剧墖鍒嗚鲸鐜囦笌杈撳叆鍥剧墖鍒嗚鲸鐜囦竴鏍�
+鏂板 澧炲姞浜哻hange浜嬩欢锛屼細鍦ㄥ浘鍍忓拰瑁佸壀妗嗕綅缃彉鍖栧悗瑙﹀彂
+鏂板 澧炲姞浜哻ompress鍙傛暟 鍘嬬缉鍥剧墖锛屽帇缂╁浘鐗囨槸涓轰簡鎻愬崌娴佺晠搴︼紝鎵�浠ュ彧浼氶拡瀵圭敤鎴锋嫋鍔ㄧ殑閭e紶鍥剧墖杩涜鍘嬬缉锛屾渶缁堣緭鍑虹殑鍥惧儚鍝佽川骞朵笉浼氬彈鍒板奖鍝�
+淇 鐢ㄦ埛鍦ㄦ病鏈変紶鍏ュ浘鍍忔椂鎶ラ敊鐨勯棶棰�
+淇 ios鍦ㄦ煇浜涙満鍨嬩笂鎷栧姩鍑虹幇娈嬬暀鐨勯棶棰�
+## 2.0.1锛�2022-07-20锛�
+淇锛歩os鎵撳寘鎴恆pp鐨勬椂鍊欐湁鍑犵巼瑁佸壀涓嶆垚鍔熺殑闂
+## 2.0.0锛�2022-07-13锛�
+鏇存柊浜�2.0鐗堟湰锛屽鍔犱簡鍥剧墖鏀惧ぇ鍔熻兘
+## bt-cropper 鍥剧墖瑁佸垏
+========
+### 2022骞�7鏈�13鏃� 鍙戝竷2.0鐗堟湰
+* 1.瀹屽叏閲嶆瀯浜嗕唬鐮侊紝骞朵笖浼樺寲浜嗘�ц兘
+* 2.鏀寔app
+* 3.淇demo鍦℉5鐨勬儏鍐典笅楂樺害閿欒鐨勯棶棰�
diff --git a/h5/uni_modules/bt-cropper/components/bt-cropper/bt-cropper.vue b/h5/uni_modules/bt-cropper/components/bt-cropper/bt-cropper.vue
new file mode 100644
index 0000000..0e9709c
--- /dev/null
+++ b/h5/uni_modules/bt-cropper/components/bt-cropper/bt-cropper.vue
@@ -0,0 +1,1095 @@
+<template>
+	<view class="bt-container" :style="[containerStyle]">
+		<!-- #ifdef APP-VUE || MP-WEIXIN || MP-QQ || H5 -->
+		<view class="mainContent" data-type="image" @touchstart="wxsModule.touchStart" @touchmove="wxsModule.touchMove" @touchend="wxsModule.touchEnd">
+		<!-- #endif -->
+		<!-- #ifndef APP-VUE || MP-WEIXIN || MP-QQ || H5 -->
+		<view class="mainContent" data-type="image" @touchstart="touchStart" @touchmove="touchMove" @touchend="touchEnd">
+		<!-- #endif -->
+			<template v-if="imageRect && cropperRect">
+				<!-- #ifdef APP-VUE || MP-WEIXIN || MP-QQ || H5 -->
+				<image mode="aspectFit" :src="imageSrc" class="image" :rotateAngle="rotateAngle" :change:rotateAngle="wxsModule.changeRotateAngle" :change:imageRect="wxsModule.changeImageRect" :imageRect="imageRect" :class="{ anim }">
+				<!-- #endif -->
+				<!-- #ifndef APP-VUE || MP-WEIXIN || MP-QQ || H5 -->
+				<image mode="aspectFit" :src="imageSrc" class="image" :style="[imageStyle]" :class="{ anim }">
+				<!-- #endif -->
+				</image>
+				<!-- #ifdef APP-VUE || MP-WEIXIN || MP-QQ || H5 -->
+				<view class="cropper" :class="{ anim }" :change:cropperRect="wxsModule.changeCropper" :cropperRect="cropperRect" :change:ratio="wxsModule.changeRatio" :ratio="ratio" >
+				<!-- #endif -->
+				<!-- #ifndef APP-VUE || MP-WEIXIN || MP-QQ || H5 -->
+				<view class="cropper" :class="{ anim }"  :style="[cropperStyle]">
+				<!-- #endif -->
+					<image class="mask" :src="mask"></image>
+					<template v-if="showGrid">
+						<view class="line row row1"></view>
+						<view class="line row row2"></view>
+						<view class="line col col1"></view>
+						<view class="line col col2"></view>
+					</template>
+					<!-- #ifdef APP-VUE || MP-WEIXIN || MP-QQ || H5  -->
+					<view class="controller vertical left" @touchstart="wxsModule.touchStart" data-type="controller" />
+					<view class="controller vertical right" @touchstart="wxsModule.touchStart" data-type="controller" />
+					<view class="controller horizon top" @touchstart="wxsModule.touchStart" data-type="controller" />
+					<view class="controller horizon bottom" @touchstart="wxsModule.touchStart" data-type="controller" />
+					<view class="controller left top" @touchstart="wxsModule.touchStart" data-type="controller" />
+					<view class="controller left bottom" @touchstart="wxsModule.touchStart" data-type="controller" />
+					<view class="controller right top" @touchstart="wxsModule.touchStart" data-type="controller" />
+					<view class="controller right bottom" @touchstart="wxsModule.touchStart" data-type="controller" />
+					<!-- #endif -->
+					<!-- #ifndef APP-VUE || MP-WEIXIN || MP-QQ || H5  -->
+					<view class="controller vertical left" @touchstart.stop="touchStart(-1, 0, $event)" />
+					<view class="controller vertical right" @touchstart.stop="touchStart(1, 0, $event)" />
+					<view class="controller horizon top" @touchstart.stop="touchStart(0, -1, $event)" />
+					<view class="controller horizon bottom" @touchstart.stop="touchStart(0, 1, $event)" />
+					<view class="controller left top" @touchstart.stop="touchStart(-1, -1, $event)" />
+					<view class="controller left bottom" @touchstart.stop="touchStart(-1, 1, $event)" />
+					<view class="controller right top" @touchstart.stop="touchStart(1, -1, $event)" />
+					<view class="controller right bottom" @touchstart.stop="touchStart(1, 1, $event)" />
+					<!-- #endif -->
+				</view>
+			</template>
+		</view>
+			<canvas v-if="type2d" type="2d" class="bt-canvas" :width="target.width" :height="target.height"></canvas>
+			<canvas
+				v-else
+				:canvas-id="canvasId"
+				class="bt-canvas"
+				:style="{
+					width: target.width + 'px',
+					height: target.height + 'px'
+				}"
+				:width="target.width * pixel"
+				:height="target.height * pixel"
+			></canvas>
+	</view>
+</template>
+
+<script>
+// #ifndef APP-VUE || MP-WEIXIN || MP-QQ || H5
+import touches from './js/touchs.js';
+// #endif
+import { parseUnit,sleep } from './utils/tools.js';
+/**
+ * better-cropper 鍥剧墖瑁佸垏鎻掍欢
+ */
+export default {
+	name: 'bt-cropper',
+	props: {
+		// 鍥剧墖璺緞锛屾敮鎸佺綉缁滆矾寰勫拰鏈湴璺緞
+		imageSrc: {
+			type: String,
+			default: '',
+			required: true
+		},
+		mask: {
+			type: String,
+			default: ''
+		},
+		// 鎵嬪姩鎸囧畾瀹瑰櫒鐨勫ぇ灏�
+		containerSize: {
+			type: Object,
+			default: null
+		},
+		// 杈撳嚭鍥剧墖鐨勬牸寮忥紝榛樿jpg
+		fileType: {
+			type: String,
+			default: 'png'
+		},
+		// 鐢熸垚鐨勫浘鐗囩殑瀹藉害,涓嶄紶鎴栬�呬紶0琛ㄧず鎸夌収鍘熷鍒嗚鲸鐜囪鍒�
+		dWidth: Number,
+		maxWidth: {
+			type: Number,
+			default: 2000
+		},
+		// 瑁佸垏姣斾緥锛�0琛ㄧず鑷敱
+		ratio: {
+			type: Number,
+			default: 0,
+			validator(value) {
+				if (typeof value === 'number') {
+					if (value < 0) {
+						return false;
+					}
+				} else {
+					return false;
+				}
+				return true;
+			}
+		},
+		// 鏃嬭浆瑙掑害
+		rotate: Number,
+		// 鏄惁灞曠ず缃戞牸
+		showGrid: {
+			type: Boolean,
+			default: false
+		},
+		// 鍥剧墖璐ㄩ噺锛�0-1 瓒婂ぇ璐ㄩ噺瓒婂ソ
+		quality: {
+			type: Number,
+			default: 1
+		},
+		canvas2d: {
+			type: Boolean,
+			default: false
+		},
+		// 鍒濆鐨勫浘鐗囦綅缃�
+		initPosition: {
+			type: Object,
+			default() {
+				return null;
+			}
+		},
+		// 鏄惁寮�鍚搷浣滅粨鏉熷悗鑷姩鏀惧ぇ
+		autoZoom: {
+			type: Boolean,
+			default: true
+		}
+	},
+	// #ifndef APP-VUE || MP-WEIXIN || MP-QQ || H5
+	mixins: [touches],
+	// #endif
+	data() {
+		return {
+			canvasId: 'bt-cropper',
+			containerRect: null,
+			imageInfo: null,
+			operationHistory: [],
+			operationIndex: 0,
+			anim: false,
+			timer: null,
+			// 鏄惁浣跨敤2D canvas
+			type2d: false,
+			pixel: 1,
+			imageRect: null,
+			cropperRect: null,
+			target:{
+				width:0,
+				height:0
+			}
+		};
+	},
+	watch: {
+		imageSrc: {
+			handler(src) {
+				if (typeof src === 'string' && src !== '') {
+					this.imageInit(src);
+				} else {
+					this.imageInfo = null;
+				}
+			},
+			immediate: true
+		},
+		ratio() {
+			if (this.ratio != 0) {
+				this.startAnim();
+				this.init();
+			}
+		}
+	},
+	computed: {
+		containerStyle() {
+			if (this.containerSize && this.containerRect) {
+				return {
+					width: this.containerRect.width + 'px',
+					height: this.containerRect.height + 'px'
+				};
+			}
+			return {};
+		},
+		rotateAngle(){
+			const angel = Number(this.rotate)
+			if(isNaN(angel)){
+				return 0
+			}else{
+				return angel % 360
+			}
+		}
+	},
+	methods: {
+		startAnim() {
+			this.stopAnim();
+			this.anim = true;
+			this.timer = setTimeout(() => {
+				this.anim = false;
+			}, 200);
+		},
+		stopAnim() {
+			this.anim = false;
+			clearTimeout(this.timer);
+		},
+		imageInit(src) {
+			uni.showLoading({
+				title: '杞藉叆涓�...'
+			});
+			uni.getImageInfo({
+				src,
+				success: res => {
+					this.imageInfo = res;
+					this.$nextTick(() => {
+						this.getContainer().then(rect => {
+							this.containerRect = rect;
+							this.init();
+						});
+					});
+				},
+				fail: (err) => {
+					this.$emit('loadFail',err);
+					uni.showToast({
+						title: '鍥剧墖涓嬭浇澶辫触!',
+						icon: 'none'
+					});
+				},
+				complete(res) {
+					uni.hideLoading();
+				}
+			});
+		},
+		initCropper() {
+			const imageRate = this.imageInfo.width / this.imageInfo.height;
+			const containerRate = this.containerRect.width / this.containerRect.height;
+			const imageRect = {};
+			let cropperRate = this.ratio;
+			if (cropperRate == 0) {
+				if (this.cropperRect) {
+					cropperRate = this.cropperRect.width / this.cropperRect.height;
+				} else {
+					cropperRate = 1;
+				}
+			}
+			const cropperRect = {};
+			if (containerRate > cropperRate) {
+				cropperRect.height = this.containerRect.height * 0.85;
+				cropperRect.width = cropperRect.height * cropperRate;
+			} else {
+				cropperRect.width = this.containerRect.width * 0.85;
+				cropperRect.height = cropperRect.width / cropperRate;
+			}
+			if (cropperRate > imageRate) {
+				imageRect.width = cropperRect.width;
+				imageRect.height = imageRect.width / imageRate;
+			} else {
+				imageRect.height = cropperRect.height;
+				imageRect.width = imageRect.height * imageRate;
+			}
+			imageRect.left = (this.containerRect.width - imageRect.width) / 2;
+			imageRect.top = (this.containerRect.height - imageRect.height) / 2;
+			cropperRect.left = imageRect.left + (imageRect.width - cropperRect.width) / 2;
+			cropperRect.top = imageRect.top + (imageRect.height - cropperRect.height) / 2;
+			return {
+				imageRect,
+				cropperRect
+			};
+		},
+		init() {
+			const {imageRect,cropperRect} = this.initCropper()
+			if(this.initPosition){
+				const scale = this.imageInfo.width/imageRect.width;
+				const {left,top,width,height} = this.initPosition;
+				if(left!==undefined&&top!==undefined&&width!==undefined&&height!==undefined){
+					cropperRect.width = width/scale;
+					cropperRect.height = height/scale;
+					cropperRect.left = left/scale;
+					cropperRect.top = top/scale;
+					this.$nextTick(this.zoomToFill);
+				}
+			}
+			this.imageRect = imageRect
+			this.cropperRect = cropperRect
+			this.operationHistory = [{imageRect,cropperRect}];
+			this.operationIndex = 0;
+			this.setTarget();
+			// #ifdef MP-WEIXIN
+			const systemInfo = uni.getSystemInfoSync();
+			if (this.canvas2d === false || systemInfo.platform === 'windows' || systemInfo.platform === 'mac') {
+				this.type2d = false;
+			} else {
+				this.type2d = true;
+				this.pixel = systemInfo.pixelRatio;
+			}
+			// #endif
+			//闈炲井淇″皬绋嬪簭绔己鍒跺叧闂璫anvas2d妯″紡
+			// #ifndef MP-WEIXIN
+			this.type2d = false;
+			// #endif
+			// #ifdef  MP-TOUTIAO || MP-LARK || MP-ALIPAY
+			this.type2d = this.canvas2d;
+			// #endif
+		},
+		// 璁剧疆鐩爣鍥惧儚鐨勫ぇ灏�
+		setTarget(){
+			const ratio = this.cropperRect.width / this.cropperRect.height;
+			if (!!this.dWidth) {
+				this.target = {
+					width: this.dWidth,
+					height: this.dWidth / (ratio || 1)
+				}
+			} else {
+				const width = Math.min(this.maxWidth, this.cropperRect.width * (this.imageInfo.width / this.imageRect.width));
+				this.target = {
+					width,
+					height: width / (ratio || 1)
+				}
+			}
+		},
+		addHistory({imageRect,cropperRect}){
+			if(this.operationIndex!==this.operationHistory.length-1){
+				this.operationHistory = this.operationHistory.slice(0,this.operationIndex)
+			}
+			this.operationHistory.push({
+				imageRect,
+				cropperRect
+			});
+			if (this.operationHistory.length > 10) {
+				this.operationHistory.shift();
+			}
+			this.operationIndex = this.operationHistory.length - 1;
+		},
+		updateData(data) {
+			this.imageRect = data.imageRect
+			this.cropperRect = data.cropperRect
+			this.addHistory(data);
+			this.setTarget();
+			if (this.autoZoom) {
+				this.timer = setTimeout(() => {
+					this.zoomToFill();
+				}, 600);
+			}
+			const {imageRect,cropperRect} = data
+			const scale = imageRect.width/this.imageInfo.width
+			this.$emit('change', {
+				left: (cropperRect.left - imageRect.left) /scale,
+				top: (cropperRect.top - imageRect.top) / scale,
+				width: cropperRect.width / scale,
+				height: cropperRect.height / scale
+			});
+		},
+		getContainer() {
+			if (this.containerSize !== null && typeof this.containerSize == 'object') {
+				const { width, height } = this.containerSize;
+				return Promise.resolve({
+					width: parseUnit(width),
+					height: parseUnit(height)
+				});
+			} else {
+				return new Promise(resolve => {
+					const query = uni.createSelectorQuery().in(this);
+					query
+						.select('.mainContent')
+						.boundingClientRect(rect => {
+							resolve(rect);
+						})
+						.exec();
+				});
+			}
+		},
+		zoomToFill() {
+			this.startAnim();
+			const beforeCropper = {
+				...this.cropperRect
+			};
+			const operation = {
+				imageRect:this.imageRect,
+				cropperRect:this.cropperRect
+			};
+			this.cropperRect = this.initCropper().cropperRect;
+			const scale = this.cropperRect.width / beforeCropper.width;
+			const ox = beforeCropper.left - this.imageRect.left;
+			const oy = beforeCropper.top - this.imageRect.top;
+			this.imageRect = {
+				width: this.imageRect.width * scale,
+				height: this.imageRect.height * scale,
+				left: this.imageRect.left + (this.cropperRect.left - beforeCropper.left) - (scale - 1) * ox,
+				top: this.imageRect.top + (this.cropperRect.top - beforeCropper.top) - (scale - 1) * oy
+			};
+		},
+		onTouchStart() {
+			this.stopAnim();
+		},
+		// 鎾ら攢
+		undo() {
+			if (this.operationIndex > 0) {
+				this.operationIndex--;
+				this.imageRect = this.operationHistory[this.operationIndex].imageRect;
+				this.cropperRect = this.operationHistory[this.operationIndex].cropperRect;
+				return true;
+			}
+			return false;
+		},
+		// 閲嶅仛
+		resume() {
+			if (this.operationIndex < this.operationHistory.length - 1) {
+				this.operationIndex++;
+				this.imageRect = this.operationHistory[this.operationIndex].imageRect;
+				this.cropperRect = this.operationHistory[this.operationIndex].cropperRect;
+				return true;
+			}
+			return false;
+		},
+		async drawImage(ctx,image,x,y,w,h){
+			if (this.type2d) {
+				await new Promise(resolve => (image.onload = resolve));
+				ctx.drawImage(image, x * this.pixel, y * this.pixel, w * this.pixel, h * this.pixel);
+			} else {
+				const path = await new Promise((resolve)=>{
+					uni.getImageInfo({
+						src:image,
+						success({path}){
+							resolve(path)
+						}
+					})
+				})
+				ctx.drawImage(path, x * this.pixel, y * this.pixel, w * this.pixel, h * this.pixel);
+				await new Promise((resolve) => ctx.draw(false,resolve));
+			}
+		},
+		async crop() {
+			let ctx;
+			let canvas;
+			this.$emit('cropStart')
+			this.setTarget()
+			if (this.type2d) {
+				const query = uni.createSelectorQuery().in(this);
+				canvas = await new Promise(resolve =>
+					query
+						.select('.bt-canvas')
+						.node(({ node }) => resolve(node))
+						.exec()
+				);
+				canvas.width = this.target.width * this.pixel;
+				canvas.height = this.target.height * this.pixel;
+				ctx = canvas.getContext('2d');
+				// #ifdef MP-TOUTIAO
+				if(this.type2d){
+					console.warn("璇锋敞鎰忥細鐩墠澶存潯绯诲皬绋嬪簭鏆傛椂鏃犳硶浣跨敤2d canvas淇濆瓨鍥剧墖锛屽缓璁崲鎴怴1鐗堟湰")
+				}
+				// #endif
+			} else {
+				ctx = uni.createCanvasContext(this.canvasId,this);
+			}
+			const scale = this.cropperRect.width / this.target.width;
+			const dx = (this.cropperRect.left - this.imageRect.left) / scale;
+			const dy = (this.cropperRect.top - this.imageRect.top) / scale;
+			let image;
+			if(this.type2d){
+				image = canvas.createImage()
+				image.src = this.imageSrc;
+			}else{
+				image = this.imageSrc;
+			}
+			const x = -dx,
+				y = -dy,
+				w = this.imageRect.width / scale,
+				h = this.imageRect.height / scale;
+			ctx.save();
+			ctx.translate(x + w / 2, y + h / 2);
+			ctx.rotate((this.rotateAngle * Math.PI) / 180);
+			ctx.translate(-(x + w / 2), -(y + h / 2));
+			await this.drawImage(ctx,image, x, y, w, h);
+			ctx.restore();
+			if (this.mask !== '') {
+				let imageData;
+				if (this.type2d) {
+					imageData = ctx.getImageData(0, 0, this.target.width, this.target.height);
+				} else {
+					imageData = await new Promise(resolve => {
+						uni.canvasGetImageData({
+							canvasId: this.canvasId,
+							x: 0,
+							y: 0,
+							width: this.target.width,
+							height: this.target.height,
+							success(res) {
+								resolve(res);
+							}
+						},this);
+					});
+				}
+				ctx.clearRect(0, 0, this.target.width, this.target.height);
+				if(this.type2d){
+					image.src = this.mask;
+				}else{
+					image = this.mask;
+				}
+				await this.drawImage(ctx,image, 0, 0, this.target.width, this.target.height);
+				let maskData;
+				if (this.type2d) {
+					maskData = ctx.getImageData(0, 0, this.target.width, this.target.height);
+				} else {
+					maskData = await new Promise((resolve,reject) => {
+						uni.canvasGetImageData({
+							canvasId: this.canvasId,
+							x: 0,
+							y: 0,
+							width: this.target.width,
+							height: this.target.height,
+							success(res) {
+								resolve(res);
+							}
+						},this);
+					});
+				}
+				ctx.clearRect(0, 0, this.target.width, this.target.height);
+				for (let index = 3; index < maskData.data.length; index += 4) {
+					const alpha = maskData.data[index];
+					if (alpha !== 0) {
+						imageData.data[index] = 0;
+					}
+				}
+				if (this.type2d) {
+					ctx.putImageData(imageData, 0, 0);
+				} else {
+					await new Promise(resolve => {
+						uni.canvasPutImageData({
+							canvasId: this.canvasId,
+							x: 0,
+							y: 0,
+							width: imageData.width,
+							height: imageData.height,
+							data: imageData.data,
+							complete: res => {
+								resolve(res);
+							}
+						},this);
+					});
+				}
+			}
+			return new Promise((resolve,reject) => {
+				const params = {};
+				if (this.type2d) {
+					params.canvas = canvas;
+				} else {
+					params.canvasId = this.canvasId;
+				}
+				
+				uni.canvasToTempFilePath({
+					...params,
+					destWidth: this.target.width,
+					destHeight: this.target.height,
+					quality: Number(this.quality) || 1,
+					fileType: this.fileType,
+					success: ({ tempFilePath }) => {
+						// #ifdef H5
+						var arr = tempFilePath.split(',');
+						var mime = arr[0].match(/:(.*?);/)[1];
+						var bstr = atob(arr[1]);
+						var n = bstr.length;
+						var u8arr = new Uint8Array(n);
+						for (var i = 0; i < n; i++) {
+							u8arr[i] = bstr.charCodeAt(i);
+						}
+						var url = URL || webkitURL;
+						resolve(
+							url.createObjectURL(
+								new Blob([u8arr], {
+									type: mime
+								})
+							)
+						);
+						// #endif
+						resolve(tempFilePath);
+					},
+					fail(err) {
+						console.log('淇濆瓨澶辫触锛岄敊璇俊鎭細',err);
+						reject(err);
+					}
+				},this);
+			});
+		}
+	}
+};
+</script>
+<!-- #ifdef APP-VUE || MP-WEIXIN || MP-QQ || H5 -->
+<script module="wxsModule" lang="wxs">
+var startTouchs = [];
+var startDistance = 0;
+var touchCenter = [];
+var ratio = 0;
+var imageInstance = null;
+var cropperInstance = null;
+var touchType = "";
+var touchInstance = null;
+var cropperRect = null;
+var imageRect = null;
+// 鏃嬭浆瑙掑害
+var rotateAngle = 0;
+// 鎿嶄綔鏃舵敼鍙樼殑瀵硅薄
+var changes = {
+	imageRect: null,
+	cropperRect: null
+}
+
+function updateImageStyle() {
+	var imageRect = changes.imageRect
+	imageInstance.setStyle({
+		left: imageRect.left + 'px',
+		top: imageRect.top + 'px',
+		width: imageRect.width + 'px',
+		height: imageRect.height + 'px',
+		transform: 'rotate(' + rotateAngle + 'deg)'
+	})
+}
+
+function updateCopperStyle() {
+	var cropperRect = changes.cropperRect
+	cropperInstance.setStyle({
+		left: cropperRect.left + "px",
+		top: cropperRect.top + "px",
+		width: cropperRect.width + "px",
+		height: cropperRect.height + "px"
+	})
+}
+
+function imageScale(scaleRate) {
+	var cw = imageRect.width * (scaleRate - 1)
+	var ch = imageRect.height * (scaleRate - 1)
+	changes.imageRect = {
+		width: imageRect.width + cw,
+		height: imageRect.height + ch,
+		left: imageRect.left - cw * (touchCenter[0]),
+		top: imageRect.top - ch * (touchCenter[1])
+	}
+}
+function getImageRotateSizeChange(w,h){
+	var cw = h*Math.sin(rotateAngle/180 * Math.PI)
+	var ch = w*Math.sin(rotateAngle/180 * Math.PI)
+	return {cw,ch}
+}
+// 瑙掑害杞姬搴�
+function ang2deg(ang){
+	return ang/180*Math.PI
+}
+// 璁$畻鏃嬭浆鍚庣湡瀹炵殑鍥剧墖澶у皬
+function getRealSize(){
+	var w = changes.imageRect.width
+	var h = changes.imageRect.height
+	var l =  changes.imageRect.left
+	var t =  changes.imageRect.top
+	// 鍐呮枩杈�
+	var R = Math.sqrt(w*w+h*h)
+	var angle = Math.atan(h/w) / Math.PI * 180
+	var rorate = rotateAngle%90
+	var direct = Math.floor(rotateAngle/90)
+	var width = R*Math.cos(ang2deg(angle-rorate))
+	var height = R*Math.sin(ang2deg(angle+rorate))
+	if(direct % 2 === 1){
+		var temp = width
+		width = height
+		height = temp
+	}
+	return {
+		width: width,
+		height: height,
+		left: l - (width - w)/2,
+		top: t - (height - h)/2,
+		dw: width - w,
+		dh: height - h
+	}
+}
+module.exports = {
+	touchStart: function (ev, oi) {
+		// #ifdef APP-PLUS || H5
+		ev.preventDefault();
+		ev.stopPropagation();
+		// #endif
+		touchInstance = ev.instance;
+		var dataSet = ev.instance.getDataset()
+		touchType = dataSet.type;
+		startTouchs = ev.touches;
+		oi.callMethod('onTouchStart')
+		if (startTouchs.length == 2) {
+			touchType = "image"
+			var x1 = startTouchs[0].clientX
+			var y1 = startTouchs[0].clientY
+			var x2 = startTouchs[1].clientX
+			var y2 = startTouchs[1].clientY
+			var distance = Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)
+			startDistance = Math.sqrt(distance)
+			var leftPercent = ((x1 + x2) / 2 - imageRect.left) / imageRect.width
+			var topPercent = ((y1 + y2) / 2 - imageRect.top) / imageRect.height
+			touchCenter = [leftPercent, topPercent]
+		}
+		return false;
+	},
+	touchMove: function (ev, io) {
+		if (touchType == "") return false
+		// #ifdef H5
+		ev.preventDefault();
+		ev.stopPropagation();
+		// #endif
+		var touches = ev.touches;
+		var changeX1 = touches[0].clientX - startTouchs[0].clientX;
+		var changeY1 = touches[0].clientY - startTouchs[0].clientY;
+		if (startTouchs.length == 1) {
+			if (touchType === 'image') {
+				changes.imageRect.left = imageRect.left + changeX1;
+				changes.imageRect.top = imageRect.top + changeY1;
+				updateImageStyle()
+			} else if (touchType === 'controller') {
+				var directionX = 0;
+				if (touchInstance.hasClass('left')) {
+					directionX = -1;
+				}
+				if (touchInstance.hasClass('right')) {
+					directionX = 1;
+				}
+				var directionY = 0;
+				if (touchInstance.hasClass('top')) {
+					directionY = -1
+				}
+				if (touchInstance.hasClass('bottom')) {
+					directionY = 1
+				}
+				var changeX = changeX1 * directionX;
+				var changeY = changeY1 * directionY;
+				// 姣斾緥缂╂斁鎺у埗
+				if (ratio !== 0) {
+					if (directionX * directionY !== 0) {
+						if (changeX / ratio > changeY) {
+							changeY = changeX / ratio
+							changeX = changeY * ratio
+						} else {
+							changeX = changeY * ratio
+							changeY = changeX / ratio
+						}
+					} else {
+						if (directionX == 0) {
+							changeX = changeY * ratio
+						} else {
+							changeY = changeX / ratio
+						}
+					}
+				}
+				var realSize = getRealSize()
+				var width = cropperRect.width + changeX
+				var height = cropperRect.height + changeY
+				// var imageRight = imageRect.left + imageRect.width
+				// var imageBottom = imageRect.top + imageRect.height
+				var imageRight = realSize.left+realSize.width
+				var imageBottom = realSize.top+realSize.height
+				if (directionX != -1) {
+					if (cropperRect.left + width > imageRight) {
+						width = imageRight - cropperRect.left
+						if (ratio !== 0) {
+							height = width / ratio
+						}
+					}
+				} else {
+					var cLeft = cropperRect.left - changeX
+					if (cLeft < realSize.left) {
+						width = cropperRect.left + cropperRect.width - realSize.left
+						if (ratio !== 0) {
+							height = width / ratio
+						}
+					}
+				}
+				// 鍒ゆ柇鏄惁瑙﹀簳
+				if (directionY != -1) {
+					if (cropperRect.top + height > imageBottom) {
+						height = imageBottom - cropperRect.top
+						if (ratio !== 0) {
+							width = height * ratio
+						}
+					}
+				} else {
+					var cTop = cropperRect.top - changeY
+					if (cTop < realSize.top) {
+						height = cropperRect.top + cropperRect.height - realSize.top
+						if (ratio !== 0) {
+							width = height * ratio
+						}
+					}
+				}
+				if (directionX == -1) {
+					changes.cropperRect.left = cropperRect.left + cropperRect.width - width
+				}
+				if (directionY == -1) {
+					changes.cropperRect.top = cropperRect.top + cropperRect.height - height
+				}
+				// 杈圭晫鎺у埗
+				changes.cropperRect.width = width
+				changes.cropperRect.height = height
+				updateCopperStyle()
+			}
+		} else if (touches.length == 2 && startTouchs.length == 2) {
+			var changeX2 = touches[0].clientX - touches[1].clientX;
+			var changeY2 = touches[0].clientY - touches[1].clientY;
+			var distance = Math.pow(changeX2, 2) + Math.pow(changeY2, 2)
+			distance = Math.sqrt(distance)
+			// 鏀惧ぇ姣斾緥
+			var scaleRate = distance / startDistance
+			imageScale(scaleRate)
+			updateImageStyle()
+		}
+		return false;
+	},
+	touchEnd: function (ev, oi) {
+		if (touchType === "image") {
+			var cropperLeft = cropperRect.left
+			var cropperRight = cropperRect.left + cropperRect.width
+			var cropperTop = cropperRect.top
+			var cropperBottom = cropperTop + cropperRect.height
+			var cropperRate = cropperRect.width / cropperRect.height
+			var realSize = getRealSize()
+			var rate = realSize.width / realSize.height
+			if (realSize.width < cropperRect.width || realSize.height < cropperRect.height) {
+				var scale = 1
+				if (rate < cropperRate) {
+					scale = cropperRect.width / realSize.width
+				} else {
+					scale = cropperRect.height / realSize.height
+				}
+				imageRect.width = changes.imageRect.width
+				imageRect.height = changes.imageRect.height
+				imageScale(scale)
+			}
+			// 杈圭晫鎺у埗start
+			if (cropperLeft < realSize.left) {
+				changes.imageRect.left = cropperLeft + realSize.dw/2
+			}
+			if (cropperRight > realSize.left + realSize.width) {
+				changes.imageRect.left = cropperRight - realSize.width + realSize.dw/2
+			}
+			if (cropperTop < realSize.top) {
+				changes.imageRect.top = cropperTop + realSize.dh/2
+			}
+			if (cropperBottom > realSize.top + realSize.height) {
+				changes.imageRect.top = cropperBottom - realSize.height + realSize.dh/2
+			}
+			// 杈圭晫鎺у埗end
+			updateImageStyle()
+		}
+		oi.callMethod('updateData', {
+			cropperRect: changes.cropperRect,
+			imageRect: changes.imageRect,
+		})
+		touchType = ""
+		startTouchs = []
+		return false;
+	},
+	// 灏嗛�昏緫灞傜殑鍥惧儚鍙樻崲鍚屾杩囨潵
+	// 瑁佸壀姣斾緥鍙樺寲
+	changeRatio: function (value) {
+		ratio = value
+	},
+	changeRotateAngle:function (value){
+		rotateAngle = value;
+		if(imageInstance){
+			updateImageStyle()
+		}
+		var realSize = getRealSize()
+	},
+	changeImageRect: function (value, oldValue, oi) {
+		if (value) {
+			imageRect = value;
+			changes.imageRect = {
+				left: value.left,
+				top: value.top,
+				width: value.width,
+				height: value.height
+			};
+			// #ifndef MP-WEIXIN || MP-QQ
+			setTimeout(function() {
+				imageInstance = oi.selectComponent('.mainContent > .image')
+				updateImageStyle();
+			});
+			// #endif
+			// #ifdef MP-WEIXIN || MP-QQ
+			imageInstance = oi.selectComponent('.mainContent > .image')
+			updateImageStyle();
+			// #endif
+		}
+	},
+	changeCropper: function (value, oldValue, oi) {
+		if (value) {
+			cropperRect = value
+			changes.cropperRect = {
+				left: value.left,
+				top: value.top,
+				width: value.width,
+				height: value.height
+			}
+			// #ifdef H5 || APP-VUE
+			setTimeout(function() {
+			// #endif
+				cropperInstance = oi.selectComponent('.mainContent > .cropper')
+				updateCopperStyle()
+			// #ifdef H5 || APP-VUE
+			});
+			// #endif
+		}
+	}
+}
+</script>
+<!-- #endif -->
+<style lang="scss" scoped>
+.bt-container {
+	// display: flex;
+	// flex-direction: column;
+	// justify-content: space-between;
+	height: 100%;
+	box-sizing: border-box;
+	// background-color: #0e1319;
+	position: relative;
+	overflow: hidden;
+
+	.bt-canvas {
+		position: fixed;
+		left: 100%;
+		top: 0;
+	}
+
+	.mainContent {
+		// flex: 1;
+		// flex-shrink:0;
+		// margin: 60rpx;
+		width: 100%;
+		height: 100%;
+		position: relative;
+		display: flex;
+		justify-content: center;
+		align-items: center;
+		// touch-action: none;
+
+		.image {
+			position: absolute;
+			// will-change: transform;
+			// transform-origin: center center;
+			width: 85%;
+			height: 85%;
+			will-change: left, top, width, height;
+		}
+
+		.controller {
+			position: absolute;
+			z-index: 99;
+			padding: 10rpx;
+			$offset: -20rpx;
+
+			&::after {
+				display: block;
+				content: '';
+				filter: drop-shadow(0 0px 10rpx rgba(0, 0, 0, 0.3));
+			}
+
+			&.vertical {
+				top: calc(50% - 30rpx);
+			}
+
+			&.horizon {
+				left: calc(50% - 30rpx);
+			}
+
+			&.left {
+				&::after {
+					height: 40rpx;
+					border-left: 10rpx solid #fff;
+				}
+
+				left: $offset;
+			}
+
+			&.right {
+				&::after {
+					height: 40rpx;
+					border-right: 10rpx solid #fff;
+				}
+
+				right: $offset;
+			}
+
+			&.top {
+				top: $offset;
+
+				&::after {
+					width: 40rpx;
+					border-top: 10rpx solid #fff;
+				}
+			}
+
+			&.bottom {
+				bottom: $offset;
+
+				&::after {
+					width: 40rpx;
+					border-bottom: 10rpx solid #fff;
+				}
+			}
+
+			&.left.bottom,
+			&.right.bottom,
+			&.left.top,
+			&.left.bottom {
+				&::after {
+					width: 30rpx;
+					height: 30rpx;
+					background-color: transparent;
+				}
+			}
+		}
+
+		.cropper {
+			position: absolute;
+			border: 1px solid #eee;
+			box-sizing: content-box;
+			// transform-origin: center center;
+			outline: 999px solid rgba(0, 0, 0, 0.5);
+			will-change: left, top, width, height;
+
+			// display: contain;
+			// pointer-events: none;
+			.mask {
+				position: absolute;
+				left: 0;
+				top: 0;
+				width: 100%;
+				height: 100%;
+				opacity: 0.5;
+			}
+
+			.line {
+				position: absolute;
+				// background-color: #eee;
+			}
+
+			.row {
+				width: 100%;
+				height: 0px;
+				left: 0;
+				border-top: 1px dashed #007aff;
+			}
+
+			.col {
+				height: 100%;
+				width: 0px;
+				border-left: 1px dashed #007aff;
+			}
+
+			.row1 {
+				top: 33%;
+			}
+
+			.row2 {
+				top: 66%;
+			}
+
+			.col1 {
+				left: 33%;
+			}
+
+			.col2 {
+				left: 66%;
+			}
+		}
+	}
+
+	// .slot {
+	// 	position: relative;
+	// 	padding-top: 20rpx;
+	// }
+}
+
+.anim {
+	transition: 0.2s;
+}
+</style>
diff --git a/h5/uni_modules/bt-cropper/components/bt-cropper/iconfont.css b/h5/uni_modules/bt-cropper/components/bt-cropper/iconfont.css
new file mode 100644
index 0000000..dd39483
--- /dev/null
+++ b/h5/uni_modules/bt-cropper/components/bt-cropper/iconfont.css
@@ -0,0 +1,22 @@
+@font-face {
+  font-family: "iconfont"; /* Project id 3311610 */
+  src: url('//at.alicdn.com/t/font_3311610_7wh8injedpd.woff2?t=1649382821379') format('woff2'),
+       url('//at.alicdn.com/t/font_3311610_7wh8injedpd.woff?t=1649382821379') format('woff'),
+       url('//at.alicdn.com/t/font_3311610_7wh8injedpd.ttf?t=1649382821379') format('truetype');
+}
+
+.iconfont {
+  font-family: "iconfont" !important;
+  font-size: 16px;
+  font-style: normal;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+
+.icon-reset:before {
+  content: "\e611";
+}
+
+.icon-move:before {
+  content: "\e67b";
+}
diff --git a/h5/uni_modules/bt-cropper/components/bt-cropper/js/touchs.js b/h5/uni_modules/bt-cropper/components/bt-cropper/js/touchs.js
new file mode 100644
index 0000000..bc90a5d
--- /dev/null
+++ b/h5/uni_modules/bt-cropper/components/bt-cropper/js/touchs.js
@@ -0,0 +1,253 @@
+var startTouchs = [];
+var touchType = ''
+var startDistance = 0;
+var touchCenter = [];
+var cropperRect = null;
+var imageRect = null;
+var directionX = 0;
+var directionY = 0;
+var ratio = 0;
+// 鎿嶄綔鏃舵敼鍙樼殑瀵硅薄
+var changes = {
+	imageRect: null,
+	cropperRect: null
+}
+// 璁$畻鏃嬭浆鍚庣湡瀹炵殑鍥剧墖澶у皬
+function getRealSize(){
+	var w = changes.imageRect.width
+	var h = changes.imageRect.height
+	var l =  changes.imageRect.left
+	var t =  changes.imageRect.top
+	// 鍐呮枩杈�
+	var R = Math.sqrt(w*w+h*h)
+	var angle = Math.atan(h/w) / Math.PI * 180
+	var rorate = rotateAngle%90
+	var direct = Math.floor(rotateAngle/90)
+	var width = R*Math.cos(ang2deg(angle-rorate))
+	var height = R*Math.sin(ang2deg(angle+rorate))
+	if(direct % 2 === 1){
+		var temp = width
+		width = height
+		height = temp
+	}
+	return {
+		width: width,
+		height: height,
+		left: l - (width - w)/2,
+		top: t - (height - h)/2,
+		dw: width - w,
+		dh: height - h
+	}
+}
+export default {
+	computed: {
+		imageStyle() {
+			const imageRect = this.imageRect
+			if (imageRect) {
+				return {
+					left: imageRect.left + 'px',
+					top: imageRect.top + 'px',
+					width: imageRect.width + 'px',
+					height: imageRect.height + 'px'
+				}
+			} else {
+				return {}
+			}
+		},
+		cropperStyle() {
+			const cropperRect = this.cropperRect
+			if (cropperRect) {
+				return {
+					left: cropperRect.left + 'px',
+					top: cropperRect.top + 'px',
+					width: cropperRect.width + 'px',
+					height: cropperRect.height + 'px'
+				}
+			} else {
+				return {}
+			}
+		}
+	},
+	methods: {
+		touchStart() {
+			let ev;
+			if (arguments.length == 3) {
+				directionX = arguments[0];
+				directionY = arguments[1];
+				ev = arguments[2];
+				touchType = "controller";
+			} else {
+				touchType = "image";
+				ev = arguments[0];
+			}
+			startTouchs = ev.touches;
+			changes = {
+				imageRect: this.imageRect,
+				cropperRect: this.cropperRect
+			};
+			ratio = this.ratio;
+			cropperRect = {
+				...changes.cropperRect
+			}
+			imageRect = {
+				...changes.imageRect
+			}
+			if (startTouchs.length == 2) {
+				const imageRect = this.imageRect
+				var x1 = startTouchs[0].clientX
+				var y1 = startTouchs[0].clientY
+				var x2 = startTouchs[1].clientX
+				var y2 = startTouchs[1].clientY
+				var distance = Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)
+				startDistance = Math.sqrt(distance)
+				var leftPercent = ((x1 + x2) / 2 - imageRect.left) / imageRect.width
+				var topPercent = ((y1 + y2) / 2 - imageRect.top) / imageRect.height
+				touchCenter = [leftPercent, topPercent]
+			}
+		},
+		touchMove(ev) {
+			if(startTouchs.length!==ev.touches.length) return
+			var touches = ev.touches;
+			var changeX1 = touches[0].clientX - startTouchs[0].clientX;
+			var changeY1 = touches[0].clientY - startTouchs[0].clientY;
+			if (startTouchs.length == 1) {
+				if (touchType === 'image') {
+					changes.imageRect.left = imageRect.left + changeX1;
+					changes.imageRect.top = imageRect.top + changeY1;
+					// console.log(startTouchs.length,ev.touches.length)
+				} else if (touchType === 'controller') {
+					var changeX = changeX1 * directionX;
+					var changeY = changeY1 * directionY;
+					// 姣斾緥缂╂斁鎺у埗
+					if (ratio !== 0) {
+						if (directionX * directionY !== 0) {
+							if (changeX / ratio > changeY) {
+								changeY = changeX / ratio
+								changeX = changeY * ratio
+							} else {
+								changeX = changeY * ratio
+								changeY = changeX / ratio
+							}
+						} else {
+							if (directionX == 0) {
+								changeX = changeY * ratio
+							} else {
+								changeY = changeX / ratio
+							}
+						}
+					}
+					var realSize = getRealSize()
+					var width = cropperRect.width + changeX
+					var height = cropperRect.height + changeY
+					var imageRight = realSize.left+realSize.width
+					var imageBottom = realSize.top+realSize.height
+					if (directionX != -1) {
+						if (cropperRect.left + width > imageRight) {
+							width = imageRight - cropperRect.left
+							if (ratio !== 0) {
+								height = width / ratio
+							}
+						}
+					} else {
+						var cLeft = cropperRect.left - changeX
+						if (cLeft < realSize.left) {
+							width = cropperRect.left + cropperRect.width - realSize.left
+							if (ratio !== 0) {
+								height = width / ratio
+							}
+						}
+					}
+					// 鍒ゆ柇鏄惁瑙﹀簳
+					if (directionY != -1) {
+						if (cropperRect.top + height > imageBottom) {
+							height = imageBottom - cropperRect.top
+							if (ratio !== 0) {
+								width = height * ratio
+							}
+						}
+					} else {
+						var cTop = cropperRect.top - changeY
+						if (cTop < realSize.top) {
+							height = cropperRect.top + cropperRect.height - realSize.top
+							if (ratio !== 0) {
+								width = height * ratio
+							}
+						}
+					}
+					if (directionX == -1) {
+						changes.cropperRect.left = cropperRect.left + cropperRect.width - width
+					}
+					if (directionY == -1) {
+						changes.cropperRect.top = cropperRect.top + cropperRect.height - height
+					}
+					// 杈圭晫鎺у埗
+					changes.cropperRect.width = width
+					changes.cropperRect.height = height
+				}
+			} else if (touches.length == 2 && startTouchs.length == 2) {
+				var changeX2 = touches[0].clientX - touches[1].clientX;
+				var changeY2 = touches[0].clientY - touches[1].clientY;
+				var distance = Math.pow(changeX2, 2) + Math.pow(changeY2, 2)
+				distance = Math.sqrt(distance)
+				// 鏀惧ぇ姣斾緥
+				var scaleRate = distance / startDistance
+				this.imageScale(scaleRate)
+			}
+		},
+		touchEnd(ev) {
+			// console.log('end',ev)
+			if(ev.touches.length!==0) return
+			if (touchType === "image") {
+				var cropperLeft = cropperRect.left
+				var cropperRight = cropperRect.left + cropperRect.width
+				var cropperTop = cropperRect.top
+				var cropperBottom = cropperTop + cropperRect.height
+				var cropperRate = cropperRect.width / cropperRect.height
+				var realSize = getRealSize()
+				var rate = realSize.width / realSize.height
+				if (realSize.width < cropperRect.width || realSize.height < cropperRect.height) {
+					var scale = 1
+					if (rate < cropperRate) {
+						scale = cropperRect.width / realSize.width
+					} else {
+						scale = cropperRect.height / realSize.height
+					}
+					imageRect.width = changes.imageRect.width
+					imageRect.height = changes.imageRect.height
+					this.imageScale(scale)
+				}
+				// 杈圭晫鎺у埗start
+				if (cropperLeft < realSize.left) {
+					changes.imageRect.left = cropperLeft + realSize.dw/2
+				}
+				if (cropperRight > realSize.left + realSize.width) {
+					changes.imageRect.left = cropperRight - realSize.width + realSize.dw/2
+				}
+				if (cropperTop < realSize.top) {
+					changes.imageRect.top = cropperTop + realSize.dh/2
+				}
+				if (cropperBottom > realSize.top + realSize.height) {
+					changes.imageRect.top = cropperBottom - realSize.height + realSize.dh/2
+				}
+				// 杈圭晫鎺у埗end
+			}
+			this.updateData({
+				cropperRect: changes.cropperRect,
+				imageRect: changes.imageRect,
+			})
+			touchType = ""
+			startTouchs = []
+			return false;
+		},
+		imageScale(scaleRate) {
+			var cw = imageRect.width * (scaleRate - 1)
+			var ch = imageRect.height * (scaleRate - 1)
+			changes.imageRect = {
+				width: imageRect.width + cw,
+				height: imageRect.height + ch,
+				left: imageRect.left - cw * (touchCenter[0]),
+				top: imageRect.top - ch * (touchCenter[1])
+			}
+		}
+	}
+}
diff --git a/h5/uni_modules/bt-cropper/components/bt-cropper/utils/tools.js b/h5/uni_modules/bt-cropper/components/bt-cropper/utils/tools.js
new file mode 100644
index 0000000..9fa9ade
--- /dev/null
+++ b/h5/uni_modules/bt-cropper/components/bt-cropper/utils/tools.js
@@ -0,0 +1,43 @@
+export function getTouchPoints(touchs) {
+	return Array.from(touchs).map(ev => {
+		return [ev.clientX, ev.clientY]
+	})
+}
+// 鍑芥暟闃叉姈
+export function debounce(fn, wait = 200) {
+	var timer = null;
+	return function (){
+		if (timer !== null) {
+			clearTimeout(timer);
+		}
+		timer = setTimeout(fn.bind(this), wait);
+	}
+}
+
+/**
+ * @description 鐫$湢
+ * @param {number} time 绛夊緟鏃堕棿姣鏁�
+ */
+export function sleep(time = 200) {
+	return new Promise(resolve => {
+		setTimeout(resolve, time)
+	})
+}
+const systemInfo = uni.getSystemInfoSync();
+
+export function parseUnit(size){
+	if(typeof size == 'number' || !isNaN(Number(size))){
+		return uni.upx2px(size)
+	}else if(typeof size === 'string') {
+		if(size.endsWith('rpx')){
+			return parseUnit(size.replace('rpx',''))
+		}else if(size.endsWith('px')){
+			return Number(size.replace('px',''))
+		}else if(size.endsWith('vw')){
+			return Number(size.replace('vw',''))*systemInfo.screenWidth/100
+		}else if(size.endsWith('vh')){
+			return Number(size.replace('vh',''))*systemInfo.screenHeight/100
+		}
+	}
+	return 0
+}
diff --git a/h5/uni_modules/bt-cropper/package.json b/h5/uni_modules/bt-cropper/package.json
new file mode 100644
index 0000000..845161f
--- /dev/null
+++ b/h5/uni_modules/bt-cropper/package.json
@@ -0,0 +1,81 @@
+{
+	"id": "bt-cropper",
+	"displayName": "bt-cropper鍥剧墖瑁佸壀鎻掍欢",
+	"version": "3.0.2",
+	"description": "涓�娆惧ソ鐢ㄧ殑鍥剧墖瑁佸壀鎻掍欢",
+	"keywords": [
+        "鍥剧墖",
+        "鍥剧墖瑁佸壀",
+        "鍥剧墖瑁佸壀",
+        "澶村儚瑁佸壀",
+        "cropper"
+    ],
+	"repository": "",
+	"engines": {
+		"HBuilderX": "^3.4.9"
+	},
+    "dcloudext": {
+        "sale": {
+			"regular": {
+				"price": "0.00"
+			},
+			"sourcecode": {
+				"price": "0.00"
+			}
+		},
+		"contact": {
+			"qq": "1097122362"
+		},
+		"declaration": {
+			"ads": "鏃�",
+			"data": "鎻掍欢涓嶉噰闆嗕换浣曟暟鎹�",
+			"permissions": "鏃�"
+		},
+        "npmurl": "",
+        "type": "component-vue"
+	},
+	"uni_modules": {
+		"dependencies": [],
+		"encrypt": [],
+		"platforms": {
+			"cloud": {
+				"tcb": "y",
+				"aliyun": "y"
+			},
+			"client": {
+				"Vue": {
+					"vue2": "y",
+					"vue3": "y"
+				},
+				"App": {
+					"app-vue": "y",
+					"app-nvue": "n"
+				},
+				"H5-mobile": {
+					"Safari": "y",
+					"Android Browser": "y",
+					"寰俊娴忚鍣�(Android)": "y",
+					"QQ娴忚鍣�(Android)": "y"
+				},
+				"H5-pc": {
+					"Chrome": "n",
+					"IE": "n",
+					"Edge": "n",
+					"Firefox": "n",
+					"Safari": "n"
+				},
+				"灏忕▼搴�": {
+					"寰俊": "y",
+					"闃块噷": "u",
+					"鐧惧害": "u",
+					"瀛楄妭璺冲姩": "y",
+					"QQ": "y"
+				},
+				"蹇簲鐢�": {
+					"鍗庝负": "n",
+					"鑱旂洘": "n"
+				}
+			}
+		}
+	}
+}
diff --git a/h5/uni_modules/bt-cropper/readme.md b/h5/uni_modules/bt-cropper/readme.md
new file mode 100644
index 0000000..3e00c4d
--- /dev/null
+++ b/h5/uni_modules/bt-cropper/readme.md
@@ -0,0 +1,108 @@
+
+
+## bt-cropper 鍥剧墖瑁佸垏
+> **缁勪欢鍚嶏細bt-cropper**
+
+鍥剧墖瑁佸垏缁勪欢锛屽湪椤甸潰涓鍒囧浘鐗囷紝杈撳嚭瑁佸垏鍚庣殑鍥剧墖锛屾敮鎸乤pp锛屽皬绋嬪簭锛孒5
+### [鍦ㄧ嚎浣撻獙](https://static-mp-8cc5bb7c-7831-45bf-a4e1-a71b10d3319c.next.bspapp.com/h5)
+
+## 灏哾emo缂栬瘧涓哄井淇″皬绋嬪簭鐨勬椂鍊欙紝涓�瀹氳濉啓appid锛侊紒锛佷笉鐒舵棤娉曚娇鐢紒锛�
+ 
+
+> **娉ㄦ剰浜嬮」**
+> 涓轰簡閬垮厤閿欒浣跨敤锛岀粰澶у甯︽潵涓嶅ソ鐨勫紑鍙戜綋楠岋紝璇峰湪浣跨敤缁勪欢鍓嶄粩缁嗛槄璇讳笅闈㈢殑娉ㄦ剰浜嬮」锛屽彲浠ュ府浣犻伩鍏嶄竴浜涢敊璇��
+> - 缁勪欢闇�瑕佷緷璧� `sass` 鎻掍欢 锛岃鑷鎵嬪姩瀹夎
+> - 鍙祴璇曚簡澶存潯灏忕▼搴忥紝app-vue 瀹夊崜锛屽井淇″皬绋嬪簭鍜孒5 澶ч儴鍒嗗钩鍙板簲璇ラ兘娌¢棶棰樹簡
+> - 鍖呰9灞傛垨瑁佸壀鍣ㄩ渶瑕佹墜鍔ㄦ寚瀹氶珮搴﹀拰瀹藉害锛屾帹鑽愭墜鍔ㄦ寚瀹氳鍓櫒鐨勫ぇ灏忥紝灏ゅ叾鏄ご鏉″皬绋嬪簭锛宩s鏈夋椂鍊欒幏鍙栦笉鍒板鍣ㄧ殑澶у皬
+> - 濡備娇鐢ㄨ繃绋嬩腑鏈変换浣曢棶棰橈紝鎴栬�呮偍鏈変竴浜涘ソ鐨勫缓璁紝娆㈣繋鑱旂郴浣滆�呭井淇�:1097122362
+
+
+
+### 瀹夎鏂瑰紡
+
+鏈粍浠剁鍚圼easycom](https://uniapp.dcloud.io/collocation/pages?id=easycom)瑙勮寖锛宍HBuilderX 2.5.5`璧凤紝鍙渶灏嗘湰缁勪欢瀵煎叆椤圭洰锛屽湪椤甸潰`template`涓嵆鍙洿鎺ヤ娇鐢紝鏃犻渶鍦ㄩ〉闈腑`import`鍜屾敞鍐宍components`銆�
+
+### 鍩烘湰鐢ㄦ硶 
+
+**绀轰緥**
+
+```html
+<template>
+	<view class="container">
+		<bt-cropper ref="cropper" :imageSrc="imageSrc"></bt-cropper>
+		<button @click="crop">瑁佸垏</button>
+	</view>
+</template>
+<style>
+	.container{
+		/** 澶栧眰涓�瀹氳鎸囧畾澶у皬 */
+		height:100vh;
+	}
+</style>
+```
+
+
+```javascript
+export default {
+   methods:{
+      crop(){
+        // 閫氳繃缁勪欢瀹氫箟鐨剅ef璋冪敤cropper鏂规硶锛岃繑鍥炰竴涓猵romise瀵硅薄
+        this.$refs.cropper.crop().then((res)=>{
+			console.log(res)
+		})
+      }
+   }
+}
+
+```
+
+### 闄愬畾瑁佸垏姣斾緥
+
+bt-cropper锛屾寚瀹歳atio鍗冲彲璁剧疆瑁佸垏妗嗙殑瀹介珮姣旓紝濡傛灉浣犳兂璁╃敤鎴疯嚜鐢辩缉鏀撅紝灏唕atio璁剧疆涓�0鍗冲彲
+
+**绀轰緥**
+
+```html
+<bt-cropper ref="cropper" :ratio="16/9":imageSrc="imageSrc"></bt-cropper>
+```
+
+## API
+
+### cropper Props 
+
+|灞炴�у悕|绫诲瀷|榛樿鍊紎璇存槑|
+|:-:|:-:|:-:|:-:|
+|ratio|number|0|瑁佸垏鍥惧儚鐨勫楂樻瘮锛�0琛ㄧず鑷敱姣斾緥|
+|dWidth|number|0|鐢熸垚鐨勫浘鐗囩殑瀹藉害,鍗曚綅锛歱x,濡傛灉浼犲叆0鐨勮瘽灏辨槸鎸夊師鍍忕礌鐨勬瘮渚嬭鍓紝涔熷氨鏄锛岃緭鍑哄浘鐗囩殑娓呮櫚搴﹀拰杈撳叆鍥剧墖鐨勬竻鏅板害涓�鏍穦
+|imageSrc|String|''|鍘熷浘鐨勮矾寰勶紝鏀寔鏈湴璺緞鍜岀綉缁滆矾寰勶紝濡傛灉鏄綉缁滆矾寰勶紝灏忕▼搴忚娉ㄦ剰閰嶇疆涓嬭浇鍩熷悕锛孒5瑕佹敞鎰忚法鍩熼棶棰榺
+|mask|String|''| 瑁佸壀鐨勮挋鐗坲rl锛岄厤鍚堣挋鐗堝彲浠ヨ鍓嚭浠讳綍褰㈢姸鐨勫浘褰� (绀轰緥瑙佸叏灞忚鍓猟emo) |
+|fileType|String|'jpg'|鐩爣鏂囦欢鐨勭被鍨嬶紝鍙敮鎸� 'jpg' 鎴� 'png'銆傞粯璁や负 'jpg'|
+|quality|Number|1|鍥剧墖鐨勮川閲忥紝鍙栧�艰寖鍥翠负 (0, 1]锛屼笉鍦ㄨ寖鍥村唴鏃跺綋浣�1.0澶勭悊|
+|showGrid|Boolean|false|鏄惁鏄剧ず涓績缃戞牸绾匡紝榛樿涓嶆樉绀簗
+|initPosition|object|null|鍥剧墖鑷畾涔夌殑鍒濆鐨勪綅缃紝鍐呭鏍煎紡瑙乧hange浜嬩欢|
+|autoZoom|Boolean|true|鏄惁寮�鍚搷浣滅粨鏉熷悗鑷姩鏀惧ぇ鍒扮獥鍙eぇ灏弢
+|containerSize|object|null|鎵嬪姩鎸囧畾瀹瑰櫒澶у皬锛屽鏋滆鍓櫒鏀惧湪澶у皬浼氱Щ鍔ㄦ垨缂╂斁鐨刣om涓紝鍒欏繀椤绘墜鍔ㄦ寚瀹氬ぇ灏忥紝鍙互甯︿笂鍗曚綅锛屽鏋滀笉甯﹀崟浣嶉粯璁x锛屾敮鎸佺殑鍗曚綅鏈夛細rpx锛宲x锛寁w锛寁m,绀轰緥锛歿width:100,height:1100}鎴栬�咃細{width:'100rpx',height:'100rpx'}|
+|canvas2d|Boolean|false| 鏄紑鍚� 2d canvas |
+
+
+
+### cropper Methods
+
+|鏂规硶鍚嶇О|璇存槑|鍙傛暟|
+|:-:|:-:|:-:|
+|crop|瑁佸壀鍥剧墖|寮�濮嬬粯鍒跺苟寮�濮嬭鍓浘鐗囷紝杩斿洖Promise瀵硅薄|
+|init|鍒濆鍖�,鍥剧墖璺緞鍙樺寲鐨勬椂鍊欒嚜鍔ㄨ皟鐢ㄦ鏂规硶锛屽鏋滃寘瑁圭殑dom澶у皬鍙樺寲浜嗭紝浣犻渶瑕佹墜鍔ㄨ皟鐢ㄦ鏂规硶|-|
+|initCropper|閲嶇疆瑁佸壀妗嗗拰鍥剧墖鐨勪綅缃拰澶у皬鍒板垵濮嬬殑浣嶇疆鍜屽ぇ灏弢-|
+|undo|鎾ら攢锛屾渶澶氬彲浠ュ洖閫�10姝-|
+|resume|閲嶅仛|-|
+
+
+### cropper Events
+
+|鏂规硶鍚嶇О|璇存槑|杩斿洖鍊紎
+|:-:|:-:|:-:|
+|change|褰撹鍓鍜屽浘鐗囩殑鐩稿浣嶇疆鍙戠敓鍙樺寲鐨勬椂鍊欒Е鍙戯紝杩斿洖瑁佸壀妗嗕笌鍥剧墖鐨勭浉瀵逛綅缃畖ev={left:number,top:number,width:number,height:number}|
+|loadFail|褰撳浘鐗囧姞杞藉け璐ユ椂瑙﹀彂| - |
+|cropStart|褰撹寮�濮嬫椂瑙﹀彂| - |
+## 甯姪
+鍦ㄤ娇鐢ㄤ腑濡傞亣鍒版棤娉曡В鍐崇殑闂锛岃鎻� [Issues](https://gitee.com/xiaojiang1996/better-uni-cropper/issues) 鎴栬�呭姞鎴� 寰俊:1097122362銆�
diff --git a/h5/uni_modules/qf-image-cropper/changelog.md b/h5/uni_modules/qf-image-cropper/changelog.md
new file mode 100644
index 0000000..0362099
--- /dev/null
+++ b/h5/uni_modules/qf-image-cropper/changelog.md
@@ -0,0 +1,34 @@
+## 2.1.6锛�2023-04-16锛�
+* 淇 缁勪欢浣跨敤 v-show 鎸囦护浼氬鑷撮�夋嫨鍥剧墖鍚庡垵濮嬩綅缃弗閲嶅亸浣嶇殑闂
+## 2.1.5锛�2023-04-16锛�
+* 鏂板 鍏煎APP骞冲彴
+
+## 2.1.4锛�2023-03-13锛�
+* 鏂板 fileType 灞炴�э紝鐢ㄤ簬鎸囧畾鐢熸垚鏂囦欢鐨勭被鍨嬶紝鍙敮鎸� 'jpg' 鎴� 'png'锛岄粯璁や负 'png'
+* 鏂板 delay 灞炴�э紝寰俊灏忕▼搴忓钩鍙颁娇鐢� `Canvas 2D` 缁樺埗鏃舵帶鍒跺浘鐗囦粠缁樺埗鍒扮敓鎴愭墍闇�鏃堕棿
+* 浼樺寲 褰撶敓鎴愬浘鐗囩殑灏哄瀹�/楂樿秴杩� Canvas 2D 鏈�澶ч檺鍒讹紙1365*1365锛夊垯灏嗙敾甯冨昂瀵哥缉鏀惧湪闄愬埗鑼冨洿鍐呯粯鍒跺畬鎴愬悗杈撳嚭鐩爣灏哄
+* 浼樺寲 鏃嬭浆鍥炬爣鎸囩ず鏂瑰悜涓庡疄闄呮棆杞柟鍚戜笉绗�
+
+## 2.1.3锛�2023-02-06锛�
+* 浼樺寲 vue3鏀寔
+
+## 2.1.2锛�2023-02-03锛�
+* 鏂板 navigation 灞炴�э紝H5骞冲彴褰� showAngle 涓� true 鏃讹紝浣跨敤鎻掍欢鐨勯〉闈㈠湪 `page.json` 涓厤缃簡 "navigationStyle": "custom" 鏃讹紝蹇呴』灏嗘鍊艰涓� false 锛屽惁鍒欏洓涓彲鎷変几瑙掔殑瑙﹀彂浣嶇疆浼氭湁鍋忓樊
+* 淇 H5骞冲彴閮ㄥ垎璁惧锛堝凡鐭Phone11浠ヤ笅鏈哄瀷锛夋媿鐓х殑鍥剧墖缂╂斁鏃朵細闂姩鐨勯棶棰�
+
+## 2.1.1锛�2022-12-06锛�
+* 淇 妯睆閫傞厤闂
+
+## 2.1.0锛�2022-12-06锛�
+* 鏂板 鍏煎H5骞冲彴锛屼娇鐢� renderjs 鍝嶅簲鎵嬪娍浜嬩欢
+
+## 2.0.0锛�2022-12-05锛�
+* 閲嶆瀯 鎻掍欢锛屼娇鐢� WXS 鍝嶅簲鎵嬪娍浜嬩欢
+* 鏂板 鍥剧墖缈昏浆
+* 鏂板 鎷変几瑁佸壀妗嗘斁澶у浘鐗�
+* 鏂板 鐩戝惉PC榧犳爣婊氳疆瑙﹀彂缂╂斁
+* 鏂板 鍦嗗舰銆佸渾瑙掔煩褰㈢殑鍥剧墖瑁佸壀
+* 浼樺寲 鍥剧墖缂╂斁锛岀Щ鍔ㄧ浠ュ弻鎸囪Е鎽镐腑蹇冪偣涓虹缉鏀句腑蹇冪偣锛孭C绔互榧犳爣鎵�鍦ㄧ偣涓虹缉鏀句腑蹇冪偣
+* 浼樺寲 瑁佸壀妗嗘牱寮�
+* 浼樺寲 鍥剧墖浣嶇疆鎷栧姩 鏀寔杈圭晫鍥炲脊鏁堟灉锛堟粦鍔ㄦ椂鍙粦鍑鸿竟鐣岋紝閲婃斁鏃跺洖寮瑰埌杈圭晫锛�
+* 浼樺寲 鐢熸垚鍥剧墖浣跨敤鏂扮増 Canvas 2D 鎺ュ彛
diff --git a/h5/uni_modules/qf-image-cropper/components/qf-image-cropper/qf-image-cropper.render.js b/h5/uni_modules/qf-image-cropper/components/qf-image-cropper/qf-image-cropper.render.js
new file mode 100644
index 0000000..7500062
--- /dev/null
+++ b/h5/uni_modules/qf-image-cropper/components/qf-image-cropper/qf-image-cropper.render.js
@@ -0,0 +1,628 @@
+/**
+ * 鍥剧墖缂栬緫鍣�-鎵嬪娍鐩戝惉
+ * 1. 鏀寔缂栬瘧鍒癮pp-vue锛坲ni-app 2.5.5鍙婁互涓婄増鏈級銆丠5涓�
+ */
+/** 鍥剧墖鍋忕Щ閲� */
+var offset = { x: 0, y: 0 };
+/** 鍥剧墖缂╂斁姣斾緥 */
+var scale = 1;
+/** 鍥剧墖鏈�灏忕缉鏀炬瘮渚� */
+var minScale = 1;
+/** 鍥剧墖鏃嬭浆瑙掑害 */
+var rotate = 0;
+/** 瑙︽懜鐐� */
+var touches = [];
+/** 鍥剧墖甯冨眬淇℃伅 */
+var img = {};
+/** 绯荤粺淇℃伅 */
+var sys = {};
+/** 瑁佸壀鍖哄煙甯冨眬淇℃伅 */
+var area = {};
+/** 瑙︽懜琛屼负绫诲瀷 */
+var touchType = '';
+/** 鎿嶄綔瑙掔殑浣嶇疆 */
+var activeAngle = 0;
+/** 瑁佸壀鍖哄煙甯冨眬淇℃伅鍋忕Щ閲� */
+var areaOffset = { left: 0, right: 0, top: 0, bottom: 0 };
+/** 鍏冪礌ID */
+var elIds = {
+	'imageStyles': 'crop-image',
+	'maskStylesList': 'crop-mask-block',
+	'borderStyles': 'crop-border',
+	'circleBoxStyles': 'crop-circle-box',
+	'circleStyles': 'crop-circle',
+	'gridStylesList': 'crop-grid',
+	'angleStylesList': 'crop-angle',
+}
+/** 璁板綍涓婃鍒濆鍖栨椂闂存埑锛屾帓闄PP閲嶅鏇存柊 */
+var timestamp = 0;
+/**
+ * 鏍峰紡瀵硅薄杞瓧绗︿覆
+ * @param {Object} style 鏍峰紡瀵硅薄
+ */
+function styleToString(style) {
+	if(typeof style === 'string') return style;
+	var str = '';
+	for (let k in style) {
+		str += k + ':' + style[k] + ';';
+	}
+	return str;
+}
+/**
+ * 
+ * @param {Object} instance 椤甸潰瀹炰緥瀵硅薄
+ * @param {Object} key 瑕佷慨鏀规牱寮忕殑key
+ * @param {Object|Array} style 鏍峰紡
+ */
+function setStyle(instance, key, style) {
+	// console.log('setStyle', instance, key, JSON.stringify(style))
+	// #ifdef APP-PLUS
+	if(Object.prototype.toString.call(style) === '[object Array]') {
+		for (var i = 0, len = style.length; i < len; i++) {
+			var el = window.document.getElementById(elIds[key] + '-' + (i + 1));
+			el && (el.style = styleToString(style[i]));
+		}
+	} else {
+		var el = window.document.getElementById(elIds[key]);
+		el && (el.style = styleToString(style));
+	}
+	// #endif
+	// #ifdef H5
+	instance[key] = style;
+	// #endif
+}
+/**
+ * 瑙﹀彂椤甸潰瀹炰緥鎸囧畾鏂规硶
+ * @param {Object} instance 椤甸潰瀹炰緥瀵硅薄
+ * @param {Object} name 鏂规硶鍚嶇О
+ * @param {Object} obj 浼犻�掑弬鏁�
+ */
+function callMethod(instance, name, obj) {
+	// #ifdef APP-PLUS
+	instance.callMethod(name, obj);
+	// #endif
+	// #ifdef H5
+	instance[name](obj);
+	// #endif
+}
+/**
+ * 璁$畻涓ょ偣闂磋窛
+ * @param {Object} touches 瑙︽懜鐐逛俊鎭�
+ */
+function getDistanceByTouches(touches) {
+	// 鏍规嵁鍕捐偂瀹氱悊姹備袱鐐归棿璺濈
+	var a = touches[1].pageX - touches[0].pageX;
+	var b = touches[1].pageY - touches[0].pageY;
+	var c = Math.sqrt(Math.pow(a, 2) + Math.pow(b, 2));
+	// 姹備袱鐐归棿鐨勪腑鐐瑰潗鏍�
+	// 1. a銆乥鍙兘涓鸿礋鍊�
+	// 2. 鍦ㄦ眰a銆乥鏃讹紝濡傜敤touches[1]鍑弔ouches[0]锛屽垯姹備腑鐐瑰潗鏍囦篃寰楃敤touches[1]鍑廰/2銆乥/2
+	// 3. 鍚岀悊锛屽湪姹俛銆乥鏃讹紝涔熷彲鐢╰ouches[0]鍑弔ouches[1]锛屽垯姹備腑鐐瑰潗鏍囦篃寰楃敤touches[0]鍑廰/2銆乥/2
+	var x = touches[1].pageX - a / 2;
+	var y = touches[1].pageY - b / 2;
+	return { c, x, y };
+};
+/**
+ * 妫�鏌ヨ竟鐣岋細闄愬埗 x銆亂 鎷栧姩鑼冨洿锛岀姝㈡粦鍑鸿竟鐣�
+ * @param {Object} e 鐐瑰潗鏍�
+ */
+function checkRange(e) {
+	var r = rotate / 90 % 2;
+	if(r === 1) { // 鍥犲浘鐗囧楂樺彲鑳戒笉绛夛紝缈昏浆 90掳 鎴� 270掳 鍚庡浘鐗囧楂橀渶鍙嶇潃璁$畻锛屼笖宸﹀彸鍜屼笂涓嬭竟鐣岃鏍规嵁宸�煎仛鍋忕Щ
+		var o = (img.height - img.width) / 2; // 瀹介珮宸�间竴鍗�
+		return {
+			x: Math.min(Math.max(e.x, -img.height + o + area.width + area.left), area.left + o),
+			y: Math.min(Math.max(e.y, -img.width - o + area.height + area.top), area.top - o)
+		}
+	}
+	return {
+		x: Math.min(Math.max(e.x, -img.width + area.width + area.left), area.left),
+		y: Math.min(Math.max(e.y, -img.height + area.height + area.top), area.top)
+	}
+};
+/**
+ * 鍙樻洿鍥剧墖甯冨眬淇℃伅
+ * @param {Object} e 甯冨眬淇℃伅
+ */
+function changeImageRect(e) {
+	// console.log('changeImageRect', e)
+	offset.x += e.x || 0;
+	offset.y += e.y || 0;
+	if(e.check) { // 妫�鏌ヨ竟鐣�
+		var point = checkRange(offset);
+		if(offset.x !== point.x || offset.y !== point.y) {
+			offset = point;
+		}
+	}
+	
+	// 鍥犻绻佷慨鏀� width/height 浼氶�犳垚澶ч噺鐨勫唴瀛樻秷鑰楋紝鏀逛负scale
+	// e.instance.imageStyles = {
+	// 	width: img.width + 'px',
+	// 	height: img.height + 'px',
+	// 	transform: 'translate(' + (offset.x + ox) + 'px, ' + (offset.y + ox) + 'px) rotate(' + rotate +'deg)'
+	// };
+	var ox = (img.width - img.oldWidth) / 2;
+	var oy = (img.height - img.oldHeight) / 2;
+	// e.instance.imageStyles = {
+	// 	width: img.oldWidth + 'px',
+	// 	height: img.oldHeight + 'px',
+	// 	transform: 'translate(' + (offset.x + ox) + 'px, ' + (offset.y + oy) + 'px) rotate(' + rotate +'deg) scale(' + scale + ')'
+	// };
+	setStyle(e.instance, 'imageStyles', {
+		width: img.oldWidth + 'px',
+		height: img.oldHeight + 'px',
+		transform: 'translate(' + (offset.x + ox) + 'px, ' + (offset.y + oy) + 'px) rotate(' + rotate +'deg) scale(' + scale + ')'
+	});
+	callMethod(e.instance, 'dataChange', {
+		width: img.width,
+		height: img.height,
+		x: offset.x,
+		y: offset.y,
+		rotate: rotate
+	});
+};
+/**
+ * 鍙樻洿瑁佸壀鍖哄煙甯冨眬淇℃伅
+ * @param {Object} e 甯冨眬淇℃伅
+ */
+function changeAreaRect(e) {
+	// console.log('changeAreaRect', e)
+	// 鍙樻洿钂欑増鏍峰紡
+	setStyle(e.instance, 'maskStylesList', [
+		{
+			left: 0,
+			width: (area.left + areaOffset.left) + 'px',
+			top: 0,
+			bottom: 0,
+		},
+		{
+			left: (area.right + areaOffset.right) + 'px',
+			right: 0,
+			top: 0,
+			bottom: 0,
+		},
+		{
+			left: (area.left + areaOffset.left) + 'px',
+			width: (area.width + areaOffset.right - areaOffset.left) + 'px',
+			top: 0,
+			height: (area.top + areaOffset.top) + 'px',
+		},
+		{
+			left: (area.left + areaOffset.left) + 'px',
+			width: (area.width + areaOffset.right - areaOffset.left) + 'px',
+			top: (area.bottom + areaOffset.bottom) + 'px',
+			// height: (area.top - areaOffset.bottom + sys.offsetBottom) + 'px',
+			bottom: 0,
+		}
+	]);
+	// 鍙樻洿杈规鏍峰紡
+	if(area.showBorder) {
+		setStyle(e.instance, 'borderStyles', {
+			left: (area.left + areaOffset.left) + 'px',
+			top: (area.top + areaOffset.top) + 'px',
+			width: (area.width + areaOffset.right - areaOffset.left) + 'px',
+			height: (area.height + areaOffset.bottom - areaOffset.top) + 'px',
+		});
+	}
+	
+	// 鍙樻洿鍙傝�冪嚎鏍峰紡
+	if(area.showGrid) {
+		setStyle(e.instance, 'gridStylesList', [
+			{
+				'border-width': '1px 0 0 0',
+				left: (area.left + areaOffset.left) + 'px',
+				right: (area.right + areaOffset.right) + 'px',
+				top: (area.top + areaOffset.top + (area.height + areaOffset.bottom - areaOffset.top) / 3 - 0.5) + 'px',
+				width: (area.width + areaOffset.right - areaOffset.left) + 'px'
+			},
+			{
+				'border-width': '1px 0 0 0',
+				left: (area.left + areaOffset.left) + 'px',
+				right: (area.right + areaOffset.right) + 'px',
+				top: (area.top + areaOffset.top + (area.height + areaOffset.bottom - areaOffset.top) * 2 / 3 - 0.5) + 'px',
+				width: (area.width + areaOffset.right - areaOffset.left) + 'px'
+			},
+			{
+				'border-width': '0 1px 0 0',
+				top: (area.top + areaOffset.top) + 'px',
+				bottom: (area.bottom + areaOffset.bottom) + 'px',
+				left: (area.left + areaOffset.left + (area.width + areaOffset.right - areaOffset.left) / 3 - 0.5) + 'px',
+				height: (area.height + areaOffset.bottom - areaOffset.top) + 'px'
+			},
+			{
+				'border-width': '0 1px 0 0',
+				top: (area.top + areaOffset.top) + 'px',
+				bottom: (area.bottom + areaOffset.bottom) + 'px',
+				left: (area.left + areaOffset.left + (area.width + areaOffset.right - areaOffset.left) * 2 / 3 - 0.5) + 'px',
+				height: (area.height + areaOffset.bottom - areaOffset.top) + 'px'
+			}
+		]);
+	}
+	
+	// 鍙樻洿鍥涗釜浼哥缉瑙掓牱寮�
+	if(area.showAngle) {
+		setStyle(e.instance, 'angleStylesList', [
+			{
+				'border-width': area.angleBorderWidth + 'px 0 0 ' + area.angleBorderWidth + 'px',
+				left: (area.left + areaOffset.left - area.angleBorderWidth) + 'px',
+				top: (area.top + areaOffset.top - area.angleBorderWidth) + 'px',
+			},
+			{
+				'border-width': area.angleBorderWidth + 'px ' + area.angleBorderWidth + 'px 0 0',
+				left: (area.right + areaOffset.right - area.angleSize) + 'px',
+				top: (area.top + areaOffset.top - area.angleBorderWidth) + 'px',
+			},
+			{
+				'border-width': '0 0 ' + area.angleBorderWidth + 'px ' + area.angleBorderWidth + 'px',
+				left: (area.left + areaOffset.left - area.angleBorderWidth) + 'px',
+				top: (area.bottom + areaOffset.bottom - area.angleSize) + 'px',
+			},
+			{
+				'border-width': '0 ' + area.angleBorderWidth + 'px ' + area.angleBorderWidth + 'px 0',
+				left: (area.right + areaOffset.right - area.angleSize) + 'px',
+				top: (area.bottom + areaOffset.bottom - area.angleSize) + 'px',
+			}
+		]);
+	}
+	
+	// 鍙樻洿鍦嗚鏍峰紡
+	if(area.radius > 0) {
+		var radius = area.radius;
+		if(area.width === area.height && area.radius >= area.width / 2) { // 鍦嗗舰
+			radius = (area.width / 2);
+		} else { // 鍦嗚鐭╁舰
+			if(area.width !== area.height) { // 闄愬埗鍦嗚鍗婂緞涓嶈兘瓒呰繃鐭竟鐨勪竴鍗�
+				radius = Math.min(area.width / 2, area.height / 2, radius);
+			}
+		}
+		setStyle(e.instance, 'circleBoxStyles', {
+			left: (area.left + areaOffset.left) + 'px',
+			top: (area.top + areaOffset.top) + 'px',
+			width: (area.width + areaOffset.right - areaOffset.left) + 'px',
+			height: (area.height + areaOffset.bottom - areaOffset.top) + 'px'
+		});
+		setStyle(e.instance, 'circleStyles', {
+			'box-shadow': '0 0 0 ' + Math.max(area.width, area.height) + 'px rgba(51, 51, 51, 0.8)',
+			'border-radius': radius + 'px'
+		});
+	}
+};
+/**
+ * 缂╂斁鍥剧墖
+ * @param {Object} e 甯冨眬淇℃伅
+ */
+function scaleImage(e) {
+	// console.log('scaleImage', e)
+	var last = scale;
+	scale = Math.min(Math.max(e.scale + scale, minScale), img.maxScale);
+	if(last !== scale) {
+		img.width = img.oldWidth * scale;
+		img.height = img.oldHeight * scale;
+		// 鍙傝�冮棶棰橈細鏈変竴涓暱4000px銆佸4000px鐨勫洓鏂瑰舰ABCD锛孉鐐圭殑鍧愭爣鍥哄畾鍦�(-2000,-2000)锛�
+		// 			璇ュ洓杈瑰舰涓婃湁涓�涓偣E锛屽潗鏍囦负(-100,-300)锛屽皢璇ュ洓鏂瑰舰澶嶅埗涓�浠藉苟缂╁皬鍒�90%鍚庯紝
+		// 			鏂板洓杈瑰舰鐨凙鐐瑰潗鏍囦负澶氬皯鏃跺彲浣挎柊鍥涜竟褰㈢殑E鐐逛笌鍘熷洓杈瑰舰鐨凟鐐归噸鍚堬紵
+		// 棰勬湡鏁堟灉锛氫粠鍥句腑閫夊彇鏌愮偣锛堝弬鐓х墿锛変负涓績鐐硅繘琛岀缉鏀撅紝缂╂斁鏃舵棤璁哄浘鍍忔�庝箞鍙樺寲锛岃鐐逛綅缃缁堝浐瀹氫笉鍙�
+		// 璁$畻鏂规硶锛氫互鐩稿悓璧风偣鍏堣绠楃缉鏀惧墠鍚庝袱鐐归棿鐨勮窛绂伙紝鍐嶅姞涓婂師鍥惧儚鍋忕Щ閲忓嵆鍙�
+		e.x = (e.x - offset.x) * (1 - scale / last);
+		e.y = (e.y - offset.y) * (1 - scale / last);
+		changeImageRect(e);
+		return true;
+	}
+	return false;
+};
+/**
+ * 鑾峰彇瑙︽懜鐐瑰湪鍝釜瑙�
+ * @param {number} x 瑙︽懜鐐箈杞村潗鏍�
+ * @param {number} y 瑙︽懜鐐箉杞村潗鏍�
+ * @return {number} 瑙掔殑浣嶇疆锛�0=鏃狅紱1=宸︿笂锛�2=鍙充笂锛�3=宸︿笅锛�4=鍙充笅锛�
+ */
+function getToucheAngle(x, y) {
+	// console.log('getToucheAngle', x, y, JSON.stringify(area))
+	var o = area.angleBorderWidth; // 闇�鎵╁ぇ瑙﹀彂鑼冨洿鍒欐妸 o 鍊煎姞澶у嵆鍙�
+	var oy = sys.navigation ? 0 : sys.windowTop;
+	if(y >= area.top - o + oy && y <= area.top + area.angleSize + o + oy) {
+		if(x >= area.left - o && x <= area.left + area.angleSize + o) {
+			return 1; // 宸︿笂瑙�
+		} else if(x >= area.right - area.angleSize - o && x <= area.right + o) {
+			return 2; // 鍙充笂瑙�
+		}
+	} else if(y >= area.bottom - area.angleSize - o + oy && y <= area.bottom + o + oy) {
+		if(x >= area.left - o && x <= area.left + area.angleSize + o) {
+			return 3; // 宸︿笅瑙�
+		} else if(x >= area.right - area.angleSize - o && x <= area.right + o) {
+			return 4; // 鍙充笅瑙�
+		}
+	}
+	return 0; // 鏃犺Е鎽稿埌瑙�
+};
+/**
+ * 閲嶇疆鏁版嵁
+ */
+function resetData() {
+	offset = { x: 0, y: 0 };
+	scale = 1;
+	minScale = 1;
+	rotate = 0;
+};
+function getTouchs(touches) {
+	var result = [];
+	var len = touches ? touches.length : 0
+	for (var i = 0; i < len; i++) {
+		result[i] = {
+			pageX: touches[i].pageX,
+			// h5鏃犳爣棰樻爮鏃讹紝绐楀彛椤堕儴璺濈浠嶄负鏍囬鏍忛珮搴︼紝涓旇Е鎽哥偣y杞村潗鏍囪繕鏄湁鏍囬鏍忕殑鍊硷紝鍗冲噺鍘绘爣棰樻爮楂樺害鐨勫��
+			pageY: touches[i].pageY + sys.windowTop
+		};
+	}
+	return result;
+};
+export default {
+	data() {
+		return {
+			imageStyles: {},
+			maskStylesList: [{}, {}, {}, {}],
+			borderStyles: {},
+			gridStylesList: [{}, {}, {}, {}],
+			angleStylesList: [{}, {}, {}, {}],
+			circleBoxStyles: {},
+			circleStyles: {}
+		}
+	},
+	created() {
+		// 鐩戝惉 PC 绔紶鏍囨粴杞�
+		// #ifdef H5
+		window.addEventListener('mousewheel', (e) => {
+			var touchs = getTouchs([e])
+			img.src && scaleImage({
+				instance: this.getInstance(),
+				check: true,
+				// 榧犳爣鍚戜笂婊氬姩鏃讹紝deltaY 鍥哄畾 -100锛岄紶鏍囧悜涓嬫粴鍔ㄦ椂锛宒eltaY 鍥哄畾 100
+				scale: e.deltaY > 0 ? -0.05 : 0.05,
+				x: touchs[0].pageX,
+				y: touchs[0].pageY
+			});
+		});
+		// #endif
+	},
+	methods: {
+		getInstance() {
+			// #ifdef APP-PLUS
+			return this.$ownerInstance;
+			// #endif
+			// #ifdef H5
+			return this;
+			// #endif
+		},
+		/**
+		 * 鍒濆鍖栵細瑙傚療鏁版嵁鍙樻洿
+		 * @param {Object} newVal 鏂版暟鎹�
+		 * @param {Object} oldVal 鏃ф暟鎹�
+		 * @param {Object} o 缁勪欢瀹炰緥瀵硅薄
+		 */
+		initObserver: function(newVal, oldVal, o, i) {
+			console.log('initObserver', newVal, oldVal, o, i)
+			if(newVal && (!img.src || timestamp !== newVal.timestamp)) {
+				timestamp = newVal.timestamp;
+				img = newVal.img;
+				sys = newVal.sys;
+				area = newVal.area;
+				resetData();
+				img.src && changeImageRect({
+					instance: this.getInstance(),
+					x: (sys.windowWidth - img.width) / 2,
+					y: (sys.windowHeight + sys.windowTop - sys.offsetBottom - img.height) / 2
+				});
+				changeAreaRect({
+					instance: this.getInstance()
+				});
+			}
+		},
+		/**
+		 * 榧犳爣婊氳疆婊氬姩
+		 * @param {Object} e 浜嬩欢瀵硅薄
+		 * @param {Object} o 缁勪欢瀹炰緥瀵硅薄
+		 */
+		mousewheel: function(e, o) {
+			// h5骞冲彴 wheel 浜嬩欢鏃犳硶鍒ゆ柇婊氳疆婊戝姩鏂瑰悜锛岄渶浣跨敤 mousewheel 
+		},
+		/**
+		 * 瑙︽懜寮�濮�
+		 * @param {Object} e 浜嬩欢瀵硅薄
+		 * @param {Object} o 缁勪欢瀹炰緥瀵硅薄
+		 */
+		touchstart: function(e, o) {
+			if(!img.src) return;
+			touches = getTouchs(e.touches);
+			activeAngle = area.showAngle ? getToucheAngle(touches[0].pageX, touches[0].pageY) : 0;
+			if(touches.length === 1 && activeAngle !== 0) {
+				touchType = 'stretch'; // 浼哥缉瑁佸壀鍖哄煙
+			} else {
+				touchType = '';
+			}
+			// console.log('touchstart', e, activeAngle)
+		},
+		/**
+		 * 瑙︽懜绉诲姩
+		 * @param {Object} e 浜嬩欢瀵硅薄
+		 * @param {Object} o 缁勪欢瀹炰緥瀵硅薄
+		 */
+		touchmove: function(e, o) {
+			if(!img.src) return;
+			// console.log('touchmove', e, o)
+			e.touches = getTouchs(e.touches);
+			if(touchType === 'stretch') { // 瑙︽懜鍥涗釜瑙掕繘琛屾媺浼�
+				var point = e.touches[0];
+				var start = touches[0];
+				var x = point.pageX - start.pageX;
+				var y = point.pageY - start.pageY;
+				if(x !== 0 || y !== 0) {
+					var maxX = area.width * (1 - area.minScale);
+					var maxY = area.height * (1 - area.minScale);
+					// console.log(x, y, maxX, maxY)
+					touches[0] = point;
+					switch(activeAngle) {
+						case 1: // 宸︿笂瑙�
+							x += areaOffset.left;
+							y += areaOffset.top;
+							if(x >= 0 && y >= 0) { // 鏈夋晥婊戝姩
+								if(x > y) { // 浠杞存粦鍔ㄨ窛绂讳负缂╂斁鍩哄噯
+									if(x > maxX) x = maxX;
+									y = x * area.height / area.width;
+								} else { // 浠杞存粦鍔ㄨ窛绂讳负缂╂斁鍩哄噯
+									if(y > maxY) y = maxY;
+									x = y * area.width / area.height;
+								}
+								areaOffset.left = x;
+								areaOffset.top = y;
+							}
+							break;
+						case 2: // 鍙充笂瑙�
+							x += areaOffset.right;
+							y += areaOffset.top;
+							if(x <= 0 && y >= 0) { // 鏈夋晥婊戝姩
+								if(-x > y) { // 浠杞存粦鍔ㄨ窛绂讳负缂╂斁鍩哄噯
+									if(-x > maxX) x = -maxX;
+									y = -x * area.height / area.width;
+								} else { // 浠杞存粦鍔ㄨ窛绂讳负缂╂斁鍩哄噯
+									if(y > maxY) y = maxY;
+									x = -y * area.width / area.height;
+								}
+								areaOffset.right = x;
+								areaOffset.top = y;
+							}
+							break;
+						case 3: // 宸︿笅瑙�
+							x += areaOffset.left;
+							y += areaOffset.bottom;
+							if(x >= 0 && y <= 0) { // 鏈夋晥婊戝姩
+								if(x > -y) { // 浠杞存粦鍔ㄨ窛绂讳负缂╂斁鍩哄噯
+									if(x > maxX) x = maxX;
+									y = -x * area.height / area.width;
+								} else { // 浠杞存粦鍔ㄨ窛绂讳负缂╂斁鍩哄噯
+									if(-y > maxY) y = -maxY;
+									x = -y * area.width / area.height;
+								}
+								areaOffset.left = x;
+								areaOffset.bottom = y;
+							}
+							break;
+						case 4: // 鍙充笅瑙�
+							x += areaOffset.right;
+							y += areaOffset.bottom;
+							if(x <= 0 && y <= 0) { // 鏈夋晥婊戝姩
+								if(-x > -y) { // 浠杞存粦鍔ㄨ窛绂讳负缂╂斁鍩哄噯
+									if(-x > maxX) x = -maxX;
+									y = x * area.height / area.width;
+								} else { // 浠杞存粦鍔ㄨ窛绂讳负缂╂斁鍩哄噯
+									if(-y > maxY) y = -maxY;
+									x = y * area.width / area.height;
+								}
+								areaOffset.right = x;
+								areaOffset.bottom = y;
+							}
+							break;
+					}
+					// console.log(x, y, JSON.stringify(areaOffset))
+					changeAreaRect({
+						instance: this.getInstance(),
+					});
+					// this.draw();
+				}
+			} else if (e.touches.length == 2) { // 鍙岀偣瑙︽懜缂╂斁
+				var start = getDistanceByTouches(touches);
+				var end = getDistanceByTouches(e.touches);
+				scaleImage({
+					instance: this.getInstance(),
+					check: !area.bounce,
+					scale: (end.c - start.c) / 100,
+					x: end.x,
+					y: end.y
+				});
+				touchType = 'scale';
+			} else if(touchType === 'scale') {// 浠庡弻鐐硅Е鎽稿彉鎴愬崟鐐硅Е鎽� / 浠庣缉鏀惧彉鎴愭嫋鍔�
+				touchType = 'move';
+			} else {
+				changeImageRect({
+					instance: this.getInstance(),
+					check: !area.bounce,
+					x: e.touches[0].pageX - touches[0].pageX,
+					y: e.touches[0].pageY - touches[0].pageY
+				});
+				touchType = 'move';
+			}
+			touches = e.touches;
+		},
+		/**
+		 * 瑙︽懜缁撴潫
+		 * @param {Object} e 浜嬩欢瀵硅薄
+		 * @param {Object} o 缁勪欢瀹炰緥瀵硅薄
+		 */
+		touchend: function(e, o) {
+			if(!img.src) return;
+			if(touchType === 'stretch') { // 鎷変几瑁佸壀鍖哄煙鐨勫洓涓缂╂斁
+				// 瑁佸壀鍖哄煙瀹藉害琚缉鏀惧埌澶氬皯
+				var left = areaOffset.left;
+				var right = areaOffset.right;
+				var top = areaOffset.top;
+				var bottom = areaOffset.bottom;
+				var w = area.width + right - left;
+				var h = area.height + bottom - top;
+				// 鍥惧儚鏀惧ぇ鍊嶆暟
+				var p = scale * (area.width / w) - scale;
+				// 澶嶅師瑁佸壀鍖哄煙
+				areaOffset = { left: 0, right: 0, top: 0, bottom: 0 };
+				changeAreaRect({
+					instance: this.getInstance(),
+				});
+				scaleImage({
+					instance: this.getInstance(),
+					scale: p,
+					x: area.left + left + (1 === activeAngle || 3 === activeAngle ? w : 0),
+					y: area.top + top + (1 === activeAngle || 2 === activeAngle ? h : 0)
+				});
+			} else if (area.bounce) { // 妫�鏌ヨ竟鐣屽苟鐭锛屽疄鐜版嫋鍔ㄥ埌杈圭晫鏃舵湁鍥炲脊鏁堟灉
+				changeImageRect({
+					instance: this.getInstance(),
+					check: true
+				});
+			}
+		},
+		/**
+		 * 椤烘椂閽堢炕杞浘鐗�90掳
+		 * @param {Object} e 浜嬩欢瀵硅薄
+		 * @param {Object} o 缁勪欢瀹炰緥瀵硅薄
+		 */
+		rotateImage: function(e, o) {
+			rotate = (rotate + 90) % 360;
+			
+			// 鍥犲浘鐗囧楂樺彲鑳戒笉绛夛紝缈昏浆鍚庡浘鐗囧楂橀渶瓒冲濉弧瑁佸壀鍖哄煙
+			var r = rotate / 90 % 2;
+			minScale = 1;
+			if(img.width < area.height) {
+				minScale = area.height / img.oldWidth;
+			} else if(img.height < area.width) {
+				minScale = (area.width / img.oldHeight)
+			}
+			if(minScale !== 1) {
+				scaleImage({
+					instance: this.getInstance(),
+					scale: minScale - scale,
+					x: sys.windowWidth / 2,
+					y: (sys.windowHeight - sys.offsetBottom) / 2
+				});
+			}
+			
+			// 鐢变簬鎷栧姩鐢诲竷鍚庝細瀵艰嚧鍥剧墖浣嶇疆鍋忕Щ锛岀炕杞椂鐨勬棆杞腑蹇冪偣闇�鏄浘鐗囧尯鍩�+鍋忕Щ鍖哄煙鐨勪腑蹇冪偣
+			// 缈昏浆x杞翠腑蹇冪偣 = (瓒呭嚭瑁佸壀鍖哄煙鍙充晶鐨勫浘鐗囧搴� - 瓒呭嚭瑁佸壀鍖哄煙宸︿晶鐨勫浘鐗囧搴�) / 2
+			// 缈昏浆y杞翠腑蹇冪偣 = (瓒呭嚭瑁佸壀鍖哄煙涓嬫柟鐨勫浘鐗囧搴� - 瓒呭嚭瑁佸壀鍖哄煙涓婃柟鐨勫浘鐗囧搴�) / 2
+			var ox = ((offset.x + img.width - area.right) - (area.left - offset.x)) / 2;
+			var oy = ((offset.y + img.height - area.bottom) - (area.top - offset.y)) / 2;
+			changeImageRect({
+				instance: this.getInstance(),
+				check: true,
+				x: -ox - oy,
+				y: -oy + ox
+			});
+		}
+	}
+}
\ No newline at end of file
diff --git a/h5/uni_modules/qf-image-cropper/components/qf-image-cropper/qf-image-cropper.vue b/h5/uni_modules/qf-image-cropper/components/qf-image-cropper/qf-image-cropper.vue
new file mode 100644
index 0000000..d70ec32
--- /dev/null
+++ b/h5/uni_modules/qf-image-cropper/components/qf-image-cropper/qf-image-cropper.vue
@@ -0,0 +1,692 @@
+<template>
+	<view class="image-cropper" @wheel="cropper.mousewheel" v-if="show">
+		<canvas v-if="use2d" type="2d" id="imgCanvas" class="img-canvas" :style="{
+			width: `${canvansWidth}px`,
+			height: `${canvansHeight}px`
+		}"></canvas>
+		<canvas v-else id="imgCanvas" canvas-id="imgCanvas" class="img-canvas" :style="{
+			width: `${canvansWidth}px`,
+			height: `${canvansHeight}px`
+		}"></canvas>
+		<view class="pic-preview" :change:init="cropper.initObserver" :init="initData" @touchstart="cropper.touchstart" @touchmove="cropper.touchmove" @touchend="cropper.touchend">
+			<image v-if="imgSrc" id="crop-image" class="crop-image" :style="cropper.imageStyles" :src="imgSrc" webp></image>
+			<view v-for="(item, index) in maskList" :key="item.id" :id="item.id" class="crop-mask-block" :style="cropper.maskStylesList[index]"></view>
+			<view v-if="showBorder" id="crop-border" class="crop-border" :style="cropper.borderStyles"></view>
+			<view v-if="radius > 0" id="crop-circle-box" class="crop-circle-box" :style="cropper.circleBoxStyles">
+				<view class="crop-circle" id="crop-circle" :style="cropper.circleStyles"></view>
+			</view>
+			<block v-if="showGrid">
+				<view v-for="(item, index) in gridList" :key="item.id" :id="item.id" class="crop-grid" :style="cropper.gridStylesList[index]"></view>
+			</block>
+			<block v-if="showAngle">
+				<view v-for="(item, index) in angleList" :key="item.id" :id="item.id" class="crop-angle" :style="cropper.angleStylesList[index]">
+					<view :style="[{
+						width: `${angleSize}px`,
+						height: `${angleSize}px`
+					}]"></view>
+				</view>
+			</block>
+		</view>
+		<view class="fixed-bottom safe-area-inset-bottom">
+			<view v-if="rotatable && !!imgSrc" class="rotate-icon" @click="cropper.rotateImage"></view>
+			<view v-if="!choosable" class="choose-btn" @click="cropClick">纭畾</view>
+			<block v-else-if="!!imgSrc">
+				<view class="rechoose" @click="chooseImage">閲嶉��</view>
+				<button class="button" size="mini" @click="cropClick">纭畾</button>
+			</block>
+			<view v-else class="choose-btn" @click="chooseImage">褰曞叆浜鸿劯</view>
+		</view>
+	</view>
+</template>
+
+<!-- #ifdef APP-VUE || H5 -->
+<script module="cropper" lang="renderjs">
+	import cropper from './qf-image-cropper.render.js';
+	export default {
+		mixins: [ cropper ]
+	}
+</script>
+<!-- #endif -->
+<!-- #ifdef MP-WEIXIN || MP-QQ -->
+<script module="cropper" lang="wxs" src="./qf-image-cropper.wxs"></script>
+<!-- #endif -->
+<script>
+	/** 瑁佸壀鍖哄煙鏈�澶у楂樻墍鍗犲睆骞曞搴︾櫨鍒嗘瘮 */
+	const AREA_SIZE = 75;
+	/** 鍥剧墖榛樿瀹介珮 */
+	const IMG_SIZE = 300;
+ 
+	export default {
+		name:"qf-image-cropper",
+		// #ifdef MP-WEIXIN
+		options: {
+			// 琛ㄧず鍚敤鏍峰紡闅旂锛屽湪鑷畾涔夌粍浠跺唴澶栵紝浣跨敤 class 鎸囧畾鐨勬牱寮忓皢涓嶄細鐩镐簰褰卞搷
+			styleIsolation: "isolated"
+		},
+		// #endif
+		props: {
+			/** 鍥剧墖璧勬簮鍦板潃 */
+			src: {
+				type: String,
+				default: ''
+			},
+			/** 瑁佸壀瀹藉害锛屾湁浜涘钩鍙版垨璁惧瀵逛簬canvas鐨勫昂瀵告湁闄愬埗锛岃繃澶у彲鑳戒細瀵艰嚧鏃犳硶姝e父缁樺埗 */
+			width: {
+				type: Number,
+				default: IMG_SIZE
+			},
+			/** 瑁佸壀楂樺害锛屾湁浜涘钩鍙版垨璁惧瀵逛簬canvas鐨勫昂瀵告湁闄愬埗锛岃繃澶у彲鑳戒細瀵艰嚧鏃犳硶姝e父缁樺埗 */
+			height: {
+				type: Number,
+				default: IMG_SIZE
+			},
+			/** 鏄惁缁樺埗瑁佸壀鍖哄煙杈规 */
+			showBorder: {
+				type: Boolean,
+				default: true
+			},
+			/** 鏄惁缁樺埗瑁佸壀鍖哄煙缃戞牸鍙傝�冪嚎 */
+			showGrid: {
+				type: Boolean,
+				default: true
+			},
+			/** 鏄惁灞曠ず鍥涗釜鏀寔浼哥缉鐨勮 */
+			showAngle: {
+				type: Boolean,
+				default: true
+			},
+			/** 瑁佸壀鍖哄煙鏈�灏忕缉鏀惧�嶆暟 */
+			areaScale: {
+				type: Number,
+				default: 0.3
+			},
+			/** 鍥剧墖鏈�澶х缉鏀惧�嶆暟 */
+			maxScale: {
+				type: Number,
+				default: 5
+			},
+			/** 鏄惁鏈夊洖寮规晥鏋滐細鎷栧姩鏃跺彲浠ユ嫋鍑鸿竟鐣岋紝閲婃斁鏃朵細寮瑰洖杈圭晫 */
+			bounce: {
+				type: Boolean,
+				default: true
+			},
+			/** 鏄惁鏀寔缈昏浆 */
+			rotatable: {
+				type: Boolean,
+				default: true
+			},
+			/** 鏄惁鏀寔浠庢湰鍦伴�夋嫨绱犳潗 */
+			choosable: {
+				type: Boolean,
+				default: true
+			},
+			/** 鍥涗釜瑙掑昂瀵革紝鍗曚綅px */
+			angleSize: {
+				type: Number,
+				default: 20
+			},
+			/** 鍥涗釜瑙掕竟妗嗗搴︼紝鍗曚綅px */
+			angleBorderWidth: {
+				type: Number,
+				default: 2
+			},
+			/** 瑁佸壀鍥剧墖鍦嗚鍗婂緞锛屽崟浣峱x */
+			radius: {
+				type: Number,
+				default: 0
+			},
+			/** 鐢熸垚鏂囦欢鐨勭被鍨嬶紝鍙敮鎸� 'jpg' 鎴� 'png'銆傞粯璁や负 'png' */
+			fileType: {
+				type: String,
+				default: 'png'
+			},
+			/**
+			 * 鍥剧墖浠庣粯鍒跺埌鐢熸垚鎵�闇�鏃堕棿锛屽崟浣峬s
+			 * 寰俊灏忕▼搴忓钩鍙颁娇鐢� `Canvas 2D` 缁樺埗鏃舵湁鏁�
+			 * 濡傜粯鍒跺ぇ鍥炬垨鍑虹幇瑁佸壀鍥剧墖绌虹櫧绛夋儏鍐靛簲閫傚綋璋冨ぇ璇ュ�硷紝鍥� `Canvas 2d` 閲囩敤鍚屾缁樺埗锛岄渶鑷繁鎶婃帶缁樺埗瀹屾垚鏃堕棿
+			 */
+			delay: {
+				type: Number,
+				default: 1000
+			},
+			// #ifdef H5
+			/** 
+			 * 椤甸潰鏄惁鏄師鐢熸爣棰樻爮
+			 * H5骞冲彴褰� showAngle 涓� true 鏃讹紝浣跨敤鎻掍欢鐨勯〉闈㈠湪 `page.json` 涓厤缃簡 "navigationStyle": "custom" 鏃讹紝蹇呴』灏嗘鍊艰涓� false 锛屽惁鍒欏洓涓彲鎷変几瑙掔殑瑙﹀彂浣嶇疆浼氭湁鍋忓樊銆�
+			 * 娉細鍥燞5骞冲彴鐨勭獥鍙i珮搴︽槸鍖呭惈鏍囬鏍忕殑锛岃�屽睆骞曡Е鎽哥偣鐨勫潗鏍囨槸涓嶅寘鍚殑
+			 */
+			navigation: {
+				type: Boolean,
+				default: true
+			}
+			// #endif
+		},
+		emits: ["crop"],
+		data() {
+			return {
+				// 鐢ㄤ笉鍚� id 浣� v-for key 涓嶉噸澶�
+				maskList: [
+					{ id: 'crop-mask-block-1' },
+					{ id: 'crop-mask-block-2' },
+					{ id: 'crop-mask-block-3' },
+					{ id: 'crop-mask-block-4' },
+				],
+				gridList: [
+					{ id: 'crop-grid-1' },
+					{ id: 'crop-grid-2' },
+					{ id: 'crop-grid-3' },
+					{ id: 'crop-grid-4' },
+				],
+				angleList: [
+					{ id: 'crop-angle-1' },
+					{ id: 'crop-angle-2' },
+					{ id: 'crop-angle-3' },
+					{ id: 'crop-angle-4' },
+				],
+				/** 鏈湴缂撳瓨鐨勫浘鐗囪矾寰� */
+				imgSrc: '',
+				/** 鍥剧墖鐨勮鍓搴� */
+				imgWidth: IMG_SIZE,
+				/** 鍥剧墖鐨勮鍓珮搴� */
+				imgHeight: IMG_SIZE,
+				/** 瑁佸壀鍖哄煙鏈�澶у搴︽墍鍗犲睆骞曞搴︾櫨鍒嗘瘮 */
+				widthPercent: AREA_SIZE,
+				/** 瑁佸壀鍖哄煙鏈�澶ч珮搴︽墍鍗犲睆骞曞搴︾櫨鍒嗘瘮 */
+				heightPercent: AREA_SIZE,
+				/** 瑁佸壀鍖哄煙甯冨眬淇℃伅 */
+				area: {},
+				/** 鏈缂╂斁杩囩殑鍥剧墖瀹� */
+				oldWidth: 0,
+				/** 鏈缂╂斁杩囩殑鍥剧墖楂� */
+				oldHeight: 0,
+				/** 绯荤粺淇℃伅 */
+				sys: uni.getSystemInfoSync(),
+				scaleWidth: 0,
+				scaleHeight: 0,
+				rotate: 0,
+				offsetX: 0,
+				offsetY: 0,
+				use2d: false,
+				canvansWidth: 0,
+				canvansHeight: 0,
+				show: false
+				// imageStyles: {},
+				// maskStylesList: [{}, {}, {}, {}],
+				// borderStyles: {},
+				// gridStylesList: [{}, {}, {}, {}],
+				// angleStylesList: [{}, {}, {}, {}],
+				// circleBoxStyles: {},
+				// circleStyles: {},
+			}
+		},
+		computed: {
+			initData() {
+				// console.log('initData')
+				return {
+					timestamp: new Date().getTime(),
+					area: {
+						...this.area,
+						bounce: this.bounce,
+						showBorder: this.showBorder,
+						showGrid: this.showGrid,
+						showAngle: this.showAngle,
+						angleSize: this.angleSize,
+						angleBorderWidth: this.angleBorderWidth,
+						minScale: this.areaScale,
+						widthPercent: this.widthPercent,
+						heightPercent: this.heightPercent,
+						radius: this.radius
+					},
+					sys: this.sys,
+					img: {
+						maxScale: this.maxScale,
+						src: this.imgSrc,
+						width: this.oldWidth,
+						height: this.oldHeight,
+						oldWidth: this.oldWidth,
+						oldHeight: this.oldHeight,
+					}
+				}
+			},
+			imgProps() {
+				return {
+					width: this.width,
+					height: this.height,
+					src: this.src,
+				}
+			}
+		},
+		watch: {
+			imgProps: {
+				handler(val) {
+					// console.log('imgProps', val)
+					// 鑷畾涔夎鍓昂锛岀ず渚嬪涓嬶細
+					this.imgWidth = Number(val.width) || IMG_SIZE;
+					this.imgHeight = Number(val.height) || IMG_SIZE;
+					let use2d = true;
+					// #ifndef MP-WEIXIN
+					use2d = false;
+					// #endif
+					// if(use2d && (this.imgWidth > 1365 || this.imgHeight > 1365)) {
+					// 	use2d = false;
+					// }
+					let canvansWidth = this.imgWidth;
+					let canvansHeight = this.imgHeight;
+					let size = Math.max(canvansWidth, canvansHeight)
+					let scalc = 1;
+					if(size > 1365) {
+						scalc = 1365 / size;
+					}
+					this.canvansWidth = canvansWidth * scalc;
+					this.canvansHeight = canvansHeight * scalc;
+					this.use2d = use2d;
+					this.initArea();
+					val.src && this.initImage(val.src);
+				},
+				immediate: true
+			},
+		},
+		methods: {
+			open() {
+				this.show = true
+			},
+			close() {
+				this.show = false
+			},
+			/** 鎻愪緵缁檞xs璋冪敤锛岀敤鏉ユ帴鏀跺浘鐗囧彉鏇存暟鎹� */
+			dataChange(e) {
+				// console.log('dataChange', e)
+				this.scaleWidth = e.width;
+				this.scaleHeight = e.height;
+				this.rotate = e.rotate;
+				this.offsetX = e.x;
+				this.offsetY = e.y;
+			},
+			/** 鍒濆鍖栬鍓尯鍩熷竷灞�淇℃伅 */
+			initArea() {
+				// 搴曢儴鎿嶄綔鏍忛珮搴� = 搴曢儴搴曢儴鎿嶄綔鏍忓唴瀹归珮搴� + 璁惧搴曢儴瀹夊叏鍖哄煙楂樺害
+				this.sys.offsetBottom = uni.upx2px(100) + this.sys.safeAreaInsets.bottom;
+				// #ifndef H5
+				this.sys.windowTop = 0;
+				this.sys.navigation = true;
+				// #endif
+				// #ifdef H5
+				// h5骞冲彴鐨勭獥鍙i珮搴︽槸鍖呭惈鏍囬鏍忕殑
+				this.sys.windowTop = this.sys.windowTop || 44;
+				this.sys.navigation = this.navigation;
+				// #endif
+				let wp = this.widthPercent;
+				let hp = this.heightPercent;
+				if (this.imgWidth > this.imgHeight) {
+					hp = hp * this.imgHeight / this.imgWidth;
+				} else if (this.imgWidth < this.imgHeight) {
+					wp = wp * this.imgWidth / this.imgHeight;
+				}
+				const size = this.sys.windowWidth > this.sys.windowHeight ? this.sys.windowHeight : this.sys.windowWidth;
+				const width = size * wp / 100;
+				const height = size * hp / 100;
+				const left = (this.sys.windowWidth - width) / 2;
+				const right = left + width;
+				const top = (this.sys.windowHeight + this.sys.windowTop - this.sys.offsetBottom - height) / 2;
+				const bottom = this.sys.windowHeight + this.sys.windowTop - this.sys.offsetBottom - top;
+				this.area = { width, height, left, right, top, bottom };
+				this.scaleWidth = width;
+				this.scaleHeight = height;
+			},
+			/** 浠庢湰鍦伴�夊彇鍥剧墖 */
+			chooseImage() {
+				// #ifdef MP-WEIXIN || MP-JD
+				if(uni.chooseMedia) {
+					uni.chooseMedia({
+						count: 1,
+						mediaType: ['image'],
+						success: (res) => {
+							this.resetData();
+							this.initImage(res.tempFiles[0].tempFilePath);
+						}
+					});
+					return;
+				}
+				// #endif
+				uni.chooseImage({
+					count: 1,
+					success: (res) => {
+						this.resetData();
+						this.initImage(res.tempFiles[0].path);
+					}
+				});
+			},
+			/** 閲嶇疆鏁版嵁 */
+			resetData() {
+				this.imgSrc = '';
+				this.rotate = 0;
+				this.offsetX = 0;
+				this.offsetY = 0;
+				this.initArea();
+			},
+			/**
+			 * 鍒濆鍖栧浘鐗囦俊鎭�
+			 * @param {String} url 鍥剧墖閾炬帴
+			 */
+			initImage(url) {
+				uni.getImageInfo({
+					src: url,
+					success: (res) => {
+						this.imgSrc = res.path;
+						let scale = res.width / res.height;
+						let areaScale = this.area.width / this.area.height;
+						if (scale > 1) { // 妯悜鍥剧墖
+							if (scale >= areaScale) { // 鍥剧墖瀹戒笉灏忎簬鐩爣瀹斤紝鍒欓珮鍥哄畾锛屽鑷�傚簲
+								this.scaleWidth = (this.scaleHeight / res.height) * this.scaleWidth * (res.width / this.scaleWidth);
+							} else { // 鍚﹀垯瀹藉浐瀹氥�侀珮鑷�傚簲
+								this.scaleHeight = res.height * this.scaleWidth / res.width;
+							}
+						} else { // 绾靛悜鍥剧墖
+							if (scale <= areaScale) { // 鍥剧墖楂樹笉灏忎簬鐩爣楂橈紝瀹藉浐瀹氾紝楂樿嚜閫傚簲
+								this.scaleHeight = (this.scaleWidth / res.width) * this.scaleHeight / (this.scaleHeight / res.height);
+							} else { // 鍚﹀垯楂樺浐瀹氾紝瀹借嚜閫傚簲
+								this.scaleWidth = res.width * this.scaleHeight / res.height;
+							}
+						}
+						// 璁板綍鍘熷瀹介珮锛屼负缂╂斁姣斿垪鍋氶檺鍒�
+						this.oldWidth = this.scaleWidth;
+						this.oldHeight = this.scaleHeight;
+					},
+					fail: (err) => {
+						console.error(err)
+					}
+				});
+			},
+			/**
+			 * 鍓垏鍥剧墖鍦嗚
+			 * @param {Object} ctx canvas 鐨勭粯鍥句笂涓嬫枃瀵硅薄
+			 * @param {Number} radius 鍦嗚鍗婂緞
+			 * @param {Number} scale 鐢熸垚鍥剧墖鐨勫疄闄呭昂瀵镐笌鎴彇鍖哄煙姣�
+			 * @param {Function} drawImage 鎵ц鍓垏鏃舵墍璋冪敤鐨勭粯鍥炬柟娉曪紝鍏ュ弬涓烘槸鍚︽墽琛屼簡鍓垏
+			 */
+			drawClipImage(ctx, radius, scale, drawImage) {
+				if(radius > 0) {
+					ctx.save();
+					ctx.beginPath();
+					const w = this.canvansWidth;
+					const h = this.canvansHeight;
+					if(w === h && radius >= w / 2) { // 鍦嗗舰
+						ctx.arc(w / 2, h / 2, w / 2, 0, 2 * Math.PI);
+					} else { // 鍦嗚鐭╁舰
+						if(w !== h) { // 闄愬埗鍦嗚鍗婂緞涓嶈兘瓒呰繃鐭竟鐨勪竴鍗�
+							radius = Math.min(w / 2, h / 2, radius);
+							// radius = Math.min(Math.max(w, h) / 2, radius);
+						}
+						ctx.moveTo(radius, 0);
+						ctx.arcTo(w, 0, w, h, radius);
+						ctx.arcTo(w, h, 0, h, radius);
+						ctx.arcTo(0, h, 0, 0, radius);
+						ctx.arcTo(0, 0, w, 0, radius);
+						ctx.closePath();
+					}
+					ctx.clip();
+					drawImage && drawImage(true);
+					ctx.restore();
+				} else {
+					drawImage && drawImage(false);
+				}
+			},
+			/**
+			 * 鏃嬭浆鍥剧墖
+			 * @param {Object} ctx canvas 鐨勭粯鍥句笂涓嬫枃瀵硅薄
+			 * @param {Number} rotate 鏃嬭浆瑙掑害
+			 * @param {Number} scale 鐢熸垚鍥剧墖鐨勫疄闄呭昂瀵镐笌鎴彇鍖哄煙姣�
+			 */
+			drawRotateImage(ctx, rotate, scale) {
+				if(rotate !== 0) {
+					// 1. 浠ュ浘鐗囦腑蹇冪偣涓烘棆杞腑蹇冪偣
+					const x = this.scaleWidth * scale / 2;
+					const y = this.scaleHeight * scale / 2;
+					ctx.translate(x, y);
+					// 2. 鏃嬭浆鐢诲竷
+					ctx.rotate(rotate * Math.PI / 180);
+					// 3. 鏃嬭浆瀹岀敾甯冨悗鎭㈠璁剧疆鏃嬭浆涓績鏃舵墍鍋氱殑鍋忕Щ
+					ctx.translate(-x, -y);
+				}
+			},
+			drawImage(ctx, image, callback) {
+				// 鐢熸垚鍥剧墖鐨勫疄闄呭昂瀵镐笌鎴彇鍖哄煙姣�
+				const scale = this.canvansWidth / this.area.width;
+				this.drawClipImage(ctx, this.radius, scale, () => {
+					this.drawRotateImage(ctx, this.rotate, scale);
+					const r = this.rotate / 90;
+					ctx.drawImage(
+						image,
+						[
+							(this.offsetX - this.area.left),
+							(this.offsetY - this.area.top),
+							-(this.offsetX - this.area.left),
+							-(this.offsetY - this.area.top)
+						][r] * scale,
+						[
+							(this.offsetY - this.area.top),
+							-(this.offsetX - this.area.left),
+							-(this.offsetY - this.area.top),
+							(this.offsetX - this.area.left)
+						][r] * scale,
+						this.scaleWidth * scale,
+						this.scaleHeight * scale
+					);
+				});
+			},
+			/**
+			 * 缁樺浘
+			 * @param {Object} canvas 
+			 * @param {Object} ctx canvas 鐨勭粯鍥句笂涓嬫枃瀵硅薄
+			 * @param {String} src 鍥剧墖璺緞
+			 * @param {Function} callback 寮�濮嬬粯鍒舵椂鍥炶皟
+			 */
+			draw2DImage(canvas, ctx, src, callback) {
+				// console.log('draw2DImage', canvas, ctx, src, callback)
+				if(canvas) {
+					const image = canvas.createImage();
+					image.onload = () => {
+						this.drawImage(ctx, image);
+						// 濡傛灉瑙夊緱`鐢熸垚鏃堕棿杩囬暱`鎴朻鍑虹幇鐢熸垚鍥剧墖绌虹櫧`鍙皾璇曡皟鏁村欢杩熸椂闂�
+						callback && setTimeout(callback, this.delay);
+					};
+					image.onerror = (err) => {
+						console.error(err)
+						uni.hideLoading();
+					};
+					image.src = src;
+				} else {
+					this.drawImage(ctx, src);
+					setTimeout(() => {
+						ctx.draw(false, callback);
+					}, 200);
+				}
+			},
+			/**
+			 * 鐢诲竷杞浘鐗囧埌鏈湴缂撳瓨
+			 * @param {Object} canvas 
+			 * @param {String} canvasId 
+			 */
+			canvasToTempFilePath(canvas, canvasId) {
+				// console.log('canvasToTempFilePath', canvas, canvasId)
+				uni.canvasToTempFilePath({
+					canvas,
+					canvasId,
+					x: 0,
+					y: 0,
+					width: this.canvansWidth,
+					height: this.canvansHeight,
+					destWidth: this.imgWidth, // 蹇呰锛屼繚璇佺敓鎴愬浘鐗囧搴︿笉鍙楄澶囧垎杈ㄧ巼褰卞搷
+					destHeight: this.imgHeight, // 蹇呰锛屼繚璇佺敓鎴愬浘鐗囬珮搴︿笉鍙楄澶囧垎杈ㄧ巼褰卞搷
+					fileType: this.fileType, // 鐩爣鏂囦欢鐨勭被鍨嬶紝榛樿png
+					success: (res) => {
+						// 鐢熸垚鐨勫浘鐗囦复鏃舵枃浠惰矾寰�
+						this.handleImage(res.tempFilePath);
+					},
+					fail: (err) => {
+						uni.hideLoading();
+						uni.showToast({ title: '瑁佸壀澶辫触锛岀敓鎴愬浘鐗囧紓甯革紒', icon: 'none' });
+					}
+				}, this);
+			},
+			/** 纭瑁佸壀 */
+			cropClick() {
+				uni.showLoading({ title: '瑁佸壀涓�...', mask: true });
+				if(!this.use2d) {
+					const ctx = uni.createCanvasContext('imgCanvas', this);
+					ctx.clearRect(0, 0, this.canvansWidth, this.canvansHeight);
+					this.draw2DImage(null, ctx, this.imgSrc, () => {
+						this.canvasToTempFilePath(null, 'imgCanvas');
+					});
+					return;
+				}
+				// #ifdef MP-WEIXIN
+				const query = uni.createSelectorQuery().in(this);
+				query.select('#imgCanvas')
+					.fields({ node: true, size: true })
+					.exec((res) => {
+						const canvas = res[0].node;
+										
+						const dpr = uni.getSystemInfoSync().pixelRatio;
+						canvas.width = res[0].width * dpr;
+						canvas.height = res[0].height * dpr;
+						const ctx = canvas.getContext('2d');
+						ctx.scale(dpr, dpr);
+						ctx.clearRect(0, 0, this.canvansWidth, this.canvansHeight);
+						
+						this.draw2DImage(canvas, ctx, this.imgSrc, () => {
+							this.canvasToTempFilePath(canvas);
+						});
+					});
+				// #endif
+			},
+			handleImage(tempFilePath){
+				// 鍦℉5骞冲彴涓嬶紝tempFilePath 涓� base64
+				// console.log(tempFilePath)
+				uni.hideLoading();
+				this.$emit('crop', { tempFilePath });
+			}
+		}
+	}
+</script>
+ 
+<style lang="scss" scoped>
+	.image-cropper {
+		position: fixed;
+		left: 0;
+		right: 0;
+		top: 0;
+		bottom: 0;
+		z-index: 999999;
+		overflow: hidden;
+		display: flex;
+		flex-direction: column;
+		background-color: #000;
+		.img-canvas {
+			position: absolute !important;
+			transform: translateX(-100%);
+		}
+		.pic-preview {
+			width: 100%;
+			flex: 1;
+			position: relative;
+
+			.crop-mask-block {
+				background-color: rgba(51, 51, 51, 0.8);
+				z-index: 2;
+				position: fixed;
+				box-sizing: border-box;
+				pointer-events: none;
+			}
+			.crop-circle-box {
+				position: fixed;
+				box-sizing: border-box;
+				z-index: 2;
+				pointer-events: none;
+				overflow: hidden;
+				.crop-circle {
+					width: 100%;
+					height: 100%;
+				}
+			}
+			.crop-image {
+				padding: 0 !important;
+				margin: 0 !important;
+				border-radius: 0 !important;
+				display: block !important;
+			}
+			.crop-border {
+				position: fixed;
+				border: 1px solid #fff;
+				box-sizing: border-box;
+				z-index: 3;
+				pointer-events: none;
+			}
+			.crop-grid {
+				position: fixed;
+				z-index: 3;
+				border-style: dashed;
+				border-color: #fff;
+				pointer-events: none;
+				opacity: 0.5;
+			}
+			.crop-angle {
+				position: fixed;
+				z-index: 3;
+				border-style: solid;
+				border-color: #fff;
+				pointer-events: none;
+			}
+		}
+
+		.fixed-bottom {
+			position: fixed;
+			left: 0;
+			right: 0;
+			bottom: 0;
+			z-index: 99;
+			display: flex;
+			flex-direction: row;
+			background-color: $uni-bg-color-grey;
+
+			.rotate-icon {
+				background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAAXNSR0IArs4c6QAABCFJREFUaEPtml3IpVMUx3//ko/ChTIyiGFSMyhllI8bc4F85yuNC2FCqLmQC1+FZORiEkUMNW7UjKjJULgxV+NzSkxDhEkZgwsyigv119J63p7zvOc8z37OmXdOb51dz82711r7/99r7bXXXucVi3xokeNnRqCvB20fDmwAlgK/5bcD+FTSr33tHXQP2H4MeHQE0A+B5yRtLiUyDQJrgVc6AAaBpyV93kXkoBMIQLbfBS5NcK8BRwDXNcD+AdwnaVMbiWkRCPBBohpxHuK7M7865sclRdgNHVMhkF6IMIpwirFEUhzo8M7lwIvASTXEqyVtH8ZgagQSbOzsDknv18HZXpHn5IL8+94IOUm7miSmSqAttjPdbgGuTrnNktYsGgLpoYuAD2qg1zRTbG8P2D4SOC6/Q7vSHPALsE/S7wWy80RsPw/ckxMfSTq/LtRJwPbxwF3ASiCUTxwHCPAnEBfVF8AWSTtL7Ng+LfWOTfmlkn6udFsJ5K15R6a4kvX6yGyUFBvTOWzHXXFzCt4g6c1OArYj9iIGh43YgR+BvztXh1PSa4cMkd0jaVmXDduPAE+k3HpJD7cSGFKvfAc8FQUX8IOk/V2L1udtB/hTgdOBW4Aba/M7Ja1qs2f7euCNlHlZUlx4/495IWQ7Jl+qGbxX0gt9AHfJ2o6zFBVoNVrDKe+F3Sm8VdK1bQQ+A85JgXckXdkFaJx527cC9TpnVdvBtl3h2iapuhsGPdBw1b9xnUvaNw7AEh3bnwDnpuwGSfeP0rN9NvAMELXRXFkxEEK2nwQeSiOtRVQJwC4Z29cAW1Nuu6TVXTrN+SaBt4ErUug2Sa/2NdhH3vZy4NvU2S/p6D768w5xI3WOrAD7LtISFpGdIhVXKfaYvjd20wP13L9M0p4DBbaFRKToSLExVkr6qs+aIwlI6iwz+izUQqC+ab29PiMwqRcmPXczD8w8MFj1zg7xXEqbpdHCw7FgWSjafZL+KcQxtpjteCeflwYulFR/J3TabSslVkj6utPChAK2f6q9uZdLitKieLQRuExSvX9ZbLRUMFs09efpUZL+KtUfVo1GW/umNHC3pOhRLtiwfSbwZS6wV9IJfRdreuBBYH0a2STp9r4G+8jbXgc8mzoDT8VSO00ClwDv1ZR7XyylC4ec7ejaLUmdsV6Aw7oSbwFXpdFdks7qA6pU1na0aR6owgeIR/1cx63UzjAC0YXYVjMQHlkn6ZtSo21ytuPZGKFagQ/xsXZ/3iGuFrYdjafXG0DiQMeBi47c9/GV3BO247UV38n5o0UAP6xmu7jFOGxjRr66On5NPBDOCBsDTapxjHY1dyOcolNXnYlx1himE53p2PmNkxosevfavhg4Izt2k7TXPwZ2S6p6QZPin/2rwcQ7OKmBohCadJGF1P8PG6aaQBKVX/8AAAAASUVORK5CYII=');
+				background-size: 60% 60%;
+				background-repeat: no-repeat;
+				background-position:center;
+				width: 80rpx;
+				height: 80rpx;
+				position: absolute;
+				top: -90rpx;
+				left: 10rpx;
+				transform: rotateY(180deg);
+			}
+			 
+			.rechoose {
+				color: $uni-color-primary;
+				padding: 0 $uni-spacing-row-lg;
+				line-height: 100rpx;
+			}
+
+			.choose-btn {
+				color: $uni-color-primary;
+				text-align: center;
+				line-height: 100rpx;
+				flex: 1;
+			}
+
+			.button {
+				margin: auto $uni-spacing-row-lg auto auto;
+				background-color: $uni-color-primary;
+				color: #fff;
+			}
+		}
+
+		.safe-area-inset-bottom {
+			padding-bottom: 0;  
+			padding-bottom: constant(safe-area-inset-bottom); // 鍏煎 IOS<11.2
+			padding-bottom: env(safe-area-inset-bottom); // 鍏煎 IOS>=11.2
+		}
+ 
+	}
+</style>
\ No newline at end of file
diff --git a/h5/uni_modules/qf-image-cropper/components/qf-image-cropper/qf-image-cropper.wxs b/h5/uni_modules/qf-image-cropper/components/qf-image-cropper/qf-image-cropper.wxs
new file mode 100644
index 0000000..6a517cf
--- /dev/null
+++ b/h5/uni_modules/qf-image-cropper/components/qf-image-cropper/qf-image-cropper.wxs
@@ -0,0 +1,543 @@
+/**
+ * 鍥剧墖缂栬緫鍣�-鎵嬪娍鐩戝惉
+ * 1. wxs 鏆備笉鏀寔 es6 璇硶
+ * 2. 鏀寔缂栬瘧鍒板井淇″皬绋嬪簭銆丵Q灏忕▼搴忋�乤pp-vue銆丠5涓婏紙uni-app 2.2.5鍙婁互涓婄増鏈級
+ */
+/** 鍥剧墖鍋忕Щ閲� */
+var offset = { x: 0, y: 0 };
+/** 鍥剧墖缂╂斁姣斾緥 */
+var scale = 1;
+/** 鍥剧墖鏈�灏忕缉鏀炬瘮渚� */
+var minScale = 1;
+/** 鍥剧墖鏃嬭浆瑙掑害 */
+var rotate = 0;
+/** 瑙︽懜鐐� */
+var touches = [];
+/** 鍥剧墖甯冨眬淇℃伅 */
+var img = {};
+/** 绯荤粺淇℃伅 */
+var sys = {};
+/** 瑁佸壀鍖哄煙甯冨眬淇℃伅 */
+var area = {};
+/** 瑙︽懜琛屼负绫诲瀷 */
+var touchType = '';
+/** 鎿嶄綔瑙掔殑浣嶇疆 */
+var activeAngle = 0;
+/** 瑁佸壀鍖哄煙甯冨眬淇℃伅鍋忕Щ閲� */
+var areaOffset = { left: 0, right: 0, top: 0, bottom: 0 };
+/**
+ * 璁$畻涓ょ偣闂磋窛
+ * @param {Object} touches 瑙︽懜鐐逛俊鎭�
+ */
+function getDistanceByTouches(touches) {
+	// 鏍规嵁鍕捐偂瀹氱悊姹備袱鐐归棿璺濈
+	var a = touches[1].pageX - touches[0].pageX;
+	var b = touches[1].pageY - touches[0].pageY;
+	var c = Math.sqrt(Math.pow(a, 2) + Math.pow(b, 2));
+	// 姹備袱鐐归棿鐨勪腑鐐瑰潗鏍�
+	// 1. a銆乥鍙兘涓鸿礋鍊�
+	// 2. 鍦ㄦ眰a銆乥鏃讹紝濡傜敤touches[1]鍑弔ouches[0]锛屽垯姹備腑鐐瑰潗鏍囦篃寰楃敤touches[1]鍑廰/2銆乥/2
+	// 3. 鍚岀悊锛屽湪姹俛銆乥鏃讹紝涔熷彲鐢╰ouches[0]鍑弔ouches[1]锛屽垯姹備腑鐐瑰潗鏍囦篃寰楃敤touches[0]鍑廰/2銆乥/2
+	var x = touches[1].pageX - a / 2;
+	var y = touches[1].pageY - b / 2;
+	return { c, x, y };
+};
+/**
+ * 妫�鏌ヨ竟鐣岋細闄愬埗 x銆亂 鎷栧姩鑼冨洿锛岀姝㈡粦鍑鸿竟鐣�
+ * @param {Object} e 鐐瑰潗鏍�
+ */
+function checkRange(e) {
+	var r = rotate / 90 % 2;
+	if(r === 1) { // 鍥犲浘鐗囧楂樺彲鑳戒笉绛夛紝缈昏浆 90掳 鎴� 270掳 鍚庡浘鐗囧楂橀渶鍙嶇潃璁$畻锛屼笖宸﹀彸鍜屼笂涓嬭竟鐣岃鏍规嵁宸�煎仛鍋忕Щ
+		var o = (img.height - img.width) / 2; // 瀹介珮宸�间竴鍗�
+		return {
+			x: Math.min(Math.max(e.x, -img.height + o + area.width + area.left), area.left + o),
+			y: Math.min(Math.max(e.y, -img.width - o + area.height + area.top), area.top - o)
+		}
+	}
+	return {
+		x: Math.min(Math.max(e.x, -img.width + area.width + area.left), area.left),
+		y: Math.min(Math.max(e.y, -img.height + area.height + area.top), area.top)
+	}
+};
+/**
+ * 鍙樻洿鍥剧墖甯冨眬淇℃伅
+ * @param {Object} e 甯冨眬淇℃伅
+ */
+function changeImageRect(e) {
+	offset.x += e.x || 0;
+	offset.y += e.y || 0;
+	var image = e.instance.selectComponent('.crop-image');
+	if(e.check) { // 妫�鏌ヨ竟鐣�
+		var point = checkRange(offset);
+		if(offset.x !== point.x || offset.y !== point.y) {
+			offset = point;
+		}
+	}
+	// image.setStyle({
+	// 	width: img.width + 'px',
+	// 	height: img.height + 'px',
+	// 	transform: 'translate(' + offset.x + 'px, ' + offset.y + 'px) rotate(' + rotate +'deg)'
+	// });
+	var ox = (img.width - img.oldWidth) / 2;
+	var oy = (img.height - img.oldHeight) / 2;
+	image.setStyle({
+		width: img.oldWidth + 'px',
+		height: img.oldHeight + 'px',
+		transform: 'translate(' + (offset.x + ox) + 'px, ' + (offset.y + oy) + 'px) rotate(' + rotate +'deg) scale(' + scale + ')'
+	});
+	
+	e.instance.callMethod('dataChange', {
+		width: img.width,
+		height: img.height,
+		x: offset.x,
+		y: offset.y,
+		rotate: rotate
+	});
+};
+/**
+ * 鍙樻洿瑁佸壀鍖哄煙甯冨眬淇℃伅
+ * @param {Object} e 甯冨眬淇℃伅
+ */
+function changeAreaRect(e) {
+	// 鍙樻洿钂欑増鏍峰紡
+	var masks = e.instance.selectAllComponents('.crop-mask-block');
+	var maskStyles = [
+		{
+			left: 0,
+			width: (area.left + areaOffset.left) + 'px',
+			top: 0,
+			bottom: 0,
+		},
+		{
+			left: (area.right + areaOffset.right) + 'px',
+			right: 0,
+			top: 0,
+			bottom: 0,
+		},
+		{
+			left: (area.left + areaOffset.left) + 'px',
+			width: (area.width + areaOffset.right - areaOffset.left) + 'px',
+			top: 0,
+			height: (area.top + areaOffset.top) + 'px',
+		},
+		{
+			left: (area.left + areaOffset.left) + 'px',
+			width: (area.width + areaOffset.right - areaOffset.left) + 'px',
+			top: (area.bottom + areaOffset.bottom) + 'px',
+			// height: (area.top - areaOffset.bottom + sys.offsetBottom) + 'px',
+			bottom: 0,
+		}
+	];
+	var len = masks.length;
+	for (var i = 0; i < len; i++) {
+		masks[i].setStyle(maskStyles[i]);
+	}
+	
+	// 鍙樻洿杈规鏍峰紡
+	if(area.showBorder) {
+		var border = e.instance.selectComponent('.crop-border');
+		border.setStyle({
+			left: (area.left + areaOffset.left) + 'px',
+			top: (area.top + areaOffset.top) + 'px',
+			width: (area.width + areaOffset.right - areaOffset.left) + 'px',
+			height: (area.height + areaOffset.bottom - areaOffset.top) + 'px',
+		});
+	}
+	
+	// 鍙樻洿鍙傝�冪嚎鏍峰紡
+	if(area.showGrid) {
+		var grids = e.instance.selectAllComponents('.crop-grid');
+		var gridStyles = [
+			{
+				'border-width': '1px 0 0 0',
+				left: (area.left + areaOffset.left) + 'px',
+				right: (area.right + areaOffset.right) + 'px',
+				top: (area.top + areaOffset.top + (area.height + areaOffset.bottom - areaOffset.top) / 3 - 0.5) + 'px',
+				width: (area.width + areaOffset.right - areaOffset.left) + 'px'
+			},
+			{
+				'border-width': '1px 0 0 0',
+				left: (area.left + areaOffset.left) + 'px',
+				right: (area.right + areaOffset.right) + 'px',
+				top: (area.top + areaOffset.top + (area.height + areaOffset.bottom - areaOffset.top) * 2 / 3 - 0.5) + 'px',
+				width: (area.width + areaOffset.right - areaOffset.left) + 'px'
+			},
+			{
+				'border-width': '0 1px 0 0',
+				top: (area.top + areaOffset.top) + 'px',
+				bottom: (area.bottom + areaOffset.bottom) + 'px',
+				left: (area.left + areaOffset.left + (area.width + areaOffset.right - areaOffset.left) / 3 - 0.5) + 'px',
+				height: (area.height + areaOffset.bottom - areaOffset.top) + 'px'
+			},
+			{
+				'border-width': '0 1px 0 0',
+				top: (area.top + areaOffset.top) + 'px',
+				bottom: (area.bottom + areaOffset.bottom) + 'px',
+				left: (area.left + areaOffset.left + (area.width + areaOffset.right - areaOffset.left) * 2 / 3 - 0.5) + 'px',
+				height: (area.height + areaOffset.bottom - areaOffset.top) + 'px'
+			}
+		];
+		var len = grids.length;
+		for (var i = 0; i < len; i++) {
+			grids[i].setStyle(gridStyles[i]);
+		}
+	}
+	
+	// 鍙樻洿鍥涗釜浼哥缉瑙掓牱寮�
+	if(area.showAngle) {
+		var angles = e.instance.selectAllComponents('.crop-angle');
+		var angleStyles = [
+			{
+				'border-width': area.angleBorderWidth + 'px 0 0 ' + area.angleBorderWidth + 'px',
+				left: (area.left + areaOffset.left - area.angleBorderWidth) + 'px',
+				top: (area.top + areaOffset.top - area.angleBorderWidth) + 'px',
+			},
+			{
+				'border-width': area.angleBorderWidth + 'px ' + area.angleBorderWidth + 'px 0 0',
+				left: (area.right + areaOffset.right - area.angleSize) + 'px',
+				top: (area.top + areaOffset.top - area.angleBorderWidth) + 'px',
+			},
+			{
+				'border-width': '0 0 ' + area.angleBorderWidth + 'px ' + area.angleBorderWidth + 'px',
+				left: (area.left + areaOffset.left - area.angleBorderWidth) + 'px',
+				top: (area.bottom + areaOffset.bottom - area.angleSize) + 'px',
+			},
+			{
+				'border-width': '0 ' + area.angleBorderWidth + 'px ' + area.angleBorderWidth + 'px 0',
+				left: (area.right + areaOffset.right - area.angleSize) + 'px',
+				top: (area.bottom + areaOffset.bottom - area.angleSize) + 'px',
+			}
+		];
+		var len = angles.length;
+		for (var i = 0; i < len; i++) {
+			angles[i].setStyle(angleStyles[i]);
+		}
+	}
+	
+	// 鍙樻洿鍦嗚鏍峰紡
+	if(area.radius > 0) {
+		var circleBox = e.instance.selectComponent('.crop-circle-box');
+		var circle = e.instance.selectComponent('.crop-circle');
+		var radius = area.radius;
+		if(area.width === area.height && area.radius >= area.width / 2) { // 鍦嗗舰
+			radius = (area.width / 2);
+		} else { // 鍦嗚鐭╁舰
+			if(area.width !== area.height) { // 闄愬埗鍦嗚鍗婂緞涓嶈兘瓒呰繃鐭竟鐨勪竴鍗�
+				radius = Math.min(area.width / 2, area.height / 2, radius);
+			}
+		}
+		circleBox.setStyle({
+			left: (area.left + areaOffset.left) + 'px',
+			top: (area.top + areaOffset.top) + 'px',
+			width: (area.width + areaOffset.right - areaOffset.left) + 'px',
+			height: (area.height + areaOffset.bottom - areaOffset.top) + 'px'
+		});
+		circle.setStyle({
+			'box-shadow': '0 0 0 ' + Math.max(area.width, area.height) + 'px rgba(51, 51, 51, 0.8)',
+			'border-radius': radius + 'px'
+		});
+	}
+};
+/**
+ * 缂╂斁鍥剧墖
+ * @param {Object} e 甯冨眬淇℃伅
+ */
+function scaleImage(e) {
+	var last = scale;
+	scale = Math.min(Math.max(e.scale + scale, minScale), img.maxScale);
+	if(last !== scale) {
+		img.width = img.oldWidth * scale;
+		img.height = img.oldHeight * scale;
+		// 鍙傝�冮棶棰橈細鏈変竴涓暱4000px銆佸4000px鐨勫洓鏂瑰舰ABCD锛孉鐐圭殑鍧愭爣鍥哄畾鍦�(-2000,-2000)锛�
+		// 			璇ュ洓杈瑰舰涓婃湁涓�涓偣E锛屽潗鏍囦负(-100,-300)锛屽皢璇ュ洓鏂瑰舰澶嶅埗涓�浠藉苟缂╁皬鍒�90%鍚庯紝
+		// 			鏂板洓杈瑰舰鐨凙鐐瑰潗鏍囦负澶氬皯鏃跺彲浣挎柊鍥涜竟褰㈢殑E鐐逛笌鍘熷洓杈瑰舰鐨凟鐐归噸鍚堬紵
+		// 棰勬湡鏁堟灉锛氫粠鍥句腑閫夊彇鏌愮偣锛堝弬鐓х墿锛変负涓績鐐硅繘琛岀缉鏀撅紝缂╂斁鏃舵棤璁哄浘鍍忔�庝箞鍙樺寲锛岃鐐逛綅缃缁堝浐瀹氫笉鍙�
+		// 璁$畻鏂规硶锛氫互鐩稿悓璧风偣鍏堣绠楃缉鏀惧墠鍚庝袱鐐归棿鐨勮窛绂伙紝鍐嶅姞涓婂師鍥惧儚鍋忕Щ閲忓嵆鍙�
+		e.x = (e.x - offset.x) * (1 - scale / last);
+		e.y = (e.y - offset.y) * (1 - scale / last);
+		changeImageRect(e);
+		return true;
+	}
+	return false;
+};
+/**
+ * 鑾峰彇瑙︽懜鐐瑰湪鍝釜瑙�
+ * @param {number} x 瑙︽懜鐐箈杞村潗鏍�
+ * @param {number} y 瑙︽懜鐐箉杞村潗鏍�
+ * @return {number} 瑙掔殑浣嶇疆锛�0=鏃狅紱1=宸︿笂锛�2=鍙充笂锛�3=宸︿笅锛�4=鍙充笅锛�
+ */
+function getToucheAngle(x, y) {
+	// console.log('getToucheAngle', x, y, JSON.stringify(area))
+	var o = area.angleBorderWidth; // 闇�鎵╁ぇ瑙﹀彂鑼冨洿鍒欐妸 o 鍊煎姞澶у嵆鍙�
+	if(y >= area.top - o && y <= area.top + area.angleSize + o) {
+		if(x >= area.left - o && x <= area.left + area.angleSize + o) {
+			return 1; // 宸︿笂瑙�
+		} else if(x >= area.right - area.angleSize - o && x <= area.right + o) {
+			return 2; // 鍙充笂瑙�
+		}
+	} else if(y >= area.bottom - area.angleSize - o && y <= area.bottom + o) {
+		if(x >= area.left - o && x <= area.left + area.angleSize + o) {
+			return 3; // 宸︿笅瑙�
+		} else if(x >= area.right - area.angleSize - o && x <= area.right + o) {
+			return 4; // 鍙充笅瑙�
+		}
+	}
+	return 0; // 鏃犺Е鎽稿埌瑙�
+};
+/**
+ * 閲嶇疆鏁版嵁
+ */
+function resetData() {
+	offset = { x: 0, y: 0 };
+	scale = 1;
+	minScale = 1;
+	rotate = 0;
+};
+module.exports = {
+	/**
+	 * 鍒濆鍖栵細瑙傚療鏁版嵁鍙樻洿
+	 * @param {Object} newVal 鏂版暟鎹�
+	 * @param {Object} oldVal 鏃ф暟鎹�
+	 * @param {Object} o 缁勪欢瀹炰緥瀵硅薄
+	 */
+	initObserver: function(newVal, oldVal, o, i) {
+		if(newVal) {
+			img = newVal.img;
+			sys = newVal.sys;
+			area = newVal.area;
+			resetData();
+			img.src && changeImageRect({
+				instance: o,
+				x: (sys.windowWidth - img.width) / 2,
+				y: (sys.windowHeight - sys.offsetBottom - img.height) / 2
+			});
+			changeAreaRect({
+				instance: o
+			});
+			// console.log('initRect', JSON.stringify(newVal))
+		}
+	},
+	/**
+	 * 榧犳爣婊氳疆婊氬姩
+	 * @param {Object} e 浜嬩欢瀵硅薄
+	 * @param {Object} o 缁勪欢瀹炰緥瀵硅薄
+	 */
+	mousewheel: function(e, o) {
+		if(!img.src) return;
+		scaleImage({
+			instance: o,
+			check: true,
+			// 榧犳爣鍚戜笂婊氬姩鏃讹紝deltaY 鍥哄畾 -100锛岄紶鏍囧悜涓嬫粴鍔ㄦ椂锛宒eltaY 鍥哄畾 100
+			scale: e.detail.deltaY > 0 ? -0.05 : 0.05,
+			x: e.touches[0].pageX,
+			y: e.touches[0].pageY
+		});
+	},
+	/**
+	 * 瑙︽懜寮�濮�
+	 * @param {Object} e 浜嬩欢瀵硅薄
+	 * @param {Object} o 缁勪欢瀹炰緥瀵硅薄
+	 */
+	touchstart: function(e, o) {
+		if(!img.src) return;
+		touches = e.touches;
+		activeAngle = area.showAngle ? getToucheAngle(touches[0].pageX, touches[0].pageY) : 0;
+		if(touches.length === 1 && activeAngle !== 0) {
+			touchType = 'stretch'; // 浼哥缉瑁佸壀鍖哄煙
+		} else {
+			touchType = '';
+		}
+		// console.log('touchstart', JSON.stringify(e), activeAngle)
+	},
+	/**
+	 * 瑙︽懜绉诲姩
+	 * @param {Object} e 浜嬩欢瀵硅薄
+	 * @param {Object} o 缁勪欢瀹炰緥瀵硅薄
+	 */
+	touchmove: function(e, o) {
+		if(!img.src) return;
+		// console.log('touchmove', JSON.stringify(e), JSON.stringify(o))
+		if(touchType === 'stretch') { // 瑙︽懜鍥涗釜瑙掕繘琛屾媺浼�
+			var point = e.touches[0];
+			var start = touches[0];
+			var x = point.pageX - start.pageX;
+			var y = point.pageY - start.pageY;
+			if(x !== 0 || y !== 0) {
+				var maxX = area.width * (1 - area.minScale);
+				var maxY = area.height * (1 - area.minScale);
+				// console.log(x, y, maxX, maxY)
+				touches[0] = point;
+				switch(activeAngle) {
+					case 1: // 宸︿笂瑙�
+						x += areaOffset.left;
+						y += areaOffset.top;
+						if(x >= 0 && y >= 0) { // 鏈夋晥婊戝姩
+							if(x > y) { // 浠杞存粦鍔ㄨ窛绂讳负缂╂斁鍩哄噯
+								if(x > maxX) x = maxX;
+								y = x * area.height / area.width;
+							} else { // 浠杞存粦鍔ㄨ窛绂讳负缂╂斁鍩哄噯
+								if(y > maxY) y = maxY;
+								x = y * area.width / area.height;
+							}
+							areaOffset.left = x;
+							areaOffset.top = y;
+						}
+						break;
+					case 2: // 鍙充笂瑙�
+						x += areaOffset.right;
+						y += areaOffset.top;
+						if(x <= 0 && y >= 0) { // 鏈夋晥婊戝姩
+							if(-x > y) { // 浠杞存粦鍔ㄨ窛绂讳负缂╂斁鍩哄噯
+								if(-x > maxX) x = -maxX;
+								y = -x * area.height / area.width;
+							} else { // 浠杞存粦鍔ㄨ窛绂讳负缂╂斁鍩哄噯
+								if(y > maxY) y = maxY;
+								x = -y * area.width / area.height;
+							}
+							areaOffset.right = x;
+							areaOffset.top = y;
+						}
+						break;
+					case 3: // 宸︿笅瑙�
+						x += areaOffset.left;
+						y += areaOffset.bottom;
+						if(x >= 0 && y <= 0) { // 鏈夋晥婊戝姩
+							if(x > -y) { // 浠杞存粦鍔ㄨ窛绂讳负缂╂斁鍩哄噯
+								if(x > maxX) x = maxX;
+								y = -x * area.height / area.width;
+							} else { // 浠杞存粦鍔ㄨ窛绂讳负缂╂斁鍩哄噯
+								if(-y > maxY) y = -maxY;
+								x = -y * area.width / area.height;
+							}
+							areaOffset.left = x;
+							areaOffset.bottom = y;
+						}
+						break;
+					case 4: // 鍙充笅瑙�
+						x += areaOffset.right;
+						y += areaOffset.bottom;
+						if(x <= 0 && y <= 0) { // 鏈夋晥婊戝姩
+							if(-x > -y) { // 浠杞存粦鍔ㄨ窛绂讳负缂╂斁鍩哄噯
+								if(-x > maxX) x = -maxX;
+								y = x * area.height / area.width;
+							} else { // 浠杞存粦鍔ㄨ窛绂讳负缂╂斁鍩哄噯
+								if(-y > maxY) y = -maxY;
+								x = y * area.width / area.height;
+							}
+							areaOffset.right = x;
+							areaOffset.bottom = y;
+						}
+						break;
+				}
+				// console.log(x, y, JSON.stringify(areaOffset))
+				changeAreaRect({
+					instance: o,
+				});
+				// this.draw();
+			}
+		} else if (e.touches.length == 2) { // 鍙岀偣瑙︽懜缂╂斁
+			var start = getDistanceByTouches(touches);
+			var end = getDistanceByTouches(e.touches);
+			scaleImage({
+				instance: o,
+				check: !area.bounce,
+				scale: (end.c - start.c) / 100,
+				x: end.x,
+				y: end.y
+			});
+			touchType = 'scale';
+		} else if(touchType === 'scale') {// 浠庡弻鐐硅Е鎽稿彉鎴愬崟鐐硅Е鎽� / 浠庣缉鏀惧彉鎴愭嫋鍔�
+			touchType = 'move';
+		} else {
+			changeImageRect({
+				instance: o,
+				check: !area.bounce,
+				x: e.touches[0].pageX - touches[0].pageX,
+				y: e.touches[0].pageY - touches[0].pageY
+			});
+			touchType = 'move';
+		}
+		touches = e.touches;
+	},
+	/**
+	 * 瑙︽懜缁撴潫
+	 * @param {Object} e 浜嬩欢瀵硅薄
+	 * @param {Object} o 缁勪欢瀹炰緥瀵硅薄
+	 */
+	touchend: function(e, o) {
+		if(!img.src) return;
+		if(touchType === 'stretch') { // 鎷変几瑁佸壀鍖哄煙鐨勫洓涓缂╂斁
+			// 瑁佸壀鍖哄煙瀹藉害琚缉鏀惧埌澶氬皯
+			var left = areaOffset.left;
+			var right = areaOffset.right;
+			var top = areaOffset.top;
+			var bottom = areaOffset.bottom;
+			var w = area.width + right - left;
+			var h = area.height + bottom - top;
+			// 鍥惧儚鏀惧ぇ鍊嶆暟
+			var p = scale * (area.width / w) - scale;
+			// 澶嶅師瑁佸壀鍖哄煙
+			areaOffset = { left: 0, right: 0, top: 0, bottom: 0 };
+			changeAreaRect({
+				instance: o,
+			});
+			scaleImage({
+				instance: o,
+				scale: p,
+				x: area.left + left + (1 === activeAngle || 3 === activeAngle ? w : 0),
+				y: area.top + top + (1 === activeAngle || 2 === activeAngle ? h : 0)
+			});
+		} else if (area.bounce) { // 妫�鏌ヨ竟鐣屽苟鐭锛屽疄鐜版嫋鍔ㄥ埌杈圭晫鏃舵湁鍥炲脊鏁堟灉
+			changeImageRect({
+				instance: o,
+				check: true
+			});
+		}
+	},
+	/**
+	 * 椤烘椂閽堢炕杞浘鐗�90掳
+	 * @param {Object} e 浜嬩欢瀵硅薄
+	 * @param {Object} o 缁勪欢瀹炰緥瀵硅薄
+	 */
+	rotateImage: function(e, o) {
+		rotate = (rotate + 90) % 360;
+		
+		// 鍥犲浘鐗囧楂樺彲鑳戒笉绛夛紝缈昏浆鍚庡浘鐗囧楂橀渶瓒冲濉弧瑁佸壀鍖哄煙
+		var r = rotate / 90 % 2;
+		minScale = 1;
+		if(img.width < area.height) {
+			minScale = area.height / img.oldWidth;
+		} else if(img.height < area.width) {
+			minScale = (area.width / img.oldHeight)
+		}
+		if(minScale !== 1) {
+			scaleImage({
+				instance: o,
+				scale: minScale - scale,
+				x: sys.windowWidth / 2,
+				y: (sys.windowHeight - sys.offsetBottom) / 2
+			});
+		}
+		
+		// 鐢变簬鎷栧姩鐢诲竷鍚庝細瀵艰嚧鍥剧墖浣嶇疆鍋忕Щ锛岀炕杞椂鐨勬棆杞腑蹇冪偣闇�鏄浘鐗囧尯鍩�+鍋忕Щ鍖哄煙鐨勪腑蹇冪偣
+		// 缈昏浆x杞翠腑蹇冪偣 = (瓒呭嚭瑁佸壀鍖哄煙鍙充晶鐨勫浘鐗囧搴� - 瓒呭嚭瑁佸壀鍖哄煙宸︿晶鐨勫浘鐗囧搴�) / 2
+		// 缈昏浆y杞翠腑蹇冪偣 = (瓒呭嚭瑁佸壀鍖哄煙涓嬫柟鐨勫浘鐗囧搴� - 瓒呭嚭瑁佸壀鍖哄煙涓婃柟鐨勫浘鐗囧搴�) / 2
+		var ox = ((offset.x + img.width - area.right) - (area.left - offset.x)) / 2;
+		var oy = ((offset.y + img.height - area.bottom) - (area.top - offset.y)) / 2;
+		changeImageRect({
+			instance: o,
+			check: true,
+			x: -ox - oy,
+			y: -oy + ox
+		});
+	},
+	// 姝ゅ鍙敤浜庡榻愬叾浠栧钩鍙扮鐨勬牱寮忓弬鏁帮紝闃叉寮傚父锛屾棤浣滅敤
+	imageStyles: {},
+	maskStylesList: [{}, {}, {}, {}],
+	borderStyles: {},
+	gridStylesList: [{}, {}, {}, {}],
+	angleStylesList: [{}, {}, {}, {}],
+	circleBoxStyles: {},
+	circleStyles: {},
+}
\ No newline at end of file
diff --git a/h5/uni_modules/qf-image-cropper/package.json b/h5/uni_modules/qf-image-cropper/package.json
new file mode 100644
index 0000000..bbce521
--- /dev/null
+++ b/h5/uni_modules/qf-image-cropper/package.json
@@ -0,0 +1,81 @@
+{
+  "id": "qf-image-cropper",
+  "displayName": "鍥剧墖瑁佸壀鎻掍欢",
+  "version": "2.1.6",
+  "description": "鍥剧墖瑁佸壀鎻掍欢锛屾敮鎸佽嚜瀹氫箟灏哄銆佸畾鐐圭瓑姣斾緥缂╂斁銆佹嫋鍔ㄣ�佸浘鐗囩炕杞�佸壀鍒囧渾褰�/鍦嗚鍥剧墖銆佸畾鍒舵牱寮忥紝鍔熻兘澶氭�ц兘楂樹綋楠屽ソ娉ㄩ噴鍏ㄣ��",
+  "keywords": [
+    "qf-image-cropper",
+    "鍥剧墖瑁佸壀",
+    "鍥剧墖缂栬緫",
+    "澶村儚瑁佸壀",
+    "灏忕▼搴�"
+],
+  "repository": "",
+  "engines": {
+    "HBuilderX": "^3.1.0"
+  },
+"dcloudext": {
+    "type": "component-vue",
+    "sale": {
+      "regular": {
+        "price": "0.00"
+      },
+      "sourcecode": {
+        "price": "0.00"
+      }
+    },
+    "contact": {
+      "qq": ""
+    },
+    "declaration": {
+      "ads": "鏃�",
+      "data": "鎻掍欢涓嶉噰闆嗕换浣曟暟鎹�",
+      "permissions": "鏃�"
+    },
+    "npmurl": ""
+  },
+  "uni_modules": {
+    "dependencies": [],
+    "encrypt": [],
+    "platforms": {
+      "client": {
+        "Vue": {
+          "vue2": "y",
+          "vue3": "y"
+        },
+        "App": {
+          "app-vue": "y",
+          "app-nvue": "n"
+        },
+        "H5-mobile": {
+          "Safari": "y",
+          "Android Browser": "y",
+          "寰俊娴忚鍣�(Android)": "y",
+          "QQ娴忚鍣�(Android)": "u"
+        },
+        "H5-pc": {
+          "Chrome": "u",
+          "IE": "u",
+          "Edge": "u",
+          "Firefox": "u",
+          "Safari": "u"
+        },
+        "灏忕▼搴�": {
+          "寰俊": "y",
+          "闃块噷": "n",
+          "鐧惧害": "n",
+          "瀛楄妭璺冲姩": "n",
+          "QQ": "u",
+          "閽夐拤": "n",
+          "蹇墜": "n",
+          "椋炰功": "n",
+          "浜笢": "n"
+        },
+        "蹇簲鐢�": {
+          "鍗庝负": "n",
+          "鑱旂洘": "n"
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/h5/uni_modules/qf-image-cropper/readme.md b/h5/uni_modules/qf-image-cropper/readme.md
new file mode 100644
index 0000000..0aebf17
--- /dev/null
+++ b/h5/uni_modules/qf-image-cropper/readme.md
@@ -0,0 +1,83 @@
+# qf-image-cropper
+## 鍥剧墖瑁佸壀鎻掍欢
+uniapp寰俊灏忕▼搴忓浘鐗囪鍓彃浠讹紝鏀寔鑷畾涔夊昂瀵搞�佸畾鐐圭瓑姣斾緥缂╂斁銆佹嫋鍔ㄣ�佸浘鐗囩炕杞�佸壀鍒囧渾褰�/鍦嗚鍥剧墖銆佸畾鍒舵牱寮忥紝鍔熻兘澶氭�ц兘楂樹綋楠屽ソ娉ㄩ噴鍏ㄣ��
+
+### 骞冲彴鏀寔锛�
+1. 鏀寔寰俊灏忕▼搴忥細绉诲姩绔�丳C绔�佸紑鍙戣�呭伐鍏�
+2. 鏀寔H5骞冲彴锛�2.1.0鐗堟湰璧凤級
+3. 鏀寔APP骞冲彴锛�2.1.5鐗堟湰璧凤級锛欰ndroid銆両OS
+4. 鍏朵粬骞冲彴鏆傛湭娴嬭瘯鍏煎鎬ф湭鐭�
+
+### 鏀寔鍔熻兘锛�
+1. 鑷畾涔夎鍓昂瀵�
+2. 瀹氱偣绛夋瘮渚嬬缉鏀撅細绉诲姩绔互鍙屾寚瑙︽懜涓績鐐逛负缂╂斁涓績鐐癸紝PC绔互榧犳爣鎵�鍦ㄧ偣涓虹缉鏀句腑蹇冪偣
+3. 鑷敱鎷栧姩锛氭敮鎸侀檺鍒舵粦鍑鸿竟鐣岋紝涔熸敮鎸佸洖寮规晥鏋滐紙婊戝姩鏃跺彲婊戝嚭杈圭晫锛岄噴鏀炬椂鍥炲脊鍒拌竟鐣岋級
+4. 鍥剧墖缈昏浆锛氬湪瑁佸壀灏哄闈� 1:1 鐨勬儏鍐典笅锛岀炕杞椂瀹介珮鏃犳硶閾烘弧瑁佸壀鍖哄煙鏃讹紝鍥剧墖浼氳嚜鍔ㄦ斁澶у埌鍚堥�傚昂瀵�
+5. 瑁佸壀鐢熸垚鏂板浘鐗�
+6. 鏈湴閫夋嫨鍥剧墖
+7. 鍙畾鍒舵牱寮忥細鍙嚜鐢遍�夋嫨鏄惁娓叉煋瑁佸壀杈规銆佸彲浼哥缉瑁佸壀椤惰銆佸弬鑰冪嚎
+8. 瑁佸壀鍦嗚鍥剧墖锛氬渾褰€�佸渾瑙掔煩褰�
+
+### 灞炴�ц鏄�
+| 灞炴�у悕 | 绫诲瀷 | 榛樿鍊� | 璇存槑 |
+|:---|:---|:---|:---|
+| src              | String        |         | 鍥剧墖璧勬簮鍦板潃 |
+| width            | Number        | 300     | 瑁佸壀瀹藉害 |
+| height           | Number        | 300     | 瑁佸壀楂樺害 |
+| showBorder       | Boolean       | true    | 鏄惁缁樺埗瑁佸壀鍖哄煙杈规 |
+| showGrid         | Boolean       | true    | 鏄惁缁樺埗瑁佸壀鍖哄煙缃戞牸鍙傝�冪嚎 |
+| showAngle        | Boolean       | true    | 鏄惁灞曠ず鍥涗釜鏀寔浼哥缉鐨勮 |
+| areaScale        | Number        | 0.3     | 瑁佸壀鍖哄煙鏈�灏忕缉鏀惧�嶆暟 |
+| maxScale         | Number        | 5       | 鍥剧墖鏈�澶х缉鏀惧�嶆暟 |
+| bounce           | Boolean       | true    | 鏄惁鏈夊洖寮规晥鏋滐細鎷栧姩鏃跺彲浠ユ嫋鍑鸿竟鐣岋紝閲婃斁鏃朵細寮瑰洖杈圭晫 |
+| rotatable        | Boolean       | true    | 鏄惁鏀寔缈昏浆 |
+| choosable        | Boolean       | true    | 鏄惁鏀寔浠庢湰鍦伴�夋嫨绱犳潗 |
+| angleSize        | Number        | 20      | 鍥涗釜瑙掑昂瀵革紝鍗曚綅px |
+| angleBorderWidth | Number        | 2       | 鍥涗釜瑙掕竟妗嗗搴︼紝鍗曚綅px |
+| radius           | Number        |         | 瑁佸壀鍥剧墖鍦嗚鍗婂緞锛屽崟浣峱x |
+| fileType         | String        | png     | 鐢熸垚鏂囦欢鐨勭被鍨嬶紝鍙敮鎸� 'jpg' 鎴� 'png'銆傞粯璁や负 'png' |
+| delay            | Number        | 1000    | 鍥剧墖浠庣粯鍒跺埌鐢熸垚鎵�闇�鏃堕棿锛屽崟浣峬s<br>寰俊灏忕▼搴忓钩鍙颁娇鐢� `Canvas 2D` 缁樺埗鏃舵湁鏁�<br>濡傜粯鍒跺ぇ鍥炬垨鍑虹幇瑁佸壀鍥剧墖绌虹櫧绛夋儏鍐靛簲閫傚綋璋冨ぇ璇ュ�硷紝鍥� `Canvas 2d` 閲囩敤鍚屾缁樺埗锛岄渶鑷繁鎶婃帶缁樺埗瀹屾垚鏃堕棿 |
+| navigation       | Boolean       | true    | 椤甸潰鏄惁鏄師鐢熸爣棰樻爮锛�<br>H5骞冲彴褰� showAngle 涓� true 鏃讹紝浣跨敤鎻掍欢鐨勯〉闈㈠湪 `page.json` 涓厤缃簡 `"navigationStyle": "custom"` 鏃讹紝蹇呴』灏嗘鍊艰涓� false 锛屽惁鍒欏洓涓彲鎷変几瑙掔殑瑙﹀彂浣嶇疆浼氭湁鍋忓樊銆�<br>娉細鍥燞5骞冲彴鐨勭獥鍙i珮搴︽槸鍖呭惈鏍囬鏍忕殑锛岃�屽睆骞曡Е鎽哥偣鐨勫潗鏍囨槸涓嶅寘鍚殑 |
+| @crop    	       | EventHandle   |         | 鍓瀹屾垚鍚庤Е鍙戯紝event = { tempFilePath }銆傚湪H5骞冲彴涓嬶紝tempFilePath 涓� base64 |
+
+### 鍩烘湰鐢ㄦ硶
+```
+<template>
+	<div>
+		<qf-image-cropper :width="500" :height="500" :radius="30" @crop="handleCrop"></qf-image-cropper>
+	</div>
+</template>
+
+<script>
+	import QfImageCropper from '@/components/qf-image-cropper/qf-image-cropper.vue';
+	export default {
+		components: {
+			QfImageCropper
+		},
+		methods: {
+			handleCrop(e) {
+				uni.previewImage({
+					urls: [e.tempFilePath],
+					current: 0
+				});
+			}
+ 		}
+	}
+</script>
+```
+### 浣跨敤璇存槑
+1.寤鸿鍦╜pages.json`涓皢寮曠敤鎻掍欢鐨勯〉闈㈡坊鍔犱竴涓嬮厤缃姝笅鎷夊埛鏂板拰绂佹椤甸潰婊戝姩锛岄槻姝㈠嚭鐜版�ц兘鎴栭〉闈㈡姈鍔ㄧ瓑闂銆�
+```
+{
+	"enablePullDownRefresh": false,
+	"disableScroll": true
+}
+```
+2.寤鸿浣跨敤鏈彃浠朵笉瑕佽缃繃澶у楂樼殑鐩爣鍥剧墖灏哄锛屽缓璁�1365x1365浠ュ唴锛屽惁鍒欏彲鑳戒細瀵艰嚧濡備笅闂锛�
+```
+1.鐣岄潰鍗¢】锛屽唴瀛樺崰鐢ㄨ繃楂�
+2.鐢熸垚鍥剧墖澶辩湡锛堟ā绯婏級
+3.纭畾瑁佸壀鍚庝竴鐩存樉绀� `瑁佸壀涓�...`锛岃闂鏄敱 `uni.canvasToTempFilePath` 鏃犳硶鍥炶皟瀵艰嚧锛屼笉鍚屽钩鍙颁笉鍚岃澶囬檺鍒跺彲鑳芥湁鎵�涓嶅悓銆�
+```
+3.濡傝鍓悗鐨勫浘鐗囧瓨鍦ㄥ亸绉荤殑闂锛岃妫�鏌ユ槸鍚﹀彈鑷繁椤圭洰涓埗缁勪欢鎴栧叏灞�鏍峰紡褰卞搷銆�
+4.src灞炴�ц缃綉缁滃浘鐗囨椂锛屽浘鐗囪祫婧愬繀椤绘槸鑳借Е鍙� `getImageInfo` API 鐨� success 鍥炶皟鎵嶅彲鐢ㄤ簬鎻掍欢瑁佸壀銆傚洜姝ゅ皬绋嬪簭骞冲彴鑾峰彇缃戠粶鍥剧墖淇℃伅闇�鍏堥厤缃甦ownload鍩熷悕鐧藉悕鍗曟墠鑳界敓鏁堛��
\ No newline at end of file

--
Gitblit v1.9.3