This commit is contained in:
全栈小学生 2025-04-19 10:41:41 +08:00
parent a602c4645b
commit 3fe60374bc
32 changed files with 1196 additions and 331 deletions

View File

@ -29,7 +29,9 @@
<view v-if="diyComponent.search.style == 'style-2'" class="diy-search-wrap style-2 relative z-10" @click="diyStore.toRedirect(diyComponent.search.link)">
<view class="flex items-center" :style="navbarInnerStyle">
<view class="img-wrap" v-if="diyComponent.search.logo"><image :src="img(diyComponent.search.logo)" mode="aspectFit" /></view>
<view :style="searchSubTitleCss" class="text-[24rpx] h-[38rpx] flex items-center px-[12rpx] rounded-r-[20rpx] rounded-t-[20rpx] rounded-bl-[2rpx]" v-if="diyComponent.search.subTitle.text">{{ diyComponent.search.subTitle.text }}</view>
<view :style="searchSubTitleCss" class="max-w-[360rpx] text-[24rpx] h-[38rpx] rounded-r-[20rpx] rounded-t-[20rpx] rounded-bl-[2rpx]" v-if="diyComponent.search.subTitle.text">
<view class="truncate leading-[38rpx] h-[38rpx] px-[12rpx]">{{ diyComponent.search.subTitle.text }}</view>
</view>
</view>
<view class="flex items-center w-full mt-[16rpx]">
<view @click.stop="locationVal.reposition()" v-if="systemStore.diyAddressInfo" :style="{color: diyComponent.search.positionColor}" class="mr-[30rpx]">

View File

