forked from gxwebsoft/websoft-cms
14 changed files with 447 additions and 39 deletions
@ -0,0 +1,86 @@ |
|||
<template> |
|||
<!-- <div class="text-center flex flex-col items-center pb-10">--> |
|||
<!-- <h2 class="text-3xl font-bold tracking-tight text-gray-900 dark:text-white sm:text-4xl lg:text-5xl">--> |
|||
<!-- {{ title }}--> |
|||
<!-- </h2>--> |
|||
<!-- <div class="sub-title">--> |
|||
<!-- <p class="text-gray-500 dark:text-gray-400 py-3">--> |
|||
<!-- {{ comments }}--> |
|||
<!-- </p>--> |
|||
<!-- </div>--> |
|||
<!-- </div>--> |
|||
<div class="xl:w-screen-xl sm:flex xl:p-0 p-4 m-auto relative"> |
|||
<el-row :gutter="24" class="flex"> |
|||
<template v-for="(item,index) in list" :key="index"> |
|||
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="6" class="mb-5 min-w-xs"> |
|||
<el-card shadow="hover" :body-style="{ padding: '0px' }" class="hover:bg-gray-50 cursor-pointer" @click="openSpmUrl(`/form`, item,item.formId)"> |
|||
<el-image |
|||
:src="`${item.photo}`" |
|||
fit="fill" :lazy="true" class="w-full md:h-[150px] h-[199px] cursor-pointer"/> |
|||
<div class="flex-1 px-4 py-5 sm:p-6 !p-4"> |
|||
<div class="text-gray-700 dark:text-white text-base font-semibold flex flex-col gap-1.5"> |
|||
<div class="flex-1 text-xl cursor-pointer">{{ item.name }}</div> |
|||
<!-- <div class="text-red-500">¥{{ item.price }}</div>--> |
|||
</div> |
|||
<!-- <div v-if="item.price && item.price > 0" class="flex items-center gap-1.5 py-2 text-gray-500 justify-between">--> |
|||
<!-- <div class="text-gray-500">{{ item.comments }}</div>--> |
|||
<!-- </div>--> |
|||
<div class="button-group flex justify-center mt-3"> |
|||
<el-button class="w-full" size="large" :icon="ElIconView" @click="openSpmUrl('/form', item,item.formId)"> |
|||
查看详情 |
|||
</el-button> |
|||
<el-button class="w-full" size="large" :icon="ElIconEdit" @click="openSpmUrl('/form', item,item.formId)">立即预约</el-button> |
|||
</div> |
|||
</div> |
|||
</el-card> |
|||
</el-col> |
|||
</template> |
|||
</el-row> |
|||
</div> |
|||
<div v-if="disabled" class="px-1 text-center text-gray-500 min-h-xs"> |
|||
没有更多了 |
|||
</div> |
|||
</template> |
|||
|
|||
<script setup lang="ts"> |
|||
import {openSpmUrl} from "~/utils/common"; |
|||
import dayjs from "dayjs"; |
|||
import {useServerRequest} from "~/composables/useServerRequest"; |
|||
import type {ApiResult, PageResult} from "~/api"; |
|||
import type {Product} from "~/api/oa/product/model"; |
|||
import type {Form} from "~/api/cms/form/model"; |
|||
|
|||
const props = withDefaults( |
|||
defineProps<{ |
|||
disabled?: boolean; |
|||
title?: string; |
|||
comments?: string; |
|||
}>(), |
|||
{ |
|||
title: '卡片标题', |
|||
comments: '卡片描述' |
|||
} |
|||
); |
|||
|
|||
const emit = defineEmits<{ |
|||
(e: 'done'): void; |
|||
}>(); |
|||
|
|||
const runtimeConfig = useRuntimeConfig(); |
|||
const list = ref<Form[]>([]); |
|||
|
|||
// 请求数据 |
|||
const reload = async () => { |
|||
const {data: response} = await useServerRequest<ApiResult<PageResult<Product>>>('/cms/form/page', { |
|||
baseURL: runtimeConfig.public.apiServer, params: { |
|||
limit: 8 |
|||
} |
|||
}) |
|||
if (response.value?.data) { |
|||
if (response.value?.data.list) { |
|||
list.value = response.value?.data.list; |
|||
} |
|||
} |
|||
} |
|||
reload(); |
|||
</script> |
@ -0,0 +1,150 @@ |
|||
<template> |
|||
<div class="page-main md:w-screen-xl m-auto p-3" v-if="form"> |
|||
<el-row :gutter="24"> |
|||
<el-col :span="18" :xs="24"> |
|||
<el-card shadow="hover" class="hover:border-green-50 hover:border-2 mb-5"> |
|||
<template #header> |
|||
<div class="card-header font-bold text-xl"> |
|||
<span>{{ data?.name }}</span> |
|||
</div> |
|||
</template> |
|||
<p v-html="data?.comments"></p> |
|||
</el-card> |
|||
<el-card shadow="hover" class="hover:border-green-50 hover:border-2 mb-5"> |
|||
<template #header> |
|||
<div class="card-header font-bold text-xl"> |
|||
<span>预约报名</span> |
|||
</div> |
|||
</template> |
|||
<el-form ref="formRef" :model="form" label-position="top" class="w-full sm:py-2" size="large" status-icon> |
|||
<el-form-item label="您的姓名" prop="name"> |
|||
<el-input |
|||
v-model="form.name" |
|||
placeholder="张三" |
|||
/> |
|||
</el-form-item> |
|||
<el-form-item label="您的年龄(岁)" prop="age"> |
|||
<el-input-number |
|||
v-model="form.age" |
|||
placeholder="24" |
|||
:min="6" |
|||
:max="99" |
|||
/> |
|||
</el-form-item> |
|||
<el-form-item label="联系电话" prop="phone"> |
|||
<el-input |
|||
v-model="form.phone" |
|||
:maxlength="11" |
|||
placeholder="13800138000" |
|||
/> |
|||
</el-form-item> |
|||
<el-form-item label="您预约的疫苗" prop="age"> |
|||
<el-radio-group v-model="form.type"> |
|||
<el-radio value="九阶" size="large" border>九阶</el-radio> |
|||
<el-radio value="四阶" size="large" border>四阶</el-radio> |
|||
</el-radio-group> |
|||
</el-form-item> |
|||
<el-form-item label="本次接种的剂次" prop="number"> |
|||
<el-checkbox-group v-model="checkList"> |
|||
<el-checkbox label="第一剂" value="第一剂" /> |
|||
<el-checkbox label="第二剂" value="第二剂" /> |
|||
<el-checkbox label="第三剂" value="第三剂" /> |
|||
</el-checkbox-group> |
|||
</el-form-item> |
|||
<el-form-item label="备注信息" prop="comments"> |
|||
<el-input |
|||
v-model="form.comments" |
|||
:rows="5" |
|||
type="textarea" |
|||
placeholder="请输入备注信息,最多300字" |
|||
/> |
|||
</el-form-item> |
|||
<div class="dialog-footer w-full"> |
|||
<el-button type="primary" size="large" class="w-full" @click="submitForm(formRef)"> 提交 </el-button> |
|||
</div> |
|||
</el-form> |
|||
</el-card> |
|||
</el-col> |
|||
</el-row> |
|||
</div> |
|||
</template> |
|||
|
|||
<script setup lang="ts"> |
|||
import {FullScreen} from '@element-plus/icons-vue' |
|||
import type {ApiResult} from "~/api"; |
|||
import type {FormInstance, FormRules} from "element-plus"; |
|||
import {useClientRequest} from "~/composables/useClientRequest"; |
|||
import {reactive, ref} from "vue"; |
|||
import useFormData from "~/utils/use-form-data"; |
|||
import type {FormRecord} from "~/api/cms/form-record/model"; |
|||
import type {Form} from "~/api/cms/form/model"; |
|||
|
|||
|
|||
const props = withDefaults( |
|||
defineProps<{ |
|||
title?: string; |
|||
data?: Form; |
|||
}>(), |
|||
{} |
|||
); |
|||
|
|||
const formRef = ref<FormInstance>() |
|||
const visible = ref<boolean>(false); |
|||
const visible2 = ref<boolean>(false); |
|||
const checkList = ref<string[]>([]); |
|||
const loading = ref<boolean>(true) |
|||
|
|||
const emit = defineEmits<{ |
|||
(e: 'done', page: number): void |
|||
}>() |
|||
|
|||
const { form, resetFields } = useFormData<FormRecord>({ |
|||
formRecordId: undefined, |
|||
formId: undefined, |
|||
name: undefined, |
|||
age: undefined, |
|||
type: undefined, |
|||
extra: undefined, |
|||
formData: undefined, |
|||
formObj: undefined, |
|||
userId: undefined, |
|||
phone: undefined, |
|||
sortNumber: undefined, |
|||
comments: undefined, |
|||
status: undefined, |
|||
createTime: undefined, |
|||
layout: undefined |
|||
}); |
|||
|
|||
|
|||
const onComments = () => { |
|||
visible.value = true; |
|||
} |
|||
|
|||
const onComplaint = () => { |
|||
visible2.value = true; |
|||
} |
|||
|
|||
const onPageChange = (page: number) => { |
|||
emit('done', page) |
|||
} |
|||
|
|||
const submitForm = async (formEl: FormInstance | undefined) => { |
|||
if (!formEl) return |
|||
form.formId = props.data?.formId; |
|||
form.extra = checkList.value.join(',') |
|||
useClientRequest<ApiResult<any>>(`/cms/form-record`, { |
|||
method: 'POST', |
|||
body: form |
|||
}).then(res => { |
|||
if (res.code == 0) { |
|||
ElMessage.success(res.message) |
|||
visible.value = false |
|||
resetFields(); |
|||
emit('done',1) |
|||
} else { |
|||
return ElMessage.error(res.message) |
|||
} |
|||
}) |
|||
} |
|||
</script> |
@ -0,0 +1,100 @@ |
|||
<template> |
|||
<div class="banner m-auto relative sm:flex"> |
|||
<svg viewBox="0 0 1440 181" fill="none" xmlns="http://www.w3.org/2000/svg" |
|||
class="pointer-events-none absolute w-full top-[-2px] transition-all text-green-5 flex-shrink-0 opacity-100 duration-[400ms] opacity-80 -z-10"> |
|||
<mask id="path-1-inside-1_414_5526" fill="white"> |
|||
<path d="M0 0H1440V181H0V0Z"></path> |
|||
</mask> |
|||
<path d="M0 0H1440V181H0V0Z" fill="url(#paint0_linear_414_5526)" fill-opacity="0.22"></path> |
|||
<path d="M0 2H1440V-2H0V2Z" fill="url(#paint1_linear_414_5526)" mask="url(#path-1-inside-1_414_5526)"></path> |
|||
<defs> |
|||
<linearGradient id="paint0_linear_414_5526" x1="720" y1="0" x2="720" y2="181" gradientUnits="userSpaceOnUse"> |
|||
<stop stop-color="currentColor"></stop> |
|||
<stop offset="1" stop-color="currentColor" stop-opacity="0"></stop> |
|||
</linearGradient> |
|||
<linearGradient id="paint1_linear_414_5526" x1="0" y1="90.5" x2="1440" y2="90.5" gradientUnits="userSpaceOnUse"> |
|||
<stop stop-color="currentColor" stop-opacity="0"></stop> |
|||
<stop offset="0.395" stop-color="currentColor"></stop> |
|||
<stop offset="1" stop-color="currentColor" stop-opacity="0"></stop> |
|||
</linearGradient> |
|||
</defs> |
|||
</svg> |
|||
<div class="md:w-screen-xl m-auto"> |
|||
<div class="sm:py-4 sm:px-0 mx-3 py-2"> |
|||
<el-breadcrumb :separator-icon="ArrowRight"> |
|||
<el-breadcrumb-item :to="{ path: '/' }"> |
|||
<el-icon class="cursor-pointer"> |
|||
<ElIconHouse/> |
|||
</el-icon> |
|||
</el-breadcrumb-item> |
|||
<el-breadcrumb-item>项目详情</el-breadcrumb-item> |
|||
</el-breadcrumb> |
|||
</div> |
|||
<div class="py-1 sm:py-16 px-3" _path="/templates" _dir="" _draft="false" _partial="false" _locale="" |
|||
_id="content:4.templates.yml" _type="yaml" _source="content" _file="4.templates.yml" _stem="4.templates" |
|||
_extension="yml"> |
|||
<div id="mse"></div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script setup lang="ts"> |
|||
import {ArrowRight} from '@element-plus/icons-vue' |
|||
import Player from "xgplayer"; |
|||
import 'xgplayer/dist/index.min.css'; |
|||
|
|||
const props = withDefaults( |
|||
defineProps<{ |
|||
title?: string; |
|||
desc?: string; |
|||
buyUrl?: string; |
|||
form?: any; |
|||
value?: number; |
|||
}>(), |
|||
{ |
|||
title: 'Templates', |
|||
desc: 'Explore community templates to get up and running in a few seconds.', |
|||
demoUrl: '/product/website', |
|||
buyUrl: 'https://github.com/websoft9/ansible-templates', |
|||
value: 4.2 |
|||
} |
|||
); |
|||
|
|||
const url = ref<string>(''); |
|||
const poster = ref<string>(''); |
|||
|
|||
onMounted(() => { |
|||
new Player({ |
|||
id: "mse", //元素id |
|||
lang: "zh", //设置中文 |
|||
volume: 0, // 默认静音 |
|||
autoplay: false, //自动播放 |
|||
screenShot: false, // 开启截图功能 |
|||
//视频地址 |
|||
url: url.value, |
|||
//封面图 |
|||
poster: poster.value, |
|||
fluid: true, // 填满屏幕 (流式布局) |
|||
playbackRate: [0.5, 1, 2] //传入倍速可选数组 |
|||
}); |
|||
}); |
|||
|
|||
watch( |
|||
() => props.form.video, |
|||
(video) => { |
|||
console.log(video,'=>video') |
|||
url.value = 'https://oss.wsdns.cn/20240417/9339681f3bc14999bfb2d26491f1c96e.mp4'; |
|||
poster.value = props.form.photo; |
|||
}, |
|||
{ immediate: true } |
|||
); |
|||
</script> |
|||
<style scoped lang="less"> |
|||
.rounded-avatar{ |
|||
border-radius: 30px; |
|||
} |
|||
.rounded-avatar-xs{ |
|||
border-radius: 20px; |
|||
} |
|||
</style> |
@ -0,0 +1,65 @@ |
|||
<!-- 文章详情 --> |
|||
<template> |
|||
<PageBanner :form="form" /> |
|||
|
|||
<Comments :data="form" /> |
|||
</template> |
|||
<script setup lang="ts"> |
|||
import type { ApiResult } from '~/api'; |
|||
import { useServerRequest } from '~/composables/useServerRequest'; |
|||
import { useWebsite } from '~/composables/configState'; |
|||
import { getIdBySpm } from '~/utils/common'; |
|||
import useFormData from '~/utils/use-form-data'; |
|||
import PageBanner from './components/PageBanner.vue'; |
|||
import type { Form } from '~/api/cms/form/model'; |
|||
import Comments from "~/pages/form/components/Comments.vue"; |
|||
|
|||
// 引入状态管理 |
|||
const route = useRoute(); |
|||
const website = useWebsite(); |
|||
|
|||
// 配置信息 |
|||
const { form, assignFields } = useFormData<Form>({ |
|||
formId: undefined, |
|||
name: '', |
|||
photo: '', |
|||
background: '', |
|||
video: '', |
|||
layout: '', |
|||
comments: '', |
|||
status: undefined, |
|||
createTime: '' |
|||
}); |
|||
|
|||
// 请求数据 |
|||
const reload = async () => { |
|||
// 要求登录 |
|||
// if (!token.value || token.value == '') { |
|||
// openSpmUrl('/passport/login'); |
|||
// return; |
|||
// } |
|||
// 存在spm(优先级高) |
|||
const { data: item } = await useServerRequest<ApiResult<Form>>('/cms/form/' + getIdBySpm(5)); |
|||
if (item.value?.data) { |
|||
assignFields(item.value.data); |
|||
form.comments = item.value?.data?.comments; |
|||
} |
|||
|
|||
// seo |
|||
useHead({ |
|||
title: `${form.name} - ${website.value.websiteName}`, |
|||
bodyAttrs: { |
|||
class: 'page-container' |
|||
} |
|||
}); |
|||
}; |
|||
|
|||
watch( |
|||
() => route.path, |
|||
path => { |
|||
console.log(path, '=>Path'); |
|||
reload(); |
|||
}, |
|||
{ immediate: true } |
|||
); |
|||
</script> |
Loading…
Reference in new issue