Browse Source

feat: 前端回款消息部分功能完善,界面优化

qiny 1 year ago
parent
commit
13d994d2e2

+ 17 - 0
client/README.md

@@ -0,0 +1,17 @@
+# 万维OA前端代码
+## 项目介绍
+当前文件夹下(client)是万维OA前端代码,使用 Vue3 + element-plus 开发,使用的node版本为 v18.18.2。
+
+## 项目运行
+```
+# 克隆项目
+git clone http://114.55.67.98:8070/Natural_p1/zjugis_OA.git
+# 进入项目目录
+cd client
+# 安装依赖
+pnpm install
+# 本地开发 启动项目
+pnpm dev
+```
+* 项目端口
+默认80端口,可在 `.env`文件中修改端口

+ 40 - 1
client/src/utils/tool.ts

@@ -1,10 +1,49 @@
 /**
  * @description 一些会用到的实用工具
  */
+import { cloneDeep } from 'lodash-es'
+import { CACHE_KEY, useCache } from '@/hooks/web/useCache'
 
 /**
  * 计算表格高度 = 页面高度 - 传入高度
  */
-export const calculateTableHeight = (height) => {
+export const calculateTableHeight = (height: number) => {
   return document.body.clientHeight - height
 }
+/**
+ * 四舍五入换算方法,把万换算成亿,保留两位小数
+ */
+export const unitConversion = (valueInTenThousand: number): string => {
+  // 判断值是否大于等于 1 亿
+  if (valueInTenThousand >= 10000) {
+    // 将以万为单位的数字除以 10,000 来得到以亿为单位的数字,并保留两位小数
+    const valueInBillion = valueInTenThousand / 10000
+    // 使用 toFixed 方法保留两位小数
+    return valueInBillion.toFixed(2) + ' 亿'
+  } else {
+    // 小于 1 亿的情况,以万为单位返回
+    return `${valueInTenThousand} 万`
+  }
+}
+/**
+ * 数组按字段排序
+ * @param key 排序字段
+ */
+export const sortByKey = (
+  dataSource: any[],
+  key: string,
+  order: 'desc' | 'asc' = 'desc'
+): any[] => {
+  const newList = cloneDeep(dataSource)
+  if (order === 'asc') return newList.sort((x, y) => x[key] - y[key])
+  return cloneDeep(dataSource).sort((x, y) => y[key] - x[key])
+}
+
+/**
+ * 获取用户信息的方法
+ */
+export const getUserId = () => {
+  const { wsCache } = useCache()
+  const userInfo = wsCache.get(CACHE_KEY.USER)
+  return userInfo.user ?? {}
+}

+ 129 - 0
client/src/views/OaSystem/marketCenter/returnMessage/MessageTable.vue

@@ -0,0 +1,129 @@
+<script lang="ts" setup>
+/**
+ * @description 回款通用组件表格
+ */
+import request from '@/config/axios'
+import { calculateTableHeight, getUserId } from '@/utils/tool'
+import { dateFormatter } from '@/utils/formatTime'
+interface ITable {
+  api: string // 请求地址
+  messageType?: 'user' | 'manager' | 'dept' // 所有、我的、部门
+  curYear?: number | string
+}
+const props = defineProps<ITable>()
+const { api, messageType = 'manager', curYear } = toRefs(props)
+const loading = ref(true) // 列表的加载中
+const dataSource = ref<any[]>([])
+const total = ref<number>(0)
+interface IParam {
+  pageNo: number
+  pageSize: number
+  year: number | string
+}
+const queryParams = reactive<IParam>({
+  pageNo: 1,
+  pageSize: 10,
+  year: curYear.value ?? ''
+})
+
+// 年份变化的时候重置查询
+watch(curYear, () => {
+  queryParams.pageNo = 1
+  queryParams.year = curYear.value ?? ''
+  queryContractListAjax()
+})
+
+// 查询表格
+const queryContractListAjax = async (): Promise<void> => {
+  if (messageType.value === 'manager') {
+    queryParams['managerId'] = getUserId().id
+  } else if (messageType.value === 'dept') {
+    queryParams['deptId'] = getUserId().deptId
+  }
+  try {
+    const result = await request.get({ url: api.value, params: queryParams }, '/business')
+    dataSource.value = result['records'] ?? []
+    total.value = result['total'] ?? 0
+  } finally {
+    loading.value = false
+  }
+}
+
+// 分页数改变
+const onSizeChange = (pageSize: number) => {
+  queryParams.pageSize = pageSize
+  queryContractListAjax()
+}
+
+// 页码改变
+const onCurrentChange = (pageNo: number) => {
+  queryParams.pageNo = pageNo
+  queryContractListAjax()
+}
+
+// 初始化表格
+onBeforeMount(() => {
+  queryContractListAjax()
+})
+
+// 点击查看详情
+const handleCellClick = (event) => {
+  console.log('点击查看详情', event)
+}
+
+onMounted(() => {})
+</script>
+<template>
+  <div class="message-table">
+    <el-table
+      v-loading="loading"
+      :data="dataSource"
+      :style="{ width: '100%', height: '100%', marginTop: '20px' }"
+      :height="calculateTableHeight(330)"
+      :header-cell-style="{
+        color: '#121518',
+        height: '50px',
+        fontWeight: 'bold',
+        fontSize: '16px'
+      }"
+      :cell-style="
+        ({ row }) => ({
+          color: row.messageContent.includes('[回款]已回款') ? '#3862A3' : '#41597D',
+          cursor: 'pointer'
+        })
+      "
+      @cell-click="handleCellClick"
+      stripe
+    >
+      <!-- <el-table-column label="序号" width="60">
+        <template #default="scope">{{ scope.$index + 1 }}</template>
+      </el-table-column> -->
+      <el-table-column
+        prop="messageContent"
+        label="消息内容"
+        show-overflow-tooltip
+        :style="{ color: '#121518' }"
+      />
+      <el-table-column
+        prop="createTime"
+        label=""
+        align="center"
+        :formatter="dateFormatter"
+        width="240"
+      />
+    </el-table>
+    <el-pagination
+      :style="{ float: 'right', marginTop: '15px' }"
+      v-model:current-page="queryParams.pageNo"
+      v-model:page-size="queryParams.pageSize"
+      :total="total"
+      :page-sizes="[10, 20, 50, 100]"
+      layout=" total, prev, pager, next, sizes, jumper"
+      @current-change="onCurrentChange"
+      @size-change="onSizeChange"
+    />
+  </div>
+</template>
+<style scoped lang="scss">
+@import url(./index.scss);
+</style>