@ -1,15 +1,66 @@
<template>
<view :style="warpCss">
表单 地址组件
<view class="relative">
<view class="p-[10rpx] flex items-center ">
<view class="w-[27%] mr-[10rpx] flex items-center">
<text class="text-overflow-ellipsis" :style="{'color': diyComponent.textColor,'font-size': (diyComponent.fontSize * 2) + 'rpx' ,'font-weight': diyComponent.fontWeight}">{{ diyComponent.field.name }}</text>
<text class="text-[#ec0003]">{{ diyComponent.field.required ? '*' : '' }}</text>
</view>
</view>
</view>
<view v-if="diyComponent.viewFormDetail" class="form-item-frame">
<view class="base-layout-one" v-if="diyGlobal.completeLayout == 'style-1'">
<view class="detail-one-content">
<text class="detail-one-content-label">{{ diyComponent.field.name }}</text>
<text class="detail-one-content-value">{{ diyComponent.field.value }}</text>
</view>
</view>
<view class="base-layout-two" v-if="diyGlobal.completeLayout == 'style-2'">
<view class="detail-two-content">
<view>{{ diyComponent.field.name }}</view>
<view class="detail-two-content-value w-[80%]">{{ diyComponent.field.value }}</view>
</view>
</view>
</view>
<view v-else :style="warpCss" class="form-item-frame">
<view class="base-layout-one" v-if="diyGlobal.completeLayout == 'style-1'">
<view class="layout-one-label">
<text class="text-overflow-ellipsis" :style="{'color': diyComponent.textColor,'font-size': (diyComponent.fontSize * 2) + 'rpx' ,'font-weight': diyComponent.fontWeight}">{{ diyComponent.field.name }}</text>
<text class="required">{{ diyComponent.field.required ? '*' : '' }}</text>
<text v-if="diyStore.mode == 'decorate' && diyComponent.isHidden" class="is-hidden">{{ t('diyForm.hidden') }}</text>
</view>
<view v-if="diyComponent.field.remark.text" class="layout-one-remark" :style="{ color: diyComponent.field.remark.color, fontSize: (diyComponent.field.remark.fontSize * 2 ) + 'rpx' }">{{ diyComponent.field.remark.text }}</view>
<view class="layout-one-error-message" v-if="errorInfo && !errorInfo.code">{{ errorInfo.message }}</view>
<view class="flex layout-one-content justify-between items-center">
<input type="text" class="flex-1" :placeholder="inputPlaceholder"
placeholderClass="layout-one-input-placeholder"
:placeholder-style="{'font-size': (diyComponent.fontSize * 2) + 'rpx' }"
:style="{'color': diyComponent.textColor,'font-size': (diyComponent.fontSize * 2) + 'rpx'}"
v-model="diyComponent.field.value" :disabled="isDisabled" @click="selectArea" />
<view class="text-[var(--primary-color)]" v-if="diyComponent.field.value" @click="reset">
清除
</view>
</view>
<textarea v-if="diyComponent.addressFormat=='province/city/district/address'" type="textarea" class="layout-one-content mt-2 w-full" placeholderClass="layout-one-input-placeholder" :placeholder-style="{'font-size': (diyComponent.fontSize * 2) + 'rpx' }" placeholder="详细地址(如小区门牌号)" :disabled="isDisabled"></textarea>
<view class="layout-one-attribute-wrap" v-if="inputAttribute().length">
<view v-for="(item,index) in inputAttribute()" :key="index" @click="eventFn(item.type)" class="layout-one-attribute-item">{{ item.title }}</view>
</view>
</view>
<view class="base-layout-two" v-if="diyGlobal.completeLayout == 'style-2'">
<text v-if="diyStore.mode == 'decorate' && diyComponent.isHidden" class="layout-two-is-hidden">{{ t('diyForm.hidden') }}</text>
<view class="layout-two-wrap" :class="{'no-border': !diyGlobal.borderControl}">
<view class="layout-two-label" :class="{'justify-start': diyGlobal.completeAlign == 'left', 'justify-end': diyGlobal.completeAlign == 'right'}">
<text class="required" v-if="diyComponent.field.required">{{ diyComponent.field.required ? '*' : '' }}</text>
<text class="name" :style="{'color': diyComponent.textColor,'font-size': (diyComponent.fontSize * 2) + 'rpx' ,'font-weight': diyComponent.fontWeight}">{{ diyComponent.field.name }}</text>
</view>
<input type="text" class="layout-two-content no-flex" :placeholder="inputPlaceholder"
placeholderClass="layout-two-input-placeholder" @click="selectArea"
:placeholder-style="{'font-size': (diyComponent.fontSize * 2) + 'rpx'}"
:style="{'color': diyComponent.textColor,'font-size': (diyComponent.fontSize * 2) + 'rpx'}"
v-model="diyComponent.field.value" :disabled="isDisabled" />
</view>
<textarea v-if="diyComponent.addressFormat=='province/city/district/address'" type="textarea" class="layout-one-content p-2 mt-2 w-full" placeholderClass="layout-one-input-placeholder" :placeholder-style="{'font-size': (diyComponent.fontSize * 2) + 'rpx' }" placeholder="详细地址(如小区门牌号)" :disabled="isDisabled"></textarea>
<view class="layout-two-error-message" v-if="errorInfo && !errorInfo.code">{{ errorInfo.message }}</view>
<view v-if="diyComponent.field.remark.text" class="layout-two-remark" :style="{ color: diyComponent.field.remark.color, fontSize: (diyComponent.field.remark.fontSize * 2 ) + 'rpx' }">{{ diyComponent.field.remark.text }}</view>
<view class="layout-two-attribute-wrap" v-if="inputAttribute().length">
<view v-for="(item,index) in inputAttribute()" :key="index" @click="eventFn(item.type)" class="layout-two-attribute-item">{{ item.title }}</view>
</view>
</view>
<view v-if="diyStore.mode == 'decorate'" class="form-item-mask"></view>
</view>
<area-select ref="areaRef" @complete="areaSelectComplete" :area-id="formData.district_id" />
</template>
<script setup lang="ts">
@ -17,10 +68,12 @@
import { ref, computed, watch,onMounted } from 'vue';
import { img } from '@/utils/common';
import useDiyStore from '@/app/stores/diy';
import { t } from '@/locale'
const props = defineProps(['component', 'index','global']);
const diyStore = useDiyStore();
const areaRef = ref()
const errorInfo: any = ref(null);
const isSelectAddress = ref(false)
const diyComponent = computed(() => {
if (diyStore.mode == 'decorate') {
return diyStore.value[props.index];
@ -28,6 +81,39 @@
return props.component;
}
})
const diyGlobal = computed(() => {
return props.global;
})
const formData: any = ref({
id: 0,
name: '',
mobile: '',
province_id: 0,
city_id: 0,
district_id: 0,
lat: '',
lng: '',
address: '',
address_name: '',
full_address: '',
is_default: 0,
area: ''
})
const inputPlaceholder = computed(() => {
let str = '请选择';
if(diyComponent.value.addressFormat=="province/city/district/address"){
str += '省/市/区/街道'
}else if(diyComponent.value.addressFormat=="province/city/district/street"){
str += '省/市/区/街道(镇)'
}else if(diyComponent.value.addressFormat=="province/city/district"){
str += '省/市/区(县)'
}else if(diyComponent.value.addressFormat=="province/city"){
str += '省/市'
}else{
str += '省份'
}
return str;
})
const warpCss = computed(() => {
var style = '';
@ -48,7 +134,18 @@
if (diyComponent.value.bottomRounded) style += 'border-bottom-right-radius:' + diyComponent.value.bottomRounded * 2 + 'rpx;';
return style;
})
const areaSelectComplete = (event: any) => {
if (isSelectAddress.value && (formData.value.province_id == event.province.id || formData.value.city_id != event.city.id || formData.value.district_id != event.district.id)) {
formData.value.lat = '';
formData.value.lng = '';
}
formData.value.province_id = event.province.id || 0
formData.value.city_id = event.city.id || 0
formData.value.district_id = event.district.id || 0
formData.value.area = `${ event.province.name || '' }${ event.city.name || '' }${ event.district.name || '' }`
diyComponent.value.field.value = formData.value.area
isSelectAddress.value = false;
}
onMounted(() => {
refresh();
//
@ -67,18 +164,57 @@
const refresh = ()=> {
}
const selectArea = () => {
isSelectAddress.value = true
areaRef.value.open()
}
// input
const inputAttribute = () => {
let arr = [];
if (diyComponent.value.autofill) {
let obj = {
title: '已自动填充'
};
arr.push(obj);
}
if (diyComponent.value.field.privacyProtection) {
let obj = {
title: '已开启隐私保护',
type: 'privacy'
};
arr.push(obj);
}
arr.forEach((item, index, arr) => {
if (index != (arr.length - 1)) {
let obj = {
title: '|'
};
arr.push(obj);
}
})
return arr;
}
//
const verify = () => {
const res = { code: true, message: '' }
// todo diyComponent.value.field.value
return res;
const res = { code: true, message: '' }
if (diyComponent.value.field.required && diyComponent.value.field.value == '' && diyStore.mode != 'decorate') {
res.code = false
res.message ='111';
}
errorInfo.value = res;
return res;
}
//
const reset = () => {
// todo diyComponent.value.field.value = '';
diyComponent.value.field.value = '';
}
const isDisabled = computed(() => {
return diyStore.mode == 'decorate';
});
defineExpose({
verify,

View File

@ -1,13 +1,39 @@
<template>
<view :style="warpCss">
<view class="relative">
<view class="p-[10rpx] flex items-center ">
<view class="w-[27%] mr-[10rpx] flex items-center">
<text class="text-overflow-ellipsis" :style="{'color': diyComponent.textColor,'font-size': (diyComponent.fontSize * 2) + 'rpx' ,'font-weight': diyComponent.fontWeight}">{{ diyComponent.field.name }}</text>
<text class="text-[#ec0003]">{{ diyComponent.field.required ? '*' : '' }}</text>
</view>
<view :style="warpCss" class="form-item-frame">
<view class="base-layout-one" v-if="diyGlobal.completeLayout == 'style-1'">
<view class="layout-one-label">
<text class="text-overflow-ellipsis" :style="{'color': diyComponent.textColor,'font-size': (diyComponent.fontSize * 2) + 'rpx' ,'font-weight': diyComponent.fontWeight}">{{ diyComponent.field.name }}</text>
<text class="required">{{ diyComponent.field.required ? '*' : '' }}</text>
<text v-if="diyStore.mode == 'decorate' && diyComponent.isHidden" class="is-hidden">{{ t('diyForm.hidden') }}</text>
</view>
<view v-if="diyComponent.field.remark.text" class="layout-one-remark" :style="{ color: diyComponent.field.remark.color, fontSize: (diyComponent.field.remark.fontSize * 2 ) + 'rpx' }">{{ diyComponent.field.remark.text }}</view>
<view class="layout-one-error-message" v-if="errorInfo && !errorInfo.code">{{ errorInfo.message }}</view>
<view class="flex flex-wrap">
<view class="relative w-[180rpx] !h-[180rpx] mr-[16rpx] mb-[16rpx] layout-one-content" v-for="(item,index) in diyComponent.field.value" :key="index">
<image class="w-[100%] h-[100%]" :src="img(item)" mode="aspectFill" />
<view class="absolute top-0 right-[0] bg-[#373737] flex justify-end h-[28rpx] w-[28rpx] rounded-bl-[40rpx]" @click="deleteImage(index)">
<text class="nc-iconfont nc-icon-guanbiV6xx !text-[20rpx] mt-[2rpx] mr-[2rpx] text-[#fff]"></text>
</view>
</view>
<view class="flex items-center flex-1">
<view class="layout-one-content !p-[0] flex-1 !items-stretch !h-[100rpx]">
<view class="flex items-center h-[100%] w-[100%] pl-[30rpx] box-border" @click="selectWeChatFile">
<text class="nc-iconfont nc-icon-weixinV6mm"></text>
<text class="text-[28rpx] ml-[10rpx]">选择微信聊天文件</text>
</view>
</view>
<view class="layout-one-content !p-[0] ml-[20rpx] !items-stretch flex-1 !h-[100rpx]">
<u-upload accept="file " @afterRead="afterRead" multiple :maxCount="9">
<view class="flex items-center h-[100%] w-[100%] pl-[30rpx] box-border">
<text class="nc-iconfont nc-icon-tupiandaohangpc"></text>
<text class="text-[28rpx] ml-[10rpx]">选择本地文件</text>
</view>
</u-upload>
</view>
</view>
</view>
</view>
<view v-if="diyStore.mode == 'decorate'" class="form-item-mask"></view>
</view>
</template>
@ -16,11 +42,11 @@
import { ref, computed, watch,onMounted } from 'vue';
import { img } from '@/utils/common';
import useDiyStore from '@/app/stores/diy';
import { t } from '@/locale'
import { uploadImage } from '@/app/api/system'
const errorInfo: any = ref(null);
const props = defineProps(['component', 'index','global']);
const diyStore = useDiyStore();
const selectValue = ref([])
const diyComponent = computed(() => {
if (diyStore.mode == 'decorate') {
@ -29,6 +55,11 @@
return props.component;
}
})
const diyGlobal = computed(() => {
return props.global;
})
const warpCss = computed(() => {
var style = '';
style += 'position:relative;';
@ -64,28 +95,57 @@
}
});
const imgListPreview = computed(() => {
return selectValue.value.map(item => {
return {url: img(item)}
})
})
// const imgListPreview = computed(() => {
// return selectValue.value.map(item => {
// return {url: img(item)}
// })
// })
//
const selectWeChatFile = () => {
uni.chooseMessageFile({
count: 9, // 9
type: 'all', // 'image', 'video', 'file', 'all'
success: (res) => {
console.log('选择的微信聊天文件:', res.tempFiles);
res.tempFiles.forEach(file => {
uploadImage({
filePath: file.path,
name: 'file'
}).then(uploadRes => {
if (diyComponent.value.field.value.length < Number(diyComponent.value.limit)) {
diyComponent.value.field.value.push(uploadRes.data.url);
}
}).catch(() => {
console.error('上传失败');
});
});
},
fail: (err) => {
console.error('选择文件失败', err);
}
});
};
// &
const afterRead = (event) => {
event.file.forEach(item => {
uploadImage({
filePath: item.url,
name: 'file'
}).then(res => {
if (selectValue.value.length < diyComponent.value.limit ) {
selectValue.value.push(res.data.url)
}
}).catch(() => {
})
})
}
event.file.forEach(item => {
uploadImage({
filePath: item.url,
name: 'file'
}).then(res => {
if (diyComponent.value.field.value.length < Number(diyComponent.value.limit)) {
diyComponent.value.field.value.push(res.data.url);
}
}).catch(() => {
console.error('上传失败');
});
});
};
const deletePic = (event)=> {
selectValue.value.splice(event.index, 1)
const deleteImage = (event) => {
diyComponent.value.field.value.splice(event.index, 1)
}
const refresh = ()=> {

View File

@ -1,24 +1,87 @@
<template>
<view :style="warpCss">
form-location
<view class="relative">
<view class="p-[10rpx] flex items-center ">
<view class="w-[27%] mr-[10rpx] flex items-center">
<text class="text-overflow-ellipsis" :style="{'color': diyComponent.textColor,'font-size': (diyComponent.fontSize * 2) + 'rpx' ,'font-weight': diyComponent.fontWeight}">{{ diyComponent.field.name }}</text>
<text class="text-[#ec0003]">{{ diyComponent.field.required ? '*' : '' }}</text>
<view :style="warpCss" class="form-item-frame">
<view class="base-layout-one" v-if="diyGlobal.completeLayout == 'style-1'">
<view class="layout-one-label">
<text class="text-overflow-ellipsis"
:style="{'color': diyComponent.textColor,'font-size': (diyComponent.fontSize * 2) + 'rpx' ,'font-weight': diyComponent.fontWeight}">{{ diyComponent.field.name }}</text>
<text class="required">{{ diyComponent.field.required ? '*' : '' }}</text>
<text v-if="diyStore.mode == 'decorate' && diyComponent.isHidden"
class="is-hidden">{{ t('diyForm.hidden') }}</text>
</view>
<view v-if="diyComponent.field.remark.text" class="layout-one-remark"
:style="{ color: diyComponent.field.remark.color, fontSize: (diyComponent.field.remark.fontSize * 2 ) + 'rpx' }">
{{ diyComponent.field.remark.text }}</view>
<view class="layout-one-error-message" v-if="errorInfo && !errorInfo.code">{{ errorInfo.message }}</view>
<view v-if="diyComponent.mode== 'authorized_wechat_location'">
<view @click.stop="locationVal.reposition()" v-if="systemStore.diyAddressInfo" class="layout-one-content">
<!-- <view class="flex items-baseline font-500">
<text class="text-[24rpx] mr-[2rpx]">{{ systemStore.diyAddressInfo.city }}</text>
<text class="iconfont iconxiaV6xx !text-[24rpx]"></text>
</view> -->
<text class="iconfont iconzuobiaofill !text-[28rpx]"></text>
<view
v-if="systemStore.diyAddressInfo.community">{{ systemStore.diyAddressInfo.community }}</view>
</view>
<view @click.stop="locationVal.reposition()" class="layout-one-content"
v-else>
<text class="iconfont iconzuobiaofill !text-[28rpx]"></text>
<text class="ml-1 text-[#999]">点击获取位置信息</text>
</view>
</view>
<view v-else>
<view @click.stop="locationVal.reposition()" v-if="systemStore.diyAddressInfo" class="layout-one-content">
<view class="flex items-baseline font-500">
<text class="text-[24rpx] mr-[2rpx]">{{ systemStore.diyAddressInfo.city }}</text>
<text class="iconfont iconxiaV6xx !text-[24rpx]"></text>
</view>
<view class="layout-one-content"
v-if="systemStore.diyAddressInfo.community">{{ systemStore.diyAddressInfo.community }}</view>
</view>
<view @click.stop="locationVal.reposition()" class="layout-one-content"
v-else>
<text class="iconfont iconzuobiaofill !text-[28rpx]"></text>
<text class="ml-1 text-[#999]">选择位置</text>
</view>
<view class="text-[var(--primary-color)] mt-1">
当前定位
</view>
</view>
<!-- <input type="text" class="layout-one-content" :placeholder=""
placeholderClass="layout-one-input-placeholder"
:placeholder-style="{'font-size': (diyComponent.fontSize * 2) + 'rpx' }"
:style="{'color': diyComponent.textColor,'font-size': (diyComponent.fontSize * 2) + 'rpx'}"
v-model="diyComponent.field.value" :disabled="isDisabled" /> -->
<!-- <view class="layout-one-attribute-wrap" v-if="inputAttribute().length">
<view v-for="(item,index) in inputAttribute()" :key="index" @click="eventFn(item.type)"
class="layout-one-attribute-item">{{ item.title }}</view>
</view> -->
</view>
<!-- <view class="relative">
<view class="p-[10rpx] flex items-center ">
<view class="w-[27%] mr-[10rpx] flex items-center">
<text class="text-overflow-ellipsis"
:style="{'color': diyComponent.textColor,'font-size': (diyComponent.fontSize * 2) + 'rpx' ,'font-weight': diyComponent.fontWeight}">{{ diyComponent.field.name}}</text>
<text class="text-[#ec0003]">{{ diyComponent.field.required ? '*' : '' }}</text>
</view>
</view>
</view> -->
</view>
</template>
<script setup lang="ts">
//
import { ref, computed, watch,onMounted } from 'vue';
import { img } from '@/utils/common';
import { ref, computed, watch, onMounted } from 'vue';
import { img } from '@/utils/common';
import useDiyStore from '@/app/stores/diy';
const props = defineProps(['component', 'index','global']);
import { useLocation } from '@/hooks/useLocation'
import useSystemStore from '@/stores/system';
const errorInfo: any = ref(null);
const systemStore = useSystemStore();
const systemInfo = uni.getSystemInfoSync();
const props = defineProps(['component', 'index', 'global']);
const diyStore = useDiyStore();
const diyComponent = computed(() => {
@ -28,19 +91,34 @@
return props.component;
}
})
const diyGlobal = computed(() => {
return props.global;
})
/************** 定位-start ****************/
let isOpenLocation = false;
if (diyComponent.value && diyStore.mode != 'decorate') {
isOpenLocation = true;
}
const locationVal = useLocation(isOpenLocation);
locationVal.onLoad();
locationVal.init();
/************** 定位-end ****************/
const warpCss = computed(() => {
var style = '';
style += 'position:relative;';
if(diyComponent.value.componentStartBgColor) {
if (diyComponent.value.componentStartBgColor && diyComponent.value.componentEndBgColor) style += `background:linear-gradient(${diyComponent.value.componentGradientAngle},${diyComponent.value.componentStartBgColor},${diyComponent.value.componentEndBgColor});`;
else style += 'background-color:' + diyComponent.value.componentStartBgColor + ';';
}
style += 'position:relative;';
if (diyComponent.value.componentStartBgColor) {
if (diyComponent.value.componentStartBgColor && diyComponent.value.componentEndBgColor) style += `background:linear-gradient(${diyComponent.value.componentGradientAngle},${diyComponent.value.componentStartBgColor},${diyComponent.value.componentEndBgColor});`;
else style += 'background-color:' + diyComponent.value.componentStartBgColor + ';';
}
if(diyComponent.value.componentBgUrl) {
style += `background-image:url('${ img(diyComponent.value.componentBgUrl) }');`;
style += 'background-size: cover;background-repeat: no-repeat;';
}
if (diyComponent.value.componentBgUrl) {
style += `background-image:url('${img(diyComponent.value.componentBgUrl)}');`;
style += 'background-size: cover;background-repeat: no-repeat;';
}
if (diyComponent.value.topRounded) style += 'border-top-left-radius:' + diyComponent.value.topRounded * 2 + 'rpx;';
if (diyComponent.value.topRounded) style += 'border-top-right-radius:' + diyComponent.value.topRounded * 2 + 'rpx;';
@ -49,24 +127,24 @@
return style;
})
onMounted(() => {
refresh();
//
if (diyStore.mode == 'decorate') {
watch(
() => diyComponent.value,
(newValue, oldValue) => {
if (newValue && newValue.componentName == 'FormLocation') {
refresh();
}
}
)
}else{
onMounted(() => {
refresh();
//
if (diyStore.mode == 'decorate') {
watch(
() => diyComponent.value,
(newValue, oldValue) => {
if (newValue && newValue.componentName == 'FormLocation') {
refresh();
}
}
)
} else {
}
});
});
const refresh = ()=> {
}
const refresh = () => {
}
//
const verify = () => {
@ -88,9 +166,10 @@
<style lang="scss" scoped>
@import '@/styles/diy_form.scss';
.text-overflow-ellipsis {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
</style>
</style>

View File

@ -1,26 +1,74 @@
<template>
<view :style="warpCss">
//
<view class="relative">
<view class="p-[10rpx] flex items-center ">
<view :style="warpCss" class="form-item-frame">
<view class="relative base-layout-one">
<view class="p-[10rpx] flex items-center">
<view class="w-[27%] mr-[10rpx] flex items-center">
<text class="text-overflow-ellipsis" :style="{'color': diyComponent.textColor,'font-size': (diyComponent.fontSize * 2) + 'rpx' ,'font-weight': diyComponent.fontWeight}">{{ diyComponent.field.name }}</text>
<text class="text-overflow-ellipsis"
:style="{'color': diyComponent.textColor,'font-size': (diyComponent.fontSize * 2) + 'rpx' ,'font-weight': diyComponent.fontWeight}">{{ diyComponent.field.name }}</text>
<text class="text-[#ec0003]">{{ diyComponent.field.required ? '*' : '' }}</text>
</view>
</view>
</view>
<!-- 下拉弹窗 -->
<u-popup v-for="(column, columnIndex) in diyComponent.columnList" :key="'popup-' + columnIndex"
:show="selectShow[columnIndex]" mode="bottom" @close="selectShow[columnIndex] = false">
<view class="p-[15rpx]">
<scroll-view scroll-y="true" class="max-h-[450rpx] px-[14rpx] box-border">
<u-radio-group v-model="column.value" placement="column" @change="groupChange(columnIndex)"
iconPlacement="right">
<view class="border-solid border-[0] border-b-[2rpx] border-[#e6e6e6] py-[20rpx]"
v-for="(option, optionIndex) in column.options" :key="optionIndex"
@click.stop="pullDownConfirmFn(columnIndex, option)">
<u-radio activeColor="var(--primary-color)" :labelSize="(diyComponent.fontSize * 2) + 'rpx'"
:labelColor="diyComponent.textColor" :style="{'width': '100%'}" :label="option.label"
:name="option.id">
</u-radio>
</view>
</u-radio-group>
</scroll-view>
</view>
</u-popup>
<!-- 修改性别 -->
<u-action-sheet :actions="sexList" :show="sexSheetShow" :closeOnClickOverlay="true"
:safeAreaInsetBottom="true" @close="sexSheetShow = false" @select="updateSex"></u-action-sheet>
<area-select ref="areaRef" @complete="areaSelectComplete" :area-id="formData.district_id" />
<view class="calendar-wrap">
<u-calendar :show="calendarShow" mode="single" @confirm="confirm" @close="calendarShow=false"
closeOnClickOverlay="true" :formatter="formatter" confirmDisabledText="禁止选择"
color="var(--primary-color)" ref="calendar" :maxDate="maxDate"></u-calendar>
<u-datetime-picker :show="show" mode="datetime" @cancel="show=false"
closeOnClickOverlay="true" @confirm="calendarConfirm" @close="show=false"
:minDate="minDate"></u-datetime-picker>
</view>
</view>
</template>
<script setup lang="ts">
//
import { ref, computed, watch,onMounted } from 'vue';
import { ref, computed, watch, onMounted } from 'vue';
import useDiyStore from '@/app/stores/diy';
import { img } from '@/utils/common';
const props = defineProps(['component', 'index','global']);
import { img, timeStampTurnTime, timeTurnTimeStamp } from '@/utils/common';
const props = defineProps(['component', 'index', 'global']);
const diyStore = useDiyStore();
const formData: any = ref({
id: 0,
name: '',
mobile: '',
province_id: 0,
city_id: 0,
district_id: 0,
lat: '',
lng: '',
address: '',
address_name: '',
full_address: '',
is_default: 0,
area: ''
})
const selectShow = ref<Array<boolean>>(Array(10).fill(false)); //
const diyComponent = computed(() => {
if (diyStore.mode == 'decorate') {
return diyStore.value[props.index];
@ -29,18 +77,190 @@
}
})
const isDisabled = computed(() => {
return diyStore.mode === 'decorate';
});
//
const openPicker = (columnIndex : number) => {
if (isDisabled.value) return;
selectShow.value[columnIndex] = true;
};
//
const getSelectRadioName = (columnIndex : number) => {
const column = diyComponent.value.columnList[columnIndex];
if (!column || !column.value) return '';
const selectedOption = column.options.find(opt => opt.id === column.value);
return selectedOption ? selectedOption.label : '';
};
//
const pullDownConfirmFn = (columnIndex : number, option : any) => {
diyComponent.value.columnList[columnIndex].value = option.id;
selectShow.value[columnIndex] = false;
};
//
const groupChange = (columnIndex : number) => {
const column = diyComponent.value.columnList[columnIndex];
if (!column || !column.value) return;
selectShow.value[columnIndex] = false;
};
const currentColumn = ref(null); //
/**
* 性别
*/
const sexSheetShow = ref(false); //
//
const sexList = computed(() => [
{ name: '男', value: 1 },
{ name: '女', value: 2 }
]);
//
const getSexName = (column : any) => {
if (!column || !column.value) return '请选择';
return column.value === 1 ? '男' : column.value === 2 ? '女' : '请选择';
};
//
const openSex = (column : any) => {
if (isDisabled.value) return;
currentColumn.value = column;
sexSheetShow.value = true;
};
//
const updateSex = (e : any) => {
if (currentColumn.value) {
currentColumn.value.value = e.value; // value
}
sexSheetShow.value = false; //
};
//
let currentDate = new Date();
currentDate.setFullYear(currentDate.getFullYear() + 1);
const maxDate = ref(currentDate.getTime());
let currentDateTime = new Date();
const minDate = ref(currentDateTime.getTime());
const calendarShow = ref(false);
const show = ref(false);
//
const startDate = computed(() => {
if (!currentColumn.value || !currentColumn.value.value) {
return diyComponent.value.placeholder || '请选择日期';
}
return getDateFn(currentColumn.value.value, currentColumn.value.dateFormat);
});
const openCalendar = (column : any) => {
if (diyStore.mode === 'decorate') return;
currentColumn.value = column;
if (column.dateFormat == 'YYYY-MM-DD HH:mm') {
show.value = true;
} else {
calendarShow.value = true;
}
};
const confirm = (e : any) => {
if (currentColumn.value) {
currentColumn.value.value = e[0]; // column
}
calendarShow.value = false;
};
const calendarConfirm = (e : any) => {
if (currentColumn.value) {
currentColumn.value.value = e.value; // column
}
show.value = false;
};
const formatter = (day) => {
const time = timeStampTurnTime(Date.parse(day.date) / 1000, "year_month_day");
return day
}
const getDateFn = (data : any = '', type : any) => {
console.log(data,type)
let timestamp = type == 'YYYY-MM-DD HH:mm' ? data : timeTurnTimeStamp(data);
let date = timestamp > 9999999999 ? new Date(timestamp) : new Date(timestamp * 1000);
let year = date.getFullYear();
let month = String(date.getMonth() + 1).padStart(2, '0');
let day = String(date.getDate()).padStart(2, '0');
console.log(year)
const hours = String(date.getHours()).padStart(2, '0');
const minutes = String(date.getMinutes()).padStart(2, '0');
let str = '';
if (type == 'YYYY年M月D日') {
str = `${year}${month}${day}`;
} else if (type == 'YYYY-MM-DD') {
str = `${year}-${month}-${day}`;
} else if (type == 'YYYY/MM/DD') {
str = `${year}/${month}/${day}`;
} else if (type == 'YYYY-MM-DD HH:mm') {
str = `${year}-${month}-${day} ${hours}:${minutes}`;
}
return str;
}
const areaRef = ref()
const isSelectAddress = ref(false)
const selectArea = (column : any) => {
currentColumn.value = column;
isSelectAddress.value = true
areaRef.value.open()
}
const areaSelectComplete = (event: any) => {
if (isSelectAddress.value && (formData.value.province_id == event.province.id || formData.value.city_id != event.city.id || formData.value.district_id != event.district.id)) {
formData.value.lat = '';
formData.value.lng = '';
}
formData.value.province_id = event.province.id || 0
formData.value.city_id = event.city.id || 0
formData.value.district_id = event.district.id || 0
formData.value.area = `${ event.province.name || '' }${ event.city.name || '' }${ event.district.name || '' }`
currentColumn.value.value = formData.value.area
isSelectAddress.value = false;
}
const inputPlaceholder = (column: any) => {
if (!column) return "请选择";
const format = column.addressFormat || "province/city/district";
if (format === "province/city/district/address") return "请选择省/市/区/街道";
if (format === "province/city/district/street") return "请选择省/市/区/街道(镇)";
if (format === "province/city/district") return "请选择省/市/区(县)";
if (format === "province/city") return "请选择省/市";
return "请选择省份";
};
const warpCss = computed(() => {
var style = '';
style += 'position:relative;';
if(diyComponent.value.componentStartBgColor) {
if (diyComponent.value.componentStartBgColor && diyComponent.value.componentEndBgColor) style += `background:linear-gradient(${diyComponent.value.componentGradientAngle},${diyComponent.value.componentStartBgColor},${diyComponent.value.componentEndBgColor});`;
else style += 'background-color:' + diyComponent.value.componentStartBgColor + ';';
}
style += 'position:relative;';
if (diyComponent.value.componentStartBgColor) {
if (diyComponent.value.componentStartBgColor && diyComponent.value.componentEndBgColor) style += `background:linear-gradient(${diyComponent.value.componentGradientAngle},${diyComponent.value.componentStartBgColor},${diyComponent.value.componentEndBgColor});`;
else style += 'background-color:' + diyComponent.value.componentStartBgColor + ';';
}
if(diyComponent.value.componentBgUrl) {
style += `background-image:url('${ img(diyComponent.value.componentBgUrl) }');`;
style += 'background-size: cover;background-repeat: no-repeat;';
}
if (diyComponent.value.componentBgUrl) {
style += `background-image:url('${img(diyComponent.value.componentBgUrl)}');`;
style += 'background-size: cover;background-repeat: no-repeat;';
}
if (diyComponent.value.topRounded) style += 'border-top-left-radius:' + diyComponent.value.topRounded * 2 + 'rpx;';
if (diyComponent.value.topRounded) style += 'border-top-right-radius:' + diyComponent.value.topRounded * 2 + 'rpx;';
@ -49,24 +269,26 @@
return style;
})
onMounted(() => {
refresh();
//
if (diyStore.mode == 'decorate') {
watch(
() => diyComponent.value,
(newValue, oldValue) => {
if (newValue && newValue.componentName == 'FormTable') {
refresh();
}
}
)
}else{
onMounted(() => {
refresh();
//
if (diyStore.mode == 'decorate') {
watch(
() => diyComponent.value,
(newValue, oldValue) => {
if (newValue && newValue.componentName == 'FormTable') {
refresh();
}
}
)
} else {
}
});
const refresh = ()=> {
}
console.log(diyComponent.value)
});
const refresh = () => {
}
//
const verify = () => {
@ -88,9 +310,10 @@
<style lang="scss" scoped>
@import '@/styles/diy_form.scss';
.text-overflow-ellipsis {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
</style>
</style>

View File

@ -1,32 +1,173 @@
<template>
<view :style="warpCss">
form-video
<view class="relative">
<view v-if="diyComponent.viewFormDetail" class="form-item-frame">
<view class="base-layout-one" v-if="diyGlobal.completeLayout == 'style-1'">
<view class="detail-one-content">
<text class="detail-one-content-label">{{ diyComponent.field.name }}</text>
<view class="flex flex-wrap detail-one-content-value pt-[6rpx]">
<view class="relative w-[180rpx] !h-[180rpx] mr-[16rpx] mb-[16rpx] "
v-for="(item,index) in diyComponent.field.value" :key="index">
<image class="w-[100%] h-[100%]" :src="img(item)" @click="handleImg(item,index)"
mode="aspectFill" />
</view>
</view>
</view>
</view>
<view class="base-layout-two" v-if="diyGlobal.completeLayout == 'style-2'">
<view class="detail-two-content">
<text class="detail-two-content-label">{{ diyComponent.field.name }}</text>
<view class="flex flex-wrap w-[80%] justify-end">
<view class="relative w-[180rpx] !h-[180rpx] mr-[16rpx] mb-[16rpx] "
v-for="(item,index) in diyComponent.field.value" :key="index">
<image class="w-[100%] h-[100%]" :src="img(item)" @click="handleImg(item,index)"
mode="aspectFill" />
</view>
</view>
</view>
</view>
</view>
<view v-else :style="warpCss" class="form-item-frame">
<view class="base-layout-one" v-if="diyGlobal.completeLayout == 'style-1'">
<view class="layout-one-label">
<text class="text-overflow-ellipsis"
:style="{'color': diyComponent.textColor,'font-size': (diyComponent.fontSize * 2) + 'rpx' ,'font-weight': diyComponent.fontWeight}">{{ diyComponent.field.name }}</text>
<text class="required">{{ diyComponent.field.required ? '*' : '' }}</text>
<text v-if="diyStore.mode == 'decorate' && diyComponent.isHidden"
class="is-hidden">{{ t('diyForm.hidden') }}</text>
</view>
<view v-if="diyComponent.field.remark.text" class="layout-one-remark"
:style="{ color: diyComponent.field.remark.color, fontSize: (diyComponent.field.remark.fontSize * 2 ) + 'rpx' }">
{{ diyComponent.field.remark.text }}</view>
<view class="layout-one-error-message" v-if="errorInfo && !errorInfo.code">{{ errorInfo.message }}</view>
<view class="flex flex-wrap">
<view class="relative w-[180rpx] !h-[180rpx] mr-[16rpx] mb-[16rpx] layout-one-content"
v-for="(item,index) in diyComponent.field.value" :key="index">
<image class="w-[100%] h-[100%]" :src="img(item)" mode="aspectFill" />
<view
class="absolute top-0 right-[0] bg-[#373737] flex justify-end h-[28rpx] w-[28rpx] rounded-bl-[40rpx]"
@click="deleteImage(index)">
<text
class="nc-iconfont nc-icon-guanbiV6xx !text-[20rpx] mt-[2rpx] mr-[2rpx] text-[#fff]"></text>
</view>
</view>
<!-- <view class="flex items-center flex-1"
v-if="diyComponent.uploadMode.length > 1 && diyComponent.field.value.length <= 0">
<view class="layout-one-content !p-[0] flex-1 !items-stretch !h-[100rpx]">
<u-upload accept="image" @afterRead="afterRead" multiple :maxCount="9" capture="camera">
<view class="flex items-center h-[100%] w-[100%] pl-[30rpx] box-border">
<text class="nc-iconfont nc-icon-xiangjiV6xx"></text>
<text class="text-[28rpx] ml-[10rpx]">拍照上传</text>
</view>
</u-upload>
</view>
<view class="layout-one-content !p-[0] ml-[20rpx] !items-stretch flex-1 !h-[100rpx]">
<u-upload accept="image" @afterRead="afterRead" multiple :maxCount="9" capture="album">
<view class="flex items-center h-[100%] w-[100%] pl-[30rpx] box-border">
<text class="nc-iconfont nc-icon-tupiandaohangpc"></text>
<text class="text-[28rpx] ml-[10rpx]">从相册中选择</text>
</view>
</u-upload>
</view>
</view> -->
<view class="layout-one-content h-[180rpx] w-[180rpx] !px-[0]">
<u-upload accept="image" v-if="diyComponent.uploadMode=='shoot_and_album'" @afterRead="afterRead"
capture="album" :maxCount="1">
<view class="flex flex-col items-center justify-center w-[180rpx] h-[180rpx] ">
<text class="nc-iconfont !text-[36rpx] nc-icon-jiahaoV6xx mb-[16rpx]"></text>
<text class="text-[28rpx] ml-[10rpx] text-[24rpx]">添加视频</text>
</view>
</u-upload>
<u-upload accept="image" v-else @afterRead="afterRead" :maxCount="1" :maxDuration="60" capture="camera">
<view class="flex flex-col items-center justify-center w-[180rpx] h-[180rpx] ">
<text class="nc-iconfont !text-[36rpx] nc-icon-jiahaoV6xx mb-[16rpx]"></text>
<text class="text-[28rpx] ml-[10rpx] text-[24rpx]">拍摄上传</text>
</view>
</u-upload>
</view>
</view>
<view class="layout-one-attribute-wrap" v-if="inputAttribute().length">
<view v-for="(item,index) in inputAttribute()" :key="index" @click="eventFn(item.type)"
class="layout-one-attribute-item">{{ item.title }}</view>
</view>
</view>
<view class="base-layout-two" v-if="diyGlobal.completeLayout == 'style-2'">
<text v-if="diyStore.mode == 'decorate' && diyComponent.isHidden"
class="layout-two-is-hidden">{{ t('diyForm.hidden') }}</text>
<view class="layout-two-wrap" :class="{'no-border': !diyGlobal.borderControl}">
<view class="layout-two-label"
:class="{'justify-start': diyGlobal.completeAlign == 'left', 'justify-end': diyGlobal.completeAlign == 'right'}">
<text class="required"
v-if="diyComponent.field.required">{{ diyComponent.field.required ? '*' : '' }}</text>
<text class="name"
:style="{'color': diyComponent.textColor,'font-size': (diyComponent.fontSize * 2) + 'rpx' ,'font-weight': diyComponent.fontWeight}">{{ diyComponent.field.name }}</text>
</view>
<view class="layout-two-content flex-wrap">
<view
class="relative border-box w-[180rpx] !h-[180rpx] ml-[16rpx] mb-[16rpx] border-box border-[2rpx] border-solid border-[#e6e6e6] rounded-[10rpx] flex items-center"
v-for="(item,index) in diyComponent.field.value" :key="index">
<image class="w-[100%] h-[100%]" :src="img(item)" mode="aspectFill" />
<view
class="absolute top-0 right-[0] bg-[#373737] flex justify-end h-[28rpx] w-[28rpx] rounded-bl-[40rpx]"
@click="deleteImage(index)">
<text
class="nc-iconfont nc-icon-guanbiV6xx !text-[20rpx] mt-[2rpx] mr-[2rpx] text-[#fff]"></text>
</view>
</view>
<view
class="items-start border-box border-[2rpx] ml-[16rpx] mb-[16rpx] border-solid border-[#e6e6e6] rounded-[10rpx]">
<u-upload accept="video" v-if="diyComponent.uploadMode=='shoot_and_album'" @afterRead="afterRead" :maxCount="1"
capture="album" >
<view class="flex flex-col items-center justify-center w-[180rpx] h-[180rpx] ">
<text class="nc-iconfont !text-[36rpx] nc-icon-jiahaoV6xx mb-[16rpx]"></text>
<text class="text-[28rpx] ml-[10rpx] text-[24rpx]">添加视频</text>
</view>
</u-upload>
<u-upload accept="video" v-else @afterRead="afterRead" :maxCount="1" :maxDuration="60" capture="camera">
<view class="flex flex-col items-center justify-center w-[180rpx] h-[180rpx] ">
<text class="nc-iconfont !text-[36rpx] nc-icon-jiahaoV6xx mb-[16rpx]"></text>
<text class="text-[28rpx] ml-[10rpx] text-[24rpx]">拍摄上传</text>
</view>
</u-upload>
</view>
</view>
</view>
<view class="layout-two-error-message" v-if="errorInfo && !errorInfo.code">{{ errorInfo.message }}</view>
<view v-if="diyComponent.field.remark.text" class="layout-two-remark"
:style="{ color: diyComponent.field.remark.color, fontSize: (diyComponent.field.remark.fontSize * 2 ) + 'rpx' }">
{{ diyComponent.field.remark.text }}</view>
<view class="layout-two-attribute-wrap" v-if="inputAttribute().length">
<view v-for="(item,index) in inputAttribute()" :key="index" @click="eventFn(item.type)"
class="layout-two-attribute-item">{{ item.title }}</view>
</view>
</view>
<view v-if="diyStore.mode == 'decorate'" class="form-item-mask"></view>
<!-- <view class="relative">
<view class="p-[10rpx] flex items-center ">
<view class="w-[25%] flex items-center">
<text class="text-overflow-ellipsis" :style="{'color': diyComponent.textColor,'font-size': (diyComponent.fontSize * 2) + 'rpx' ,'font-weight': diyComponent.fontWeight}">{{ diyComponent.field.name }}</text>
<text class="text-overflow-ellipsis"
:style="{'color': diyComponent.textColor,'font-size': (diyComponent.fontSize * 2) + 'rpx' ,'font-weight': diyComponent.fontWeight}">{{ diyComponent.field.name }}</text>
<text class="text-[#ec0003]">{{ diyComponent.field.required ? '*' : '' }}</text>
</view>
<view class="w-[75%] flex justify-center items-center">
<u-upload :fileList="imgListPreview" :disabled="isDisabled" @afterRead="afterRead" @delete="deletePic" multiple :maxCount="diyComponent.limit"/>
<u-upload :fileList="imgListPreview" :disabled="isDisabled" @afterRead="afterRead"
@delete="deletePic" multiple :maxCount="diyComponent.limit" />
</view>
</view>
</view>
</view> -->
</view>
</template>
<script setup lang="ts">
//
import { ref, computed, watch,onMounted } from 'vue';
import { ref, computed, watch, onMounted } from 'vue';
import useDiyStore from '@/app/stores/diy';
import { img } from '@/utils/common';
import { uploadImage } from '@/app/api/system'
const props = defineProps(['component', 'index','global']);
import { img } from '@/utils/common';
import { uploadVideo } from '@/app/api/system'
import { t } from '@/locale'
const props = defineProps(['component', 'index', 'global']);
const diyStore = useDiyStore();
const selectValue = ref([])
const errorInfo: any = ref(null);
const diyComponent = computed(() => {
if (diyStore.mode == 'decorate') {
return diyStore.value[props.index];
@ -34,18 +175,33 @@
return props.component;
}
})
//
const uploadType = computed(() => {
let type = '';
if (diyComponent.value && diyComponent.value.uploadMode) {
if(diyComponent.value.uploadMode=='shoot_and_album'){
type = 'album'
}else if(diyComponent.value.uploadMode=='shoot_only'){
type = 'camera'
}
}
return type;
});
const diyGlobal = computed(() => {
return props.global;
})
const warpCss = computed(() => {
var style = '';
style += 'position:relative;';
if(diyComponent.value.componentStartBgColor) {
if (diyComponent.value.componentStartBgColor && diyComponent.value.componentEndBgColor) style += `background:linear-gradient(${diyComponent.value.componentGradientAngle},${diyComponent.value.componentStartBgColor},${diyComponent.value.componentEndBgColor});`;
else style += 'background-color:' + diyComponent.value.componentStartBgColor + ';';
}
style += 'position:relative;';
if (diyComponent.value.componentStartBgColor) {
if (diyComponent.value.componentStartBgColor && diyComponent.value.componentEndBgColor) style += `background:linear-gradient(${diyComponent.value.componentGradientAngle},${diyComponent.value.componentStartBgColor},${diyComponent.value.componentEndBgColor});`;
else style += 'background-color:' + diyComponent.value.componentStartBgColor + ';';
}
if(diyComponent.value.componentBgUrl) {
style += `background-image:url('${ img(diyComponent.value.componentBgUrl) }');`;
style += 'background-size: cover;background-repeat: no-repeat;';
}
if (diyComponent.value.componentBgUrl) {
style += `background-image:url('${img(diyComponent.value.componentBgUrl)}');`;
style += 'background-size: cover;background-repeat: no-repeat;';
}
if (diyComponent.value.topRounded) style += 'border-top-left-radius:' + diyComponent.value.topRounded * 2 + 'rpx;';
if (diyComponent.value.topRounded) style += 'border-top-right-radius:' + diyComponent.value.topRounded * 2 + 'rpx;';
@ -54,20 +210,20 @@
return style;
})
onMounted(() => {
refresh();
//
if (diyStore.mode == 'decorate') {
watch(
() => diyComponent.value,
(newValue, oldValue) => {
if (newValue && newValue.componentName == 'FormVideo') {
refresh();
}
}
)
}
});
onMounted(() => {
refresh();
//
if (diyStore.mode == 'decorate') {
watch(
() => diyComponent.value,
(newValue, oldValue) => {
if (newValue && newValue.componentName == 'FormVideo') {
refresh();
}
}
)
}
});
const isDisabled = computed(() => {
@ -76,41 +232,76 @@
const imgListPreview = computed(() => {
return selectValue.value.map(item => {
return {url: img(item)}
return { url: img(item) }
})
})
const afterRead = (event) => {
event.file.forEach(item => {
uploadImage({
filePath: item.url,
name: 'file'
}).then(res => {
if (selectValue.value.length < diyComponent.value.limit ) {
selectValue.value.push(res.data.url)
}
}).catch(() => {
})
})
// uni.setStorageSync('sku_form_refresh', true);
event.file.forEach(item => {
upload(item);
})
}
const upload = (data: any) => {
// if (diyComponent.value.field.value.length > Number(diyComponent.value.limit)) {
// uni.showToast({ title: `${ diyComponent.value.limit }`, icon: 'none' })
// return false
// }
uploadVideo({
filePath: data.url,
name: 'file'
}).then(res => {
// if (diyComponent.value.field.value.length < Number(diyComponent.value.limit)) {
diyComponent.value.field.value.push(res.data.url)
// }
}).catch(() => {
})
}
const deleteImage = (event) => {
diyComponent.value.field.value.splice(event.index, 1)
}
// input
const inputAttribute = () => {
let arr = [];
if (diyComponent.value.autofill) {
let obj = {
title: '已自动填充'
};
arr.push(obj);
}
arr.forEach((item, index, arr) => {
if (index != (arr.length - 1)) {
let obj = {
title: '|'
};
arr.push(obj);
}
})
return arr;
}
const deletePic = (event)=> {
selectValue.value.splice(event.index, 1)
const refresh = () => {
}
const refresh = ()=> {
}
//
const verify = () => {
const res = { code: true, message: '' }
// todo diyComponent.value.field.value
return res;
const res = { code: true, message: '' }
// todo diyComponent.value.field.value
if (diyComponent.value.field.required && (!diyComponent.value.field.value || diyComponent.value.field.value && !diyComponent.value.field.value.length)) {
res.code = false
res.message = `请上传视频`;
}
errorInfo.value = res;
return res;
}
//
const reset = () => {
// todo diyComponent.value.field.value = '';
// todo
diyComponent.value.field.value = [];
}
defineExpose({
@ -121,4 +312,4 @@
<style lang="scss" scoped>
@import '@/styles/diy_form.scss';
</style>
</style>

View File

@ -1,26 +1,76 @@
<template>
<view :style="warpCss">
form-wechat-name
<view class="relative">
<view class="p-[10rpx] flex items-center ">
<view class="w-[27%] mr-[10rpx] flex items-center">
<text class="text-overflow-ellipsis" :style="{'color': diyComponent.textColor,'font-size': (diyComponent.fontSize * 2) + 'rpx' ,'font-weight': diyComponent.fontWeight}">{{ diyComponent.field.name }}</text>
<text class="text-[#ec0003]">{{ diyComponent.field.required ? '*' : '' }}</text>
</view>
</view>
</view>
<view v-if="diyComponent.viewFormDetail" class="form-item-frame">
<view class="base-layout-one" v-if="diyGlobal.completeLayout == 'style-1'">
<view class="detail-one-content">
<text class="detail-one-content-label">{{ diyComponent.field.name }}</text>
<text class="detail-one-content-value">{{ diyComponent.field.value }}</text>
</view>
</view>
<view class="base-layout-two" v-if="diyGlobal.completeLayout == 'style-2'">
<view class="detail-two-content">
<view>{{ diyComponent.field.name }}</view>
<view class="detail-two-content-value w-[80%]">{{ diyComponent.field.value }}</view>
</view>
</view>
</view>
<view v-else :style="warpCss" class="form-item-frame">
<view class="base-layout-one" v-if="diyGlobal.completeLayout == 'style-1'">
<view class="layout-one-label">
<text class="text-overflow-ellipsis" :style="{'color': diyComponent.textColor,'font-size': (diyComponent.fontSize * 2) + 'rpx' ,'font-weight': diyComponent.fontWeight}">{{ diyComponent.field.name }}</text>
<text class="required">{{ diyComponent.field.required ? '*' : '' }}</text>
<text v-if="diyStore.mode == 'decorate' && diyComponent.isHidden" class="is-hidden">{{ t('diyForm.hidden') }}</text>
</view>
<view v-if="diyComponent.field.remark.text" class="layout-one-remark" :style="{ color: diyComponent.field.remark.color, fontSize: (diyComponent.field.remark.fontSize * 2 ) + 'rpx' }">{{ diyComponent.field.remark.text }}</view>
<view class="layout-one-error-message" v-if="errorInfo && !errorInfo.code">{{ errorInfo.message }}</view>
<input type="nickname" class="layout-one-content" placeholder="获取填表人的微信名"
placeholderClass="layout-one-input-placeholder"
:placeholder-style="{'font-size': (diyComponent.fontSize * 2) + 'rpx' }"
:style="{'color': diyComponent.textColor,'font-size': (diyComponent.fontSize * 2) + 'rpx'}"
v-model="diyComponent.field.value" :disabled="isDisabled" @click="openInfo" />
<!-- <view class="layout-one-attribute-wrap" v-if="inputAttribute().length">
<view v-for="(item,index) in inputAttribute()" :key="index" @click="eventFn(item.type)" class="layout-one-attribute-item">{{ item.title }}</view>
</view> -->
</view>
<view class="base-layout-two" v-if="diyGlobal.completeLayout == 'style-2'">
<text v-if="diyStore.mode == 'decorate' && diyComponent.isHidden" class="layout-two-is-hidden">{{ t('diyForm.hidden') }}</text>
<view class="layout-two-wrap" :class="{'no-border': !diyGlobal.borderControl}">
<view class="layout-two-label" :class="{'justify-start': diyGlobal.completeAlign == 'left', 'justify-end': diyGlobal.completeAlign == 'right'}">
<text class="required" v-if="diyComponent.field.required">{{ diyComponent.field.required ? '*' : '' }}</text>
<text class="name" :style="{'color': diyComponent.textColor,'font-size': (diyComponent.fontSize * 2) + 'rpx' ,'font-weight': diyComponent.fontWeight}">{{ diyComponent.field.name }}</text>
</view>
<input type="nickname" class="layout-two-content no-flex" placeholder="获取填表人的微信名"
placeholderClass="layout-two-input-placeholder" @click="openInfo"
:placeholder-style="{'font-size': (diyComponent.fontSize * 2) + 'rpx'}"
:style="{'color': diyComponent.textColor,'font-size': (diyComponent.fontSize * 2) + 'rpx'}"
v-model="diyComponent.field.value" :disabled="isDisabled" />
</view>
<view class="layout-two-error-message" v-if="errorInfo && !errorInfo.code">{{ errorInfo.message }}</view>
<view v-if="diyComponent.field.remark.text" class="layout-two-remark" :style="{ color: diyComponent.field.remark.color, fontSize: (diyComponent.field.remark.fontSize * 2 ) + 'rpx' }">{{ diyComponent.field.remark.text }}</view>
<!-- <view class="layout-two-attribute-wrap" v-if="inputAttribute().length">
<view v-for="(item,index) in inputAttribute()" :key="index" @click="eventFn(item.type)" class="layout-two-attribute-item">{{ item.title }}</view>
</view> -->
</view>
<view v-if="diyStore.mode == 'decorate'" class="form-item-mask"></view>
</view>
<!-- #ifdef MP-WEIXIN -->
<!-- <information-filling ref="infoFill"></information-filling> -->
<!-- #endif -->
</template>
<script setup lang="ts">
//
import { ref, computed, watch,onMounted } from 'vue';
import useDiyStore from '@/app/stores/diy';
import { img } from '@/utils/common';
import { img, isWeixinBrowser } from '@/utils/common'
import { useLogin } from '@/hooks/useLogin'
import { t } from '@/locale'
import useMemberStore from '@/stores/member'
const memberStore = useMemberStore()
const login = useLogin()
const props = defineProps(['component', 'index','global']);
const diyStore = useDiyStore();
const infoFill: any = ref(false)
const errorInfo: any = ref(null);
const diyComponent = computed(() => {
if (diyStore.mode == 'decorate') {
return diyStore.value[props.index];
@ -28,6 +78,68 @@
return props.component;
}
})
const diyGlobal = computed(() => {
return props.global;
})
const inputAttribute = () => {
let arr = [];
if (diyComponent.value.autofill) {
let obj = {
title: '已自动填充'
};
arr.push(obj);
}
if (diyComponent.value.field.privacyProtection) {
let obj = {
title: '已开启隐私保护',
type: 'privacy'
};
arr.push(obj);
}
arr.forEach((item, index, arr) => {
if (index != (arr.length - 1)) {
let obj = {
title: '|'
};
arr.push(obj);
}
})
return arr;
}
const openInfo = ()=>{
// #ifdef H5
wechatGetInfo();
// #endif
// #ifdef MP
weappGetInfo()
// #endif
}
const wechatGetInfo = async () => {
// if (isWeixinBrowser()) {
// const userInfo = await login.getAuthCode({ scopes: 'snsapi_userinfo' });
if (memberStore) {
console.log(memberStore)
diyComponent.value.field.value = memberStore.info.nickname;
}
// }
};
const weappGetInfo = async () => {
// #ifdef MP-WEIXIN
wx.getUserInfo({
success: function(res) {
},
fail: function(res) {}
});
// #endif
};
const warpCss = computed(() => {
var style = '';
@ -70,15 +182,23 @@
//
const verify = () => {
const res = { code: true, message: '' }
// todo diyComponent.value.field.value
return res;
const res = { code: true, message: '' }
if (diyComponent.value.field.required && diyComponent.value.field.value == '' && diyStore.mode != 'decorate') {
res.code = false
res.message ='111';
}
errorInfo.value = res;
return res;
}
//
const reset = () => {
// todo diyComponent.value.field.value = '';
diyComponent.value.field.value = '';
}
const isDisabled = computed(() => {
return diyStore.mode == 'decorate';
});
defineExpose({
verify,

View File

@ -57,11 +57,11 @@
</swiper-item>
</swiper>
<view class="graphic-nav-indicator-dot" v-if="shouldShowIndicator && swiperHeight">
<div class="dots-wrap" :class="[diyComponent.swiper.indicatorAlign]">
<div v-for="(item,index) in Math.ceil(diyComponent.list.length / (diyComponent.pageCount * diyComponent.rowCount))"
<view class="dots-wrap" :class="[diyComponent.swiper.indicatorAlign]">
<view v-for="(item,index) in Math.ceil(diyComponent.list.length / (diyComponent.pageCount * diyComponent.rowCount))"
:class="['dot',index == swiperIndex ? 'dot-active' : '',diyComponent.swiper.indicatorStyle]"
:style="{ background : index == swiperIndex ? diyComponent.swiper.indicatorActiveColor : diyComponent.swiper.indicatorColor}"></div>
</div>
:style="{ background : index == swiperIndex ? diyComponent.swiper.indicatorActiveColor : diyComponent.swiper.indicatorColor}"></view>
</view>
</view>
</view>

View File

@ -44,9 +44,9 @@
<view class="w-[570rpx] px-[32rpx] popup-common center">
<view class="title">公告</view>
<scroll-view :scroll-y="true" class="px-[30rpx] box-border h-[260rpx]">
<block v-for="(item) in noticeContent.split('\n')">
<template v-for="(item) in noticeContent.split('\n')">
<view class="text-[28rpx] leading-[40rpx] mb-[20rpx]">{{ item }}</view>
</block>
</template>
</scroll-view>
<view class="btn-wrap !pt-[40rpx]">
<button class="primary-btn-bg w-[480rpx] h-[70rpx] text-[26rpx] leading-[70rpx] rounded-[35rpx] !text-[#fff] font-500" @click="noticeShow = false">我知道了</button>

View File

@ -4,12 +4,12 @@
<view class="diy-text relative">
<view v-if="diyComponent.style == 'style-1'" class="px-[var(--pad-sidebar-m)]">
<view @click="diyStore.toRedirect(diyComponent.link)">
<view class="leading-[1]" :style="{ fontSize: diyComponent.fontSize * 2 + 'rpx', color: diyComponent.textColor, fontWeight: (diyComponent.fontWeight == 'normal' ? 500 : diyComponent.fontWeight), textAlign : diyComponent.textAlign }">{{ diyComponent.text }}</view>
<view class="leading-[1]" :style="textStyle1">{{ diyComponent.text }}</view>
</view>
</view>
<view v-if="diyComponent.style == 'style-2'" class=" px-[20rpx] flex items-center">
<view @click="diyStore.toRedirect(diyComponent.link)">
<view class="max-w-[200rpx] truncate leading-[1]" :style="{ fontSize: diyComponent.fontSize * 2 + 'rpx', color: diyComponent.textColor, fontWeight: (diyComponent.fontWeight == 'normal' ? 500 : diyComponent.fontWeight) }">{{ diyComponent.text }}</view>
<view class="max-w-[200rpx] truncate leading-[1]" :style="textStyle2">{{ diyComponent.text }}</view>
</view>
<text v-if="diyComponent.subTitle.text" :style="{background: diyComponent.subTitle.color}" class="mx-[10rpx] w-[2rpx] h-[24rpx] opacity-70"></text>
<text class="max-w-[300rpx] truncate" :style="{ color: diyComponent.subTitle.color, fontSize: diyComponent.subTitle.fontSize * 2 + 'rpx', }">{{ diyComponent.subTitle.text }}</text>
@ -41,6 +41,25 @@ const diyComponent = computed(() => {
}
})
//
const textStyle1 = computed(() => {
return {
fontSize: diyComponent.value.fontSize * 2 + 'rpx',
color: diyComponent.value.textColor,
fontWeight: diyComponent.value.fontWeight === 'normal' ? 500 : diyComponent.value.fontWeight,
textAlign: diyComponent.value.textAlign
};
});
//
const textStyle2 = computed(() => {
return {
fontSize: diyComponent.value.fontSize * 2 + 'rpx',
color: diyComponent.value.textColor,
fontWeight: diyComponent.value.fontWeight === 'normal' ? 500 : diyComponent.value.fontWeight
};
});
const warpCss = computed(() => {
var style = '';
style += 'position:relative;';

View File

@ -182,7 +182,7 @@ onLoad(async(option: any) => {
//
// #ifdef MP-WEIXIN
if (configStore.login.is_username && !configStore.login.is_mobile && !configStore.login.is_auth_register) {
if (!configStore.login.is_auth_register) {
isShowQuickLogin.value = false;
} else {
isShowQuickLogin.value = true;
@ -192,18 +192,14 @@ onLoad(async(option: any) => {
// #ifdef H5
if (isWeixinBrowser()) {
//
if (configStore.login.is_username && !configStore.login.is_mobile && !configStore.login.is_auth_register) {
if (!configStore.login.is_auth_register) {
isShowQuickLogin.value = false;
} else {
isShowQuickLogin.value = true;
}
} else {
//
if (configStore.login.is_username && !configStore.login.is_mobile) {
isShowQuickLogin.value = false;
} else {
isShowQuickLogin.value = true;
}
isShowQuickLogin.value = false;
}
// #endif
})

View File

@ -4,9 +4,9 @@
<view class="w-[570rpx] px-[32rpx] popup-common center" v-if="Object.keys(configInfo).length">
<view class="title">{{ configInfo.pay_explain_title }}</view>
<scroll-view :scroll-y="true" class="px-[30rpx] box-border max-h-[260rpx]" v-if="configInfo.pay_explain_content">
<block v-for="(item) in configInfo.pay_explain_content.split('\n')">
<template v-for="(item) in configInfo.pay_explain_content.split('\n')">
<view class="text-[28rpx] leading-[40rpx] mb-[20rpx]">{{ item }}</view>
</block>
</template>
</scroll-view>
<view class="btn-wrap !pt-[40rpx]">
<button class="primary-btn-bg w-[480rpx] h-[70rpx] text-[26rpx] leading-[70rpx] rounded-[35rpx] !text-[#fff] font-500" @click="closeFn">我知道了</button>

View File

@ -26,7 +26,10 @@
import { ref, nextTick } from 'vue';
import { useDiy } from '@/hooks/useDiy'
import { redirect } from '@/utils/common';
import { useShare } from '@/hooks/useShare'
import diyGroup from '@/addon/components/diy/group/index.vue'
const { setShare } = useShare()
uni.hideTabBar() // tabbar
@ -51,6 +54,8 @@ diy.onShow((data: any) => {
//
redirect({ url: data.page, mode: 'reLaunch' })
}
let share = data.share ? JSON.parse(data.share) : null;
setShare(share);
diyGroupRef.value?.refresh();
// #ifdef MP
nextTick(() => {

View File

@ -2,7 +2,7 @@
<view class="w-screen h-screen bg-[var(--page-bg-color)] overflow-hidden" :style="themeColor()">
<scroll-view scroll-y="true">
<view class="sidebar-margin card-template top-mar account pb-[20rpx]">
<block v-if="formData.account_type == 'bank'">
<template v-if="formData.account_type == 'bank'">
<view class="text-center text-[32rpx] font-500 mt-[10rpx] text-[#333] leading-[42rpx]">{{ formData.account_id ? t('editBankCard') : t('addBankCard') }}</view>
<view class="text-center text-[24rpx] mt-[16rpx] text-[var(--text-color-light9)]">{{ formData.account_id ? t('editBankCardTips') : t('addBankCardTips') }}</view>
<view class="mt-[70rpx] px-[10rpx]">
@ -24,9 +24,9 @@
</view>
</u-form>
</view>
</block>
</template>
<block v-if="formData.account_type == 'alipay'">
<template v-if="formData.account_type == 'alipay'">
<view class="text-center text-[32rpx] font-500 mt-[20rpx] text-[#333] leading-[42rpx]">{{ formData.account_id ? t('editAlipayAccount') : t('addAlipayAccount') }}</view>
<!-- <view class="text-center text-[28rpx] mt-[16rpx] text-[var(--text-color-light9)] leading-[36rpx]">{{ formData.account_id ? t('editAlipayAccountTips') : t('addAlipayAccountTips') }}</view> -->
@ -55,9 +55,9 @@
</view>
</u-form>
</view>
</block>
</template>
<block v-if="formData.account_type == 'wechat_code'">
<template v-if="formData.account_type == 'wechat_code'">
<view class="text-center text-[32rpx] font-500 mt-[20rpx] text-[#333] leading-[42rpx]">{{ formData.account_id ? t('editWechatCodeAccount') : t('addWechatCodeAccount') }}</view>
<!-- <view class="text-center text-[28rpx] mt-[16rpx] text-[var(--text-color-light9)] leading-[36rpx]">{{ formData.account_id ? t('editWechatCodeAccountTips') : t('addWechatCodeAccountTips') }}</view> -->
@ -86,7 +86,7 @@
</view>
</u-form>
</view>
</block>
</template>
</view>
<view class="common-tab-bar-placeholder"></view>
<view class="common-tab-bar fixed left-[var(--sidebar-m)] right-[var(--sidebar-m)] bottom-[0]">

View File

@ -25,17 +25,17 @@
</view>
</view>
<view class="mt-[60rpx] flex justify-around" v-if="Object.keys(cashOutConfigObj).length && (systemStore.siteAddons.includes('recharge') || cashOutConfigObj.is_open == 1 || rechargeConfigObj.is_use == 1)">
<block v-if="systemStore.siteAddons.includes('recharge')">
<template v-if="systemStore.siteAddons.includes('recharge')">
<button v-if="rechargeConfigObj.is_use == 1"
class="w-[250rpx] h-[70rpx] rounded-[40rpx] text-[26rpx] font-500 !bg-[#fff] !text-[var(--primary-color)] flex-center !m-0 border-[2rpx] border-[var(--primary-color)] border-solid box-border"
hover-class="none" shape="circle"
@click="redirect({url: '/addon/recharge/pages/recharge'})">充值</button>
</block>
</template>
<view v-if="cashOutConfigObj.is_open == 1"
:class="{'!w-[340rpx]': !systemStore.siteAddons.includes('recharge')}"
class="text-center w-[250rpx] h-[70rpx] rounded-[40rpx] text-[26rpx] !text-[#fff] flex-center font-500 !m-0"
style="background: linear-gradient( 94deg, #FB7939 0%, #FE120E 99%), #EF000C;"
@click="applyCashOut">{{ t('cashOut') }}</view>
@click="applyCashOut">提现</view>
</view>
</view>
<view class="mt-[30rpx] bg-[var(--page-bg-color)] tab-style-1">

View File

@ -1,6 +1,6 @@
<template>
<view class="min-h-[100vh] bg-[var(--page-bg-color)] overflow-hidden" :style="themeColor()">
<block v-if="!loading">
<template v-if="!loading">
<view class="sidebar-margin card-template mt-[20rpx] !pt-[60rpx] !pb-[40rpx]">
<!-- <view class="flex flex-col justify-center items-center mb-[44rpx]" v-if="cashOutInfo.status == 4 && cashOutInfo.transfer_type == 'wechatpay'">
<image class="h-[70rpx] w-[70rpx] mb-[24rpx]" :src="img('static/resource/images/member/apply_withdrawal/transfer.png')" mode="widthFix" />
@ -111,7 +111,7 @@
:loading="operateLoading" @click="cashTransfer"
v-else-if="cashOutInfo.transfer_type == 'wechatpay' && cashOutInfo.status == 4">{{ t('cashOutNow') }}</button>
</view>
</block>
</template>
<loading-page :loading="loading"></loading-page>
</view>
</template>
@ -201,7 +201,9 @@ const cashOut = () => {
clearTimeout(timer)
}, 6000)
})
})
}).catch((err:any)=>{
operateLoading.value = false;
})
}
const cashTransfer = () => {

View File

@ -24,6 +24,8 @@
<script setup lang="ts">
import { ref, computed, nextTick } from 'vue';
import { useDiy } from '@/hooks/useDiy'
import { useShare } from '@/hooks/useShare'
import { redirect } from '@/utils/common';
import diyGroup from '@/addon/components/diy/group/index.vue'
import useMemberStore from '@/stores/member'
@ -31,6 +33,7 @@ import useMemberStore from '@/stores/member'
//
const memberStore = useMemberStore()
const userInfo = computed(() => memberStore.info)
const { setShare } = useShare()
const diy = useDiy({
name: 'DIY_MEMBER_INDEX'
@ -53,6 +56,8 @@ diy.onShow((data: any) => {
//
redirect({ url: data.page, mode: 'reLaunch' })
}
let share = data.share ? JSON.parse(data.share) : null;
setShare(share);
diyGroupRef.value?.refresh();
if (userInfo.value) {
useMemberStore().getMemberInfo()

View File

@ -52,13 +52,13 @@
<view class="mx-[86rpx]">
<scroll-view :scroll-x="true" scroll-with-animation :scroll-into-view="'id' + ( levelIndex ? levelIndex - 1 : 0)">
<view class="flex flex-nowrap py-[10rpx]">
<block v-for="(item,index) in list" :key="item.id">
<template v-for="(item,index) in list" :key="item.id">
<view :style="levelStyle" class=" flex-shrink-0 flex flex-col items-center justify-center"
@click="changeLevel(index)" :id="'id' + index">
<view class="w-[14rpx] h-[14rpx] level-class" :class="{'level-select': levelIndex == (index)}"></view>
<view :style="maxWidth" class="text-[22rpx] text-[#aaa] mt-[16rpx] truncate" :class="{'!text-[#fff]': levelIndex == (index)}">{{ item.level_name }}</view>
</view>
</block>
</template>
</view>
</scroll-view>
</view>

View File

@ -80,7 +80,7 @@
<view class="mt-[var(--top-m)] sidebar-margin card-template" v-if="pointList.length">
<view class="title">做任务领积分</view>
<block v-for="(item,index) in pointList">
<template v-for="(item,index) in pointList">
<view class="flex items-center justify-between mt-[30rpx]">
<view class="flex items-center flex-1">
<image class="h-[80rpx] w-[80rpx]" :src="img(item.icon||'')" mode="heightFix" />
@ -92,7 +92,7 @@
<button v-if="item.button" class="h-[54rpx] !m-0 rounded-[40rpx] text-[24rpx] flex-center !text-[#fff] primary-btn-bg"
shape="circle" @click="toLink(item.button.wap_redirect)">{{ item.button.text }}</button>
</view>
</block>
</template>
</view>
</template>
<loading-page :loading="loading"></loading-page>

View File

@ -46,7 +46,7 @@
</view>
</view>
<view v-show="item.flag">
<block v-for="(subItem,subIndex) in item.month_data" :key="subItem.id">
<template v-for="(subItem,subIndex) in item.month_data" :key="subItem.id">
<view class="flex items-center ">
<view class="w-[60rpx] h-[60rpx]">
<image v-if="subItem.account_data > 0" :src="img('static/resource/images/member/point/detail/point_add.png')" class="w-[60rpx] h-[60rpx]"/>
@ -60,7 +60,7 @@
<view class="text-[36rpx] font-500 text-[#03B521] price-font" :class="{ '!text-primary' : subItem.account_data > 0 }">{{ subItem.account_data > 0 ? '+' + subItem.account_data : subItem.account_data }}</view>
</view>
</view>
</block>
</template>
</view>
</view>
<mescroll-empty :option="{tip : '暂无积分明细'}" v-if="!pointList.length && loading"></mescroll-empty>

View File

@ -49,7 +49,7 @@
<text class="w-[14.28%] leading-[36rpx] text-center">周日</text>
</view>
<view class="flex flex-wrap items-center justify-start" v-if="!flag">
<block v-for="(item,index) in state.weekCount" :key="index">
<template v-for="(item,index) in state.weekCount" :key="index">
<view class="w-[14.28%] flex flex-col justify-center items-center">
<view v-if="filteredDate(item)"
class="w-[74rpx] h-[92rpx] bg-[#f4f4f4] text-[var(--text-color-light6)] box-border py-[10rpx] rounded-[8rpx] flex flex-col items-center"
@ -69,10 +69,10 @@
</view>
<view class="w-[10rpx] h-[10rpx] rounded-[50%] bg-[var(--primary-color)]" v-if="isCurrentDate(item)"></view>
</view>
</block>
</template>
</view>
<view class="flex flex-wrap items-center justify-start" v-else>
<block v-for="(item,index) in state.dataCount">
<template v-for="(item,index) in state.dataCount">
<view class="w-[14.28%] flex flex-col justify-center items-center mb-[30rpx]">
<view v-if="filteredDate(item)"
class="w-[74rpx] h-[92rpx] bg-[#F6FAFF] text-[var(--text-color-light6)] box-border py-[10rpx] rounded-[8rpx] flex flex-col items-center"
@ -91,7 +91,7 @@
</view>
<view class="w-[10rpx] h-[10rpx] rounded-[50%] bg-[var(--primary-color)]" v-if="isCurrentDate(item)"></view>
</view>
</block>
</template>
</view>
<view class="mt-[40rpx] flex justify-center" v-if="state.curMonth + 1 == (new Date().getMonth() + 1) && state.curYear == new Date().getFullYear() ">
<button v-if="!info.is_sign"
@ -164,9 +164,9 @@
<view class="popup-common">
<view class="title">签到规则</view>
<scroll-view :scroll-y="true" class="px-[30rpx] box-border h-[360rpx] overflow-auto">
<block v-for="(item) in info.rule_explain.split('\n')">
<template v-for="(item) in info.rule_explain.split('\n')">
<view class="text-[28rpx] leading-[40rpx] mb-[20rpx]">{{ item }}</view>
</block>
</template>
</scroll-view>
<view class="btn-wrap">
<button class="primary-btn-bg btn" @click="signPopup = false">知道了</button>
@ -186,14 +186,14 @@
<view class="text-[36rpx] text-[#EF000C] font-500 mb-[10rpx] text-center">{{ signAward.title }}</view>
<view class="text-[24rpx] text-[#333] leading-[34rpx] text-center mb-[60rpx]" v-if="signAward.info">{{ signAward.info }}</view>
<view class="px-[68rpx] mb-[100rpx]">
<block v-for="(item,index) in signAward.awards">
<template v-for="(item,index) in signAward.awards">
<template v-if="item.content" v-for="(subItem,subIndex) in item.content">
<view class="flex items-center mb-[30rpx]">
<image :src="img(subItem.icon)" class="w-[42rpx] h-[42rpx]" />
<view class="ml-[20rpx] text-[28rpx] text-[#303133] leading-[38rpx]">{{ subItem.text }}</view>
</view>
</template>
</block>
</template>
</view>
<view class="flex justify-center relative z-30">
<view class="w-[370rpx] h-[80rpx] primary-btn-bg font-500 rounded-[100rpx] text-[#ffffff] text-center leading-[80rpx] text-[26rpx]" @click="awardShow = false">我知道了</view>
@ -216,14 +216,14 @@
<view class="text-[36rpx] text-[#303133] font-500 mb-[10rpx] text-center relative z-20">{{ packInfo.title }}</view>
<view class="text-[24rpx] text-[#333] leading-[34rpx] text-center mb-[60rpx]">{{ packInfo.info }}</view>
<view class="px-[68rpx] mb-[100rpx]">
<block v-for="(item,index) in packInfo.awards">
<template v-for="(item,index) in packInfo.awards">
<template v-if="item.content">
<view class="flex items-center mb-[32rpx]" v-for="(subItem,subIndex) in item.content" :key="subIndex">
<image :src="img(subItem.icon)" class="w-[42rpx] h-[42rpx]" />
<view class="ml-[20rpx] text-[28rpx] text-[#303133] leading-[38rpx]">{{ subItem.text }}</view>
</view>
</template>
</block>
</template>
</view>
<view class="flex justify-center relative z-30">
<view class="w-[370rpx] h-[80rpx] border-[2rpx] text-[var(--primary-color)] border-solid rounded-[40rpx] border-[var(--primary-color)] text-center flex-center text-[26rpx] box-border" @click="packShow = false">我知道了</view>

View File

@ -1,6 +1,6 @@
<template>
<view :style="themeColor()" class="bg-[var(--page-bg-color)] min-h-[100vh] overflow-hidden">
<block v-if="!loading">
<template v-if="!loading">
<view class="pt-[20rpx] sidebar-margin">
<view class="flex flex-col card-template">
<view class="flex" :class="{'mb-[20rpx]': verifyInfo.value.list.length-1 != index}" v-for="(item,index) in verifyInfo.value.list" :key="index">
@ -9,7 +9,7 @@
<view class="flex flex-col flex-1 ml-[20rpx] py-[4rpx]">
<view class="leading-[40rpx] truncate max-w-[490rpx] text-[28rpx]">{{ item.name }}</view>
<view class="mt-[14rpx] truncate text-[24rpx] text-[var(--text-color-light9)] leading-[28rpx] max-w-[490rpx] " v-if="item.sub_name">{{ item.sub_name }}</view>
<view class="text-[var(--text-color-light6)] text-[26rpx] mt-[20rpx]">x1</view>
<view class="text-[var(--text-color-light6)] text-[26rpx] mt-[20rpx]">x{{item.verify_num}}</view>
</view>
</view>
</view>
@ -47,7 +47,7 @@
</view>
</view>
</block>
</template>
<loading-page :loading="loading"></loading-page>
</view>
</template>

View File

@ -12,7 +12,7 @@
</view>
<mescroll-body ref="mescrollRef" top="88rpx" @init="mescrollInit" :down="{ use: false }" @up="geVerifyRecordFn">
<view class="sidebar-margin pt-[var(--top-m)]" v-if="list.length">
<block v-for="(item,index) in list" :key="item.id">
<template v-for="(item,index) in list" :key="item.id">
<view class="w-full flex flex-col mb-[var(--top-m)] card-template" @click="toLink(item)">
<view class="flex items-center mb-[30rpx] leading-[1] text-[26rpx]">
<view class="nc-iconfont nc-icon-hexiaotaiV6xx !text-[26rpx] pr-[10rpx]"></view>
@ -20,7 +20,7 @@
<text class="ml-[10rpx] max-w-[494rpx]">{{ item.code }}</text>
<text class="text-[#303133] text-[26rpx] font-400 nc-iconfont nc-icon-fuzhiV6xx1 ml-[11rpx]" @click.stop="copy(item.code)"></text>
</view>
<view class="flex flex-1" v-for="(dataItem,dataIndex) in item.value.list" :key="dataIndex">
<view class="flex flex-1 mb-2" v-for="(dataItem,dataIndex) in item.value.list" :key="dataIndex">
<u--image width="130rpx" height="130rpx" :radius="'var(--goods-rounded-big)'" :src="img(dataItem.cover ? dataItem.cover : '')" mode="aspectFill">
<template #error>
<image class="w-[130rpx] h-[130rpx] rounded-[var(--goods-rounded-big)] overflow-hidden" :src="img('static/resource/images/diy/shop_default.jpg')" mode="aspectFill"/>
@ -29,7 +29,7 @@
<view class="flex flex-col flex-1 ml-[20rpx] py-[4rpx]">
<view class="max-w-[490rpx] leading-[1.3] truncate text-[28rpx] text-[#303133]">{{ dataItem.name }}</view>
<view class="mt-[14rpx] truncate text-[24rpx] text-[var(--text-color-light9)] max-w-[490rpx] " v-if="item.sub_name">{{ item.sub_name }}</view>
<view class="text-[24rpx] mt-[10rpx] text-[var(--text-color-light9)]">x1</view>
<view class="text-[24rpx] mt-[10rpx] text-[var(--text-color-light9)]">x{{dataItem.verify_num}}</view>
</view>
</view>
<view class="flex bg-[var(--temp-bg)] py-[20rpx] px-[20rpx] rounded-[12rpx] mt-[20rpx]">
@ -43,7 +43,7 @@
</view>
</view>
</view>
</block>
</template>
</view>
<mescroll-empty v-if="!list.length && loading" :option="{tip : '暂无核销记录'}"></mescroll-empty>
</mescroll-body>

View File

@ -1,6 +1,6 @@
<template>
<view :style="themeColor()" class="bg-[var(--page-bg-color)] min-h-[100vh] overflow-hidden">
<block v-if="!loading && verifyInfo && verifyInfo.value">
<template v-if="!loading && verifyInfo && verifyInfo.value">
<view class="p-[30rpx] bg-[#fff]">
<view class="text-[var(--primary-color)] fixed top-[40rpx] right-[30rpx] flex items-center" @click="redirect({url:'/app/pages/verify/record'})">
<text class="nc-iconfont nc-icon-lishijiluV6xx !text-[28rpx] -mb-[2rpx]"></text>
@ -23,11 +23,17 @@
<image class="w-[150rpx] h-[150rpx] rounded-[var(--goods-rounded-big)]" mode="aspectFill" v-if="item.cover" :src="img(item.cover)"/>
<image class="w-[150rpx] h-[150rpx] rounded-[var(--goods-rounded-big)]" mode="aspectFill" v-else :src="img('addon/tourism/tourism/member/hotel.png')"/>
<view class="flex flex-col flex-1 ml-[20rpx] py-[4rpx]">
<view class="leading-[1]">
<view class="leading-[40rpx] truncate max-w-[490rpx] text-[28rpx]">{{ item.name }}</view>
<view class="mt-[14rpx] truncate text-[24rpx] text-[var(--text-color-light9)] leading-[28rpx] max-w-[490rpx]" v-if="item.sub_name">{{ item.sub_name }}</view>
</view>
<view class="text-[var(--text-color-light6)] text-[28rpx] mt-[20rpx]">x1</view>
<view class="leading-[1]">
<view class="leading-[40rpx] truncate max-w-[490rpx] text-[28rpx]">{{ item.name }}</view>
<view class="mt-[14rpx] truncate text-[24rpx] text-[var(--text-color-light9)] leading-[28rpx] max-w-[490rpx]" v-if="item.sub_name">{{ item.sub_name }}</view>
</view>
<view class="flex items-center mt-[20rpx]">
<view class="text-[var(--text-color-light6)] text-[28rpx] ">x{{item.verify_num }}</view>
<view class="leading-[1] ml-3 text-[var(--price-text-color)] text-[28rpx]">
{{item.un_use_msg}}
</view>
</view>
</view>
</view>
</view>
@ -52,9 +58,10 @@
<text class="text-[28rpx] text-[#333]">{{ subItem.value }}</text>
</view>
</view>
<view class="common-tab-bar w-[100%]"></view>
<view class="verify-tab-bar fixed flex-center !text-[26rpx] rounded-[50rpx] h-[80rpx] left-[20rpx] right-[20rpx] text-[#fff] font-500" :class="verifyInfo.is_can_use ? 'primary-btn-bg' : 'bg-[#ccc]'" @click="verifyFn">确定</view>
<view class="fixed bottom-[30rpx] primary-btn-bg text-[#fff] flex-center !text-[26rpx] rounded-[50rpx] h-[80rpx] left-[20rpx] right-[20rpx] font-500" @click="verifyFn">确定</view>
</block>
</template>
<loading-page :loading="loading"></loading-page>
</view>
</template>
@ -129,6 +136,7 @@ const getVerifierInfoFn = () => {
}
let isLoading = false;
const verifyFn = () => {
if (!verifyInfo.value.is_can_use) return;
if (isLoading) return false;
isLoading = true;
@ -148,4 +156,8 @@ const verifyFn = () => {
</script>
<style lang="scss" scoped>
.verify-tab-bar{
bottom: calc(constant(safe-area-inset-bottom) + 30rpx);
bottom: calc(env(safe-area-inset-bottom) + 30rpx);
}
</style>

View File

@ -154,46 +154,48 @@ const getPhoneNumber = (e: any) => {
}
}
const confirm = async() => {
formRef.value.validate().then(async() => {
if (loading.value) return
loading.value = true
const confirm = async () => {
formRef.value.validate().then(async () => {
if (loading.value) return;
loading.value = true;
if (info.value) {
//
await modifyMember({ field: 'headimg', value: formData.headimg }).then(() => {
memberStore.info.headimg = formData.headimg
}).catch(() => {
loading.value = false
})
if (!loading.value) return
try {
if (info.value) {
//
await modifyMember({ field: 'headimg', value: formData.headimg });
memberStore.info.headimg = formData.headimg;
//
modifyMember({ field: 'nickname', value: formData.nickname }).then(() => {
memberStore.info.nickname = formData.nickname
loading.value = false
show.value = false
}).catch(() => {
loading.value = false
})
//
await modifyMember({ field: 'nickname', value: formData.nickname });
memberStore.info.nickname = formData.nickname;
// #ifdef MP-WEIXIN
const login = useLogin()
if (info.value && !info.value.weapp_openid) {
login.getAuthCode({ updateFlag: true }) // openid
// openid
if (info.value && !info.value.weapp_openid) {
const login = useLogin();
await login.getAuthCode({ updateFlag: true }); // openid
}
//
show.value = false;
} else {
// todo
// #ifdef MP-WEIXIN
const login = useLogin();
await login.getAuthCode({ backFlag: true, ...formData }); //
show.value = false;
// #endif
}
// #endif
} else {
// todo
// #ifdef MP-WEIXIN
const login = useLogin()
login.getAuthCode({ backFlag: true, ...formData }) //
// #endif
} catch (error) {
//
console.error("发生错误:", error);
} finally {
loading.value = false; // loading
}
})
}
const checkAuth = (e, type) => {
// #ifdef MP-WEIXIN
wx.getUserInfo({

View File

@ -1,5 +1,6 @@
<template>
<view
v-if="wxsProp"
class="mescroll-body mescroll-render-touch"
:class="{'mescorll-sticky': sticky}"
:style="{'minHeight':minHeight, 'padding-top': padTop, 'padding-bottom': padBottom}"

View File

@ -14,13 +14,13 @@
<view class="text-right flex-1 pl-[30rpx] truncate">{{ payInfo.body }}</view>
</view>
<view class="mx-[var(--popup-sidebar-m)] px-[30rpx] bg-white rounded-[20rpx] bg-[var(--temp-bg)]">
<block v-if="payInfo.pay_type_list.length">
<template v-if="payInfo.pay_type_list.length">
<view class="pay-item py-[30rpx] flex items-center border-0 border-b border-solid border-[#eee]" v-for="(item, index) in payInfo.pay_type_list" :key="index" @click="type = item.key">
<u-image :src="img(item.icon)" width="50rpx" height="50rpx"></u-image>
<view class="flex-1 px-[20rpx] text-[28rpx] font-500">{{ item.name }}</view>
<u-icon name="checkbox-mark" color="var(--primary-color)" v-if="item.key == type"></u-icon>
</view>
</block>
</template>
<view class="py-[30rpx] text-center text-[24rpx] text-gray-subtitle" v-else>{{ t('pay.notHavePayType') }}</view>
</view>
</scroll-view>

View File

@ -1,11 +1,11 @@
<template>
<template v-if="tabbar && Object.keys(tabbar).length">
<u-tabbar :value="value" zIndex="9999" :fixed="true" :placeholder="true" :safeAreaInsetBottom="true" :inactive-color="tabbar.value.textColor" :active-color="tabbar.value.textHoverColor" :border="props.border" class="custom-tabbar">
<block v-for="item in tabbar.value.list">
<template v-for="item in tabbar.value.list">
<u-tabbar-item class="py-[5rpx]" :custom-style="{'background-color': tabbar.value.backgroundColor}" :text="item.text" :icon="img(value == item.link.url ? item.iconSelectPath : item.iconPath)" :name="item.link.url" v-if="tabbar.value.type == 1" @click="itemBtn(item.link.url)"></u-tabbar-item>
<u-tabbar-item class="py-[5rpx]" :custom-style="{'background-color': tabbar.value.backgroundColor}" :icon="img(value == item.link.url ? item.iconSelectPath : item.iconPath)" :name="item.link.url" v-if="tabbar.value.type == 2" @click="itemBtn(item.link.url)"></u-tabbar-item>
<u-tabbar-item class="py-[5rpx]" :custom-style="{'background-color': tabbar.value.backgroundColor}" :text="item.text" :name="item.link.url" v-if="tabbar.value.type == 3" @click="itemBtn(item.link.url)"></u-tabbar-item>
</block>
</template>
</u-tabbar>
<view class="tab-bar-placeholder"></view>
</template>

View File

@ -1,15 +1,17 @@
<template>
<view v-if="showPop">
<view class="privacy-mask">
<view class="privacy-wrap">
<view class="privacy-title">用户隐私保护提示</view>
<view class="privacy-desc">感谢您使用本小程序在使用前您应当阅读并同意<text class="privacy-link" @tap="openPrivacyContract">{{ privacyContractName }}</text> 当点击同意并继续时即表示您已理解并同意该条款内容该条款将对您产生法律约束力如您不同意将无法继续使用小程序相关功能</view>
<view class="privacy-button-flex">
<button class="privacy-button-btn bg-disagree" @tap="handleDisagree">不同意</button>
<button id="agree-btn" class="privacy-button-btn bg-agree" open-type="agreePrivacyAuthorization" @agreeprivacyauthorization="handleAgree">同意并继续</button>
</view>
</view>
</view>
<view @touchmove.prevent.stop>
<u-popup :show="showPop" type="bottom" @close="disPopUp">
<view>
<view class="p-[30rpx]">
<view class="privacy-title">用户隐私保护提示</view>
<view class="privacy-desc">感谢您使用本小程序在使用前您应当阅读并同意<text class="privacy-link" @tap="openPrivacyContract">{{ privacyContractName }}</text> 当点击同意并继续时即表示您已理解并同意该条款内容该条款将对您产生法律约束力如您不同意将无法继续使用小程序相关功能</view>
<view class="privacy-button-flex">
<button class="privacy-button-btn bg-disagree" @tap="handleDisagree">拒绝</button>
<button id="agree-btn" class="privacy-button-btn bg-agree" open-type="agreePrivacyAuthorization" @agreeprivacyauthorization="handleAgree">同意</button>
</view>
</view>
</view>
</u-popup>
</view>
</template>
@ -183,18 +185,18 @@ defineExpose({
}
.privacy-title {
padding: 0rpx 30rpx 40rpx 30rpx;
padding: 10rpx 40rpx;
font-weight: 700;
font-size: 36rpx;
text-align: center;
font-size: 30rpx;
// text-align: center;
}
.privacy-desc {
font-size: 30rpx;
font-size: 28rpx;
color: #555;
line-height: 2;
line-height: 1.5;
text-align: left;
padding: 0 40rpx;
padding: 15rpx 40rpx;
}
.privacy-link {
@ -203,17 +205,17 @@ defineExpose({
.privacy-button-flex {
display: flex;
padding: 20rpx 40rpx;
padding: 20rpx 100rpx;
}
.privacy-button-btn {
color: #FFF;
font-size: 30rpx;
font-weight: 500;
line-height: 100rpx;
line-height: 80rpx;
text-align: center;
height: 100rpx;
border-radius: 20rpx;
height: 80rpx;
border-radius: 10rpx;
border: none;
background: #07c160;
flex: 1;

View File

@ -323,7 +323,8 @@ export function useLogin() {
scopes: params.scopes
}).then((res: any) => {
uni.setStorageSync('wechat_login_back', true) // 微信公众号手动授权登录回调标识
location.href = res.data.url
location.replace(res.data.url);
// location.href = res.data.url
})
// #endif

View File

@ -289,12 +289,17 @@ export function isUrl(str: string): boolean {
*/
export function img(path: string): string {
// #ifdef H5
return isUrl(path) ? path : `${ import.meta.env.VITE_IMG_DOMAIN || location.origin }/${ path }`
let imgDomain = import.meta.env.VITE_IMG_DOMAIN || location.origin
// #endif
// #ifndef H5
return isUrl(path) ? path : `${ import.meta.env.VITE_IMG_DOMAIN }/${ path }`
let imgDomain = import.meta.env.VITE_IMG_DOMAIN
// #endif
if (typeof path == 'string' && path.startsWith('/')) path = path.replace(/^\//, '')
if (typeof imgDomain == 'string' && imgDomain.endsWith('/')) imgDomain = imgDomain.slice(0, -1)
return isUrl(path) ? path : `${imgDomain}/${path}`
}
/**
@ -640,7 +645,7 @@ export function setThemeColor (path: string) {
if (configStore.addon != route) {
configStore.addon = route;
}
// 设置插件应用的主色调,排除系统
const theme_color_list = uni.getStorageSync('theme_color_list');
const current_theme_color = uni.getStorageSync('current_theme_color');
@ -660,7 +665,7 @@ export function setThemeColor (path: string) {
}
} catch (e) {
// 设置插件应用的主色调发生错误,若不存在则使用最后有效的主色调
if(!current_theme_color && theme_color_list){
if(!current_theme_color && theme_color_list && theme_color_list.length>0){
currTheme = theme_color_list.app || Object.values(theme_color_list)[0];
configStore.themeColor = themeColorToHex(currTheme.theme)
uni.setStorageSync('current_theme_color', JSON.stringify(themeColorToHex(currTheme.theme)));
@ -669,11 +674,11 @@ export function setThemeColor (path: string) {
}
}
}else if(!current_theme_color && theme_color_list){
currTheme = theme_color_list.app || Object.values(theme_color_list)[0];
configStore.themeColor = themeColorToHex(currTheme.theme)
uni.setStorageSync('current_theme_color', JSON.stringify(themeColorToHex(currTheme.theme)));
}
}else if (!current_theme_color && theme_color_list && theme_color_list.length>0) {
currTheme = theme_color_list.app || Object.values(theme_color_list)[0]
configStore.themeColor = themeColorToHex(currTheme.theme)
uni.setStorageSync("current_theme_color", JSON.stringify(themeColorToHex(currTheme.theme)))
}
}
export function themeColorToHex (param: any) {
@ -708,4 +713,4 @@ export function rgbaToHex (r, g, b, a) {
let hex = "#" + componentToHex(rBlend) + componentToHex(gBlend) + componentToHex(bBlend)
return hex.toUpperCase()
}
}

View File

@ -12,9 +12,11 @@ export function getNeedLoginPages() {
// 获取分包中需要登录的页面
if (pagesJson.subPackages) {
pagesJson.subPackages.forEach(subPackages => {
subPackages.pages.forEach(item => {
if (item.needLogin) pages.push(`/${ subPackages.root }/${ item.path }`)
})
if(subPackages.pages) {
subPackages.pages.forEach(item => {
if (item.needLogin) pages.push(`/${ subPackages.root }/${ item.path }`)
})
}
})
}
return pages
@ -37,9 +39,11 @@ export function getSubPackagesPages() {
// 获取分包中需要登录的页面
if (pagesJson.subPackages) {
pagesJson.subPackages.forEach(subPackages => {
subPackages.pages.forEach(item => {
pages.push(`/${ subPackages.root }/${ item.path }`)
})
if(subPackages.pages) {
subPackages.pages.forEach(item => {
pages.push(`/${ subPackages.root }/${ item.path }`)
})
}
})
}
return pages