Просмотр исходного кода

我的报告前端页面布局开发

Kevin Jiang лет назад: 3
Родитель
Сommit
893f00570f

+ 7 - 0
src/assets/base.scss

@@ -72,3 +72,10 @@ body {
   -webkit-font-smoothing: antialiased;
   -moz-osx-font-smoothing: grayscale;
 } */
+
+$border-color-primary: #f0f0f0;
+$border-color-secondary: #e0e0e0;
+
+h1.title {
+  font-size: 1.75em;
+}

+ 18 - 0
src/components/PageHeader.vue

@@ -0,0 +1,18 @@
+<script setup lang="ts">
+defineProps({
+  title: {
+    type: String,
+    required: true,
+  }
+});
+</script>
+
+<template>
+  <h1 class="title">{{ title }}</h1>
+</template>
+
+<style scoped lang="scss">
+h1.title {
+  font-size: 1.75em;
+}
+</style>

+ 1 - 1
src/router/index.ts

@@ -103,7 +103,7 @@ export const router = createRouter({
         {
           path: "",
           name: "FavoriteIndex",
-          component: () => import("../views/FavoriteView.vue"),
+          component: () => import("../views/favorite/FavoriteView.vue"),
         }
       ]
     },

+ 0 - 3
src/views/FavoriteView.vue

@@ -1,3 +0,0 @@
-<template>
-  我的收藏
-</template>

+ 1 - 1
src/views/detail/components/DocCatalog.vue