+ 77 - 0
client/src/views/OaSystem/marketCenter/returnMessage/MessageTop.vue

@@ -0,0 +1,77 @@
+<script lang="ts" setup>
+/**
+ * @description 回款通用组件头部
+ */
+import { ref } from 'vue'
+import { getAssetURL } from '@/utils/auth'
+interface ITop {
+  curYear: string // 年份
+  signNum: string // 已签
+  newNum: string // 新开拓
+  returnNum: string // 回款
+  yearOnChange: (val: string) => void
+}
+const props = defineProps<ITop>()
+const yearRef = ref<any>(null)
+const { curYear, signNum, newNum, returnNum, yearOnChange } = toRefs(props)
+const infoList: any = ref([
+  {
+    name: '已签(万元)',
+    icon: 'xmzx/xmzcz',
+    num: signNum
+  },
+  {
+    name: '新开拓(万元)',
+    icon: 'xmzx/xmzcb',
+    num: newNum
+  },
+  {
+    name: '回款(万元)',
+    icon: 'xmzx/xmzlr',
+    num: returnNum
+  }
+])
+// 打开年份弹窗
+const onFocus = () => {
+  yearRef.value?.focus()
+}
+// 设置年份选择范围为最近十年
+const yearOptions = (time) => {
+  const tenYearsAgo = new Date()
+  tenYearsAgo.setFullYear(tenYearsAgo.getFullYear() - 10)
+  return time.getTime() < tenYearsAgo.getTime() || time.getTime() > new Date().getTime()
+}
+</script>
+<template>
+  <div class="message-top">
+    <ul>
+      <li class="year">
+        <span :style="{ cursor: 'pointer' }" @click="onFocus"
+          >年份:
+          {{ curYear }}
+          <el-date-picker
+            ref="yearRef"
+            :model-value="curYear"
+            :default-value="curYear"
+            type="year"
+            :style="{
+              width: 0,
+              border: 'none',
+              opacity: 0
+            }"
+            @focus="onFocus"
+            @panel-change="yearOnChange"
+            :disabled-date="yearOptions"
+        /></span>
+      </li>
+      <li v-for="(item, index) in infoList" :key="index" class="data">
+        <img class="icon" :src="getAssetURL(item.icon)" alt="" />
+        <span class="label">{{ item.name }}:</span>
+        <span>{{ item.num }}</span>
+      </li>
+    </ul>
+  </div>
+</template>
+<style scoped lang="scss">
+@import url(./index.scss);
+</style>

