添加主题列表管理页面,主题模板文件增删改查管理、下载页面

This commit is contained in:
wcq 2023-12-07 14:49:00 +08:00
parent 411c5ebe6a
commit 6fb0df2f38
24 changed files with 4142 additions and 9724 deletions

100
README.md
View File

@ -1,92 +1,8 @@
# file-receive-manage-web
## Getting started
To make it easy for you to get started with GitLab, here's a list of recommended next steps.
Already a pro? Just edit this README.md and make it your own. Want to make it easy? [Use the template at the bottom](#editing-this-readme)!
## Add your files
- [ ] [Create](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#create-a-file) or [upload](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#upload-a-file) files
- [ ] [Add files using the command line](https://docs.gitlab.com/ee/gitlab-basics/add-file.html#add-a-file-using-the-command-line) or push an existing Git repository with the following command:
```
cd existing_repo
git remote add origin http://139.9.146.228:8083/file-receive/file-receive-manage-web.git
git branch -M main
git push -uf origin main
```
## Integrate with your tools
- [ ] [Set up project integrations](http://139.9.146.228/file-receive/file-receive-manage-web/-/settings/integrations)
## Collaborate with your team
- [ ] [Invite team members and collaborators](https://docs.gitlab.com/ee/user/project/members/)
- [ ] [Create a new merge request](https://docs.gitlab.com/ee/user/project/merge_requests/creating_merge_requests.html)
- [ ] [Automatically close issues from merge requests](https://docs.gitlab.com/ee/user/project/issues/managing_issues.html#closing-issues-automatically)
- [ ] [Enable merge request approvals](https://docs.gitlab.com/ee/user/project/merge_requests/approvals/)
- [ ] [Set auto-merge](https://docs.gitlab.com/ee/user/project/merge_requests/merge_when_pipeline_succeeds.html)
## Test and Deploy
Use the built-in continuous integration in GitLab.
- [ ] [Get started with GitLab CI/CD](https://docs.gitlab.com/ee/ci/quick_start/index.html)
- [ ] [Analyze your code for known vulnerabilities with Static Application Security Testing(SAST)](https://docs.gitlab.com/ee/user/application_security/sast/)
- [ ] [Deploy to Kubernetes, Amazon EC2, or Amazon ECS using Auto Deploy](https://docs.gitlab.com/ee/topics/autodevops/requirements.html)
- [ ] [Use pull-based deployments for improved Kubernetes management](https://docs.gitlab.com/ee/user/clusters/agent/)
- [ ] [Set up protected environments](https://docs.gitlab.com/ee/ci/environments/protected_environments.html)
***
# Editing this README
When you're ready to make this README your own, just edit this file and use the handy template below (or feel free to structure it however you want - this is just a starting point!). Thank you to [makeareadme.com](https://www.makeareadme.com/) for this template.
## Suggestions for a good README
Every project is different, so consider which of these sections apply to yours. The sections used in the template are suggestions for most open source projects. Also keep in mind that while a README can be too long and detailed, too long is better than too short. If you think your README is too long, consider utilizing another form of documentation rather than cutting out information.
## Name
Choose a self-explaining name for your project.
## Description
Let people know what your project can do specifically. Provide context and add a link to any reference visitors might be unfamiliar with. A list of Features or a Background subsection can also be added here. If there are alternatives to your project, this is a good place to list differentiating factors.
## Badges
On some READMEs, you may see small images that convey metadata, such as whether or not all the tests are passing for the project. You can use Shields to add some to your README. Many services also have instructions for adding a badge.
## Visuals
Depending on what you are making, it can be a good idea to include screenshots or even a video (you'll frequently see GIFs rather than actual videos). Tools like ttygif can help, but check out Asciinema for a more sophisticated method.
## Installation
Within a particular ecosystem, there may be a common way of installing things, such as using Yarn, NuGet, or Homebrew. However, consider the possibility that whoever is reading your README is a novice and would like more guidance. Listing specific steps helps remove ambiguity and gets people to using your project as quickly as possible. If it only runs in a specific context like a particular programming language version or operating system or has dependencies that have to be installed manually, also add a Requirements subsection.
## Usage
Use examples liberally, and show the expected output if you can. It's helpful to have inline the smallest example of usage that you can demonstrate, while providing links to more sophisticated examples if they are too long to reasonably include in the README.
## Support
Tell people where they can go to for help. It can be any combination of an issue tracker, a chat room, an email address, etc.
## Roadmap
If you have ideas for releases in the future, it is a good idea to list them in the README.
## Contributing
State if you are open to contributions and what your requirements are for accepting them.
For people who want to make changes to your project, it's helpful to have some documentation on how to get started. Perhaps there is a script that they should run or some environment variables that they need to set. Make these steps explicit. These instructions could also be useful to your future self.
You can also document commands to lint the code or run tests. These steps help to ensure high code quality and reduce the likelihood that the changes inadvertently break something. Having instructions for running tests is especially helpful if it requires external setup, such as starting a Selenium server for testing in a browser.
## Authors and acknowledgment
Show your appreciation to those who have contributed to the project.
## License
For open source projects, say how it is licensed.
## Project status
If you have run out of energy or time for your project, put a note at the top of the README saying that development has slowed down or stopped completely. Someone may choose to fork your project or volunteer to step in as a maintainer or owner, allowing your project to keep going. You can also make an explicit request for maintainers.
## 页面
```text
1.主题列表页
-主题编辑
2.主题接收单列表页
-新增接收单
3.
```

View File

@ -1,6 +1,9 @@
<template>
<el-config-provider :locale="currentLocale">
<router-view/>
<router-view/>
<!-- <div>-->
<!-- <file-upload v-model="filePath" :data="data"/>-->
<!-- </div>-->
<ReDialog/>
</el-config-provider>
</template>
@ -12,14 +15,21 @@ import zhCn from "element-plus/lib/locale/lang/zh-cn";
import {ReDialog} from "@/components/ReDialog";
import {api} from "@/api/api";
import {handleAsyncRoutes, initRouter} from "@/router/utils";
import {spost} from "@/api/smebiz";
import {useUserStore} from "@/store/modules/user";
import {storageLocal} from "@pureadmin/utils";
import {usePermissionStoreHook} from "@/store/modules/permission";
import FileUpload from "@/views/receive/components/FileUpload.vue";
export default defineComponent({
name: "app",
data: () => {
return {
filePath: null,
data:{name:'zxczxc'}
}
},
components: {
FileUpload,
[ElConfigProvider.name]: ElConfigProvider,
ReDialog
},

View File

@ -1,4 +1,4 @@
import {sapi} from "./apis"
import {sapi} from "./common"
import {components} from "./schema";
type st = components['schemas']

3049
src/api/schema.d.ts vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,72 +0,0 @@
import createClient from "openapi-fetch";
import {paths} from "./schema";
import {formatToken, getToken} from "@/utils/auth";
import {useUserStoreHook} from "@/store/modules/user";
import {FilterKeys, PathsWithMethod} from "openapi-typescript-helpers";
import {FetchOptions} from "openapi-fetch/src";
let timeoutPromise = (timeout: number) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject('服务器地址不可用');
}, timeout)
})
};
function createSmebizClient<Paths extends {}>(clientOptions: Parameters<typeof createClient>[0] = {}, timeout?: number) {
const baseClient = createClient<Paths>(clientOptions);
return {
...baseClient,
async post<P extends PathsWithMethod<Paths, "post">>(url: P, body?: FetchOptions<FilterKeys<Paths[P], "post">>['body'], init?: FetchOptions<FilterKeys<Paths[P], "post">>) {
if (!init) init = {} as FetchOptions<FilterKeys<Paths[P], "post">>
if (body) init.body = body
if (!init.headers) init.headers = {}
const userData = getToken();
if (userData) {
const now = new Date().getTime();
const expired = parseInt(userData.expires) - now <= 0;
if (expired) {
useUserStoreHook().logOut();
} else {
init.headers["Authorization"] = formatToken(userData.accessToken);
}
}
if (timeout) {
let controller = new AbortController();
init.signal = controller.signal;
setTimeout(() => {
// 当时间到达之后运行 abort
controller.abort();
}, timeout);
}
return await baseClient.POST(url, init)
}
}
}
export const sapi = createSmebizClient<paths>({baseUrl: ""}, 10000)
//
// export const sApi = new Proxy(baseClient, {
// get(_, key: keyof typeof baseClient) {
// const headers = {}
// const data = getToken();
// if (data) {
// const now = new Date().getTime();
// const expired = parseInt(data.expires) - now <= 0;
// if (expired) {
// useUserStoreHook().logOut();
// } else {
// headers["Authorization"] = formatToken(data.accessToken);
// }
// }
// const newClient = createClient<paths>({
// headers: headers,
// baseUrl: "",
// });
// return newClient[key];
// },
// });
// sPost('/file-receive/rate/rate_serve/get')

View File

@ -1,7 +0,0 @@
import {sapi} from "./apis"
import {components} from "./schema";
type st = components['schemas']
const spost = sapi.post
export {sapi, spost}
export type {st}

2255
src/api/wide/schema.d.ts vendored

File diff suppressed because it is too large Load Diff

View File

@ -5,7 +5,7 @@ export default {
path: "/",
name: "Home",
component: Layout,
redirect: "/dashboard",
redirect: "/subjects",
meta: {
icon: "homeFilled",
title: "首页",
@ -13,11 +13,11 @@ export default {
},
children: [
{
path: "/dashboard",
name: "dashboard",
component: () => import("@/views/dashboard/dashboard.vue"),
path: "/subjects",
name: "subjects",
component: () => import("@/views/receive/subjects.vue"),
meta: {
title: "首页",
title: "主题列表",
showLink: VITE_HIDE_HOME === "true" ? false : true
}
},

View File

@ -1,119 +0,0 @@
<template>
<div :id="elId" style="width: 100%;height: 100%;min-height: 10rem;min-width: 10rem"></div>
</template>
<script setup lang="ts">
import {EChartsType} from 'echarts/core';
import {nextTick, onBeforeMount, onMounted, ref, watch} from "vue";
import * as echarts from 'echarts/core';
import { GridComponent } from 'echarts/components';
import { LineChart } from 'echarts/charts';
import { UniversalTransition } from 'echarts/features';
import { CanvasRenderer } from 'echarts/renderers';
import {useDark} from "@pureadmin/utils";
echarts.use([GridComponent, LineChart, CanvasRenderer, UniversalTransition]);
const chartOption = ref(
{
backgroundColor: "rgba(0,0,0,0)",
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
}
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
top:"10%",
containLabel: true
},
xAxis: [
{
type: 'category',
data: ['23/8/12', '23/8/13', '23/8/14', '23/8/15', '23/8/16', '23/8/17', '23/8/18'],
axisTick: {
alignWithLabel: true
}
}
],
yAxis: [
{
minInterval: 1,
type: 'value'
}
],
series: [
{
name: 'Direct',
type: 'line',
// barWidth: '60%',
data: [10, 52, 200, 334, 390, 330, 220],
itemStyle: {
//
color: 'rgb(123,103,255)'
}
}
]
}
)
type ChartData = [string, number][]
const data = ref<ChartData>()
const props = withDefaults(defineProps<{ data: ChartData }>(), {
data: () => []
});
const chartObj: {
chartDom: HTMLElement,
chart: EChartsType
} = {
chartDom: null,
chart: null
}
const elId = ref('apply_bar_' + Date.now())
onBeforeMount(() => {
})
const isDark = useDark()
watch(() => isDark.isDark.value, (value: boolean) => {
if (chartObj.chart) {
chartObj.chart.dispose();
chartObj.chart = echarts.init(document.getElementById(elId.value), value ? 'dark' : 'light'); //init'light'/'dark'
chartObj.chart.setOption(chartOption.value);
props.data && chartObj.chart?.setOption(dataToOptionsData(props.data));
}
})
onMounted(() => {
elId.value = 'apply_bar_' + Date.now() + Math.random()
nextTick(() => {
const chartDom = document.getElementById(elId.value)!;
chartObj.chart = echarts.init(chartDom, isDark.isDark.value ? 'dark' : 'light')
chartObj.chartDom = chartDom
chartObj.chart?.setOption(chartOption.value)
window.addEventListener('resize', () => {
setTimeout(() => chartObj.chart?.resize(), 300)
})
})
})
const dataToOptionsData = (data) => {
return {
xAxis: [{data: data.map(item => item[0])}],
series: [{data: data.map(item => item[1])}]
}
}
watch(() => props.data, (newVal) => {
newVal && chartObj.chart?.setOption(dataToOptionsData(newVal));
}, {
immediate: true
})
</script>
<style scoped lang="scss">
</style>

View File

@ -1,11 +0,0 @@
<script setup lang="ts">
</script>
<template>
</template>
<style scoped lang="scss">
</style>

View File

@ -1,131 +0,0 @@
<template>
<div :id="elId" style="width: 100%;height: 100%;min-height: 10rem;min-width: 10rem"></div>
</template>
<script setup lang="ts">
import * as echarts from 'echarts/core';
import {
TitleComponent,
TooltipComponent,
LegendComponent
} from 'echarts/components';
import {PieChart} from 'echarts/charts';
import {LabelLayout} from 'echarts/features';
import {CanvasRenderer} from 'echarts/renderers';
import {useDark} from "@pureadmin/utils";
import {nextTick, onBeforeMount, onMounted, ref, watch} from "vue";
import {EChartsType} from "echarts/core";
echarts.use([
TitleComponent,
TooltipComponent,
LegendComponent,
PieChart,
CanvasRenderer,
LabelLayout
]);
const chartOption = ref(
{
backgroundColor: "rgba(0,0,0,0)",
title: {
// text: 'Referer of a Website',
// subtext: 'Fake Data',
// left: 'center'
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
top: "10%",
containLabel: true
},
tooltip: {
trigger: 'item'
},
legend: {
orient: 'vertical',
left: 'left'
},
series: [
{
name: '等级',
type: 'pie',
radius: '80%',
data: [
{value: 1048, name: 'C'},
{value: 735, name: 'B'},
{value: 580, name: 'A'},
{value: 484, name: 'AA'},
{value: 300, name: 'AAA'}
],
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
}
)
type ChartData = [string, number][]
const data = ref<ChartData>()
const props = withDefaults(defineProps<{ data: ChartData }>(), {
data: () => [['AAA', 300], ['AA', 484], ['A', 580], ['B', 735], ['C', 1048]]
});
const chartObj: {
chartDom: HTMLElement,
chart: EChartsType
} = {
chartDom: null,
chart: null
}
const elId = ref('rate_level_pie_' + Date.now())
onBeforeMount(() => {
})
const isDark = useDark()
watch(() => isDark.isDark.value, (value: boolean) => {
if (chartObj.chart) {
chartObj.chart.dispose();
chartObj.chart = echarts.init(document.getElementById(elId.value), value ? 'dark' : 'light'); //init'light'/'dark'
chartObj.chart.setOption(chartOption.value);
props.data && chartObj.chart?.setOption(dataToOptionsData(props.data));
}
})
onMounted(() => {
elId.value = 'rate_level_pie_' + Date.now() + Math.random()
nextTick(() => {
const chartDom = document.getElementById(elId.value)!;
chartObj.chart = echarts.init(chartDom, isDark.isDark.value ? 'dark' : 'light')
chartObj.chartDom = chartDom
chartObj.chart?.setOption(chartOption.value)
window.addEventListener('resize', () => {
setTimeout(() => chartObj.chart?.resize(), 300)
})
})
})
const dataToOptionsData = (data) => {
return {
series: [{data: data.map(item => ({name: item[0], value: item[1]}))}]
}
}
watch(() => props.data, (newVal) => {
newVal && chartObj.chart?.setOption(dataToOptionsData(newVal));
}, {
immediate: true
})
</script>
<style scoped lang="scss">
</style>

View File

@ -1,181 +0,0 @@
<template>
<div class="h-full">
<div class="p-4 md:p-12">
<div class="w-full p-4 text-center board-border">评级作业看板</div>
<div class="board-border p-4 my-4">
<div class="mb-2">待处理作业:</div>
<div
class="grid grid-cols-2 sm:grid-cols-3 min-[850px]:grid-cols-4 items-center gap-4"
>
<el-card
v-for="key in ['examining', 'rating', 'publish']"
class="num-data-item item-border"
:style="{ color: itemColorConfig[key] }"
>
<div>
<div class="num-data-item__num">{{ resData[key] }}</div>
<div class="num-data-item__title">{{ nameDic[key] }}</div>
</div>
</el-card>
</div>
</div>
<div class="board-border p-4 my-4">
<div class="mb-2">作业质量管理:</div>
<div
class="grid grid-cols-2 sm:grid-cols-3 min-[850px]:grid-cols-4 items-center gap-4"
>
<el-card
v-for="key in ['published', 'average_work_day']"
class="num-data-item item-border"
:style="{ color: itemColorConfig[key] }"
>
<div>
<div class="num-data-item__num">{{ resData[key] }}</div>
<div class="num-data-item__title">{{ nameDic[key] }}</div>
</div>
</el-card>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { api } from "@/api/api";
import { ElMessage } from "element-plus";
import { onMounted, ref } from "vue";
import ApplyBar from "@/views/dashboard/components/ApplyBar.vue";
import RateLevelPie from "@/views/dashboard/components/RateLevelPie.vue";
import { spost, st } from "@/api/smebiz";
defineOptions({
name: "dashboard",
});
type RateLevel = "AAA" | "AA" | "A" | "B" | "c";
interface DashboardData {
num_data: {
企业总数: number;
昨日新增: number;
待处理申请: number;
申请企业数: number;
待评级企业: number;
总申请数: number;
待披露企业: number;
披露企业数: number;
};
七日评级申请趋势数据: [string, number][];
已披露企业评级等级扇形数据: [RateLevel, number][];
}
const itemColorConfig = {
企业总数: "rgb(218,30,255)",
昨日新增: "rgb(255,245,51)",
待处理申请: "rgb(190,255,64)",
申请企业数: "rgb(168,86,255)",
待评级企业: "rgb(255,60,221)",
总申请数: "rgb(107,255,201)",
待披露企业: "rgb(246,203,255)",
披露企业数: "rgb(130,170,255)",
examining: "rgb(218,30,255)",
rating: "rgb(96 119 255)",
publish: "rgb(255 143 21)",
published: "rgb(168,86,255)",
average_work_day: "rgb(130,170,255)",
};
const dashboardData = ref<DashboardData>({
num_data: {
待处理申请: 0,
待披露企业: 0,
待评级企业: 0,
总申请数: 0,
披露企业数: 0,
昨日新增: 0,
申请企业数: 0,
企业总数: 0,
},
七日评级申请趋势数据: [],
已披露企业评级等级扇形数据: [],
});
const resData = ref<st["DashboardDataGetRes"]>({
examining: 0,
rating: 0,
publish: 0,
published: 0,
average_work_day: 0,
});
const nameDic = {
examining: "材料审核",
rating: "评级作业",
publish: "信息披露",
published: "已披露公司",
average_work_day: "平均作业天数",
};
const getData = () => {
spost("/file-receive/rate/rate_serve/dashboard_data/get").then((res) => {
const { error, data } = res;
if (error) {
console.log(error);
} else {
resData.value = data;
console.log(data);
}
});
return;
api
.post<any, { data: DashboardData }>(
"/file-receive/smebiz_rate/company_rate/get_dashboard_data",
{}
)
.then((res) => {
dashboardData.value = res.data;
})
.catch((e) => {
ElMessage.warning(e.response?.data?.detail || e.response?.statusText);
});
};
onMounted(() => getData());
</script>
<style scoped lang="scss">
html[class*="dark"] .item-border {
background: var(--el-bg-color);
border: 2px solid rgba(162, 160, 160, 0.3);
border-radius: 0.5rem;
}
html[class*="dark"] .board-border {
background: none;
border: 2px solid rgba(162, 160, 160, 0.3);
border-radius: 0.5rem;
}
.item-border {
background: rgb(141 122 232 / 17%);
border: 1px solid rgb(141 122 232 / 17%);
border-radius: 0.5rem;
}
.board-border {
background: white;
border: 2px solid rgba(255, 255, 255, 0.87);
border-radius: 0.5rem;
}
.num-data-item {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 9rem;
max-height: 9rem;
font-size: 1.25rem;
}
.num-data-item__num {
//font-family: Din pro,Din alternate;
text-align: center;
font-size: 2rem;
font-style: normal;
font-weight: 600;
}
</style>

View File

@ -1,114 +0,0 @@
<template>
<div class="h-full">
<div class="p-4 md:p-12">
<div class="grid grid-cols-2 sm:grid-cols-3 min-[850px]:grid-cols-4 items-center gap-4">
<el-card v-for="(item,key) in dashboardData.num_data"
class="num-data-item item-border"
:style="{color:itemColorConfig[key]}">
<div>
<div class="num-data-item__num">{{ item }}</div>
<div class="num-data-item__title">{{ key }}</div>
</div>
</el-card>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 my-4">
<div style="height: 16rem;" class="item-border flex flex-col pb-2 bg-white dark:bg-opacity-0">
<div class="opacity-80 text-center my-4 ">七日评级申请趋势</div>
<apply-bar class="flex-1" :data="dashboardData.七日评级申请趋势数据"></apply-bar>
</div>
<div style="height: 16rem;" class="item-border flex flex-col pb-2 bg-white dark:bg-opacity-0">
<div class="opacity-80 text-center my-4">已披露企业评级等级分布</div>
<rate-level-pie class="flex-1" :data="dashboardData.已披露企业评级等级扇形数据"></rate-level-pie>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import {api} from "@/api/api";
import {ElMessage} from "element-plus";
import {onMounted, ref} from "vue";
import ApplyBar from "@/views/dashboard/components/ApplyBar.vue";
import RateLevelPie from "@/views/dashboard/components/RateLevelPie.vue";
defineOptions({
name: "dashboard"
})
type RateLevel = "AAA" | "AA" | "A" | "B" | "c"
interface DashboardData {
num_data: {
企业总数: number,
昨日新增: number,
待处理申请: number,
申请企业数: number,
待评级企业: number,
总申请数: number,
待披露企业: number,
披露企业数: number,
}
七日评级申请趋势数据: [string, number][],
已披露企业评级等级扇形数据: [RateLevel, number][]
}
const itemColorConfig = {
企业总数: "rgb(218,30,255)",
昨日新增: "rgb(255,245,51)",
待处理申请: "rgb(190,255,64)",
申请企业数: "rgb(168,86,255)",
待评级企业: "rgb(255,60,221)",
总申请数: "rgb(107,255,201)",
待披露企业: "rgb(246,203,255)",
披露企业数: "rgb(130,170,255)",
}
const dashboardData = ref<DashboardData>({
num_data: {
待处理申请: 0,
待披露企业: 0,
待评级企业: 0,
总申请数: 0,
披露企业数: 0,
昨日新增: 0,
申请企业数: 0,
企业总数: 0,
},
七日评级申请趋势数据: [],
已披露企业评级等级扇形数据: [],
})
const getData = () => {
return
api.post<any, { data: DashboardData }>('/file-receive/smebiz_rate/company_rate/get_dashboard_data', {}).then(res => {
dashboardData.value = res.data
}).catch(e => {
ElMessage.warning(e.response?.data?.detail || e.response?.statusText)
})
}
onMounted(() => getData())
</script>
<style scoped lang="scss">
.item-border {
border: 2px solid rgba(162, 160, 160, 0.3);
border-radius: 0.5rem;
}
.num-data-item {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 9rem;
max-height: 9rem;
font-size: 1.25rem;
}
.num-data-item__num {
//font-family: Din pro,Din alternate;
text-align: center;
font-size: 2rem;
font-style: normal;
font-weight: 600;
}
</style>

View File

@ -0,0 +1,115 @@
<template>
<div>
<!-- <div style="word-wrap: break-word">-->
<!-- {{ filePath ? filePath : "请选择文件" }}-->
<!-- </div>-->
<div>
<el-upload
v-model:file-list="fileList"
:data="{data:JSON.stringify(data)}"
class="inline-block mr-2 w-40"
ref="upload"
:action="action"
:limit="1"
:on-exceed="handleExceed"
:auto-upload="false"
:headers="headers"
:on-error="onError"
:on-success="onSuccess"
>
<template #trigger>
<el-button type="primary" size="small">选择文件</el-button>
</template>
</el-upload>
<el-button
type="primary"
v-if="filePath && props.showDownload === true"
@click="fileDownload"
>下载
</el-button
>
</div>
<!-- <div>-->
<!-- <el-button @click="submitUpload">上传</el-button>-->
<!-- </div>-->
</div>
</template>
<script setup lang="ts">
import {computed, onMounted, ref} from "vue";
import {ElMessage, genFileId, UploadFile, UploadFiles} from "element-plus";
import type {UploadInstance, UploadProps, UploadRawFile} from "element-plus";
import {getToken} from "@/utils/auth";
import {api} from "@/api/api";
const submitUpload = () => {
upload.value!.submit()
}
const fileList = ref([])
const props = defineProps<{ modelValue?: string | null; showDownload?: boolean, data: any, action: string }>();
const emit = defineEmits(["update:modelValue"]);
const headers = ref({Authorization: ""});
const upload = ref<UploadInstance>();
const filePath = computed({
get() {
return props.modelValue;
},
set(newVal) {
console.log(newVal, "newValnewValnewVal");
emit("update:modelValue", newVal);
}
});
const fileDownload = () => {
// api
// .post("/wd-smebiz/smebiz_rate/form_file/get", {md: fileId.value})
// .then(res => {
// let fileUrl = res.data.file_url;
// ElMessage.success("");
// const a = document.createElement("a");
// a.style.display = "none";
// a.download = res.data.file_name;
// a.href = fileUrl;
// document.body.appendChild(a);
// a.click();
// document.body.removeChild(a);
// /*
// * download: HTML5
// * url:
// */
// })
// .catch(e => {
// ElMessage.warning("");
// throw e;
// });
};
let file
const handleExceed: UploadProps["onExceed"] = files => {
upload.value!.clearFiles();
file = files[0] as UploadRawFile;
file.uid = genFileId();
upload.value!.handleStart(file);
};
const onSuccess = (
response: any,
uploadFile: UploadFile,
uploadFiles: UploadFiles
) => {
console.log(response, "response");
filePath.value = response.file_path;
emit('success')
};
const onError = error => {
ElMessage.warning("上传失败");
};
onMounted(() => {
headers.value.Authorization = "Bearer " + getToken().accessToken;
});
function getFileList(){
return fileList.value
}
defineExpose({
upload, submitUpload, getFileList
})
</script>

View File

@ -0,0 +1,114 @@
<template>
<div>
<!-- <div style="word-wrap: break-word">-->
<!-- {{ filePath ? filePath : "请选择文件" }}-->
<!-- </div>-->
<div>
<el-upload
v-model:file-list="fileList"
:data="{data:JSON.stringify(data)}"
class="inline-block mr-2 w-40"
ref="upload"
:action="action"
:limit="1"
:on-exceed="handleExceed"
:auto-upload="true"
:headers="headers"
:on-error="onError"
:on-success="onSuccess"
>
<template #trigger>
<el-button type="primary" size="small">修改文件</el-button>
</template>
</el-upload>
<!-- <el-button-->
<!-- type="primary"-->
<!-- v-if="filePath && props.showDownload === true"-->
<!-- @click="fileDownload"-->
<!-- >下载-->
<!-- </el-button-->
<!-- >-->
</div>
<!-- <div>-->
<!-- <el-button @click="submitUpload">上传</el-button>-->
<!-- </div>-->
</div>
</template>
<script setup lang="ts">
import {computed, onMounted, ref} from "vue";
import {ElMessage, genFileId, UploadFile, UploadFiles} from "element-plus";
import type {UploadInstance, UploadProps, UploadRawFile} from "element-plus";
import {getToken} from "@/utils/auth";
import {api} from "@/api/api";
const submitUpload = () => {
upload.value!.submit()
}
const fileList = ref([])
const props = defineProps<{ modelValue?: string | null; showDownload?: boolean, data: any, action: string }>();
const emit = defineEmits(["update:modelValue"]);
const headers = ref({Authorization: ""});
const upload = ref<UploadInstance>();
const filePath = computed({
get() {
return props.modelValue;
},
set(newVal) {
emit("update:modelValue", newVal);
}
});
const fileDownload = () => {
// api
// .post("/wd-smebiz/smebiz_rate/form_file/get", {md: fileId.value})
// .then(res => {
// let fileUrl = res.data.file_url;
// ElMessage.success("");
// const a = document.createElement("a");
// a.style.display = "none";
// a.download = res.data.file_name;
// a.href = fileUrl;
// document.body.appendChild(a);
// a.click();
// document.body.removeChild(a);
// /*
// * download: HTML5
// * url:
// */
// })
// .catch(e => {
// ElMessage.warning("");
// throw e;
// });
};
let file
const handleExceed: UploadProps["onExceed"] = files => {
upload.value!.clearFiles();
file = files[0] as UploadRawFile;
file.uid = genFileId();
upload.value!.handleStart(file);
};
const onSuccess = (
response: any,
uploadFile: UploadFile,
uploadFiles: UploadFiles
) => {
console.log(response, "response");
filePath.value = response.file_path;
emit('success')
};
const onError = error => {
ElMessage.warning("上传失败");
};
onMounted(() => {
headers.value.Authorization = "Bearer " + getToken().accessToken;
});
function getFileList(){
return fileList.value
}
defineExpose({
upload, submitUpload, getFileList
})
</script>

View File

@ -0,0 +1,137 @@
<template>
<el-dialog v-model="itemAddVisible" title="添加数据" class="item-add-dialog"
style="width: fit-content"
append-to-body>
<el-form
:class="addColumns.length>9?'grid grid-cols-3 gap-x-6 mx-20':'mx-20'"
:label-position="addColumns.length>9?'top':'right'"
@submit.native.prevent=""
ref="addRuleFormRef"
:model="itemAddTemp"
label-width="auto"
>
<el-form-item
:class="addColumns.length>9?'w-48':''"
v-for="column in addColumns"
:prop="column.key"
:label="column.name"
:rules="!column.key.includes('template_path')?[
{
required: column?.require?.add===true,
message: '请输入' + column.name,
trigger: 'blur'
}
]:[]"
>
<div v-if="column.key=='template_path'">
<file-upload @success="onSuccess" ref="fileUploadRef" :data="itemAddTemp"
action="/file-receive/receive/receive_subject_file/add_with_file"/>
</div>
<input-column
v-else
:class="addColumns.length>9?'':'max-w-[12rem]'"
:ctx="itemAddTemp"
:column="column"
:model-value="getValueFromPath(column.key,itemAddTemp)"
@update:model-value="(newVal)=>setValueFromPath(column.key,newVal,itemAddTemp)"
/>
</el-form-item>
</el-form>
<template #footer>
<div class="flex">
<div class="ml-auto">
<el-button size="small" @click="itemAddVisible = false">取消</el-button>
<el-button
size="small"
type="primary"
@click="addItem(addRuleFormRef)"
native-type="submit"
>保存
</el-button>
</div>
</div>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import InputColumn from "@/wcq-components/TablePlus/components/InputColumn/index.vue";
import {ref} from "vue";
import {ElMessage, FormInstance} from "element-plus";
import {getColumnDefaultValue, getValueFromPath, setValueFromPath} from "@/wcq-components/TablePlus/utils";
import {TablePlusProps} from "@/wcq-components/TablePlus/types";
import {useColumns} from "@/wcq-components/TablePlus/setups";
import FileUpload from "./FileUpload.vue";
const fileUploadRef = ref()
const itemAddTemp = ref({});
const itemAddVisible = ref(false);
const addRuleFormRef = ref<FormInstance>();
const props = defineProps<TablePlusProps>();
const emit = defineEmits(["add", "change", 'success'])
const {addColumns, idKey, crudApi} = useColumns(props)
function show(subjectId: number) {
let tempValue = {subject_id: subjectId};
addColumns.value.forEach(col => {
tempValue[col.key] = getColumnDefaultValue(col)
});
itemAddTemp.value = tempValue;
itemAddVisible.value = true;
}
function onSuccess() {
emit("add")
emit("change")
ElMessage.success("添加成功");
itemAddVisible.value = false;
props.handel?.afterAdd?.()
props.handel?.afterDataChange?.()
}
async function addItem(formEl: FormInstance) {
console.log(fileUploadRef, 'fileUploadRef')
if (!formEl) return;
await formEl.validate((valid, fields) => {
if (valid) {
if (!fileUploadRef.value?.[0]?.getFileList()?.length) {
return ElMessage.warning('请选择文件')
}
fileUploadRef.value?.[0]?.submitUpload()
// crudApi.value
// .add(itemAddTemp.value)
// .then(_res => {
// emit("add")
// emit("change")
// ElMessage.success("");
// itemAddVisible.value = false;
// props.handel?.afterAdd?.()
// props.handel?.afterDataChange?.()
// })
// .catch(e => {
// ElMessage.warning(e.response?.data?.detail || e.response?.statusText);
// throw e;
// });
} else {
return fields;
}
});
}
defineExpose({
show
})
</script>
<style lang="scss">
.item-add-dialog {
//max-width: 800px;
padding: 0.5rem 1rem 1rem 1rem;
border-radius: 1rem;
margin-bottom: 0;
}
.item-add-dialog > .el-dialog__body {
padding-top: 1rem;
padding-bottom: 0.5rem;
}
</style>

View File

@ -0,0 +1,166 @@
<template>
<el-dialog v-model="itemEditVisible" title="编辑数据" class="item-edit-dialog" style="width: fit-content;"
append-to-body>
<div>
<el-form
class="justify-end"
:class="updateColumns.length>9?'grid grid-cols-3 gap-x-6 mx-20':'mx-20'"
:label-position="updateColumns.length>9?'top':'right'"
@submit.native.prevent=""
label-width="auto"
ref="editRuleFormRef"
:model="itemEditTemp"
>
<el-form-item
:class="updateColumns.length>9?'w-48':''"
v-for="column in updateColumns"
:label="column.name"
:prop="column.key"
:rules="!column.key.includes('template_path')?[
{
required: column?.require?.update === true,
message: '请输入' + column.name,
trigger: 'blur'
}
]:[]"
>
<div v-if="column.key=='template_path'">
<file-upload-change @success="onUploadSuccess" ref="fileUploadRef" :data="itemEditTemp"
action="/file-receive/receive/receive_subject_file/update_file"/>
</div>
<input-column
v-else
:class="updateColumns.length>9?'':'max-w-[12rem]'"
:ctx="itemEditTemp"
:column="column"
:model-value="getValueFromPath(column.key,itemEditTemp)"
@update:model-value="(newVal)=>setValueFromPath(column.key,newVal,itemEditTemp)"
/>
</el-form-item>
</el-form>
</div>
<template #footer>
<div class="flex">
<div class="ml-auto">
<el-button size="small" type="danger" @click="showDeleteConfirm">删除</el-button>
<el-button size="small" @click="itemEditVisible = false">取消</el-button>
<el-button size="small" type="primary" native-type="submit" @click="saveChange(editRuleFormRef)">保存
</el-button>
</div>
</div>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import InputColumn from "@/wcq-components/TablePlus/components/InputColumn/index.vue";
import {ref} from "vue";
import {ElMessage, ElMessageBox, FormInstance} from "element-plus";
import {TablePlusProps} from "@/wcq-components/TablePlus/types";
import {useColumns} from "@/wcq-components/TablePlus/setups";
import {getValueFromPath, setValueFromPath} from "@/wcq-components/TablePlus/utils"
import FileUpload from "@/views/receive/components/FileUpload.vue";
import FileUploadChange from "@/views/receive/components/FileUploadChange.vue";
const itemEditTemp = ref({});
const itemEditVisible = ref(false);
const editRuleFormRef = ref<FormInstance>();
const props = defineProps<TablePlusProps>();
const emit = defineEmits(["delete", "update", "change"])
const {updateColumns, idKey, crudApi} = useColumns(props)
function onUploadSuccess() {
emit("update")
emit("change")
ElMessage.success("修改成功");
props.handel?.afterUpdate?.()
props.handel?.afterDataChange?.()
}
function showDeleteConfirm() {
ElMessageBox.confirm("确认删除?", "Warning", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
})
.then(() => {
crudApi.value
.delete(itemEditTemp.value[idKey.value])
.then(_res => {
ElMessage.success("删除成功");
emit("delete")
emit("change")
itemEditVisible.value = false;
props.handel?.afterDelete?.()
props.handel?.afterDataChange?.()
})
.catch(e => {
ElMessage.warning(e);
throw e;
});
})
.catch(() => {
});
}
async function saveChange(formEl: FormInstance) {
//id
if (!formEl) return;
await formEl.validate((valid, fields) => {
if (valid) {
delete itemEditTemp.value['template_path']
delete itemEditTemp.value['type']
//
crudApi.value
.update(itemEditTemp.value)
.then(_res => {
emit("update")
emit("change")
ElMessage.success("修改成功");
itemEditVisible.value = false;
props.handel?.afterUpdate?.()
props.handel?.afterDataChange?.()
})
.catch(e => {
ElMessage.warning("错误");
throw e;
});
} else {
return fields;
}
})
}
function show(item: any) {
console.log(updateColumns.value.length, updateColumns, "updateColumns")
const id = item[idKey.value]
//get
crudApi.value.get(id).then(res => {
itemEditTemp.value = res.data
itemEditVisible.value = true;
}).catch(
e => {
ElMessage.warning(e.response?.data?.detail || e.response?.statusText);
throw e;
}
)
}
defineExpose({
show
})
</script>
<style lang="css">
.item-edit-dialog {
//max-width: 800px; padding: 0.5rem 1rem 1rem 1rem; border-radius: 1rem; margin-bottom: 0;
}
.item-edit-dialog > .el-dialog__body {
padding-top: 1rem;
padding-bottom: 0.5rem;
}
</style>

View File

@ -0,0 +1,172 @@
<template>
<div class="flex flex-col" style="height: 100%;">
<div class="flex overflow-y-auto">
<div class="ml-[2rem] mr-14">
<div>接收文件:</div>
<div>
<el-button size="small"
@click="() => itemAddDialogRef.show(subjectId)" type="primary">新增
</el-button>
</div>
</div>
<div class="flex flex-col overflow-y-auto flex-1">
<div v-for="item in tableData" class="flex-1 mb-6 flex ">
<table class="w-[40rem] file-info-item">
<thead>
<tr>
<th>序号</th>
<th>文件名称</th>
<th>文件类型</th>
<th>大小限制</th>
<th>示例模板</th>
</tr>
</thead>
<tbody class="text-center">
<tr>
<td>{{ item.id }}</td>
<td>{{ item.name }}</td>
<td>{{ item.type }}</td>
<td>{{ item.file_size_limit }}</td>
<td>
<el-button size="small"
@click="()=>downFile(item.template_path,item.name,item.type)">下载
</el-button>
</td>
</tr>
<tr>
<td>说明</td>
<td colspan="4" class="h-24">
<div class="flex h-full p-2">
{{ item.name }}
</div>
</td>
</tr>
</tbody>
</table>
<div class="mx-4">
<el-button size="small" type="primary" @click="()=>itemEditDialogRef.show(item)">编辑</el-button>
</div>
</div>
</div>
</div>
<subject-file-add-dialog ref="itemAddDialogRef" v-bind="props" @change="getTableData"/>
<subject-file-edit-dialog ref="itemEditDialogRef" v-bind="props" @change="getTableData"/>
</div>
</template>
<script setup lang="ts">
import type {ElTable} from "element-plus";
import {ElMessage} from "element-plus";
import {computed, onActivated, ref, watch} from "vue";
import type {TablePlusProps} from "@/wcq-components/TablePlus/types";
import CellColumn from "@/wcq-components/TablePlus/components/CellColumn/index.vue";
import QueryColumn from "@/wcq-components/TablePlus/components/QueryColumn/index.vue";
import TableConfigDialog from "@/wcq-components/TablePlus/components/TableConfigDialog.vue";
import {useColumns} from "@/wcq-components/TablePlus/setups"
import ItemEditDialog from "@/wcq-components/TablePlus/components/ItemEditDialog.vue";
import ItemAddDialog from "@/wcq-components/TablePlus/components/ItemAddDialog.vue";
import {getQueryValue, getValueFromPath, setQueryValue, setValueFromPath} from "@/wcq-components/TablePlus/utils";
import {Query} from "@/wcq-components/TablePlus/api";
import {receiveSubjectFileModel} from "@/views/receive/models";
import {ReceiveSubjectFile} from "@/views/receive/types";
import SubjectFileAddDialog from "@/views/receive/components/SubjectFileAddDialog.vue";
import SubjectFileEditDialog from "@/views/receive/components/SubjectFileEditDialog.vue";
interface Props extends TablePlusProps {
// subject_id: number
}
//@ts-ignore
const props = withDefaults(defineProps<Props>(), {
tableModel: () => receiveSubjectFileModel,
mainElTableProps: () => ({}),
formLabelWidth: 100,
selection: null,
});
const subjectId = ref(0)
const showColumnKeys = ref([])
const tableData = ref<ReceiveSubjectFile[]>([]);
const count = ref(0);
const query = ref<Query>({params: [], page: 1, page_size: 20});
const {idKey, crudApi} = useColumns(props)
const itemEditDialogRef = ref<InstanceType<typeof ItemEditDialog> | null>(null)
const itemAddDialogRef = ref<InstanceType<typeof ItemAddDialog> | null>(null)
const tableConfigDialogRef = ref<InstanceType<typeof TableConfigDialog> | null>(null)
const table = ref(null)
const tableButtonConfig = computed(() => [
{name: "添加数据", func: itemAddDialogRef.value?.show},
{name: "更新数据", func: getTableData},
{name: "表格配置", func: tableConfigDialogRef.value?.show},
])
// watch(
// () => props.tableModel,
// newVal => {
// getTableData();
// },
// {deep: true, immediate: true}
// );
async function getTableData(subjectIdValue: number) {
if (subjectIdValue) {
subjectId.value = subjectIdValue
}
try {
const res = await crudApi.value.queryCommon({
...query.value,
order: {id: 'asc'},
params: [...query.value.params.filter(item => [null, undefined, ""].indexOf(item.value) === -1), {name: "subject_id", value: subjectId.value, type: '='}]
});
count.value = res.data.count;
tableData.value = res.data.items;
} catch (e) {
console.error(e);
ElMessage.warning(e.response?.data?.detail || e.response?.statusText);
}
}
function downFile(path: string, name: string, type: string) {
let fileUrl = '/file-receive/' + path
ElMessage.success("开始下载");
const a = document.createElement("a");
a.style.display = "none";
a.download = name +'.'+ type;
a.href = fileUrl;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}
defineExpose({
getTableData
})
</script>
<style lang="css">
.el-popper {
min-width: 10px !important;
}
.table-plus {
width: 100%;
border: 1px solid #ffffff24;
border-radius: 0.5rem;
border-bottom: none;
}
</style>
<style scoped>
.file-info-item thead {
background: #212122;
}
.file-info-item table, th, td {
border: 1px solid #383838;
padding: 0.2rem;
}
.file-info-item {
background: #121212;
}
</style>

150
src/views/receive/models.ts Normal file
View File

@ -0,0 +1,150 @@
import type {TableModel} from "@/wcq-components/TablePlus/types";
const receiveSubjectModel = {
props: {
hiddenColumns: ['des']
},
tableName: "receive_subject",
name: "接收主题",
columns: [
{
key: "id",
name: "主题ID",
require: {
add: false,
update: false
},
primary: true,
type: "integer"
},
{
key: "name",
name: "主题名称",
type: "string",
require: {
add: true,
update: true
},
query: {
type: "like"
}
},
{
key: "receiver",
name: "接收人",
type: "string",
require: {
add: true,
update: true
},
},
{
key: "start_time",
name: "开始时间",
type: "datetime"
},
{
key: "finish_time",
name: "结束时间",
type: "datetime"
},
{
key: "state",
name: "主题状态",
type: "enum",
config: {
options: [{name: '接收中', value: 'receiving'}, {name: '审核中', value: 'examining'}, {
name: '已完成',
value: 'finish'
}]
}
},
{
key: "folder_name",
name: "接收目录",
type: "string"
},
{
key: "create_time",
name: "创建时间",
require: {
add: false,
},
type: "datetime"
},
{
key: "des",
name: "说明",
type: "text"
}
// {
// "key": "files",
// "name": "files",
// "type": "set"
// }
],
url: "/file-receive/receive/receive_subject"
}
const receiveSubjectFileModel :TableModel= {
props: {
hiddenColumns: ['des']
},
tableName: "receive_subject_file",
name: "主题文件",
columns: [
{
key: "id",
name: "文件ID",
require: {
add: false,
update: false
},
primary: true,
type: "integer"
},
{
key: "name",
name: "文件名称",
type: "string",
require: {
add: true,
update: true
},
query: {
type: "like"
}
},
{
key: "template_path",
name: "模板文件",
type: "string",
require: {
add: true,
}
},
{
key: "type",
name: "文件类型",
type: "string",
require: {
add: false,
update: false
},
},
{
key: "file_size_limit",
name: "文件大小限制mb",
type: "integer",
default:10
},
{
key: "des",
name: "说明",
type: "text"
}
],
url: "/file-receive/receive/receive_subject_file"
}
export {receiveSubjectModel,receiveSubjectFileModel}

View File

@ -0,0 +1,193 @@
<template>
<div class="flex flex-col" style="height: 100%;">
<el-table
v-bind="mainElTableProps"
class="flex-1 table-plus"
:data="tableData"
height="100%"
>
<template #empty>
<el-empty description="无数据"/>
</template>
<el-table-column align="center" :label="column.name||column.key"
v-for="column in tableModel.columns.filter(item=>showColumnKeys.indexOf(item.key)!==-1)">
<template #header v-if="column.query">
<query-column
@change="getTableData"
:ctx="query"
:column="column"
:model-value="getQueryValue(column,query)"
@update:model-value="(newValue)=>setQueryValue(column,query,newValue)"
/>
</template>
<template #default="{ row }">
<cell-column
class="overflow-auto"
:column="column"
:model-value="getValueFromPath(column.key,row)"
@update:model-value="(newVal)=>setValueFromPath(column.key,newVal,row)"
:ctx="row"
/>
</template>
</el-table-column>
<el-table-column align="center" fixed="right" label="操作" width="165">
<template #header>
<el-popover width="auto" trigger="click">
<template #reference>
<el-button size="small">操作</el-button>
</template>
<div class="flex-c flex flex-col">
<div v-for="item in tableButtonConfig">
<el-button
class="block m-1.5"
type="primary"
size="small"
@click="item.func">
{{ item.name }}
</el-button>
</div>
</div>
</el-popover>
</template>
<template #default="scope">
<div>
<el-button
type="primary"
size="small"
@click="() => itemEditDialogRef.show(scope.row)">
编辑
</el-button>
<el-button
type="primary"
size="small"
@click="() =>{ subjectFilesEditVisible=true;itemTemp=scope.row;nextTick(()=>subjectFilesRef.getTableData(scope.row.id))}">
文件配置
</el-button>
</div>
</template>
</el-table-column>
</el-table>
<div class="flex justify-center mt-1.5">
<el-pagination
v-model:current-page="query.page"
v-model:page-size="query.page_size"
@size-change="getTableData"
:page-sizes="[10, 20,30,40]"
:small="false"
layout="total,sizes,prev,pager,next"
:total="count"
@current-change="getTableData"
/>
</div>
<item-edit-dialog ref="itemEditDialogRef" v-bind="props" @change="getTableData"/>
<item-add-dialog ref="itemAddDialogRef" v-bind="props" @change="getTableData"/>
<table-config-dialog ref="tableConfigDialogRef" :tableModel="tableModel"
v-model:showColumnKeys="showColumnKeys"/>
<el-dialog :title="itemTemp.name+'-接收文件列表'" class="subject-files-dialog" v-model="subjectFilesEditVisible">
<subject-files class="overflow-y-auto" ref="subjectFilesRef"></subject-files>
</el-dialog>
</div>
</template>
<script setup lang="ts">
import type {ElTable} from "element-plus";
import {ElMessage} from "element-plus";
import {computed, nextTick, onActivated, ref, watch} from "vue";
import type {TablePlusProps} from "@/wcq-components/TablePlus/types";
import CellColumn from "@/wcq-components/TablePlus/components/CellColumn/index.vue";
import QueryColumn from "@/wcq-components/TablePlus/components/QueryColumn/index.vue";
import TableConfigDialog from "@/wcq-components/TablePlus/components/TableConfigDialog.vue";
import {useColumns} from "@/wcq-components/TablePlus/setups"
import ItemEditDialog from "@/wcq-components/TablePlus/components/ItemEditDialog.vue";
import ItemAddDialog from "@/wcq-components/TablePlus/components/ItemAddDialog.vue";
import {getQueryValue, getValueFromPath, setQueryValue, setValueFromPath} from "@/wcq-components/TablePlus/utils";
import {Query} from "@/wcq-components/TablePlus/api";
import {receiveSubjectModel} from "@/views/receive/models";
import SubjectFiles from "@/views/receive/components/SubjectFiles.vue";
//@ts-ignore
const props = withDefaults(defineProps<TablePlusProps>(), {
tableModel: () => receiveSubjectModel,
mainElTableProps: () => ({}),
formLabelWidth: 100,
selection: null
});
const subjectFilesEditVisible = ref(false)
const subjectFilesRef = ref()
const showColumnKeys = ref([])
const tableData = ref([]);
const count = ref(0);
const query = ref<Query>({params: [], page: 1, page_size: 20});
const {idKey, crudApi} = useColumns(props)
const itemEditDialogRef = ref<InstanceType<typeof ItemEditDialog> | null>(null)
const itemAddDialogRef = ref<InstanceType<typeof ItemAddDialog> | null>(null)
const tableConfigDialogRef = ref<InstanceType<typeof TableConfigDialog> | null>(null)
const table = ref(null)
const itemTemp = ref({
id: 0,
name: ''
})
const tableButtonConfig = computed(() => [
{name: "添加数据", func: itemAddDialogRef.value?.show},
{name: "更新数据", func: getTableData},
{name: "表格配置", func: tableConfigDialogRef.value?.show},
])
watch(
() => props.tableModel,
newVal => {
getTableData();
},
{deep: true, immediate: true}
);
async function getTableData() {
try {
const res = await crudApi.value.queryCommon({
...query.value,
params: query.value.params.filter(item => [null, undefined, ""].indexOf(item.value) === -1)
});
count.value = res.data.count;
tableData.value = res.data.items;
} catch (e) {
console.error(e);
ElMessage.warning(e.response?.data?.detail || e.response?.statusText);
}
}
defineExpose({
getTableData
})
</script>
<style lang="css">
.el-popper {
min-width: 10px !important;
}
.table-plus {
width: 100%;
border: 1px solid #ffffff24;
border-radius: 0.5rem;
border-bottom: none;
}
.subject-files-dialog {
width: 90%;
height: 90%;
margin-bottom: 0;
margin-top: 2%;
display: flex;
flex-direction: column;;
}
.item-edit-dialog {
//max-width: 800px; padding: 0.5rem 1rem 1rem 1rem; border-radius: 1rem;
}
.subject-files-dialog > .el-dialog__body {
flex:1;
overflow-y: auto;
padding-top: 1rem;
padding-bottom: 0.5rem;
}
</style>

View File

@ -0,0 +1,19 @@
enum ReceiveSubjectState {
receiving = 'receiving',
examining = 'examining',
finish = 'finish'
}
interface ReceiveSubjectFile {
id: number
subject_id: number
name: string
type: string
des: string
template_path: string
file_size_limit: number
}
export {ReceiveSubjectState}
export type {ReceiveSubjectFile}

View File

@ -291,7 +291,7 @@ export type {
type MainElTableProps = InstanceType<typeof ElTable>["$props"];
export interface TablePlusProps {
tableModel: TableModel;
tableModel?: TableModel;
mainElTableProps?: MainElTableProps;
formLabelWidth?: number;
handel?: {