update
This commit is contained in:
@@ -1,12 +1,16 @@
|
||||
<script setup>
|
||||
import {onMounted} from "vue";
|
||||
import {onMounted, reactive} from "vue";
|
||||
import XModal from "./XModal.vue";
|
||||
import XQrCode from "./XQrCode.vue";
|
||||
import Api from "../api/index.js";
|
||||
|
||||
const show = defineModel('show');
|
||||
const detail = reactive({});
|
||||
|
||||
onMounted(() => {
|
||||
|
||||
Api.system.getQrcode(1).then(({data}) => {
|
||||
Object.assign(detail, data);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -14,11 +18,12 @@ onMounted(() => {
|
||||
<x-modal
|
||||
v-model:show="show">
|
||||
<view class="px-[30rpx] py-[40rpx] relative">
|
||||
<image @click="show=false" class="!w-[52rpx] !h-[52rpx] absolute top-[-110rpx] right-[calc(-100%-10rpx)]" src="/static/icons/close.png"></image>
|
||||
<image @click="show=false" class="!w-[52rpx] !h-[52rpx] absolute top-[-110rpx] right-[calc(-100%-10rpx)]"
|
||||
src="/static/icons/close.png"></image>
|
||||
|
||||
<view class="title">微信扫码添加</view>
|
||||
<view class="!mt-[24rpx] w-[320rpx] !mx-auto aspect-square">
|
||||
<x-qr-code size="320rpx" :qrSize="180" content="公众号"></x-qr-code>
|
||||
<image class="!size-full" :src="detail.qrcode"></image>
|
||||
</view>
|
||||
<view class="desc !mt-[24rpx]">请发送 [我的] 页面截图给客服</view>
|
||||
<view class="desc">再描述您的问题</view>
|
||||
|
||||
@@ -3,6 +3,9 @@ import ICON1 from '../static/icons/path1.png';
|
||||
import ICON2 from '../static/icons/path2.png';
|
||||
import ICON3 from '../static/icons/path3.png';
|
||||
import ICON4 from '../static/icons/path4.png';
|
||||
import {useUserStore} from "../pinia/UserStore/index.js";
|
||||
|
||||
const UserStore = useUserStore();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -14,7 +17,7 @@ import ICON4 from '../static/icons/path4.png';
|
||||
|
||||
<view class="!absolute left-1/2 top-1/2 -translate-1/2 !flex flex-col justify-center items-center">
|
||||
<view class="score">
|
||||
90
|
||||
{{ UserStore?.userInfo?.score }}
|
||||
</view>
|
||||
<view class="score-info">
|
||||
信用分
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import {computed} from 'vue';
|
||||
import messageIcon from "../static/icons/messageIcon.png";
|
||||
import XActionsheet from "./XActionsheet.vue";
|
||||
import OpenTypeFun from "./OpenTypeFun.js";
|
||||
|
||||
const itemList = computed(() => {
|
||||
const item = [];
|
||||
@@ -10,10 +11,18 @@ const itemList = computed(() => {
|
||||
item.push({text: '标记已读', type: 1});
|
||||
return item;
|
||||
})
|
||||
const {contextRow} = defineProps({
|
||||
const {contextRow, type, data} = defineProps({
|
||||
contextRow: {
|
||||
type: String,
|
||||
default: 'ellipsis-1'
|
||||
},
|
||||
type: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
data: {
|
||||
type: Object,
|
||||
default: null
|
||||
}
|
||||
});
|
||||
|
||||
@@ -27,19 +36,20 @@ const selectActionsheet = (e) => {
|
||||
@success="selectActionsheet"
|
||||
:itemList="itemList">
|
||||
<view
|
||||
@click.stop="OpenTypeFun(data)"
|
||||
class="!py-[30rpx] !px-[24rpx] bg-[#fff] rounded-[8rpx] !flex items-center gap-[20rpx] overflow-hidden relative !mb-[20rpx]">
|
||||
<image class="!size-[72rpx] flex-shrink-0" mode="aspectFill" :src="messageIcon"></image>
|
||||
<view class="flex-grow !flex flex-col gap-[12rpx]">
|
||||
<view class="!flex justify-between items-center">
|
||||
<view class="bh">任务编号: DF12122</view>
|
||||
<view class="bh">{{ type === 0 ? '任务编号: DF12122' : data.title }}</view>
|
||||
<view class="time">2024-01-26 14:00</view>
|
||||
</view>
|
||||
<view :class="['context', contextRow]">
|
||||
商家:您的回填数据1由于***未通过,请按照文档文档文档文档文档文档文档文档文档文档文档文档文档文档文档文档文档文档中操作
|
||||
{{ data.content }}
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="status">置顶</view>
|
||||
<view class="status" v-if="data.is_top === 1">置顶</view>
|
||||
</view>
|
||||
</x-actionsheet>
|
||||
</template>
|
||||
|
||||
32
src/components/OpenTypeFun.js
Normal file
32
src/components/OpenTypeFun.js
Normal file
@@ -0,0 +1,32 @@
|
||||
import {toPage} from "../utils/uils.js";
|
||||
|
||||
const OpenTypeFun = async (options) => {
|
||||
console.log('OpenTypeFun打开', options);
|
||||
const {type, url, single_id} = options;
|
||||
switch (type) {
|
||||
case 0: { // 空
|
||||
break;
|
||||
}
|
||||
case 1: { // 站内url
|
||||
await toPage(url);
|
||||
break;
|
||||
}
|
||||
case 2: { // 站内富文本
|
||||
await toPage(`/pages/richPage/index?id=${single_id}`);
|
||||
break;
|
||||
}
|
||||
case 3: { // 微信连接
|
||||
break;
|
||||
}
|
||||
case 4: { // 外部连接
|
||||
window.open(url);
|
||||
break;
|
||||
}
|
||||
case 5: { // 弹窗
|
||||
console.log('弹窗');
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default OpenTypeFun;
|
||||
@@ -1,30 +1,39 @@
|
||||
<script setup>
|
||||
import dy from "../static/images/抖音.png";
|
||||
import qrw from "../static/icons/qrw.png";
|
||||
import {numberToCharacter, toPage} from "../utils/uils.js";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
const {data} = defineProps({
|
||||
data: {
|
||||
type: Object,
|
||||
default: null
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="rounded-[8rpx] bg-[#fff] !p-[24rpx]">
|
||||
<view class="rounded-[8rpx] bg-[#fff] !p-[24rpx]" @click="toPage(`/pages/taskDetails/index?id=${data.id}`)">
|
||||
<view class="!flex gap-[26rpx]">
|
||||
<image class="!size-[88rpx] rounded-[50%] overflow-hidden" mode="aspectFill" :src="dy"></image>
|
||||
<view class="!h-[88rpx] !flex flex-col justify-between">
|
||||
<view class="title">美白祛斑洗面奶</view>
|
||||
<view class="title">{{ data.goods_name }}</view>
|
||||
<view class="!flex gap-[8rpx]">
|
||||
<view class="tag">抖音</view>
|
||||
<view class="tag">三连发</view>
|
||||
<view class="tag">{{ data.platform }}</view>
|
||||
<view class="tag">{{ numberToCharacter(data.fb_num - 1) }}连发</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="!h-[88rpx] !ml-auto">
|
||||
<view class="price">
|
||||
<text class="unit">¥</text>
|
||||
8.56
|
||||
{{ data.real_price.toFixed(2) }}
|
||||
</view>
|
||||
<view class="price-info">剩余3个名额</view>
|
||||
<view class="price-info">剩余{{ data.children_num }}个名额</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="!mt-[34rpx] !px-[20rpx] !py-[10rpx] bg-[#F2F3F5] info relative">
|
||||
截止时间:08月23日 14:00
|
||||
截止时间:{{ dayjs(data.end_time).format('MM月DD日 HH:mm') }}
|
||||
<view class="absolute top-1/2 -translate-y-1/2 right-0">
|
||||
<image class="!w-[168rpx]" :src="qrw" mode="widthFix"></image>
|
||||
</view>
|
||||
|
||||
@@ -37,7 +37,8 @@ const success = () => {
|
||||
<view class="py-[40rpx] px-[32rpx] !flex justify-center flex-col items-center gap-[20rpx]">
|
||||
<template v-if="!$slots.context">
|
||||
<view class="title">{{ title }}</view>
|
||||
<view class="info">{{ info }}</view>
|
||||
<view class="info" v-if="!$slots.info">{{ info }}</view>
|
||||
<slot name="info" v-else></slot>
|
||||
</template>
|
||||
<slot name="context" v-else></slot>
|
||||
</view>
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
<script setup>
|
||||
|
||||
const {active} = defineProps({
|
||||
active: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="!py-[14rpx] !px-[24rpx] text">
|
||||
<view :class="['!py-[14rpx] !px-[24rpx] text', active ? 'active' : '']">
|
||||
<slot></slot>
|
||||
</view>
|
||||
</template>
|
||||
@@ -16,5 +21,11 @@
|
||||
line-height: 140%;
|
||||
letter-spacing: 0;
|
||||
text-align: left;
|
||||
background-color: #fff;
|
||||
transition: 500ms;
|
||||
}
|
||||
|
||||
.active {
|
||||
background-color: rgba(106, 161, 255, 0.2);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,13 +1,29 @@
|
||||
<script setup>
|
||||
import {ref} from "vue";
|
||||
import XDropdownItem from "./XDropdownItem.vue";
|
||||
|
||||
const show = ref(false);
|
||||
const modelValue = defineModel();
|
||||
const emits = defineEmits(['change']);
|
||||
const {option} = defineProps({
|
||||
option: {
|
||||
type: Array,
|
||||
default: [],
|
||||
}
|
||||
});
|
||||
|
||||
const change = (id) => {
|
||||
modelValue.value = id;
|
||||
emits('change');
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="relative z-[99]">
|
||||
<view class="relative z-[9990]">
|
||||
<view @click="show=!show">
|
||||
<slot></slot>
|
||||
<view class="bg-[#fff] !py-[14rpx] !px-[24rpx] rounded-[8rpx]">
|
||||
{{ option.find(v => v.id === modelValue)?.name }}
|
||||
</view>
|
||||
|
||||
<tui-icon
|
||||
:style="{
|
||||
@@ -20,8 +36,11 @@ const show = ref(false);
|
||||
</view>
|
||||
|
||||
<transition name="fade">
|
||||
<view v-if="show" class="absolute top-[calc(100%+10rpx)] min-w-full bg-[#fff] rounded-[8rpx] x-dropdown-card">
|
||||
<slot name="menu"></slot>
|
||||
<view v-if="show"
|
||||
class="absolute top-[calc(100%+10rpx)] min-w-full bg-[#fff] rounded-[8rpx] x-dropdown-card">
|
||||
<x-dropdown-item v-for="v in option" @click="change(v.id)" :active="modelValue===v.id">
|
||||
{{ v.name }}
|
||||
</x-dropdown-item>
|
||||
</view>
|
||||
</transition>
|
||||
</view>
|
||||
|
||||
@@ -14,6 +14,7 @@ const {model, rules} = defineProps({
|
||||
|
||||
const verify = () => {
|
||||
Object.entries(model).forEach(([key, value]) => {
|
||||
console.log(rules[key], key)
|
||||
if (!rules[key].reg.test(value)) {
|
||||
showToast({
|
||||
icon: 'error',
|
||||
|
||||
@@ -9,7 +9,7 @@ const {label} = defineProps({
|
||||
|
||||
<template>
|
||||
<view class="x-form-item">
|
||||
<view class="!mb-[8rpx]" v-if="label">{{ label }}</view>
|
||||
<view class="!mb-[8rpx] x-form-item-label" v-if="label">{{ label }}</view>
|
||||
<slot></slot>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
@@ -16,7 +16,7 @@ const modelValue = defineModel();
|
||||
<template>
|
||||
<view class="x-input rounded-[12rpx] !flex items-center px-[32rpx]">
|
||||
<slot name="prefix"></slot>
|
||||
<input v-model="modelValue" :placeholder="placeholder"></input>
|
||||
<input v-model="modelValue" v-bind="$attrs" :placeholder="placeholder"></input>
|
||||
<slot name="suffix"></slot>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
29
src/components/XPrompt.vue
Normal file
29
src/components/XPrompt.vue
Normal file
@@ -0,0 +1,29 @@
|
||||
<script setup>
|
||||
import {ref} from "vue";
|
||||
import ICON from "../static/icons/prompt.png";
|
||||
import XConfirmModal from "./XConfirmModal.vue";
|
||||
|
||||
const show = ref(false);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<image v-if="!$slots.button" class="!size-[24rpx]" :src="ICON" mode="aspectFill" @click="show=true"></image>
|
||||
<div v-else @click="show=true">
|
||||
<slot name="button"></slot>
|
||||
</div>
|
||||
|
||||
<x-confirm-modal
|
||||
width="500rpx"
|
||||
v-bind="$attrs"
|
||||
:cancel="false"
|
||||
confirm-text="知道了"
|
||||
v-model:show="show">
|
||||
<template #info v-if="$slots.info">
|
||||
<slot name="info"></slot>
|
||||
</template>
|
||||
</x-confirm-modal>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
</style>
|
||||
51
src/components/XSelect.vue
Normal file
51
src/components/XSelect.vue
Normal file
@@ -0,0 +1,51 @@
|
||||
<script setup lang="ts">
|
||||
import DOWNICON from "../static/icons/down.png";
|
||||
import {onMounted, reactive} from "vue";
|
||||
|
||||
const {placeholder, api} = defineProps({
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: "请选择"
|
||||
},
|
||||
api: {
|
||||
type: Function,
|
||||
default: () => {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const list = reactive([]);
|
||||
const modelValue = defineModel();
|
||||
|
||||
const change = ({detail: {value}}) => {
|
||||
modelValue.value = list[value].id;
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
api && api().then(({data}) => {
|
||||
list.length = 0;
|
||||
list.push(...data);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<picker :range="list.filter(v => !v.hidden).map(v => v.name)" @change="change">
|
||||
<view class="x-select">
|
||||
<view v-if="modelValue === null" class="text-[#86909C] test-28r">
|
||||
{{ placeholder }}
|
||||
</view>
|
||||
<view v-else>
|
||||
{{ list.find(v => v.id === modelValue)?.name }}
|
||||
</view>
|
||||
|
||||
<image :src="DOWNICON" class="!size-[24rpx]" mode="aspectFill"></image>
|
||||
</view>
|
||||
</picker>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.x-select {
|
||||
@apply px-[24rpx] py-[16rpx] bg-[#F2F3F5] rounded-[4rpx] h-[80rpx] flex items-center justify-between;
|
||||
}
|
||||
</style>
|
||||
60
src/components/XUpload.vue
Normal file
60
src/components/XUpload.vue
Normal file
@@ -0,0 +1,60 @@
|
||||
<script setup lang="ts">
|
||||
import ADDICON from "../static/icons/add.png";
|
||||
import {uploadFile} from "../utils/uils";
|
||||
import XImage from "./XImage.vue";
|
||||
|
||||
const {size} = defineProps({
|
||||
size: {
|
||||
type: String,
|
||||
default: "160rpx"
|
||||
}
|
||||
});
|
||||
const emits = defineEmits(['success']);
|
||||
const files = defineModel('files');
|
||||
|
||||
const upload = async () => {
|
||||
uploadFile({
|
||||
count: 1,
|
||||
}).then(({data}) => {
|
||||
files.value.push(data);
|
||||
emits('success', data);
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="!flex gap-[12rpx] flex-wrap">
|
||||
<view class="x-upload" @click="upload">
|
||||
<image class="!size-[28rpx]" :src="ADDICON"></image>
|
||||
<view>上传图片</view>
|
||||
</view>
|
||||
|
||||
<x-image
|
||||
:style="{
|
||||
width: size,
|
||||
height: size,
|
||||
}"
|
||||
class="border border-[rgb(229,230,235)]"
|
||||
v-for="v in files"
|
||||
:src="v"
|
||||
:list="[v]"
|
||||
:key="v">
|
||||
</x-image>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.x-upload {
|
||||
border: 1px dashed rgb(229, 230, 235);
|
||||
background-color: #F2F3F5;
|
||||
width: v-bind(size);
|
||||
height: v-bind(size);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 22rpx;
|
||||
font-size: 24rpx;
|
||||
border-radius: 4px;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user