소스 검색

ADD 小程序添加二维码生成组件

Yue 2 년 전
부모
커밋
c6e834f7ec

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 29 - 0
UI/XYH.APP/src/components/vber/qrcode/vb-qrcode.vue


+ 1 - 0
UI/XYH.APP/src/core/uQrcode/cache.js

@@ -0,0 +1 @@
+export const cacheImageList = [];

+ 41 - 0
UI/XYH.APP/src/core/uQrcode/queue.js

@@ -0,0 +1,41 @@
+function Queue() {
+  let waitingQueue = (this.waitingQueue = [])
+  let isRunning = (this.isRunning = false) // 记录是否有未完成的任务
+
+  function execute(task, resolve, reject) {
+    task()
+      .then((data) => {
+        resolve(data)
+      })
+      .catch((e) => {
+        reject(e)
+      })
+      .finally(() => {
+        // 等待任务队列中如果有任务,则触发它;否则设置isRunning = false,表示无任务状态
+        if (waitingQueue.length) {
+          const next = waitingQueue.shift()
+          execute(next.task, next.resolve, next.reject)
+        } else {
+          isRunning = false
+        }
+      })
+  }
+  this.exec = function (task) {
+    return new Promise((resolve, reject) => {
+      if (isRunning) {
+        waitingQueue.push({
+          task,
+          resolve,
+          reject,
+        })
+      } else {
+        isRunning = true
+        execute(task, resolve, reject)
+      }
+    })
+  }
+}
+
+/* 队列实例,某些平台一起使用多个组件时需要通过队列逐一绘制,否则部分绘制方法异常,nvue端的iOS gcanvas尤其明显,在不通过队列绘制时会出现图片丢失的情况 */
+export const queueDraw = new Queue()
+export const queueLoadImage = new Queue()

+ 3 - 0
UI/XYH.APP/src/core/uQrcode/types/cache.d.ts

@@ -0,0 +1,3 @@
+declare module '*/common/cache' {
+  export const cacheImageList: Array;
+}

+ 4 - 0
UI/XYH.APP/src/core/uQrcode/types/queue.d.ts

@@ -0,0 +1,4 @@
+declare module '*/common/queue' {
+  export const queueDraw: any;
+  export const queueLoadImage: any;
+}

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 33 - 0
UI/XYH.APP/src/core/uQrcode/uqrcode.js


+ 80 - 5
UI/XYH.APP/src/pages-sub/activity/detail.vue

@@ -1,12 +1,12 @@
 <template>
   <view v-if="ready" class="page-container pb-100px">
     <view
-      v-if="isUser"
+      v-if="isAuthor"
       @click="onApplyAudit"
       class="pos-f h-40px text-white ps-15 pe-10 fs-18"
       style="bottom: 40%; right: 0; border-radius: 30px 0 0 30px; background: rgba(14, 148, 137, 0.9); z-index: 1000"
     >
-      <view v-if="isUser" class="h-100 d-fc">
+      <view v-if="isAuthor" class="h-100 d-fc">
         <i class="iconfont icon-add-user fs-26 me-3"></i>
         <text class="">报名审核</text>
       </view>
@@ -124,7 +124,9 @@
         >
           报名结束
         </vb-button>
-        <vb-button v-else-if="isUser" @click="onApplyAudit" :block="false" custom-class=" w-120px">报名审核</vb-button>
+        <vb-button v-else-if="isAuthor" @click="onApplyAudit" :block="false" custom-class=" w-120px">
+          报名审核
+        </vb-button>
         <template v-else>
           <vb-button v-if="myApply.auditStatus == undefined" :block="false" custom-class="w-120px" @click="onApply">
             马上报名
@@ -167,6 +169,48 @@
         <view class="text-gray-6" v-else>暂无报名</view>
       </view>
     </vb-cell-group>