+ 20 - 130
client/src/views/OaSystem/marketCenter/returnMessage/deptReturnMessage.vue

@@ -1,146 +1,36 @@
 <template>
   <div class="_ReturnMessageBox">
-    <div class="cardBox">
-      <div>
-        <p class="title">年份</p>
-        <p class="numberBox">
-          <span class="value">{{ curYear }}</span>
-        </p>
-      </div>
-      <ul>
-        <li>
-          <p class="value">{{ messageInfo['sign'] }}</p>
-          <p class="title">已签(万元)</p>
-        </li>
-        <li>
-          <p class="value">{{ messageInfo['new'] }}</p>
-          <p class="title">新开拓(万元)</p>
-        </li>
-        <li>
-          <p class="value">{{ messageInfo['return'] }}</p>
-          <p class="title">回款(万元)</p>
-        </li>
-      </ul>
-    </div>
-    <div class="tableBox">
-      <div class="table" ref="tableRef">
-        <el-table
-          :data="tableData"
-          style="width: 100%; height: 100%"
-          :style="{ height: tableHeight + 'px' }"
-          :header-cell-style="{
-            background: '#F7F8FA',
-            color: '#121518',
-            height: '50px'
-          }"
-        >
-          <el-table-column label="序号" width="60">
-            <template #default="scope">{{ scope.$index + 1 }}</template>
-          </el-table-column>
-          <el-table-column prop="messageContent" label="消息内容" width="1350" />
-          <el-table-column prop="createTime" label="消息时间" width="240" />
-          <el-table-column label="操作" width="80">
-            <template #default="scope">
-              <div class="operateBtn" @click="operateClick(scope.row)">
-                <span>查看</span>
-              </div>
-            </template>
-          </el-table-column>
-        </el-table>
-      </div>
-      <div class="pageBox">
-        <el-pagination
-          v-model:current-page="queryParams.pageNo"
-          :page-size="10"
-          background
-          layout="total, prev, pager, next, jumper"
-          :total="total"
-          @current-change="handleCurrentChange"
-        />
-      </div>
-    </div>
+    <MessageTop
+      :signNum="messageInfo['sign']"
+      :newNum="messageInfo['new']"
+      :returnNum="messageInfo['return']"
+      :curYear="curYear"
+      :yearOnChange="yearOnChange"
+    />
+
+    <MessageTable api="/contract-message/page" messageType="dept" :curYear="curYear" />
   </div>
 </template>
 <script setup lang="ts">
-import moment from 'moment'
-import { useRouter } from 'vue-router'
-import request from '@/config/axios'
-import { getAssetURL } from '@/utils/auth'
-import { isSignListAll } from '@/utils/business'
-import { signWayAllList } from '@/utils/business'
-import { mainTypeAllList } from '@/utils/business'
-import { secondTypeAllList } from '@/utils/business'
-import { CACHE_KEY, useCache } from '@/hooks/web/useCache'
+/**
+ * @description 部门回款消息
+ */
+import MessageTop from './MessageTop.vue'
+import MessageTable from './MessageTable.vue'
+import dayjs from 'dayjs'
 
 defineOptions({ name: 'ReturnMessage' })
-const curYear = new Date().getFullYear()
-const { wsCache } = useCache()
-const user = wsCache.get(CACHE_KEY.USER)
-const deptId = user.user.deptId ? user.user.deptId : ''
-const router = useRouter()
-const tableRef: any = ref(null)
-const tableHeight: any = ref(0)
-const queryParams = reactive<{
-  pageNo: number
-  pageSize: number
-  year: string
-  deptId: string
-}>({
-  pageNo: 1,
-  pageSize: 10,
-  year: '',
-  deptId: deptId
-})
 
+const curYear: any = ref(new Date().getFullYear())
+const yearOnChange = (val) => {
+  curYear.value = dayjs(val).format('YYYY')
+}
 const messageInfo = ref({
   sign: 0,
   new: 0,
   return: 0
 })