@@ -4,7 +4,7 @@ import type { CatalogNode } from "@/types/doc.types";
 
 const props = defineProps({
   catalog: {
-    type: Object as PropType<CatalogNode[]>,
+    type: Array as PropType<CatalogNode[]>,
     default() {
       return [];
     }

+ 72 - 0
src/views/favorite/FavoriteView.vue

@@ -0,0 +1,72 @@
+<script setup lang="ts">
+import { ref } from "vue";
+import PageHeader from "@/components/PageHeader.vue";
+
+const currentPage = ref(1);
+
+function handleCancel(id: number) {
+  console.log("cancel", id);
+}
+</script>
+
+<template>
+  <PageHeader title="我的收藏" />
+  <a-tabs>
+    <a-tab-pane key="favorite" tab="文献收藏">
+      <div class="item-wrap" v-for="(i) in [1, 2, 3, 4]" :key="i">
+        <a-row type="flex" justify="space-between" :gutter="8">
+          <a-col>
+            <h4>
+              <a href="#">工程检测</a>
+            </h4>
+            <div class="metadata">作者:item.author 机构:item.unit</div>
+          </a-col>
+          <a-col>
+            <a-button type="link" @click="handleCancel(i)">取消收藏</a-button>
+          </a-col>
+        </a-row>
+      </div>
+    </a-tab-pane>
+  </a-tabs>
+  <div class="pagination">
+    <a-pagination v-model:current="currentPage" simple :total="50">
+      <template #itemRender="{ type, originalElement }">
+        <a-button v-if="type === 'prev'" size="small"> 上一页</a-button>
+        <a-button v-else-if="type === 'next'" size="small">下一页</a-button>
+        <component :is="originalElement" v-else></component>
+      </template>
+    </a-pagination>
+  </div>
+</template>
+
+<style scoped lang="scss">
+@import "@/assets/base.scss";
+
+.item-wrap {
+  margin-top: 8px;
+  padding: 8px 16px;
+  border: 1px solid $border-color-primary;
+  border-radius: 5px;
+
+  &:first-child {
+    margin-top: 0;
+  }
+
+  &:hover {
+    background-color: #fcfcfc;
+  }
+
+  .metadata {
+    color: gray;
+  }
+}
+
+.pagination {
+  margin-top: 16px;
+  text-align: right;
+
+  .ant-pagination {
+    height: 28px;
+  }
+}
+</style>

+ 2 - 11
src/views/history/HistoryView.vue

@@ -1,5 +1,6 @@
 <script setup lang="ts">
 import { ref } from "vue";
+import PageHeader from "@/components/PageHeader.vue";
 import DocumentHistoryView from "./DocumentHistoryView.vue";
 import SearchHistoryView from "./SearchHistoryView.vue";
 
@@ -7,7 +8,7 @@ const activeKey = ref('search');
 </script>
 
 <template>
-  <h1 class="title">历史记录</h1>
+  <PageHeader title="历史记录" />
   <a-tabs v-model:activeKey="activeKey">
     <a-tab-pane key="search" tab="检索记录">
       <SearchHistoryView />
@@ -17,13 +18,3 @@ const activeKey = ref('search');
     </a-tab-pane>
   </a-tabs>
 </template>
-
-<style scoped lang="scss">
-.title {
-  font-size: 1.75em;
-}
-
-.history-list-wrap {
-  margin-top: 16px;
-}
-</style>

+ 3 - 1
src/views/history/components/HistoryItem.vue

@@ -36,9 +36,11 @@ function handleDelete() {
 </template>
 
 <style scoped lang="scss">
+@import "@/assets/base.scss";
+
 .history-item-wrap {
   padding: 8px 16px;
-  border: 1px solid #e0e0e0;
+  border: 1px solid $border-color-primary;
   border-radius: 5px;
 
   &:hover {

+ 1 - 1
src/views/history/components/HistoryList.vue

@@ -5,7 +5,7 @@ import HistoryItemComp from "./HistoryItem.vue";
 
 defineProps({
   data: {
-    type: Object as PropType<HistoryItem[]>,
+    type: Array as PropType<HistoryItem[]>,
     required: true,
   }
 });

+ 91 - 1
src/views/report/ReportView.vue

@@ -1 +1,91 @@
-<template>报告列表</template>
+<script setup lang="ts">
+import { ref } from "vue";
+import PageHeader from '@/components/PageHeader.vue';
+import QueryBox from './components/QueryBox.vue';
+import CompanySelect from "./components/CompanySelect.vue";
+import ReportItem from './components/ReportItem.vue';
+
+const currentPage = ref(1);
+
+const companies = ref([
+  {
+    label: "企业名称1",
+    tail: 3,
+    checked: false,
+  },
+  {
+    label: "企业名称2",
+    tail: 7,
+    checked: true,
+  },
+  {
+    label: "企业名称3",
+    tail: 12,
+    checked: false,
+  }
+]);
+
+function onCompanySelectChange(event: {index: number, checked: boolean}) {
+  console.log('company select change', event);
+  const company = companies.value[event.index];
+  company.checked = event.checked;
+}
+
+function onPaginationChange(page: number, pageSize: number) {
+  console.log('page', page, 'pageSize', pageSize);
+}
+</script>
+
+<template>
+  <div class="reports-wrap">
+    <PageHeader title="我的报告" />
+    <div class="query-box-wrap">
+      <QueryBox />
+    </div>
+    <a-row class="main-content" :gutter="24">
+      <a-col :xxl="5" :xl="6" :lg="7" :span="8" class="company-filter-wrap">
+        <h3>我所服务的企业</h3>
+        <CompanySelect :data="companies" @change="onCompanySelectChange" />
+      </a-col>
+      <a-col :xxl="19" :xl="18" :lg="17" :span="16">
+        <ReportItem v-for="(i) in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]" :key="i" class="report-item" />
+      </a-col>
+    </a-row>
+    <div class="pagination-wrap">
+      <a-pagination v-model:current="currentPage" :total="500" @change="onPaginationChange" />
+    </div>
+  </div>
+</template>
+
+<style scoped lang="scss">
+@import "@/assets/base.scss";
+
+.reports-wrap {
+  .query-box-wrap {
+    width: 80%;
+    margin: 0 auto;
+  }
+
+  .main-content {
+    margin-top: 1.5em;
+
+    .company-filter-wrap {
+      border: 1px solid $border-color-primary;
+      padding: 20px 16px;
+    }
+
+    .report-item {
+      margin-top: 16px;
+
+      &:first-child {
+        margin-top: 0;
+      }
+    }
+  }
+
+  .pagination-wrap {
+    margin-top: 1em;
+    text-align: right;
+  }
+}
+</style>

+ 36 - 0
src/views/report/components/CompanySelect.vue

@@ -0,0 +1,36 @@
+<script setup lang="ts">
+import type { PropType } from "vue";
+import CompanySelectItem from "./CompanySelectItem.vue";
+import type { Prop } from "./CompanySelectItem.vue";
+
+defineProps({
+  data: {
+    type: Array as PropType<Prop[]>,
+    required: true,
+  }
+});
+
+const emits = defineEmits<{
+  (e: "change", event: {index: number, checked: boolean}): void;
+}>();
+
+function onItemChange(index: number, checked: boolean) {
+  emits("change", {index, checked});
+}
+</script>
+
+<template>
+  <CompanySelectItem
+    v-for="(item, i) in data"
+    :key="i"
+    :data="item"
+    @change="onItemChange(i, $event)"
+    class="select-item"
+  />
+</template>
+
+<style scoped lang="scss">
+.select-item {
+  margin-top: 0.5em;
+}
+</style>

+ 47 - 0
src/views/report/components/CompanySelectItem.vue

@@ -0,0 +1,47 @@
+<script setup lang="ts">
+import { ref, watch, type PropType, onMounted } from "vue";
+
+export interface Prop {
+  label: string;
+  tail: string | number;
+  checked?: boolean;
+}
+
+const props = defineProps({
+  data: {
+    type: Object as PropType<Prop>,
+    required: true,
+  }
+});
+
+const checked = ref(false);
+
+watch(
+  () => !!props.data.checked,
+  (value: boolean) => checked.value = value
+);
+
+onMounted(() => {
+  checked.value = !!props.data.checked;
+
+});
+
+const emits = defineEmits<{
+  (e: "change", checked: boolean): void;
+}>();
+
+function onChange() {
+  emits("change", checked.value);
+}
+</script>
+
+<template>
+  <a-row type="flex">
+    <a-col :flex="1">
+      <a-checkbox v-model:checked="checked" @change="onChange">{{ data.label }}</a-checkbox>
+    </a-col>
+    <a-col>
+      {{ data.tail }}
+    </a-col>
+  </a-row>
+</template>

+ 48 - 0
src/views/report/components/QueryBox.vue

@@ -0,0 +1,48 @@
+<script setup lang="ts">
+import type { SelectProps } from "ant-design-vue";
+import { ref } from "vue";
+
+const field = ref('title');
+const keyword = ref('');
+
+const fieldOptions = ref<SelectProps['options']>([
+  { value: 'title', label: '按标题' },
+  { value: 'company_name', label: '按企业名称' },
+]);
+
+function onFieldChange(value: string) {
+  console.log('field value', value);
+}
+
+const emits = defineEmits<{
+  (e: "search", data: { field: string, keyword: string }): void;
+}>();
+
+function onSearch() {
+  emits("search", { field: field.value, keyword: keyword.value})
+}
+</script>
+
+<template>
+  <a-row type="flex">
+    <a-col>
+      <a-select
+        ref="select"
+        :value="field"
+        style="width: 140px"
+        :options="fieldOptions"
+        @change="onFieldChange"
+        size="large"
+      ></a-select>
+    </a-col>
+    <a-col flex="1">
+      <a-input-search
+        :value="keyword"
+        placeholder="请输入关键词进行查询"
+        enter-button="查&nbsp;&nbsp;询"
+        size="large"
+        @search="onSearch"
+      />
+    </a-col>
+  </a-row>
+</template>

+ 27 - 0
src/views/report/components/ReportItem.vue

@@ -0,0 +1,27 @@
+<!-- 报告列表的一项 -->
+
+<template>
+  <a-card size="small" title="企业名称 - 报告名称">
+    <template #extra>
+      <a-button type="link">编辑</a-button>
+      <a-button type="link">下载</a-button>
+    </template>
+    <div class="report-metadata-wrap">
+      <p><span>企业名称:</span><span></span></p>
+      <p><span>项目名称:</span><span></span></p>
+      <p><span>项目负责人:</span><span></span></p>
+      <p><span>起止时间:</span><span></span></p>
+      <p><span>创建时间:</span><span></span></p>
+      <p><span>最后编辑时间:</span><span></span></p>
+    </div>
+  </a-card>
+</template>
+
+<style scoped lang="scss">
+.report-metadata-wrap {
+  p {
+    margin-top: 0.3em;
+    margin-bottom: 0.3em;
+  }
+}
+</style>