+    <vb-cell-group v-if="isAuthor && !isClose && activity.auditStatus == '1'">
+      <view class="d-fcv py-15">
+        <view class="bg-warning text-white w-100 text-center py-8 br-8 mx-10" @click="onGenQrcode('AD')">
+          报名二维码
+        </view>
+        <view class="bg-success text-white w-100 text-center py-8 br-8 mx-10" @click="onGenQrcode('AA')">
+          签到二维码
+        </view>
+      </view>
+      <view v-if="showQrCodeBox" class="d-fc flex-column w-100 p-20 pt-5">
+        <view class="text-danger mb-10">
+          活动
+          <text class="font-bold">{{ qrType == "AD" ? "报名" : "签到" }}</text>
+          二维码
+        </view>
+        <vb-qrcode
+          ref="qrcodeRef"
+          :canvas-id="qrcode.id"
+          :value="qrcode.value"
+          :size="qrcode.size"
+          :options="{
+            margin: 20,
+            backgroundPadding: 10,
+            areaColor: '#f2f2f2',
+            foregroundColor: '#0e9489',
+            foregroundImageSrc: qrcode.logo,
+            // foregroundImageWidth: 50,
+            // foregroundImageHeight: 50,
+            // foregroundImagePadding: 1,
+            // foregroundImageBackgroundColor: '#f5f5f5',
+            foregroundImageBorderRadius: qrcode.size / 4,
+          }"
+        ></vb-qrcode>
+        <view class="mt-15 bg-vb text-white w-100 text-center py-8 br-8" @click="onSaveQrcode">保存二维码</view>
+        <view
+          class="mt-15 bg-gray-1 text-vb border border-1 border-vb w-100 text-center py-8 br-8"
+          @click="showQrCodeBox = false"
+        >
+          关闭二维码
+        </view>
+      </view>
+    </vb-cell-group>
     <Comment :source-id="activityId" source-type="activity"></Comment>
   </view>
   <view v-else class="d-fc h-200px bg-tran">
@@ -182,6 +226,7 @@ import configs from "@/core/config"
 import appStore from "@/stores"
 import Comment from "@/components/comment.vue"
 
+const qrcodeRef = ref()
 const activity = ref<any>({})
 const ready = ref(false)
 const myApply = ref<any>({ auditStatus: undefined })
@@ -190,11 +235,22 @@ const applyAvatars = ref<any[]>([])
 //const commentCount = ref(0)
 const params = route.getRouteParams("activityDetail")
 const activityId = ref(params.id)
-
+const qrType = ref("AD")
+const qrLogo = ref("/static/logos/yz_logo.png")
+const qrSize = ref(300)
+const showQrCodeBox = ref(false)
+const qrcode = computed(() => {
+  return {
+    id: qrType.value + activityId.value,
+    value: qrType.value + "@" + activityId.value,
+    size: qrSize.value,
+    logo: qrLogo.value,
+  }
+})
 function formatDate(date: any, format = "YYYY-MM-DD") {
   return dayjs(new Date(date)).format(format)
 }