-
-const handleCurrentChange = (pageNo: number) => {
-  queryParams.pageNo = pageNo
-  queryContractListAjax()
-}
-const operateClick = (row: any) => {
-  // router.push({
-  //   path: '/projectDetail',
-  //   query: { id: row.projectId, contractId: row.id }
-  // })
-}
-const tableData = ref<Array<any>>([])
-const total = ref<number>()
-const searchHandle: () => void = () => {
-  queryContractListAjax()
-}
-const queryContractListAjax = async (): Promise<void> => {
-  const urlApi = `/contract-message/page`
-  const sendData = {
-    ...queryParams,
-    pageSize: 10
-  }
-  const result = await request.get({ url: urlApi, params: sendData }, '/business')
-  tableData.value = result['records']
-  total.value = result['total']
-}
-queryContractListAjax()
-
-const filterNodeMethod = (value, data) => {
-  return data.name.includes(value)
-}
-onMounted(() => {
-  tableHeight.value = tableRef.value.clientHeight
-})
 </script>
 <style lang="scss" scoped>
-@import url(./returnMessage.scss);
-._ReturnMessageBox {
-  margin-top: 20px;
-  height: calc(100% - 20px);
-  background-color: #fff;
-  border-radius: 20px;
-  padding: 20px;
-  position: relative;
-  text-align: center;
-}
+@import url(./index.scss);
 </style>

+ 50 - 0
client/src/views/OaSystem/marketCenter/returnMessage/index.scss

@@ -0,0 +1,50 @@
+._ReturnMessageBox {
+  // width: calc(100% - 30px);
+  height: calc(100% - 30px);
+  background: #ffffff;
+  border-radius: 20px;
+  margin-top: 15px;
+  padding: 26px;
+}
+.message-top {
+  width: 100%;
+  height: 60px;
+  background: #f3f8fc;
+  border-radius: 4px 4px 4px 4px;
+
+  .el-input__wrapper {
+  }
+
+  ul {
+    width: 100%;
+    height: 100%;
+    display: flex;
+    align-items: center;
+    padding: 0 20px;
+    li {
+      list-style: none;
+      display: flex;
+      align-items: center;
+      font-size: 16px;
+      font-weight: bold;
+      img {
+        margin-right: 12px;
+      }
+    }
+    .year {
+      padding-right: 38px;
+      border-right: 1px solid #b6c1ca;
+    }
+    .data {
+      margin-left: 40px;
+      .label {
+        font-weight: 400;
+        color: #121518;
+      }
+    }
+  }
+}
+.message-table {
+  height: auto;
+  width: 100%;
+}

+ 21 - 131
client/src/views/OaSystem/marketCenter/returnMessage/myReturnMessage.vue

@@ -1,146 +1,36 @@
 <template>
   <div class="_ReturnMessageBox">
-    <div class="cardBox">
-      <div>
-        <p class="title">年份</p>
-        <p class="numberBox">
-          <span class="value">{{ curYear }}</span>
-        </p>
-      </div>
-      <ul>
-        <li>
-          <p class="value">{{ messageInfo['sign'] }}</p>
-          <p class="title">已签(万元)</p>
-        </li>
-        <li>
-          <p class="value">{{ messageInfo['new'] }}</p>
-          <p class="title">新开拓(万元)</p>
-        </li>
-        <li>
-          <p class="value">{{ messageInfo['return'] }}</p>
-          <p class="title">回款(万元)</p>
-        </li>
-      </ul>
-    </div>
-    <div class="tableBox">
-      <div class="table" ref="tableRef">
-        <el-table
-          :data="tableData"
-          style="width: 100%; height: 100%"
-          :style="{ height: tableHeight + 'px' }"
-          :header-cell-style="{
-            background: '#F7F8FA',
-            color: '#121518',
-            height: '50px'
-          }"
-        >
-          <el-table-column label="序号" width="60">
-            <template #default="scope">{{ scope.$index + 1 }}</template>
-          </el-table-column>
-          <el-table-column prop="messageContent" label="消息内容" width="1350" />
-          <el-table-column prop="createTime" label="消息时间" width="240" />
-          <el-table-column label="操作" width="80">
-            <template #default="scope">
-              <div class="operateBtn" @click="operateClick(scope.row)">
-                <span>查看</span>
-              </div>
-            </template>
-          </el-table-column>
-        </el-table>
-      </div>
-      <div class="pageBox">
-        <el-pagination
-          v-model:current-page="queryParams.pageNo"
-          :page-size="10"
-          background
-          layout="total, prev, pager, next, jumper"
-          :total="total"
-          @current-change="handleCurrentChange"
-        />
-      </div>
-    </div>
+    <MessageTop
+      :signNum="messageInfo['sign']"
+      :newNum="messageInfo['new']"
+      :returnNum="messageInfo['return']"
+      :curYear="curYear"
+      :yearOnChange="yearOnChange"
+    />
+
+    <MessageTable api="/contract-message/page" messageType="manager" :curYear="curYear" />
   </div>
 </template>
 <script setup lang="ts">
