Quellcode durchsuchen

📦传承人作品页面

快乐的梦鱼 vor 2 Wochen
Ursprung
Commit
6d533225e0

+ 1 - 0
package-lock.json

@@ -17,6 +17,7 @@
         "ant-design-vue": "^4.2.6",
         "axios": "^1.9.0",
         "bootstrap": "^5.3.0",
+        "dayjs": "^1.11.18",
         "lodash-es": "^4.17.21",
         "md5": "^2.3.0",
         "mitt": "^3.0.1",

+ 1 - 0
package.json

@@ -23,6 +23,7 @@
     "ant-design-vue": "^4.2.6",
     "axios": "^1.9.0",
     "bootstrap": "^5.3.0",
+    "dayjs": "^1.11.18",
     "lodash-es": "^4.17.21",
     "md5": "^2.3.0",
     "mitt": "^3.0.1",

+ 48 - 0
src/api/inheritor/InheritorContent.ts

@@ -1,5 +1,6 @@
 import { DataModel } from '@imengyu/js-request-transform';
 import { AppServerRequestModule } from '../RequestModules';
+import dayjs from 'dayjs';
 
 export class CommonInfo<T extends DataModel> extends DataModel<T> {
 
@@ -211,6 +212,11 @@ export class InheritorInfo extends CommonInfo<InheritorInfo> {
           }
         },
       ],