-const isUser = computed(() => {
+const isAuthor = computed(() => {
   return activity.value.createBy == appStore.authStore.getUser().userName
 })
 
@@ -254,6 +310,25 @@ function onApplyList() {
 function onApplyAudit() {
   route.navigate("activityApplyAudit", params)
 }
+function onGenQrcode(type: string) {
+  if (qrType.value == type) {
+    showQrCodeBox.value = true
+
+    return
+  }
+  showQrCodeBox.value = false
+  nextTick(() => {
+    qrType.value = type
+    showQrCodeBox.value = true
+  })
+}
+function onSaveQrcode() {
+  qrcodeRef.value.save({
+    success: () => {
+      message.msgSuccess("保存成功")
+    },
+  })
+}
 
 function loadData() {
   // 加载活动信息

+ 139 - 24
UI/XYH.APP/src/pages-sub/activity/edit.vue

@@ -1,9 +1,69 @@
 <template>
   <view class="page-container">
-    <view v-if="activityId">
-      <view class="text-center text-danger mb-5" v-if="form.isClose == 1">活动已关闭</view>
-      <view class="text-center text-danger mb-5" v-else-if="form.auditStatus == 2">活动未通过审核,修改后重新发布</view>
+    <view v-if="activityId" class="mb-15">
+      <view class="text-center text-danger" v-if="form.isClose == 1">活动已关闭</view>
+      <view class="text-center text-danger" v-else-if="form.auditStatus == 2">活动未通过审核,修改后重新发布</view>
+      <view class="text-center text-vb font-bold" v-else-if="form.auditStatus == 1">活动报名中</view>
     </view>
+    <vb-cell-group v-if="form.isClose != 1 && form.auditStatus == '1'">
+      <view class="d-fcv py-15">
+        <view class="bg-warning text-white w-100 text-center py-8 br-8 mx-10" @click="onGenQrcode('AD')">
+          报名二维码
+        </view>
+        <view class="bg-success text-white w-100 text-center py-8 br-8 mx-10" @click="onGenQrcode('AA')">
+          签到二维码
+        </view>
+      </view>
+      <view v-if="showQrCodeBox" class="d-fc flex-column w-100 p-20 pt-5">
+        <view class="text-danger mb-10">
+          活动
+          <text class="font-bold">{{ qrType == "AD" ? "报名" : "签到" }}</text>
+          二维码
+        </view>
+        <vb-qrcode
+          ref="qrcodeRef"
+          :canvas-id="qrcode.id"
+          :value="qrcode.value"
+          :size="qrcode.size"
+          :options="{
+            margin: 20,
+            backgroundPadding: 10,
+            areaColor: '#f2f2f2',
+            foregroundColor: '#0e9489',
+            foregroundImageSrc: qrcode.logo,
+            // foregroundImageWidth: 50,
+            // foregroundImageHeight: 50,
+            // foregroundImagePadding: 1,
+            // foregroundImageBackgroundColor: '#f5f5f5',
+            foregroundImageBorderRadius: qrcode.size / 4,
+          }"
+        ></vb-qrcode>
+        <view class="mt-15 bg-vb text-white w-100 text-center py-8 br-8" @click="onSaveQrcode">保存二维码</view>
+        <view
+          class="mt-15 bg-gray-1 text-vb border border-1 border-vb w-100 text-center py-8 br-8"
+          @click="showQrCodeBox = false"
+        >
+          关闭二维码
+        </view>
+      </view>
+      <view class="d-fcv pb-15">
+        <view
+          v-if="form.auditStatus == 1"
+          class="w-100 bg-vb text-white text-center py-8 br-8 mx-10"
+          @click="onApplyAudit"
+        >
+          报名审核
+        </view>
+        <view
+          type="danger"
+          v-if="form.isClose && form.isClose != 1"
+          class="w-100 bg-danger text-white text-center py-8 br-8 mx-10"
+          @click="onCloseActivity"
+        >
+          关闭活动
+        </view>
+      </view>
+    </vb-cell-group>
     <uni-forms :modelValue="form" ref="formRef" :label-width="75" label-align="right" border validate-trigger="bind">
       <vb-cell-group outset>
         <uni-forms-item
@@ -12,7 +72,13 @@
           name="title"
           :rules="[{ required: true, errorMessage: '请填写活动标题' }]"
         >
-          <uni-easyinput type="text" v-model="form.title" :inputBorder="false" placeholder="请输入活动标题" />
+          <uni-easyinput
+            type="text"
+            v-model="form.title"
+            :disabled="disabled"
+            :inputBorder="false"
+            placeholder="请输入活动标题"
+          />
         </uni-forms-item>
         <uni-forms-item
           required
@@ -20,13 +86,19 @@
           name="category"
           :rules="[{ required: true, errorMessage: '请选择活动分类' }]"
         >
-          <vb-picker v-model="form.category" :columns="categoryColumns" label="活动分类"></vb-picker>
+          <vb-picker
+            v-model="form.category"
+            :disabled="disabled"
+            :columns="categoryColumns"
+            label="活动分类"
+          ></vb-picker>
         </uni-forms-item>
         <uni-forms-item required label="人数上限" name="peopleMax">
           <uni-easyinput
             type="number"
             v-model="form.peopleMax"
             :inputBorder="false"
+            :disabled="disabled"
             :rules="[{ required: true, errorMessage: '请填写活动填写' }]"
             placeholder="请输入活动人数上限"
           />
@@ -35,6 +107,7 @@
           <uni-easyinput
             type="text"
             v-model="form.contact"
+            :disabled="disabled"
             :inputBorder="false"
             :rules="[{ required: true, errorMessage: '请填写联系方式' }]"
             placeholder="请输入联系方式"
@@ -44,6 +117,7 @@
           <uni-datetime-picker
             type="date"
             v-model="form.activityDate"
+            :disabled="disabled"
             :start="dateStart"
             :end="dateEnd"
             :border="false"
@@ -55,6 +129,7 @@
           <uni-datetime-picker
             type="date"
             v-model="form.expiryDate"
+            :disabled="disabled"
             :start="dateStart"
             :end="dateEnd"
             :border="false"
@@ -68,10 +143,21 @@
           name="area"
           :rules="[{ required: true, errorMessage: '请选择活动方式' }]"
         >
-          <vb-picker v-model="form.area" :columns="activityAreaColumns" label="活动方式"></vb-picker>
+          <vb-picker
+            v-model="form.area"
+            :disabled="disabled"
+            :columns="activityAreaColumns"
+            label="活动方式"
+          ></vb-picker>
         </uni-forms-item>
         <uni-forms-item v-if="form.area == '线下活动'" label="详细地点" name="address">
-          <uni-easyinput type="text" v-model="form.address" :inputBorder="false" placeholder="请填写详细地点" />
+          <uni-easyinput
+            type="text"
+            :disabled="disabled"
+            v-model="form.address"
+            :inputBorder="false"
+            placeholder="请填写详细地点"
+          />
         </uni-forms-item>
         <uni-forms-item
           required
@@ -85,6 +171,7 @@
               { value: '0', text: '不需要缴费' },
               { value: '1', text: '需要缴费(填写费用说明)' },
             ]"
+            :disabled="disabled"
             selectedColor="var(--vb-color)"
             selectedTextColor="var(--vb-color)"
           ></uni-data-checkbox>
@@ -94,6 +181,7 @@
             type="textarea"
             v-model="form.cost"
             :inputBorder="false"
+            :disabled="disabled"
             autoHeight
             placeholder="请填写费用说明"
           />
@@ -103,6 +191,7 @@
             type="textarea"
             v-model="form.content"
             :inputBorder="false"
+            :disabled="disabled"
             autoHeight
             placeholder="请填写活动详情"
           />
@@ -112,6 +201,8 @@
             ref="imageUploadRef"
             v-model="imageList"
             fileMediatype="image"
+            :disabled="disabled"
+            :del-icon="!disabled"
             mode="grid"
             limit="8"
             title="上传图片"
@@ -128,23 +219,6 @@
         </vb-button>
       </vb-cell-group>
     </uni-forms>
-    <view class="d-flex mb-15">
-      <view
-        v-if="form.auditStatus == 1"
-        class="w-100 bg-vb text-white text-center py-8 br-5 mx-5"
-        @click="onApplyAudit"
-      >
-        报名审核
-      </view>
-      <view
-        type="danger"
-        v-if="form.isClose && form.isClose != 1"
-        class="w-100 bg-danger text-white text-center py-8 br-5 mx-5"
-        @click="onCloseActivity"
-      >
-        关闭活动
-      </view>
-    </view>
   </view>
 </template>
 
@@ -155,6 +229,7 @@ import route from "@/route"
 import configs from "@/core/config"
 
 const imageUploadRef = ref()
+const qrcodeRef = ref()
 
 const form = ref<any>({
   activityId: "",
@@ -171,6 +246,7 @@ const form = ref<any>({
   address: "",
   images: "",
 })
+
 const params = route.getRouteParams("activityEdit")
 const activityId = ref(params?.id)
 const categoryColumns = ref<any[]>([])
@@ -181,12 +257,33 @@ const activityAreaColumns = computed(() => {
   ]
 })
 const imageList = ref<any[]>([])
+const disabled = computed(() => {
+  return form.value.isClose == 1 || form.value.auditStatus == 1
+})
+
 const dateStart = computed(() => {
   return dayjs(new Date()).format("YYYY-MM-DD")
 })
 const dateEnd = computed(() => {
   return dayjs(new Date()).add(6, "M").format("YYYY-MM-DD")
 })
+
+const qrType = ref("AD")
+const qrLogo = ref("/static/logos/yz_logo.png")
+const qrSize = ref(300)
+const showQrCodeBox = ref(false)
+const qrcode = computed(() => {
+  return {
+    id: qrType.value + activityId.value,
+    value: qrType.value + "@" + activityId.value,
+    size: qrSize.value,
+    logo: qrLogo.value,
+  }
+})
+// function formatDate(date: any, format = "YYYY-MM-DD") {
+//   return dayjs(new Date(date)).format(format)
+// }
+
 function onApplyAudit() {
   route.navigate("activityApplyAudit", params)
 }
@@ -239,7 +336,25 @@ function onSubmit() {
     }, 1500)
   })
 }