-import moment from 'moment'
-import { useRouter } from 'vue-router'
-import request from '@/config/axios'
-import { getAssetURL } from '@/utils/auth'
-import { isSignListAll } from '@/utils/business'
-import { signWayAllList } from '@/utils/business'
-import { mainTypeAllList } from '@/utils/business'
-import { secondTypeAllList } from '@/utils/business'
-import { CACHE_KEY, useCache } from '@/hooks/web/useCache'
+/**
+ * @description 我的回款消息
+ */
+import MessageTop from './MessageTop.vue'
+import MessageTable from './MessageTable.vue'
+import dayjs from 'dayjs'
 
 defineOptions({ name: 'ReturnMessage' })
-const curYear = new Date().getFullYear()
-const { wsCache } = useCache()
-const user = wsCache.get(CACHE_KEY.USER)
-const userId = user.user.id ? user.user.id : ''
-const router = useRouter()
-const tableRef: any = ref(null)
-const tableHeight: any = ref(0)
-const queryParams = reactive<{
-  pageNo: number
-  pageSize: number
-  year: string
-  managerId: string
-}>({
-  pageNo: 1,
-  pageSize: 10,
-  year: '',
-  managerId: userId
-})
 
+const curYear: any = ref(new Date().getFullYear())
+const yearOnChange = (val) => {
+  curYear.value = dayjs(val).format('YYYY')
+}
 const messageInfo = ref({
   sign: 0,
   new: 0,
   return: 0
 })
-
-const handleCurrentChange = (pageNo: number) => {
-  queryParams.pageNo = pageNo
-  queryContractListAjax()
-}
-const operateClick = (row: any) => {
-  // router.push({
-  //   path: '/projectDetail',
-  //   query: { id: row.projectId, contractId: row.id }
-  // })
-}
-const tableData = ref<Array<any>>([])
-const total = ref<number>()
-const searchHandle: () => void = () => {
-  queryContractListAjax()
-}
-const queryContractListAjax = async (): Promise<void> => {
-  const urlApi = `/contract-message/page`
-  const sendData = {
-    ...queryParams,
-    pageSize: 10
-  }
-  const result = await request.get({ url: urlApi, params: sendData }, '/business')
-  tableData.value = result['records']
-  total.value = result['total']
-}
-queryContractListAjax()
-
-const filterNodeMethod = (value, data) => {
-  return data.name.includes(value)
-}
-onMounted(() => {
-  tableHeight.value = tableRef.value.clientHeight
-})
 </script>
-<style lang="scss" scoped>
-@import url(./returnMessage.scss);
-._ReturnMessageBox {
-  margin-top: 20px;
-  height: calc(100% - 20px);
-  background-color: #fff;
-  border-radius: 20px;
-  padding: 20px;
-  position: relative;
-  text-align: center;
-}
+<style scoped lang="scss">
+@import url(./index.scss);
 </style>

+ 20 - 124
client/src/views/OaSystem/marketCenter/returnMessage/returnMessage.vue

@@ -1,140 +1,36 @@
 <template>
   <div class="_ReturnMessageBox">