+      works: {
+        clientSide: 'array',
+        clientSideChildDataModel: InheritorWorkInfo,
+        serverSide: 'array' 
+      },
     };
     this._convertKeyType = (key, direction) => {
       if (key.endsWith('Text') || key.endsWith('_text')) {
@@ -255,6 +261,7 @@ export class InheritorInfo extends CommonInfo<InheritorInfo> {
   batchText = '' as string;
   ichSiteTypeText = '' as string;
   progressText = '' as string;
+  works = [] as InheritorWorkInfo[];
 }
 export class InheritorExpandInfo extends DataModel<InheritorExpandInfo> {
   constructor() {
@@ -295,6 +302,47 @@ export class InheritorExpandInfo extends DataModel<InheritorExpandInfo> {
   }
   modelId = 7;
 }
+export class InheritorWorkInfo extends DataModel<InheritorWorkInfo> {
+  constructor() {
+    super(InheritorWorkInfo, "传承人作品");
+    this.setNameMapperCase('Camel', 'Snake');
+    this._convertTable = {
+      collectionTime: { clientSide: 'dayjs', serverSide: 'string' },
+    };
+    this._convertKeyType = (key, direction) => {
+      if (key.endsWith('Text') || key.endsWith('_text')) {
+        return {
+          clientSide: 'string',
+          serverSide: 'undefined',
+        };
+      }
+    };
+    this._afterSolveServer = (self) => {
+    };
+    this._afterSolveClient = (data) => {
+    };
+  }
+
+  id = 0;
+  category = '';
+  feature = '';
+  otherName = '';
+  creator = '';
+  language = '';
+  overview = '';
+  ethnicGroup = '';
+  creationEra = '';
+  mainPerformer = '';
+  otherPerformers = '';
+  fullString = '';
+  tune = '';
+  development = '';
+  spread = '';
+  influence = '';
+  collector = '';
+  collectionTime = dayjs();
+  collectionLocation = '';
+}
 export class SeminarInfo extends CommonInfo<SeminarInfo> {
   constructor() {
     super(SeminarInfo, "传习所信息");

+ 0 - 86
src/assets/scss/main.scss

@@ -118,9 +118,6 @@ $small-banner-height: 445px;
   &-type2 {
     background-image: url('@/assets/images/Bg2.png');
   }
-  &-type3 {
-    background-image: url('@/assets/images/index/IntrodRight.jpg');
-  }
 }
 .main-clickable {
   cursor: pointer;
@@ -274,89 +271,6 @@ $small-banner-height: 445px;
 
 //Card box
 
-.main-card-box {
-  position: relative;
-  min-height: 330px;
-  color: #fff;
-  margin-right: 24px;
-  overflow: hidden;
-  //transform: translateX(-50%);
-
-  .content {
-    position: absolute;
-    inset: 24px;
-    z-index: 10;
-    display: flex;
-    flex-direction: column;
-
-    h4 {
-      font-family: SourceHanSerifCNBold;
-      font-size: 1.5rem;
-      margin: 0;
-      margin-bottom: 32px;
-    }
-    .descs {
-      display: flex;
-      flex-direction: row;
-      flex-wrap: wrap;
-
-      .box {
-        flex: 1 1 50%;
-        margin-bottom: 32px;
-        cursor: pointer;
-        color: #fff;
-        text-decoration: none;
-
-        h5 {
-          font-size: 1rem;
-          font-weight: normal;
-          margin: 0;
-        }
-        p {
-          font-family: Impact;
-          font-weight: normal;
-          font-size: 2.8rem;
-          margin: 0;
-        }
-      }
-    }
-  }
-
-  $background-types: (
-    type1: (url('@/assets/images/index/BoxPrinting2.png'), url('@/assets/images/index/Box3.jpg')),
-    type2: (url('@/assets/images/index/BoxPrinting1.png'), url('@/assets/images/index/Box1.png')),
-    type3: (url('@/assets/images/index/BoxPrinting4.png'), url('@/assets/images/index/Box2.jpg'))
-  );
-
-  @each $typeName, $type in $background-types {
-    &.#{$typeName} {
-      &::after {
-        content: '';
-        position: absolute;
-        inset: 0;
-        background-image: list.nth($type, 2);
-        z-index: 0;
-      }
-      &::before {
-        content: '';
-        position: absolute;
-        bottom: -10px;
-        right: -10px;
-        width: 180px;
-        height: 180px;
-        background-size: 180px;
-        background-image: list.nth($type, 1);
-        z-index: 1;
-      }
-    }
-  }
-
-  &.type3 .descs div {
-    flex-basis: 33%;
-    margin-bottom: 22px;
-  }
-}
-
 @media (max-width: 1280px) {
   .main-section {
     padding: 100px 80px;

+ 1 - 0
src/components/dynamicf/Editor/Quill.d.ts

@@ -0,0 +1 @@
+declare module 'quill-image-uploader';

+ 168 - 11
src/components/dynamicf/Editor/QuillEditorWrapper.vue

@@ -1,7 +1,7 @@
 <template>
   <QuillEditor
     :modules="modules" 
-    toolbar="full" 
+    :toolbar="toolbarOptions" 
     theme="snow"
     contentType="html"
     v-bind="$attrs"
@@ -11,11 +11,48 @@
 </template>
 
 <script lang="ts" setup>
-import { QuillEditor } from '@vueup/vue-quill'
+import { QuillEditor, Quill } from '@vueup/vue-quill'
 import '@vueup/vue-quill/dist/vue-quill.snow.css'
 import ImageUploader from 'quill-image-uploader';
 import CommonContent from '@/api/CommonContent';
 
+const Size   = Quill.import('attributors/style/size')
+const Font   = Quill.import('attributors/style/font')
+const Align  = Quill.import('attributors/style/align')
+const Color  = Quill.import('attributors/style/color')
+const BgColor= Quill.import('attributors/style/background')
+
+Size.whitelist  = [  
+  '12px',
+  '14px',
+  '16px',
+  '18px',
+  '22px',
+  '26px',
+  '36px',
+  '42px',
+  '52px',
+  '64px'
+];
+Font.whitelist  = [
+  'SimSun',
+  'SimHei',
+  'Microsoft-YaHei',
+  'Kaiti',
+  'FangSong',
+  'STXihei',
+  'STKaiti',
+  'STSong',
+  'Arial',
+  'Times-New-Roman',
+]
+
+Quill.register(Size,    true)
+Quill.register(Font,    true)
+Quill.register(Align,   true)
+Quill.register(Color,   true)
+Quill.register(BgColor, true)
+
 const emit = defineEmits(['update:modelValue'])
 const props = defineProps({
   modelValue: {
@@ -24,14 +61,134 @@ const props = defineProps({
   }
 })
 
-const modules = [{
-  name: 'imageUploader',
-  module: ImageUploader,
-  options: {
-    upload: async (file: any) => {
-      const { url } = await CommonContent.uploadSmallFile(file);
-      return url;
+
+const toolbarOptions = [
+  ['bold', 'italic', 'underline', 'strike'],        // toggled buttons
+  ['blockquote'],
+  ['link', 'image', 'video'],
+
+  [{ 'list': 'ordered'}, { 'list': 'bullet' }, { 'list': 'check' }],
+  [{ 'indent': '-1'}, { 'indent': '+1' }],          // outdent/indent
+  [{ 'direction': 'rtl' }],                         // text direction
+
+  [{ 'size': Size.whitelist }],  // custom dropdown
+  [{ 'header': [1, 2, 3, 4, 5, 6, false] }],
+
+  [{ 'color': [] }, { 'background': [] }],          // dropdown with defaults from theme
+  [{ 'font': Font.whitelist }],
+  [{ 'align': [] }],
+
+  ['clean']                                         // remove formatting button
+];
+const modules = [
+  {
+    name: 'imageUploader',
+    module: ImageUploader,
+    options: {
+      upload: async (file: any) => {
+        const { url } = await CommonContent.uploadSmallFile(file);
+        return url;
+      }
+    }
+  }, 
+];
+</script>
+
+<style lang="scss">
+
+$sizeList: (
+  '12px': '小四',
+  '14px': '四号',
+  '16px': '小三',
+  '18px': '二号',
+  '22px': '一号',
+  '26px': '小初',
+  '36px': '初号',
+  '42px': '特大号',
+  '52px': '超大号',
+  '64px': '特大初'
+);
+$fontList: (
+  'SimSun': "宋体",
+  'SimHei': "黑体",
+  'Microsoft-YaHei': "微软雅黑",
+  'Kaiti': "楷体",
+  'FangSong': "仿宋",
+  'STXihei': "华文细黑",
+  'STKaiti': "华文楷体",
+  'STSong': "华文宋体",
+  'Arial': "Arial",
+  'Times-New-Roman': "Times New Roman"
+);
+
+.ql-snow {
+  
+  .ql-tooltip{ 
+    &::before {
+      content: "访问超链接:";
+    }
+    &[data-mode=link]::before {
+      content: "输入超链接:";
+    }
+    &[data-mode=video]::before {
+      content: "嵌入视频链接:";
     }
+    &.ql-editing a.ql-action::after {
+      content: '保存';
+    }
+     a.ql-action::after {
+      content: '编辑';
+    }
+    a.ql-remove::before {
+      content: '删除';
+    }
+  }
+  .ql-picker {
+    &.ql-font {
+
+
+      @each $key, $value in $fontList {
+        .ql-picker-item[data-value='#{$key}']::before, .ql-picker-label[data-value='#{$key}']::before {
+          content: '#{$value}';
+        }
+      }
+    }
+    &.ql-size {
+
+      @each $key, $value in $sizeList {
+        .ql-picker-item[data-value='#{$key}']::before, .ql-picker-label[data-value='#{$key}']::before {
+          content: '#{$value}';
+        }
+      }
+    }
+    &.ql-header {
+      $headerList: (
+        '1': '一级标题',
+        '2': '二级标题',
+        '3': '三级标题',
+        '4': '四级标题',
+        '5': '五级标题',
+        '6': '六级标题',
+      );
+      @each $key, $value in $headerList {
+        .ql-picker-item::before, .ql-picker-label::before {
+          content: '正文';
+        }
+        .ql-picker-item[data-value='#{$key}']::before, .ql-picker-label[data-value='#{$key}']::before {
+          content: '#{$value}';
+        }
+      }
+    }
+
+  }
+}
+
+@each $key, $value in $fontList {
+  .ql-font-#{$key} { 
+    font-family: #{$value},serif; 
   }
-}];
-</script>
+}
+@each $key, $value in $sizeList {
+  .ql-size-#{$key}   { font-size: #{$key}; }
+}
+</style>

+ 6 - 1
src/components/parts/EmptyToRecord.vue

@@ -2,12 +2,16 @@
 const emit = defineEmits([ 'edit' ]);
 defineProps({
   model: {
-    type: Object,
+    type: null,
     default: undefined
   },
   title: {
     type: String,
     default: '非遗项目'
+  },
+  showEdited: {
+    type: Boolean,
+    default: true
   }
 })
 </script>
@@ -25,6 +29,7 @@ defineProps({
   </a-result>
   <div v-else>
     <a-alert
+      v-if="showEdited"
       :message="`点击这里可以修改 ${title} 信息`"
       type="info"
       show-icon

+ 18 - 4
src/pages/forms/form.vue

@@ -5,6 +5,7 @@
     <!-- 表单 -->
     <section class="main-section ">
       <div class="content">
+        <a-button :icon="h(ArrowLeftOutlined)" @click="handleBack">返回主页</a-button>
         <div class="title">
           <h2>{{ title }}</h2>
         </div>
@@ -27,7 +28,7 @@
                 提交
               </a-button>
             </a-tab-pane>
-            <a-tab-pane key="2" tab="扩展信息">
+            <a-tab-pane v-if="extendFormOptions" key="2" tab="扩展信息">
               <DynamicForm
                 ref="formExtend"
                 :model="(extendFormModel as any)" 
@@ -50,11 +51,12 @@
 </template>
 
 <script setup lang="ts" generic="T extends DataModel, U extends DataModel">
-import { onMounted, ref, toRefs, type PropType } from 'vue';
+import { onMounted, ref, toRefs, type PropType, h } from 'vue';
 import { useRouter } from 'vue-router';
 import { useWindowOnUnLoadConfirm } from '@/composeable/WindowOnUnLoad';
 import { DynamicForm, type IDynamicFormOptions, type IDynamicFormRef } from '@imengyu/vue-dynamic-form';
 import { message, Modal, type FormInstance } from 'ant-design-vue';
+import { ArrowLeftOutlined } from '@ant-design/icons-vue';
 import InheritorContent from '@/api/inheritor/InheritorContent';
 import type { DataModel } from '@imengyu/js-request-transform';
 
@@ -73,11 +75,11 @@ const props = defineProps({
   },
   extendFormModel: {
     type: Object as PropType<U>,
-    required: true
+    default: null
   },
   extendFormOptions: {
     type: Object as PropType<IDynamicFormOptions>,
-    required: true
+    default: null
   },
   load: {
     type: Function as PropType<() => Promise<void>>,
@@ -179,6 +181,18 @@ async function loadData() {
   }
 }
 
+function handleBack() {
+  Modal.confirm({
+    title: '确定返回吗?',
+    content: '返回后将丢失当前填写的信息,若有修改请先提交哦',
+    okText: '确定',
+    okType: 'danger',
+    onOk() {
+      router.back();
+    },
+  });
+}
+
 onMounted(async () => {
   await loadData();
 })

+ 1 - 1
src/pages/forms/inheritor.vue

@@ -69,8 +69,8 @@ const formOptions = ref<IDynamicFormOptions>({
         { label: '出生日期', name: 'dateBirth', type: 'text', additionalProps: { placeholder: '请选择出生日期' } },
         { label: '逝世日期', name: 'deathBirth', type: 'text', additionalProps: { placeholder: '请选择逝世日期' } },
         { label: '单位', name: 'unit', type: 'text', additionalProps: { placeholder: '请输入单位' } },
-        { label: '内容', name: 'content', type: 'richtext', additionalProps: { placeholder: '请输入内容' } },
         { label: '简介', name: 'intro', type: 'richtext', additionalProps: { placeholder: '请输入简介' } },
+        { label: '详情', name: 'content', type: 'richtext', additionalProps: { placeholder: '请输入详情' } },
         { label: '奖项-成就', name: 'prize', type: 'richtext', additionalProps: { placeholder: '请输入奖项-成就' } },
         { 
           type: 'array-object', label: '代表性图片', name: 'typicalImages',

+ 1 - 1
src/pages/forms/seminar.vue

@@ -51,7 +51,7 @@ const formOptions = ref<IDynamicFormOptions>({
             loadData: async () => (await CommonContent.getCategoryList(2)).map(p => ({ label: p.title, value: p.id, raw: p }))
           },
         },
-        { label: '内容', name: 'content', type: 'richtext', additionalProps: { placeholder: '请输入内容' } },
+        { label: '简介', name: 'content', type: 'richtext', additionalProps: { placeholder: '请输入内容' } },
         
         { label: '地图坐标', name: 'lonlat', type: 'map-pick-point' },
         

+ 113 - 0
src/pages/forms/works.vue

@@ -0,0 +1,113 @@
+<template>
+  <!-- 传承人作品采集 -->
+  <Form 
+    :formModel="formModel"
+    :formOptions="formOptions"
+    :load="loadData"
+  />
+</template>
+
+<script setup lang="ts">
+import { ref, type Ref } from 'vue';
+import { useImageSimpleUploadCo } from '@/common/upload/ImageUploadCo';
+import Form from './form.vue';
+import InheritorContent, { InheritorWorkInfo } from '@/api/inheritor/InheritorContent';
+import CommonContent from '@/api/CommonContent';
+import type { IDynamicFormOptions } from '@imengyu/vue-dynamic-form';
+import type { SelectProps } from 'ant-design-vue';
+import type { UploadImageFormItemProps } from '@/components/dynamicf/UploadImageFormItem';
+import { useRoute } from 'vue-router';
+
+const formModel = ref(new InheritorWorkInfo()) as Ref<InheritorWorkInfo>;
+const formOptions = ref<IDynamicFormOptions>({
+  formLabelCol: { span: 6 },
+  formWrapperCol: { span: 24 },
+  formAdditionaProps: {
+    layout: 'vertical',
+    scrollToFirstError: true,
+  },
+  formNestNameGenerateType: 'array',
+  formItems: [
+      {
+        type: 'group-flat', label: '作品信息', name: 'baseInfo',
+        childrenColProps: { span: 24 },
+        children: [
+          { label: '标题', name: 'title', type: 'text', additionalProps: { placeholder: '请输入标题' } },
+          { label: '地区', name: 'region', type: 'select-id', additionalProps: { placeholder: '请选择地区', loadData: async () => (await CommonContent.getCategoryList(1)).map(p => ({ label: p.title, value: p.id, raw: p })) } },
+          { label: '类型', name: 'type', type: 'select', additionalProps: { placeholder: '请选择类型', options: [{ text: '文章', value: 1 }, { text: '音频', value: 2 }, { text: '视频', value: 3 }, { text: '相册', value: 4 }, { text: '数字档案', value: 5 }] } },
+          { label: '图片', name: 'image', type: 'single-image', additionalProps: { placeholder: '请上传图片', uploadCo: useImageSimpleUploadCo(), name: 'file', accept: 'image/*' } as UploadImageFormItemProps },
+          { label: '图片说明', name: 'imageDesc', type: 'text', additionalProps: { placeholder: '请输入图片说明' } },
+          { label: '组图', name: 'images', type: 'mulit-image', additionalProps: { placeholder: '请上传组图', uploadCo: useImageSimpleUploadCo(), name: 'file', accept: 'image/*', maxCount: 20 } as UploadImageFormItemProps },
+          { label: '内容介绍', name: 'content', type: 'richtext', additionalProps: { placeholder: '请输入内容介绍' } },
+          { 
+            label: '音频', name: 'audio', type: 'single-image', 
+            hidden: { callback: (_, model) => (model as InheritorWorkInfo).type !== 2 },
+            additionalProps: { 
+              placeholder: '请上传音频', 
+              uploadCo: useImageSimpleUploadCo(), name: 'file' 
+            } as UploadImageFormItemProps 
+          },
+          { 
+            label: '视频', name: 'video', type: 'single-video', 
+            hidden: { callback: (_, model) => (model as InheritorWorkInfo).type !== 3 },
+            additionalProps: { 
+              placeholder: '请上传视频', uploadCo: useImageSimpleUploadCo(), name: 'file' 
+            } as UploadImageFormItemProps 
+          },
+          { 
+            label: '数字档案', name: 'archives', type: 'mulit-image', 
+            hidden: { callback: (_, model) => (model as InheritorWorkInfo).type !== 5 },
+            additionalProps: { placeholder: '请上传数字档案', uploadCo: useImageSimpleUploadCo(), name: 'file', maxCount: 20 } as UploadImageFormItemProps 
+          },
+        ]
+      },
+      {
+        type: 'group-flat', label: '扩展信息', name: 'extendInfo',
+        childrenColProps: { span: 24 },
+        children: [
+          { label: '转自', name: 'from', type: 'text', additionalProps: { placeholder: '请输入转自' } },
+          { label: '关键字', name: 'keywords', type: 'select', additionalProps: { mode: 'tags', options: [], placeholder: '请输入关键字,回车添加' } as SelectProps },
+          { label: '描述', name: 'desc', type: 'text-area', additionalProps: { placeholder: '请输入描述' } },
+          { label: 'TAG', name: 'tags', type: 'text', additionalProps: { placeholder: '请输入TAG' } },
+          { label: '分类', name: 'category', type: 'text', additionalProps: { placeholder: '请输入分类' } },
+          { label: '特点', name: 'feature', type: 'text', additionalProps: { placeholder: '请输入特点' } },
+          { label: '别名别称', name: 'otherName', type: 'text', additionalProps: { placeholder: '请输入别名别称' } },
+          { label: '创作者', name: 'creator', type: 'text', additionalProps: { placeholder: '请输入创作者' } },
+          { label: '语言', name: 'language', type: 'text', additionalProps: { placeholder: '请输入语言' } },
+          { label: '内容概览', name: 'overview', type: 'text', additionalProps: { placeholder: '请输入内容概览' } },
+          { label: '族属', name: 'ethnicGroup', type: 'text', additionalProps: { placeholder: '请输入族属' } },
+          { label: '形成或记录年代', name: 'creationEra', type: 'text', additionalProps: { placeholder: '请输入形成或记录年代' } },
+          { label: '主要演述人', name: 'mainPerformer', type: 'text', additionalProps: { placeholder: '请输入主要演述人' } },
+          { label: '其他代表人物', name: 'otherPerformers', type: 'text', additionalProps: { placeholder: '请输入其他代表人物' } },
+          { label: '作品全文', name: 'fullString', type: 'text-area', additionalProps: { placeholder: '请输入作品全文' } },
+          { label: '曲调', name: 'tune', type: 'text', additionalProps: { placeholder: '请输入曲调' } },
+          { label: '发展演变', name: 'development', type: 'text', additionalProps: { placeholder: '请输入发展演变' } },
+          { label: '流传情况', name: 'spread', type: 'text', additionalProps: { placeholder: '请输入流传情况' } },
+          { label: '影响力', name: 'influence', type: 'text', additionalProps: { placeholder: '请输入影响力' } },
+          { label: '采集人', name: 'collector', type: 'text', additionalProps: { placeholder: '请输入采集人' } },
+          { label: '采集时间', name: 'collectionTime', type: 'date-time', additionalProps: { placeholder: '请选择采集时间' } },
+          { label: '采集地点', name: 'collectionLocation', type: 'text', additionalProps: { placeholder: '请输入采集地点' } },
+        ]
+      }
+    ],
+  formRules: {
+    title: [{ required: true, message: '请输入标题' }],
+    region: [{ required: true, message: '请选择地区' }],
+    image: [{ required: true, message: '请上传图片' }],
+    type: [{ required: true, message: '请选择类型' }],
+    images: [{ required: true, message: '请上传组图' }],
+    content: [{ required: true, message: '请输入内容介绍' }],
+  }
+});
+
+const route = useRoute();
+
+async function loadData() {
+  const id = parseFloat(route.params.id as string);
+  if (id) {
+    const works = await InheritorContent.getInheritorInfo();
+    formModel.value = works.works.find((item) => item.id === id) || new InheritorWorkInfo();
+  }
+}
+
+</script>

+ 19 - 1
src/pages/inheritor.vue

@@ -73,7 +73,25 @@
               </a-descriptions>
             </EmptyToRecord>
           </a-tab-pane>
-          <a-tab-pane key="3" tab="传习所">
+          <a-tab-pane key="3" tab="作品">
+            <EmptyToRecord title="作品" :model="inheritorData?.works" :showEdited="false" @edit="router.push({ name: 'FormWork' })">
+              <a-list item-layout="horizontal" :data-source="inheritorData?.works || []">
+                <template #renderItem="{ item }">
+                  <a-list-item>
+                    <a-list-item-meta
+                      :title="item.title"
+                      :description="item.desc"
+                    >
+                      <template #avatar>
+                        <a-avatar :src="item.image" />
+                      </template>
+                    </a-list-item-meta>
+                  </a-list-item>
+                </template>
+              </a-list>
+            </EmptyToRecord>
+          </a-tab-pane>
+          <a-tab-pane key="4" tab="传习所">
             <EmptyToRecord title="传习所" :model="seminarData" @edit="router.push({ name: 'FormSeminar' })">
               <a-descriptions class="mt-3" title="传习所信息" v-if="seminarData" bordered :column="{ xs: 1, sm: 1, md: 1, lg: 2 }">
                 <a-descriptions-item label="标题"><ShowValueOrNull :value="seminarData.title" /></a-descriptions-item>

+ 5 - 0
src/router/index.ts

@@ -26,6 +26,11 @@ const router = createRouter({
       component: () => import('@/pages/forms/seminar.vue'),
     }, 
     {
+      path: '/forms/work',
+      name: 'FormWork',
+      component: () => import('@/pages/forms/works.vue'),
+    }, 
+    {
       path: '/login',
       name: 'Login',
       component: () => import('@/pages/login.vue'),

+ 1 - 0
vite.config.ts

@@ -12,6 +12,7 @@ export default defineConfig({
     vueJsx(),
     vueDevTools(),
   ],
+  base: './',
   resolve: {
     alias: {
       '@': fileURLToPath(new URL('./src', import.meta.url))