+function onGenQrcode(type: string) {
+  if (qrType.value == type) {
+    showQrCodeBox.value = true
 
+    return
+  }
+  showQrCodeBox.value = false
+  nextTick(() => {
+    qrType.value = type
+    showQrCodeBox.value = true
+  })
+}
+function onSaveQrcode() {
+  qrcodeRef.value.save({
+    success: () => {
+      message.msgSuccess("保存成功")
+    },
+  })
+}
 function loadCategory() {
   apis.system.categoryApi.getActivityCategory().then((res) => {
     categoryColumns.value = []

+ 21 - 2
UI/XYH.APP/src/pages-sub/help/edit.vue

@@ -12,7 +12,13 @@
           name="title"
           :rules="[{ required: true, errorMessage: '请填写互助标题' }]"
         >
-          <uni-easyinput type="text" v-model="form.title" :inputBorder="false" placeholder="请输入互助标题" />
+          <uni-easyinput
+            type="text"
+            v-model="form.title"
+            :disabled="disabled"
+            :inputBorder="false"
+            placeholder="请输入互助标题"
+          />
         </uni-forms-item>
         <uni-forms-item
           required
@@ -20,7 +26,12 @@
           name="category"
           :rules="[{ required: true, errorMessage: '请选择互助分类' }]"
         >
-          <vb-picker v-model="form.category" :columns="categoryColumns" label="互助分类"></vb-picker>
+          <vb-picker
+            v-model="form.category"
+            :disabled="disabled"
+            :columns="categoryColumns"
+            label="互助分类"
+          ></vb-picker>
         </uni-forms-item>
 
         <!-- <uni-forms-item required label="联系方式" name="contact">
@@ -37,6 +48,7 @@
           <uni-datetime-picker
             type="date"
             v-model="form.expiryDate"
+            :disabled="disabled"
             :start="dateStart"
             :end="dateEnd"
             :border="false"
@@ -53,6 +65,7 @@
           <vb-picker-m
             v-model="area"
             isCascade
+            :disabled="disabled"
             :columns="areaColumns"
             label="有效区域"
             @confirm="onAreaConfirm"
@@ -63,6 +76,7 @@
           <uni-easyinput
             type="textarea"
             v-model="form.content"
+            :disabled="disabled"
             :inputBorder="false"
             autoHeight
             placeholder="请填写互助详情"
@@ -73,6 +87,8 @@
             ref="imageUploadRef"
             v-model="imageList"
             fileMediatype="image"
+            :disabled="disabled"
+            :del-icon="!disabled"
             mode="grid"
             limit="8"
             title="上传图片"
@@ -127,6 +143,9 @@ const categoryColumns = ref<any[]>([])
 const areaColumns = [useCascaderAreaData(true)]
 
 const imageList = ref<any[]>([])
+const disabled = computed(() => {
+  return form.value.isClose == 1 || form.value.auditStatus == 1
+})
 const dateStart = computed(() => {
   return dayjs(new Date()).format("YYYY-MM-DD")
 })

이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.