| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269 |
- <!--
- * @since: 2024-12-30
- * BasicInfo.vue
- -->
- <template>
- <CardLayout title="基础配置" :isShowWraning="false" :mandatory="false">
- <el-form
- ref="ruleFormRef"
- label-width="auto"
- :model="ruleForm"
- :rules="formRules"
- :label-position="labelPosition"
- class="el-form-outer"
- >
- <el-form-item label="消息样式: " prop="messageType">
- <el-radio-group v-model="ruleForm.messageType" :disabled="!pageScopedDisabled">
- <el-radio :value="item.value" v-for="item in messageTypeOptions" :key="item.value"
- >{{ item.label }}
- </el-radio>
- </el-radio-group>
- </el-form-item>
- <el-form-item label="消息标题: " prop="title">
- <el-input
- v-model="ruleForm.title"
- placeholder="请输入20字以内的消息标题"
- maxlength="20"
- show-word-limit
- :disabled="!pageScopedDisabled"
- />
- </el-form-item>
- <el-form-item label="Banner图片: " prop="bannerUrl" v-if="ruleForm.messageType === MessageTypeEnum.BANNER">
- <el-upload
- ref="upload"
- v-model:file-list="fileList"
- :action="actionUrl"
- :headers="getHeaders()"
- :data="{ bizType: 'PUSH_MESSAGE' }"
- :on-success="handleAvatarSuccess"
- :before-upload="beforeAvatarUpload"
- :limit="1"
- list-type="picture-card"
- :on-exceed="handleExceed"
- :on-preview="handlePictureCardPreview"
- :disabled="!pageScopedDisabled"
- >
- <el-icon class="avatar-uploader-icon"><Plus /></el-icon>
- </el-upload>
- <span class="tip-message">支持格式:.jpg、.jpeg、.png,文件不超过 20MB,建议上传 4:3 比例的图片!</span>
- </el-form-item>
- <el-form-item label="推送渠道: " prop="pushChannel">
- <el-checkbox-group v-model="ruleForm.pushChannel">
- <el-checkbox
- v-for="item in pushChannelName"
- :key="item.value"
- :value="item.value"
- :label="item.label"
- :disabled="!pageScopedDisabled"
- />
- </el-checkbox-group>
- </el-form-item>
- <el-form-item label="失效时间: " prop="expirationTime">
- <el-date-picker
- v-model="ruleForm.expirationTime"
- type="datetime"
- placeholder="请选择失效时间"
- format="YYYY/MM/DD hh:mm:ss"
- value-format="YYYY-MM-DD hh:mm:ss"
- :disabled="!pageScopedDisabled"
- :disabled-date="disabledDate"
- />
- <span class="tip-message">请注意:超过该日期后,【APP/PC 主页】将不再弹出消息!</span>
- </el-form-item>
- <PushObject
- ref="childFromRef"
- :recipientType="ruleForm.recipientType"
- :userGroupList="ruleForm.userGroupList"
- :customUserList="ruleForm.customUserList"
- :disabled="!pageScopedDisabled"
- :has-all="true"
- />
- </el-form>
- </CardLayout>
- <el-dialog v-model="dialogVisible">
- <img w-full :src="dialogImageUrl" alt="Preview Image" />
- </el-dialog>
- </template>
- <script setup lang="ts">
- import { ref, watch, computed, unref } from 'vue';
- import { useRoute } from 'vue-router';
- import type {
- FormInstance,
- FormProps,
- FormRules,
- UploadProps,
- UploadUserFile,
- UploadInstance,
- UploadRawFile,
- } from 'element-plus';
- import { ElMessage, genFileId } from 'element-plus';
- import { Plus } from '@element-plus/icons-vue';
- import PushObject from '../../components/PushObject.vue';
- import CardLayout from './CardLayout.vue';
- import { RuleFormView, MessageTypeEnum, RuleFormAdd } from '../type';
- import { messageTypeOptions, pushChannelName } from '../../constant';
- import urlJoin from 'url-join';
- import { useGlobSetting } from '@/hooks/setting';
- import { getHeaders } from '@/utils/http/axios';
- import { isEmpty } from 'lodash-es';
- const { urlPrefix } = useGlobSetting();
- interface Props {
- dataSoure: RuleFormView;
- isDisabled: boolean;
- }
- const props = defineProps<Props>();
- const route = useRoute();
- const pageScopedDisabled = computed(() => props.isDisabled === false || route.query.viewModel === 'edit');
- const labelPosition = ref<FormProps['labelPosition']>('left');
- const childFromRef = ref<InstanceType<typeof PushObject>>();
- const actionUrl = computed(() => {
- return urlJoin(urlPrefix!, `/admin/minio/uploadFile`);
- });
- /**
- * 表单相关操作
- */
- type Rule = Omit<RuleFormView, 'introduction' | 'contentType' | 'content' | 'contentUrl' | 'operator'>;
- const formRules: FormRules<Rule> = {
- messageType: [{ required: true, trigger: 'change', message: '请选择消息样式' }],
- title: [{ required: true, trigger: 'change', message: '请输入消息标题' }],
- pushChannel: [{ required: true, trigger: 'change', message: '请选择推送渠道' }],
- recipientType: [{ required: true, trigger: 'change', message: '请选择推送对象' }],
- bannerUrl: [{ required: true, trigger: 'change', message: '请选择banner图片' }],
- };
- const ruleForm = ref<Rule>({
- messageType: MessageTypeEnum.TEXT,
- title: '',
- bannerUrl: '',
- pushChannel: [],
- expirationTime: '',
- recipientType: 1, // 默认全员
- userGroupList: [],
- customUserList: [],
- });
- const fileList = ref<UploadUserFile[]>([]);
- watch(
- () => props.dataSoure,
- (value) => {
- if (value) {
- ruleForm.value = { ...value };
- if (!isEmpty(value.bannerUrl)) {
- fileList.value = [
- {
- name: '',
- url: value.bannerUrl,
- },
- ];
- }
- }
- },
- {
- immediate: true,
- deep: true,
- },
- );
- const ruleFormRef = ref<FormInstance>();
- const isValidate = ref<boolean>();
- const validate = async () => {
- if (!ruleFormRef.value) return;
- try {
- const isSuccess = await ruleFormRef.value.validate();
- return isSuccess;
- } catch (error) {
- ElMessage.error('请完善信息填写');
- throw error;
- }
- };
- const handleAvatarSuccess: UploadProps['onSuccess'] = (response) => {
- // 注意,这里 response 是 没有被拦截处理
- ruleForm.value.bannerUrl = response.data.url;
- };
- // 上传前限制
- const beforeAvatarUpload: UploadProps['beforeUpload'] = (rawFile) => {
- if (!['image/jpeg', 'image/png', 'image/jpg'].includes(rawFile.type)) {
- ElMessage.error('文件格式仅支持:.jpg, .jpeg, .png');
- return false;
- } else if (rawFile.size / 1024 / 1024 > 20) {
- ElMessage.error('文件不支持超过 20MB!');
- return false;
- }
- return true;
- };
- // 图片预览
- const dialogImageUrl = ref('');
- const dialogVisible = ref(false);
- const handlePictureCardPreview: UploadProps['onPreview'] = (uploadFile) => {
- dialogImageUrl.value = uploadFile.url!;
- dialogVisible.value = true;
- };
- const upload = ref<UploadInstance>();
- const handleExceed: UploadProps['onExceed'] = (files) => {
- upload.value!.clearFiles();
- const file = files[0] as UploadRawFile;
- file.uid = genFileId();
- upload.value!.handleStart(file);
- };
- const buildFromData = () => {
- const childValue = childFromRef.value!.getChildValue();
- childFromRef.value!.submitForm().then((res) => {
- isValidate.value = res;
- });
- const basicInfo = { ...unref(ruleForm) } as RuleFormAdd;
- if (childValue) {
- basicInfo.recipientType = childValue.recipientType!;
- basicInfo.userGroupList = childValue.userGroupList!;
- basicInfo.customUserList = childValue.customUserList!;
- }
- return basicInfo;
- };
- const disabledDate = (time: Date) => {
- return time.getTime() < Date.now();
- };
- defineExpose({ validate, buildFromData });
- </script>
- <style scoped lang="scss">
- .avatar-uploader .avatar {
- width: 58px;
- height: 58px;
- display: block;
- }
- .avatar-uploader .el-upload {
- border: 1px dashed var(--el-border-color);
- border-radius: 6px;
- cursor: pointer;
- position: relative;
- overflow: hidden;
- transition: var(--el-transition-duration-fast);
- }
- .avatar-uploader .el-upload:hover {
- border-color: var(--el-color-primary);
- }
- .el-icon.avatar-uploader-icon {
- font-size: 28px;
- color: #8c939d;
- width: 58px;
- height: 58px;
- text-align: center;
- }
- .tip-message {
- margin-left: 20px;
- }
- </style>
|