-    <div class="cardBox">
-      <div>
-        <p class="title">年份</p>
-        <p class="numberBox">
-          <span class="value">{{ curYear }}</span>
-        </p>
-      </div>
-      <ul>
-        <li>
-          <p class="value">{{ messageInfo['sign'] }}</p>
-          <p class="title">已签(万元)</p>
-        </li>
-        <li>
-          <p class="value">{{ messageInfo['new'] }}</p>
-          <p class="title">新开拓(万元)</p>
-        </li>
-        <li>
-          <p class="value">{{ messageInfo['return'] }}</p>
-          <p class="title">回款(万元)</p>
-        </li>
-      </ul>
-    </div>
-    <div class="tableBox">
-      <div class="table" ref="tableRef">
-        <el-table
-          :data="tableData"
-          style="width: 100%; height: 100%"
-          :style="{ height: tableHeight + 'px' }"
-          :header-cell-style="{
-            background: '#F7F8FA',
-            color: '#121518',
-            height: '50px'
-          }"
-        >
-          <el-table-column label="序号" width="60">
-            <template #default="scope">{{ scope.$index + 1 }}</template>
-          </el-table-column>
-          <el-table-column prop="messageContent" label="消息内容" width="1350" />
-          <el-table-column prop="createTime" label="消息时间" width="240" />
-          <el-table-column label="操作" width="80">
-            <template #default="scope">
-              <div class="operateBtn" @click="operateClick(scope.row)">
-                <span>查看</span>
-              </div>
-            </template>
-          </el-table-column>
-        </el-table>
-      </div>
-      <div class="pageBox">
-        <el-pagination
-          v-model:current-page="queryParams.pageNo"
-          :page-size="10"
-          background
-          layout="total, prev, pager, next, jumper"
-          :total="total"
-          @current-change="handleCurrentChange"
-        />
-      </div>
-    </div>
+    <MessageTop
+      :signNum="messageInfo['sign']"
+      :newNum="messageInfo['new']"
+      :returnNum="messageInfo['return']"
+      :curYear="curYear"
+      :yearOnChange="yearOnChange"
+    />
+
+    <MessageTable api="/contract-message/page" :curYear="curYear" />
   </div>
 </template>
 <script setup lang="ts">
-import moment from 'moment'
-import { useRouter } from 'vue-router'
-import request from '@/config/axios'
-import { getAssetURL } from '@/utils/auth'
-import { isSignListAll } from '@/utils/business'
-import { signWayAllList } from '@/utils/business'
-import { mainTypeAllList } from '@/utils/business'
-import { secondTypeAllList } from '@/utils/business'
+/**
+ * @description 回款消息
+ */
+import MessageTop from './MessageTop.vue'
+import MessageTable from './MessageTable.vue'
+import dayjs from 'dayjs'
 
 defineOptions({ name: 'ReturnMessage' })
-const curYear = new Date().getFullYear()
-const router = useRouter()
-const tableRef: any = ref(null)
-const tableHeight: any = ref(0)
-const queryParams = reactive<{
-  pageNo: number
-  pageSize: number
-  year: string
-}>({
-  pageNo: 1,
-  pageSize: 10,
-  year: ''
-})
 
+const curYear: any = ref(new Date().getFullYear())
+const yearOnChange = (val) => {
+  curYear.value = dayjs(val).format('YYYY')
+}
 const messageInfo = ref({
   sign: 0,
   new: 0,
   return: 0
 })
-
-const handleCurrentChange = (pageNo: number) => {
-  queryParams.pageNo = pageNo
-  queryContractListAjax()
-}
-const operateClick = (row: any) => {
-  // router.push({
-  //   path: '/projectDetail',
-  //   query: { id: row.projectId, contractId: row.id }
-  // })
-}
-const tableData = ref<Array<any>>([])
-const total = ref<number>()
-const searchHandle: () => void = () => {
-  queryContractListAjax()
-}
-const queryContractListAjax = async (): Promise<void> => {
-  const urlApi = `/contract-message/page`
-  const sendData = {
-    ...queryParams,
-    pageSize: 10
-  }
-  const result = await request.get({ url: urlApi, params: sendData }, '/business')
-  tableData.value = result['records']
-  total.value = result['total']
-}
-queryContractListAjax()
-
-const filterNodeMethod = (value, data) => {
-  return data.name.includes(value)
-}
-onMounted(() => {
-  tableHeight.value = tableRef.value.clientHeight
-})
 </script>
 <style lang="scss" scoped>
-@import url(./returnMessage.scss);
-._ReturnMessageBox {
-  margin-top: 20px;
-  height: calc(100% - 20px);
-  background-color: #fff;
-  border-radius: 20px;
-  padding: 20px;
-  position: relative;
-  text-align: center;
-}
+@import url(./index.scss);
 </style>