Commit 08087ac4 authored by chenqikuai's avatar chenqikuai

feat: 东西太多了先保存吧

parent 6c2349f4
......@@ -13,8 +13,8 @@
<body>
<div id="app"></div>
<script src="//at.alicdn.com/t/font_2543933_cg1fy18na6.js"></script>
<script src="//at.alicdn.com/t/font_2990811_5ef22ofxikf.js"></script>
<script src="//at.alicdn.com/t/font_2543933_7ir8fd8gh06.js"></script>
<script type="module" src="/src/main.ts"></script>
</body>
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -9,10 +9,10 @@
},
"dependencies": {
"axios": "^0.26.1",
"cqk-sy-ui": "^1.2.14",
"crypto-js": "^4.1.1",
"element-plus": "^2.1.9",
"js-md5": "^0.7.3",
"pdfjs-dist": "^2.5.207",
"simple-components01": "^0.1.15",
"unplugin-element-plus": "^0.3.2",
"vue": "^3.2.33",
......
export const blue = {
color: "var(--sy-blue)",
backgroundColor: "#EAEBFD",
};
export const red = {
color: "#FF1818",
backgroundColor: "#FFEDEC",
};
export const yellow = {
color: "#FF831E",
backgroundColor: "#FFF7EC",
};
export const green = {
color: "#479543",
backgroundColor: "#ECF8E6",
};
export const betweenGreenAndBlue = {
color: "#20B8C4",
backgroundColor: "#DFF8FA",
};
<template>
<button :style="status?.style" class="approveStatus">
{{ status?.label }}
</button>
</template>
<script setup lang="ts">
import { computed } from "vue";
import { eStatus, allStatus } from "./status";
const props = defineProps<{
type: eStatus;
}>();
const status = computed(() => {
return allStatus.find((i) => i.value === props.type);
});
</script>
<style scoped>
.approveStatus {
font-size: 12px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
width: 70px;
height: 25px;
border-radius: 4px;
}
</style>
import { betweenGreenAndBlue, blue, green, red, yellow } from "./btnStyle";
export enum eStatus {
/**
* 平台核验
*/
platformVerification = "platformVerification",
/**
* 已撤回
*/
withdrawn = "withdrawn",
/**
* 平台驳回
*/
platformDismissed = "platformDismissed",
/**
* 提交审核
*/
submitReview = "submitReview",
/**
* 平台未提交
*/
platformNotSubmitted = "platformNotSubmitted",
/**
* 待审核
*/
pendingReview = "pendingReview",
/**
* 同意
*/
agree = "agree",
/**
* 已驳回
*/
rejected = "rejected",
/**
* 已提交
*/
submitted = "submitted",
/**
* 待终审
*/
pendingFinalReview = "pendingFinalReview",
/**
* 审核通过
*/
approved = "approved",
all = "all",
}
export const platformVerification = {
value: eStatus.platformVerification,
label: "平台核验",
style: blue,
};
export const withdrawn = {
value: eStatus.withdrawn,
label: "已撤回",
style: green,
};
export const platformDismissed = {
value: eStatus.platformDismissed,
label: "平台驳回",
style: red,
};
export const submitReview = {
value: eStatus.submitReview,
label: "提交审核",
style: yellow,
};
export const platformNotSubmitted = {
value: eStatus.platformNotSubmitted,
label: "平台未提交",
style: blue,
};
export const pendingReview = {
value: eStatus.pendingReview,
label: "待审核",
style: yellow,
};
export const agree = {
value: eStatus.agree,
label: "同意",
style: green,
};
export const rejected = {
value: eStatus.rejected,
label: "已驳回",
style: red,
};
export const submitted = {
value: eStatus.submitted,
label: "已提交",
style: betweenGreenAndBlue,
};
export const pendingFinalReview = {
value: eStatus.pendingFinalReview,
label: "待终审",
style: green,
};
export const approved = {
value: eStatus.approved,
label: "审核通过",
style: blue,
};
export const allStatus = [
platformVerification,
withdrawn,
platformDismissed,
submitReview,
platformNotSubmitted,
pendingReview,
agree,
rejected,
submitted,
pendingFinalReview,
approved,
];
<template>
<div
class="avatar flex-shrink-0 flex justify-center items-center text-white cursor-pointer"
>
{{
(globalState.userInfos.user && globalState.userInfos.user.slice(0, 1)) ||
"K"
}}
</div>
</template>
<script lang="ts" setup>
import { globalState } from "@/store/state";
globalState;
</script>
<style lang="scss" scoped>
.avatar {
width: 35px;
height: 35px;
background: var(--sy-blue);
border-radius: 100%;
}
</style>
<template>
<syCommonDialog
type="element"
:visible="visible"
@closePopup="$emit('update:visible', false)"
>
<div class="text-center title -mt-5 mb-3">提示</div>
<div class="content">
{{ notifyContent }}
</div>
<div class="text-center">
<syButton
mode="elementBtn"
type="primary"
size="large"
style="width: 157px"
@click="$router.push('/copyrightApplication')"
>我已知晓</syButton
>
</div>
</syCommonDialog>
</template>
<script setup lang="ts">
import { syCommonDialog, syButton } from "cqk-sy-ui";
defineProps<{
visible: boolean;
}>();
const notifyContent = `1、上链查作为版权中心的版权登记授权平台,将为您的作品,申请版权登记;
2、请确保提交内容的真实性,如有弄虚作假,骗取作品登记的,版权局著作权行政管理部门将依照《版权局著作权管理办法》第30条撤销登记;
3、当前上链查仅支持为用户本人进行版权登记,暂不支持为他人进行版权登记。
`;
const handleClickConfirm = (value: any): value is string => {
return value;
};
interface Person {
name: string;
age: number;
gender: "male" | "female";
}
//批量把一个接口中的属性都变成可选的
type PartPerson = {
[Key in keyof Person]?: Person[Key];
};
let p1: PartPerson = {};
</script>
<style scoped>
.title {
font-size: 18px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #000000;
}
.content {
white-space: pre-line;
margin-bottom: 38px;
}
</style>
<template>
<div
class="inline-block relative hoverme"
ref="containerEl"
@mouseover="mouseover"
@mouseout="mouseout"
>
<slot></slot>
<component :is="teleport ? Teleport : 'div'" to="body">
<div
class="messageBox"
ref="box"
:style="{
left: left + marginLeft + 'px',
top: top + marginTop + 'px',
}"
@mouseover="boxMouseOver"
@mouseout="boxMouseOut"
>
<slot name="message"> </slot>
</div>
</component>
</div>
</template>
<script setup lang="ts">
import {
ref,
watch,
Teleport as teleport_,
TeleportProps,
VNodeProps,
onMounted,
} from "vue";
const box = ref<HTMLDivElement>();
withDefaults(
defineProps<{
teleport?: boolean;
marginLeft?: number;
marginTop?: number;
}>(),
{
teleport: true,
marginLeft: 0,
marginTop: 0,
}
);
onMounted(() => {});
const containerEl = ref<HTMLDivElement>();
const left = ref(0);
const top = ref(0);
const Teleport = teleport_ as {
new (): {
$props: VNodeProps & TeleportProps;
};
};
const t = "all .5s ease-out";
const hover = ref(false);
const boxHover = ref(false);
const finalHover = ref(false);
const emit = defineEmits(["over", "out"]);
watch(
() => [hover.value, boxHover.value],
() => {
if (hover.value || boxHover.value) {
finalHover.value = true;
} else if (!hover.value && !boxHover.value) {
finalHover.value = false;
}
}
);
watch(finalHover, () => {
if (finalHover.value) {
const rect = containerEl.value?.getBoundingClientRect();
left.value = rect?.left!;
top.value = rect?.top!;
if (!box.value) return;
emit("over");
box.value.style.transition = "none";
box.value.style.transition = t;
box.value.style.display = "block";
box.value.style.opacity = "0";
setTimeout(() => {
box.value!.style.opacity = "1";
});
} else {
if (!box.value) return;
emit("out");
box.value.style.opacity = "0";
box.value.ontransitionend = () => {
if (box.value!.style.opacity === "0") box.value!.style.display = "none";
};
}
});
const mouseover = () => {
hover.value = true;
};
const mouseout = () => {
hover.value = false;
};
const boxMouseOver = () => {
boxHover.value = true;
};
const boxMouseOut = () => {
boxHover.value = false;
};
</script>
<style lang="scss">
/*
in block -> opacity 1
out opacity 0 -> none
*/
.hoverme {
}
.messageBox {
display: none;
z-index: 100;
position: fixed;
padding: 19px 18px;
width: 308px;
background: #f7f7f7;
box-shadow: 0px 2px 10px 0px rgba(200, 200, 200, 0.5);
border-radius: 8px;
border: 1px solid #e7e7e7;
font-size: 12px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #717171;
line-height: 22px;
}
</style>
<template>
<svg class="icon" aria-hidden="true">
<use :xlink:href="'#' + iconName"></use>
</svg>
</template>
<script lang="ts" setup>
defineProps<{
iconName: string;
}>();
</script>
<style lang="scss"></style>
<template>
<div class="layout">
<slot></slot>
</div>
</template>
<script lang="ts" setup></script>
<style lang="scss">
.layout {
padding-left: 33px;
padding-top: 42.5px;
padding-right: 31px;
background: white;
height: 100%;
box-sizing: border-box;
}
</style>
<template>
<div
class="menuItem"
:class="{
menuActive: active,
}"
>
<div class="icon">
<slot name="icon"></slot>
</div>
<div class="menuName">{{ name }}</div>
</div>
</template>
<script lang="ts" setup>
const props = defineProps<{
name: string;
active: boolean;
}>();
</script>
<style lang="scss" scoped>
$notSelectColor: #959595;
$selectColor: #353535;
.menuItem {
cursor: pointer;
display: flex;
align-items: center;
color: $notSelectColor;
width: 184px;
height: 40px;
.icon {
margin-left: 27px;
margin-right: 17px;
}
.menuName {
font-size: 14px;
font-family: PingFangSC-Semibold, PingFang SC;
font-weight: 600;
line-height: 20px;
}
}
.menuActive {
color: $selectColor;
background: #e5e5e5;
border-radius: 4px;
}
</style>
<template>
<div class="menu">
<div class="appLine">
<div class="icon"></div>
<div class="appName">SLC</div>
</div>
<div
v-for="(obj, index) in menuList"
:key="index"
style="width: 100%; display: flex; justify-content: center"
>
<MenuItem
v-if="obj.type === 'menuItem'"
:name="obj.name!"
@click="handleClickMenu(obj)"
:active="isMenuActive(obj)"
>
<template #icon>
<Icon
:icon-name="isMenuActive(obj) ? obj.icon?.active.iconName! : obj.icon?.notActive.iconName!"
v-bind="isMenuActive(obj) ? obj.icon?.active.props! : obj.icon?.notActive.props!"
></Icon>
</template>
</MenuItem>
<div
class="menuDivideLine"
v-else-if="obj.type === 'menuDivideLine'"
></div>
<div class="menuGroupName" v-else-if="obj.type === 'menuGroupName'">
{{ obj.name }}
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import { router } from "@/router";
import { useRoute } from "vue-router";
import MenuItem from "./MenuItem.vue";
import { syIcon } from "cqk-sy-ui";
import Icon from "../Icon/index.vue";
const route = useRoute();
const isMenuActive = (obj: typeof menuList[0]) => {
return (
obj.path === route.path ||
obj.otherActivePath?.includes(route.path) ||
false
);
};
const menuList = [
{
type: "menuItem",
name: "溯源管理",
path: "/tracingManagement",
icon: {
active: { iconName: "iconsuyuan2", props: { color: "#3A3A3A" } },
notActive: { iconName: "iconsuyuan1", props: { color: "#3A3A3A" } },
},
},
{
type: "menuItem",
name: "版权管理",
path: "/copyrightManagement",
otherActivePath: ["/draftBox"],
icon: {
active: { iconName: "iconbanquan2", props: { color: "#3A3A3A" } },
notActive: { iconName: "iconbanquan1", props: { color: "#3A3A3A" } },
},
},
{
type: "menuItem",
name: "资产管理",
path: "/passList",
otherActivePath: ["/transferRecord"],
icon: {
active: { iconName: "iconzichan21", props: { color: "#3A3A3A" } },
notActive: { iconName: "iconzichan21", props: { color: "#959595" } },
},
},
{
type: "menuGroupName",
name: "配置管理",
},
{
type: "menuItem",
name: "模板管理",
path: "/templateManagement",
icon: {
active: { iconName: "iconmoban2", props: {} },
notActive: { iconName: "iconmoban1", props: {} },
},
},
{
type: "menuDivideLine",
},
{
type: "menuItem",
name: "回收站",
path: "/recycleBin",
icon: {
active: { iconName: "iconhuishouzhan2", props: {} },
notActive: { iconName: "iconhuishouzhan1", props: {} },
},
},
];
const handleClickMenu = (obj: typeof menuList[0]) => {
router.push({
path: obj.path!,
});
};
</script>
<style lang="scss">
.menu {
width: 230px;
height: 100vh;
background-color: #f9f9f9;
.appLine {
display: flex;
align-items: center;
padding-top: 39px;
margin-bottom: 29px;
.icon {
margin-left: 38px;
}
.appName {
margin-left: 8px;
font-size: 24px;
font-family: Arial-Black, Arial;
font-weight: 900;
color: #191919;
line-height: 33px;
letter-spacing: 1px;
}
}
.menuDivideLine {
width: 190px;
height: 1px;
border: 1px solid #eeeeee;
}
.menuGroupName {
width: 100%;
padding-left: 50px;
font-size: 12px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
height: 43px;
line-height: 43px;
color: #a3a3a3;
}
}
</style>
<template>
<div class="w-full">
<div class="w-full">
<canvas :id="`pdfCanvas${page}`" v-for="page in n" :key="page"></canvas>
</div>
</div>
</template>
<script lang="ts" setup>
import { reactive, nextTick, onMounted, computed } from "vue";
import * as PDF from "pdfjs-dist";
import entry from "pdfjs-dist/build/pdf.worker.entry"; // 引入时会报红线错误,不影响运行
const props = withDefaults(
defineProps<{
pdfPath: string;
renderPageSize?: number;
}>(),
{
pdfPath: "proxyPdf",
renderPageSize: 1,
}
);
const data = reactive({
pdfPages: [] as any, // 页数
pdfWidth: "", // 宽度
pdfSrc: "", // 地址
pdfDoc: "" as any, // 文档内容
pdfScale: 1.0, // 放大倍数
});
const n = computed(() => {
return props.renderPageSize > data.pdfPages
? data.pdfPages
: props.renderPageSize;
});
onMounted(() => {
PDF.GlobalWorkerOptions.workerSrc = entry;
loadFile(props.pdfPath);
});
const loadFile = (url: string) => {
let loadingTask = PDF.getDocument(url);
loadingTask.promise.then((pdf: any) => {
data.pdfDoc = pdf;
data.pdfPages = pdf.numPages;
nextTick(() => {
renderPage(1);
});
});
};
const renderPage = (num: number) => {
if (num > n.value) return;
data.pdfDoc.getPage(num).then((page: any) => {
let canvas: any = document.getElementById("pdfCanvas" + num);
let ctx = canvas.getContext("2d");
let dpr = window.devicePixelRatio || 1;
let bsr =
ctx.webkitBackingStorePixelRatio ||
ctx.mozBackingStorePixelRatio ||
ctx.msBackingStorePixelRatio ||
ctx.oBackingStorePixelRatio ||
ctx.backingStorePixelRatio ||
1;
let ratio = dpr / bsr;
let viewport = page.getViewport({ scale: data.pdfScale });
canvas.width = viewport.width * ratio;
canvas.height = viewport.height * ratio;
canvas.style.width = "100%";
canvas.style.height = "100%";
data.pdfWidth = viewport.width + "px";
ctx.setTransform(ratio, 0, 0, ratio, 0, 0);
let renderContext = {
canvasContext: ctx,
viewport: viewport,
};
page.render(renderContext);
if (data.pdfPages > num) {
renderPage(num + 1);
}
});
};
</script>
<style scoped lang="scss"></style>
<template>
<div class="search w-full flex items-center">
<Icon
iconName="iconsuyuan-chaxun"
size="10"
color="#838383"
style="margin-left: 15px; margin-right: 8px"
></Icon>
<input
type="text"
:placeholder="placeholder"
@value="modelValue"
@input="(e) => $emit('update:modelValue', (e.target as any).value)"
class="flex-grow outline-none mr-4"
/>
</div>
</template>
<script lang="ts" setup>
import Icon from "@/components/Icon/index.vue";
defineProps<{
placeholder: string;
modelValue?: string;
}>();
defineEmits(["update:modelValue"]);
</script>
<style lang="scss">
.search {
height: 35px;
background: #f5f5f5;
border-radius: 4px;
input {
background: transparent;
font-size: 13px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #606266;
}
}
</style>
<template>
<div class="flex flex-shrink-0 w-full justify-between step">
<div
v-for="(ele, index) in eleList"
:key="index"
class="flex"
:class="{
'flex-grow': ele.type === 'line',
}"
>
<div
v-if="ele.type === 'line'"
class="flex-grow relative transition-all"
style="height: 3px; top: 16px"
:style="{
backgroundColor:
ele.mode === 'dark' ? 'var(--dark)' : 'var(--sy-blue)',
}"
></div>
<div
v-else-if="ele.type === 'circle'"
class="flex flex-col items-center cursor-pointer"
@click="$emit('update:current', ele.value)"
>
<div class="w-full flex items-center">
<div
class="flex-grow transition-all"
style="height: 3px"
:style="{
backgroundColor:
ele.mode === 'dark' ? 'var(--dark)' : 'var(--sy-blue)',
opacity: ele.index !== 1 ? 1 : 0,
}"
></div>
<div
class="circle flex items-center justify-center transition-all"
:style="{
background:
ele.mode === 'dark' ? 'var(--dark)' : 'var(--sy-blue)',
}"
>
<Icon
:style="{
color: ele.mode === 'dark' ? '#959595' : 'white',
}"
icon-name="iconweixuanze3"
class="flex-shrink-0 transition-all"
v-if="ele.index === steps.length"
></Icon>
<span
v-if="ele.index !== steps.length"
class="number transition-all"
:style="{
color: ele.mode === 'dark' ? '#959595' : 'white',
}"
>
{{ ele.index }}
</span>
</div>
<div
class="flex-grow transition-all"
style="height: 3px"
:style="{
backgroundColor:
ele.mode === 'dark' ? 'var(--dark)' : 'var(--sy-blue)',
opacity: ele.index !== steps.length ? 1 : 0,
}"
></div>
</div>
<div
style="margin-top: 13px"
class="whitespace-nowrap stepName text-center"
:style="{
color: ele.mode === 'dark' ? 'var(--text-gray)' : 'var(--sy-blue)',
}"
>
<div class="transition-all">
{{ ele.name }}
</div>
<div class="opacity-0">{{ maxLenStepName }}</div>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { computed } from "vue";
import Icon from "../Icon/index.vue";
const props = defineProps<{
steps: { name: string; value: any }[];
current: any;
}>();
defineEmits(["update:current"]);
interface iLine {
type: "line";
mode: "dark" | "light";
}
interface iCircle {
type: "circle";
name: string;
value: any;
mode: "dark" | "light";
index: number;
}
const maxLenStepName = computed(() => {
return props.steps.reduce((prev, cur) => {
return prev.length > cur.name.length ? prev : cur.name;
}, "");
});
const eleList = computed(() => {
const list: (iLine | iCircle)[] = [];
props.steps.forEach((step, index, arr) => {
const isLight = isGreenMode(step);
list.push({
...step,
type: "circle",
index: index + 1,
mode: isLight ? "light" : "dark",
});
if (index !== props.steps.length - 1) {
const nextIsLight = isGreenMode(arr[index + 1]);
list.push(
...[
{
type: "line" as const,
mode: isLight ? ("light" as const) : ("dark" as const),
},
{
type: "line" as const,
mode: nextIsLight ? ("light" as const) : ("dark" as const),
},
]
);
}
});
return list;
});
const isGreenMode = (step: { name: string; value: any }) => {
return (
props.steps.findIndex((i) => i.value === step.value) <=
props.steps.findIndex((i) => i.value === props.current)
);
};
</script>
<style scoped lang="scss">
.step {
--dark: #eaeaea;
.circle {
width: 35px;
height: 35px;
background: var(--dark);
border-radius: 100%;
}
.stepName {
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
line-height: 20px;
}
}
</style>
import { computed, reactive, watch } from "vue";
export function useTableData({
page_size = 15,
fetchData,
}: {
page_size?: number;
fetchData: (fetchDataConfig: {
page: number;
page_size: number;
}) => Promise<{ total: number; data: any[] }>;
}) {
const tableState = reactive({
page: 1,
page_size: page_size,
list: [] as any[],
total: 0,
loading: true,
lock: false,
firstFetch: true,
});
handleFetch(true);
function handleFetch(firstFetch: boolean) {
tableState.loading = firstFetch;
fetchData({
page: tableState.page,
page_size: tableState.page_size,
}).then((ret) => {
tableState.total = ret.total;
tableState.list = firstFetch
? ret.data
: [...tableState.list, ...ret.data];
tableState.loading = false;
tableState.lock = false;
if (tableState.firstFetch) tableState.firstFetch = false;
});
}
watch(
() => [tableState.page],
() => {
handleFetch(tableState.firstFetch);
}
);
const fetchNextPage = () => {
if (tableState.lock) return;
tableState.lock = true;
if (tableState.page * tableState.page_size < tableState.total) {
tableState.page++;
}
};
return {
/** 表格数据 */
tableData: computed(() => tableState.list),
/** 获取下一页 */
fetchNextPage,
/** 刷新 */
refetch: () => handleFetch(true),
loading: computed(() => tableState.loading),
};
}
<template>
<el-table :data="data" style="width: 100%" ref="tableRef">
<el-table-column
v-for="(column, index) in columns"
:key="index"
:prop="column.prop"
:label="column.label"
:width="column.width"
:min-width="column.minWidth"
>
<template #header>
<div v-if="column.headerSlotName" class="tableHeader">
<slot :name="column.headerSlotName"></slot>
</div>
<div v-else class="tableHeader">
{{ column.label }}
</div>
</template>
<template #default="scope">
<div v-if="!column.slotName" class="tableCell">
{{ scope.row[column.prop] }}
</div>
<div v-else>
<slot :name="column.slotName" v-bind="scope.row"></slot>
</div>
</template>
</el-table-column>
</el-table>
</template>
<script lang="ts" setup>
import { ElTable, ElTableColumn } from "element-plus";
import { ref } from "vue";
import { iTableColumn } from "./types";
const tableRef = ref();
defineExpose({
getEl: () => tableRef.value.$el,
});
withDefaults(
defineProps<{
columns: iTableColumn[];
data: any[];
}>(),
{
columns: () => [],
data: () => [],
}
);
</script>
<style lang="scss" scoped>
.tableHeader {
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #353535;
}
.tableCell {
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #606266;
}
</style>
export type iTableColumn = {
prop: string;
label: string;
minWidth: string;
width?: string;
slotName?: string;
headerSlotName?: string;
};
<template>
<div class="title">
<slot></slot>
</div>
</template>
<script setup lang="ts"></script>
<style lang="scss">
.title {
font-size: 24px;
font-family: PingFangSC-Semibold, PingFang SC;
font-weight: 600;
color: #191919;
line-height: 33px;
letter-spacing: 1px;
}
</style>
declare module "vue-cropper";
declare module "pdfjs-dist*"
\ No newline at end of file
......@@ -27,6 +27,38 @@ const routes = [
),
},
{
path: "/recycleBin",
name: "recycleBin",
component: () =>
import(
/* webpackChunkName: 'recycleBin' */ "@/views/category/recycleBin.vue"
),
},
{
path: "/templateManagement",
name: "templateManagement",
component: () =>
import(
/* webpackChunkName: 'templateManagement' */ "@/views/category/templateManagement.vue"
),
},
{
path: "/tracingManagement",
name: "tracingManagement",
component: () => import("@/views/category/tracingManagement.vue"),
},
{
path: "/copyrightManagement",
name: "copyrightManagement",
component: () => import("@/views/copyrightManagement/index.vue"),
},
{
path: "/draftBox",
name: "draftBox",
component: () => import("@/views/draftBox/index.vue"),
},
{
path: "/passManage",
name: "passManage",
component: () =>
......@@ -115,6 +147,11 @@ const routes = [
],
},
{
path: "/copyrightApplication",
name: "copyrightApplication",
component: () => import("@/views/copyrightApplication/index.vue"),
},
{
path: "/passMaker",
name: "passMaker",
component: () => import("@/views/pass/PassMaker/index.vue"),
......@@ -126,16 +163,16 @@ const router = createRouter({
routes,
});
router.beforeEach((to, from, next) => {
const urls = ["/", "/signIn"];
if (to.path === `/signIn` && getLoginCode()) {
next();
}
if (!urls.includes(to.path) && !getLoginCode()) {
return next({ path: "/signIn" });
} else {
next();
}
});
// router.beforeEach((to, from, next) => {
// const urls = ["/", "/signIn"];
// if (to.path === `/signIn` && getLoginCode()) {
// next();
// }
// if (!urls.includes(to.path) && !getLoginCode()) {
// return next({ path: "/signIn" });
// } else {
// next();
// }
// });
export { router };
......@@ -4,6 +4,7 @@
* {
--bg-gray: #f8f8f8;
--text-gray: #797D84;
box-sizing: content-box;
}
......@@ -25,7 +26,13 @@
height: 40px;
width: 610px;
}
.icon {
width: 1em;
height: 1em;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}
.el-button.is-disabled,
.el-button.is-disabled:focus,
.el-button.is-disabled:hover {
......
export const getSuffixName = (str: string) => {
const matched = str.match(/(.*)\.(.*)$/);
return matched ? matched[2] : "";
};
export const getFileName = (str: string) => {
const matched = str.match(/(.*)\.(.*)$/);
return matched ? matched[1] : "";
};
/**
*
* @param file 文件
* @param fileType accept字段
*/
export const fileTypeChecked = (file: File, fileType: string) => {
// .jpg,audio/aac
const types = fileType.split(",");
return types.some(
(type) => file.type === type || "." + getSuffixName(file.name) === type
);
};
export const getFileSize = (size: number) => {
const k = (size / 1024).toFixed(2);
if (Number(k) < 900) {
return k + "K";
} else {
const m = (Number(k) / 1024).toFixed(2);
return m + "M";
}
};
......@@ -2,18 +2,19 @@
<div class="main !h-screen">
<!-- 左侧导航 -->
<div class="!h-full">
<sySideBar v-bind="sideBarState">
<Menu></Menu>
<!-- <sySideBar v-bind="sideBarState">
<template #passList>
<span class="iconfont2 icon-a-pass-activec9b87262"></span>
</template>
</sySideBar>
</sySideBar> -->
</div>
<div class="col_right">
<syBusinessHeader
<!-- <syBusinessHeader
:handle-logout="handleLogout"
style="box-shadow: 0px 2px 40px 0px rgb(65 70 76 / 7%); z-index: 1"
:user-id="userId"
></syBusinessHeader>
></syBusinessHeader> -->
<div class="main_wrapper">
<router-view />
</div>
......@@ -21,6 +22,7 @@
</div>
</template>
<script lang="ts" setup>
import Menu from "@/components/Menu/index.vue";
import { router } from "@/router";
import { $ajax } from "@/service";
import { setuserInfos } from "@/store/mutations";
......@@ -145,7 +147,7 @@ const getUserInfos = async () => {
.main_wrapper {
flex: 1;
min-height: 0;
background: white;
background-color: #f8f8f8;
height: 100%;
}
</style>
<template>
<DeletedVue :ToUpdate="1" />
</template>
<script lang="ts" setup>
import DeletedVue from "./components/Deleted.vue";
</script>
<style lang="scss"></style>
<template>
<syTraceTemplateManage
:navigate="navigate"
:showTip="showTip"
:setTemplateNum="() => {}"
:TemplateType="globalState.templateType"
:setTemplateType="(v: number) => (globalState.templateType = v)"
:templateData="globalState.templateData"
:setTemplateData="
(v: any) => {
globalState.templateData = v;
}
"
></syTraceTemplateManage>
</template>
<script lang="ts" setup>
import { syTraceTemplateManage } from "cqk-sy-ui";
import { showTip } from "@/components/GlobalMount/api";
import { globalState } from "@/store/state";
import { router } from "@/router";
const navigate = router.push;
</script>
<style lang="scss"></style>
<template>
<syTraceProofRecord
:showTip="showTip"
:setDepositCertificate="() => {}"
:userInfos_auth_suc="userInfos_auth_suc"
:navigate="navigate"
:setListOfInformation="setListOfInformation"
:setGoodsNum="setGoodsNum"
:setChainStatus="setChainStatus"
:theAnchor="theAnchor"
:setTheAnchor="setTheAnchor"
:depositCertificate="depositCertificate"
:page="page"
:setPage="setPage"
>
<template #table="slotProps">
<IncrementalTable
@increment="slotProps.incrementOperation"
@delete-goods="slotProps.deleteGoodsShow"
@upload="slotProps.upload"
@delete-incremental="slotProps.deleteTheIncremental"
@incremental-chain="slotProps.incrementalOnChain"
@create-copy="slotProps.createCopy"
@privacy-settings="slotProps.privacySettings"
@update="slotProps.getList"
></IncrementalTable>
</template>
</syTraceProofRecord>
</template>
<script lang="ts" setup>
import { syTraceProofRecord } from "cqk-sy-ui";
import IncrementalTable from "./components/IncrementalTable.vue";
import { showTip } from "@/components/GlobalMount/api";
import {
setChainStatus,
setDepositCertificate,
setGoodsNum,
setListOfInformation,
setTheAnchor,
} from "@/store/mutations";
import { router } from "@/router";
import { globalState } from "@/store/state";
import { computed } from "vue";
const navigate = router.push;
const userInfos_auth_suc = computed(() => {
return globalState.userInfos.auth_suc;
});
const theAnchor = computed(() => {
return globalState.theAnchor;
});
const depositCertificate = computed(() => {
return globalState.depositCertificate;
});
const page = computed(() => {
return globalState.page;
});
const setPage = (v: number) => {
globalState.page = v;
};
</script>
<style lang="scss"></style>
<template>
<div class="box">
<slot></slot>
</div>
</template>
<script setup lang="ts"></script>
<style scoped lang="scss">
.box {
width: 858px;
margin: 0 auto;
background: #ffffff;
box-shadow: 0px 2px 20px 0px #f0f0f0;
border-radius: 20px;
padding: 56px 127px 0 127px;
}
</style>
<template>
<div class="fileDisplay flex items-center w-full justify-between">
<Icon
:icon-name="getIconNameBySuffixName(suffixName)"
style="font-size: 24px"
></Icon>
<div class="middleContent flex-grow">
<div class="flex items-center justify-between">
<div class="name">{{ fileName }}</div>
<div class="size">{{ getFileSize(props.file.size) }}</div>
<div class="size">
已完成
{{ (props.file.progress * 100).toFixed(1) }} %
</div>
</div>
<div
class="line transition-all"
:style="{
width: getLinWidth,
marginTop: '4px',
}"
></div>
</div>
<Icon
icon-name="iconzhengque"
:class="{
'opacity-0': props.file.progress < 1,
}"
style="font-size: 18px; margin-right: 19px"
></Icon>
<Icon
@click="onClose"
icon-name="iconzuzhigoujia-xuanzechengyuan-yixuanze-shanchu"
class="cursor-pointer"
style="font-size: 20px"
></Icon>
</div>
</template>
<script setup lang="ts">
import { computed } from "vue";
import { iFile } from "./types";
import { getFileName, getFileSize, getSuffixName } from "@/utils/file";
import Icon from "@/components/Icon/index.vue";
const iconNameMapping = {
icontupian1: ".jpg,.jpeg,.gif,.bmp,.png",
iconshipin: ".mp4,.wmv",
iconWORD: ".doc,.docx",
iconPDF: ".pdf",
iconyinpin: ".ppt,.pptx",
iconexcel: ".xls,.xlsx",
"icona-bianzu21": ".txt",
};
const getIconNameBySuffixName = (SuffixName: string) => {
let iconName = "";
Object.entries(iconNameMapping).find(([key, value]) => {
if (value.split(",").findIndex((i) => i === "." + SuffixName) !== -1) {
iconName = key;
}
});
return iconName;
};
const onClose = () => {
emit("close");
};
const getLinWidth = computed(() => {
return props.file.progress * 100 + "%";
});
const emit = defineEmits(["close"]);
const props = defineProps<{
file: iFile & { id: number };
}>();
const fileName = computed(() => {
return getFileName(props.file.name);
});
const suffixName = computed(() => {
return getSuffixName(props.file.name);
});
</script>
<style scoped lang="scss">
.fileDisplay {
padding: 0 17px;
height: 55px;
background: #ffffff;
box-shadow: 0px 2px 15px 0px #e7eef3;
border-radius: 10px;
.middleContent {
margin: 0 17px;
font-weight: 400;
line-height: 17px;
.name {
color: #353535;
}
.size {
color: #8b8b8b;
}
.line {
width: 0;
height: 5px;
background: var(--sy-blue);
border-radius: 4px;
}
}
}
</style>
<template>
<div class="fileUpload w-full">
<input
type="file"
name=""
id=""
ref="inputRef"
accept=".jpg,.jpeg,.gif,.bmp,.png,.mp4,.wmv,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.pdf,.txt"
class="hidden"
@change="handleFile"
/>
<div
class="uploadBox text-center flex items-center justify-center h-full cursor-pointer"
@click="modelValue.length <= 4 && inputRef!.click()"
>
<div>
<Icon
icon-name="iconshangchuan"
style="font-size: 50px"
class="mx-auto uploadIcon"
></Icon>
<div>上传作品</div>
</div>
</div>
<div style="margin-top: 18px">
<FileDisplayItem
v-for="file in modelValue"
:key="file.id"
:file="file"
style="margin-top: 10px"
@close="deleteFile(file.id)"
></FileDisplayItem>
</div>
<div class="request" style="margin-top: 32px">
上传要求:<br />
1、上传的作品必须包含您存证过的作品<br />
2、单文件大小不超过200M,最多上传5个文件
<br />
3、支持文件格式,分别如下: <br />
图片类:JPG、JPEG、GIF、BMP、PNG;<br />
视频类:MP4、WMV;<br />
音频类:MP3、WAV; <br />
文件类:DOC、DOCX、XLS、XLSX、PPT、PPTX、PDF、 TXT。
</div>
</div>
</template>
<script setup lang="ts">
import Icon from "@/components/Icon/index.vue";
import { nextTick, ref } from "vue";
import { iFile } from "./types";
import FileDisplayItem from "./FileDisplayItem.vue";
import { fileTypeChecked } from "@/utils/file";
import { ElMessage, useFormItem } from "element-plus";
const props = defineProps<{
modelValue: (iFile & { id: number })[];
}>();
const emit = defineEmits(["update:modelValue"]);
const formItem = useFormItem();
let id = 1;
const setState = (value: (iFile & { id: number })[]) => {
emit("update:modelValue", value);
};
const addFile = (value: iFile & { id: number }) => {
// 添加文件
setState([...props.modelValue, value]);
};
const deleteFile = (id: number) => {
// 删除文件
setState(props.modelValue.filter((i) => i.id !== id));
console.log("blur");
nextTick(() => {
formItem.formItem?.validate("blur");
});
// 取消文件上传??????
// cancelUpload();
};
const uploadFileToServer = (file: File, id: number) => {
// 上传文件??????
let p = 0;
const s = setInterval(() => {
p += 0.1;
updateFile(id, {
progress: p >= 1 ? 1 : p,
});
p >= 1 && clearInterval(s);
}, 1000);
};
const updateFile = (id: number, value: Partial<iFile & { id: number }>) => {
// 更新文件
const list = [...props.modelValue];
const file = list.find((i) => i.id === id);
if (!file) return;
Object.keys(value).forEach((keyOfValue) => {
(file as any)[keyOfValue] = (value as any)[keyOfValue];
});
setState(list);
};
const inputRef = ref<HTMLInputElement>();
const handleFile = (e: Event) => {
const files = (e.target as HTMLInputElement).files;
if (!files || files?.length === 0) return;
const file = files[0];
if (!fileTypeChecked(file, inputRef.value!.accept)) {
ElMessage.error("请上传指定类型的文件");
return;
}
addFile({
id: ++id,
file: file,
name: file.name,
size: file.size,
url: "",
progress: 0,
});
uploadFileToServer(file, id);
inputRef.value!.value = "";
nextTick(() => {
formItem.formItem?.validate("blur");
});
};
</script>
<style scoped lang="scss">
.fileUpload {
.uploadBox {
height: 158px;
background: #f7f7f7;
border-radius: 10px;
border: 1px dashed #e2e2e2;
font-size: 14px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: var(--sy-gray-text);
.uploadIcon {
color: #c3c3c3;
}
}
.request {
font-size: 12px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: var(--text-gray);
}
}
</style>
<template>
<div class="file">
<ElForm
:rules="rules"
:model="modelValue"
label-position="top"
ref="formRef"
>
<ElFormItem label="上传作品" prop="files">
<FileUpload
:model-value="modelValue.files"
@update:model-value="
(v) =>
$emit('update:modelValue', {
...modelValue,
files: v,
})
"
></FileUpload>
</ElFormItem>
<div class="el-form-item is-error is-required">
<label for="powerOfAttorney" class="el-form-item__label relative"
>作品登记委托书
<span
style="color: var(--sy-blue); margin-left: 16px"
class="cursor-pointer mr-3"
>下载《作品登记委托书》附件</span
>
<HoverMe :margin-top="20" class="!absolute" style="margin-top: 3px">
<Icon
icon-name="iconshenpiweitongguo-chakanyuanyin"
style="font-size: 17px"
></Icon>
<template #message>
1、您的作品将委托上链查进行代理登记,需要提交《作品登记代理委托书》。2、《作品登记代理委托书》需要加盖公章,法定代表人签字。文件请上传jpg、png、jpeg、pdf格式。
</template>
</HoverMe>
</label>
</div>
<ElFormItem label="" prop="powerOfAttorney">
<PowerOfAttUpload
:model-value="modelValue.powerOfAttorney"
@update:model-value="
(v) =>
$emit('update:modelValue', {
...modelValue,
powerOfAttorney: v,
})
"
></PowerOfAttUpload>
</ElFormItem>
</ElForm>
</div>
</template>
<script setup lang="ts">
import { ElForm, ElFormItem, FormInstance } from "element-plus";
import { ref } from "vue";
import { iFile } from "./types";
import FileUpload from "./FileUpload.vue";
import HoverMe from "@/components/HoverMe/index.vue";
import Icon from "@/components/Icon/index.vue";
import PowerOfAttUpload from "./powerOfAttUpload.vue";
const props = defineProps<{
modelValue: {
files: (iFile & { id: number })[];
powerOfAttorney: iFile | null;
};
}>();
const formRef = ref<FormInstance>();
const emit = defineEmits(["update:modelValue"]);
const rules = ref({
files: [{ required: true, message: "请上传作品" }],
powerOfAttorney: [
{
required: true,
message: "请上传作品登记委托书",
},
// {
// validator(rule: any, value: any, callback: any) {
// console.log(value, "show value");
// callback();
// },
// },
],
});
defineExpose({
formRef: formRef,
});
</script>
<style scoped>
.file {
--sy-gray-text: #787d85;
}
</style>
<template>
<div class="upload">
<input
type="file"
name=""
id=""
accept=".jpg,.png,.jpeg,.pdf"
class="hidden"
ref="inputRef"
@change="handleChange"
/>
<div
class="box text-center flex items-center justify-center h-full cursor-pointer"
v-if="!modelValue"
@click="inputRef?.click"
>
<div>
<Icon
icon-name="iconshangchuan"
style="font-size: 50px; color: #c3c3c3"
class="mx-auto"
></Icon>
<div>上传作品</div>
</div>
</div>
<div class="fileContainer relative overflow-hidden" v-if="modelValue">
<Pdf
v-if="getSuffixName(modelValue.name) === 'pdf'"
:url="localUrl"
></Pdf>
<img v-else :src="localUrl" alt="" class="w-full h-full object-cover" />
<div
class="reupload text-white flex items-center justify-center transform top-1/2 -translate-y-1/2 left-1/2 -translate-x-1/2 absolute cursor-pointer"
@click="inputRef?.click"
>
<Icon1 icon-name="iconzhongxin" class="mr-2"></Icon1>
重新上传
</div>
</div>
<div style="margin-top: 29px; color: var(--text-gray)">
请上传jpg、png、jpeg、pdf格式的作品登记委托书,需加盖公章,法定代表人签字。
</div>
</div>
</template>
<script setup lang="ts">
import Icon from "@/components/Icon/index.vue";
import { nextTick, onBeforeUnmount, onMounted, ref } from "vue";
import { iFile } from "./types";
import Pdf from "../../../components/Pdf/index.vue";
import { fileTypeChecked, getSuffixName } from "@/utils/file";
import { ElMessage, useFormItem } from "element-plus";
import Icon1 from "@/components/Icon/index.vue";
const inputRef = ref<HTMLInputElement>();
const props = defineProps<{
modelValue: iFile | null;
}>();
const formItem = useFormItem();
const emit = defineEmits(["update:modelValue"]);
const localUrl = ref("");
const handleChange = (e: Event) => {
const files = (e.target as HTMLInputElement).files;
if (!files || files?.length === 0) return;
const file = files[0];
if (!fileTypeChecked(file, inputRef.value!.accept)) {
ElMessage.error("请上传指定类型的文件");
return;
}
emit("update:modelValue", {
file: file,
name: file.name,
size: file.size,
progress: 0,
url: "",
} as iFile);
uploadFileToServer(file);
nextTick(() => {
formItem.formItem?.validate("blur");
});
};
onMounted(() => {
if (!props.modelValue) return;
const url = URL.createObjectURL(props.modelValue?.file);
localUrl.value = url;
});
const uploadFileToServer = (file: File) => {
// 上传??????
const url = URL.createObjectURL(file);
localUrl.value = url;
};
onBeforeUnmount(() => {
URL.revokeObjectURL(localUrl.value);
});
</script>
<style scoped lang="scss">
.box {
width: 249px;
height: 139px;
background: #f7f7f7;
border-radius: 10px;
border: 1px dashed #e2e2e2;
font-size: 14px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: var(--sy-gray-text);
}
.fileContainer {
width: 136px;
height: 169px;
background: #f7f7f7;
box-shadow: 0px 2px 10px 0px rgba(186, 186, 186, 0.5),
inset 0px 1px 3px 0px rgba(251, 251, 251, 0.5);
border-radius: 4px;
border: 1px solid #e2e2e2;
.reupload {
display: none;
width: 87px;
height: 30px;
background: rgba(0, 0, 0, 0.6);
border-radius: 4px;
font-size: 12px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
}
&:hover {
.reupload {
display: flex;
}
}
}
</style>
export interface iFile {
name: string;
size: number;
progress: number;
file: File;
url?: string;
}
<template>
<div class="headeline flex items-center">
<button
class="box flex items-center justify-center cursor-pointer"
@click="$router.back"
>
<Icon icon-name="iconsuyuanxiangqing-fanhui"></Icon>
</button>
<div class="text">版权申请</div>
<div class="flex-grow"></div>
<button
class="box flex items-center justify-center cursor-pointer"
@click="$router.back"
>
<Icon icon-name="iconshanchu"></Icon>
</button>
</div>
</template>
<script setup lang="ts">
import Icon from "@/components/Icon/index.vue";
</script>
<style scoped>
.headeline {
height: 50px;
background: #ffffff;
border: 1px solid #efefef;
padding: 0 22px;
}
.box {
width: 32px;
height: 26px;
background: #ffffff;
box-shadow: 0px 1px 2px 1px rgba(197, 197, 197, 0.5);
border-radius: 6px;
}
.text {
margin-left: 22px;
font-size: 16px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #353535;
}
</style>
<template>
<div class="min-h-screen flow-root" style="background: #f9f9f9">
<HeaderLine></HeaderLine>
<ContentBox
style="margin-top: 17px; padding-bottom: 150px; margin-bottom: 40px"
>
<Step :steps="steps" v-model:current="currentStep"></Step>
<FileUploadForm
v-if="currentStep === eStep.file"
ref="fileUploadFormRef"
v-model="fileUploadFormModel"
></FileUploadForm>
<div class="flex" style="margin-top: 59px">
<syButton
mode="elementBtn"
style="width: 113px"
type="primary"
@click="next"
>下一步</syButton
>
<syButton mode="elementBtn" style="width: 113px">保存草稿箱</syButton>
</div>
</ContentBox>
</div>
</template>
<script setup lang="ts">
import Step from "@/components/Step/index.vue";
import { ref } from "vue";
import { eStep } from "./types";
import HeaderLine from "./HeaderLine.vue";
import ContentBox from "./ContentBox.vue";
import FileUploadForm from "./FileUploadForm/index.vue";
import { syButton } from "cqk-sy-ui";
import { iFile } from "./FileUploadForm/types";
const currentStep = ref(eStep.file);
const fileUploadFormRef = ref<InstanceType<typeof FileUploadForm>>();
const next = async () => {
const isValid = await checkFormValid();
if (!isValid) return;
goToNextStep();
};
const checkFormValid = () => {
const step = steps.find((step) => step.value === currentStep.value);
return new Promise((r) => {
step?.ref?.value?.formRef?.validate((isValid) => {
r(isValid);
});
});
};
const goToNextStep = () => {
const currentIndex = steps.findIndex(
(step) => step.value === currentStep.value
);
currentStep.value = steps[currentIndex + 1].value;
};
const steps = [
{
name: "作品文件",
value: eStep.file,
ref: fileUploadFormRef,
},
{
name: "作品信息",
value: eStep.msg,
},
{
name: "作品权属",
value: eStep.ownership,
},
{
name: "著作权人与作者",
value: eStep.ownerAndAuther,
},
];
const fileUploadFormModel = ref<{
files: (iFile & { id: number })[];
powerOfAttorney: iFile | null;
}>({
files: [],
powerOfAttorney: null,
});
</script>
<style scoped></style>
export enum eStep {
file,
msg,
ownership,
ownerAndAuther,
}
<template>
<Table
ref="tableRef"
:columns="tableColumns"
:data="data"
v-loading="loading"
element-loading-text="加载中..."
>
<template #currentStatusCell="slotProps">
<div class="flex items-center">
<ApproveStatus :type="eStatus.approved"></ApproveStatus>
<HoverShowReason
:rowData="slotProps"
v-if="
eStatus.rejected === slotProps.status ||
eStatus.platformDismissed === slotProps.status
"
></HoverShowReason>
</div>
</template>
<template #currentStatusHeader>
<div class="flex items-center">
当前状态
<Icon1
v-if="showStateFilterIcon"
icon-name="iconlujingbeifen1"
class="cursor-pointer ml-1"
@click="handleClickCurrentStatusTableHeader"
></Icon1></div
></template>
<template #operate="slotProps">
<syMoreOperate
:teleport="true"
:list="getOperateList(slotProps)"
@click-item="(value) => handleClickItem(value, slotProps)"
:margin-left="-10"
>
<Icon1
icon-name="iconbianzu7"
style="font-size: 40px"
class="cursor-pointer"
></Icon1>
</syMoreOperate>
</template>
</Table>
</template>
<script setup lang="ts">
import Table from "@/components/Table/index.vue";
import Icon1 from "@/components/Icon/index.vue";
import { tableColumns } from "./table";
import { syMoreOperate } from "cqk-sy-ui";
import { onBeforeUnmount, onMounted, ref } from "vue";
import { throttle } from "lodash";
import { eStatus } from "@/components/ApproveStatus/status";
import { mappingFromStatusToOperate } from "./statusMapping";
import ApproveStatus from "@/components/ApproveStatus/index.vue";
import HoverShowReason from "./HoverShowReason.vue";
defineProps<{
data: any[];
loading: boolean;
showStateFilterIcon?: boolean;
}>();
const emit = defineEmits(["scrollToEnd"]);
const tableRef = ref<InstanceType<typeof Table>>();
onMounted(() => {
listener();
});
function listener() {
const tableEl = tableRef.value?.getEl();
const wrap = tableEl.querySelector(".el-scrollbar__wrap") as HTMLDivElement;
if (wrap.offsetHeight + wrap.scrollTop >= wrap.scrollHeight) {
emit("scrollToEnd");
}
wrap.onresize = () => {
console.log("resize");
};
wrap.onscroll = throttle(() => {
if (wrap.offsetHeight + wrap.scrollTop >= wrap.scrollHeight) {
emit("scrollToEnd");
}
}, 100);
}
defineExpose({
listener,
});
onBeforeUnmount(() => {
const tableEl = tableRef.value?.getEl();
const wrap = tableEl.querySelector(".el-scrollbar__wrap") as HTMLDivElement;
wrap.onscroll = null;
});
const getOperateList = (slotProps: any) => {
const status: Exclude<eStatus, eStatus.all> =
slotProps.status || eStatus.agree;
return mappingFromStatusToOperate[status].map((i) => ({
name: i,
value: i,
}));
};
const handleClickItem = (value: any, slotProps: any) => {
console.log(value, slotProps, "show value");
};
const handleClickCurrentStatusTableHeader = () => {};
</script>
<style></style>
<template>
<HoverMe class="ml-2" :margin-top="20" :margin-left="-154" @over="over">
<template #default>
<Icon icon-name="iconshenpiweitongguo-chakanyuanyin"></Icon>
</template>
<template #message>
<span v-if="!msg" class="text-xs">原因加载中...</span>
<span v-else class="">
{{ msg }}
</span>
</template>
</HoverMe>
</template>
<script setup lang="ts">
import HoverMe from "@/components/HoverMe/index.vue";
import Icon from "@/components/Icon/index.vue";
import { ref } from "vue";
const props = defineProps<{
rowData: any;
}>();
const msg = ref("");
const over = () => {
setTimeout(() => {
msg.value = "msgmsgmsg";
}, 2000);
};
</script>
<style></style>
<template>
<LayoutVue>
<div class="flex flex-col w-full h-full">
<div class="flex items-center">
<Search v-model="searchValue" placeholder="搜索版权"></Search>
<Avatar
class="ml-7"
@click="() => $router.push('/userCenter')"
></Avatar>
</div>
<div class="flex items-center justify-between" style="margin-top: 26px">
<Title>版权列表</Title>
<div class="flex items-center">
<syButton
style="width: 113px"
mode="elementBtn"
size="large"
@click="
() => {
$router.push('/draftBox');
}
"
type="default"
>
<Icon icon-name="iconcaogao" style="margin-right: 3px"></Icon>
草稿箱</syButton
>
<syButton
style="width: 113px"
mode="elementBtn"
size="large"
@click="copyRightNotifyVisible = true"
type="primary"
>添加版权</syButton
>
</div>
</div>
<syMenu v-model="activedMenu" :menu-list="menuList"></syMenu>
<div class="flex-grow overflow-hidden">
<CopyrightTable
v-show="activedMenu === eTableTab.going"
:data="tableDataForGoing"
:loading="loadingForGoing"
:show-state-filter-icon="true"
height="100%"
@scrollToEnd="fetchNextPageForGoing"
>
</CopyrightTable>
<CopyrightTable
v-show="activedMenu === eTableTab.end"
:data="tableDataForEnd"
:loading="loadingForEnd"
height="100%"
@scrollToEnd="fetchNextPageForEnd"
>
</CopyrightTable>
</div>
</div>
<CopyRightNotify v-model:visible="copyRightNotifyVisible"></CopyRightNotify>
</LayoutVue>
</template>
<script lang="ts" setup>
import LayoutVue from "@/components/Layout.vue";
import { ref, watch } from "vue";
import Search from "@/components/Search/index.vue";
import Avatar from "@/components/Avatar/index.vue";
import Title from "@/components/Title.vue";
import { syButton, syMenu } from "cqk-sy-ui";
import Icon from "@/components/Icon/index.vue";
import ApprovedStatus from "@/components/ApproveStatus/index.vue";
import { eStatus } from "@/components/ApproveStatus/status";
import HoverMe from "@/components/HoverMe/index.vue";
import CopyrightTable from "./CopyrightTable.vue";
import { eTableTab } from "./types";
import { useTableData } from "@/components/Table/hooks";
import { debounce, throttle } from "lodash";
import CopyRightNotify from "@/components/Dialogs/CopyRightNotify/index.vue";
const copyRightNotifyVisible = ref(false);
const searchValue = ref("");
const menuList = [
{
value: eTableTab.going,
label: "进行中",
},
{
value: eTableTab.end,
label: "已完成",
},
];
const activedMenu = ref(eTableTab.going);
const currentStatusForGoing = ref(eStatus.all); // 进行中的表格的状态
const fetchTableData = ({
page,
page_size,
currentStatus,
}: {
page: number;
page_size: number;
currentStatus: eStatus;
}) => {
/* 请求所需要的参数 */
page;
page_size;
// 当前状态
currentStatus;
return new Promise<any>((r) => {
setTimeout(() => {
r({
total: 100,
data: "1"
.repeat(page_size)
.split("")
.map((i, index) => ({
name: index + (page - 1) * page_size + currentStatus,
status: eStatus.rejected,
address: searchValue.value,
})),
});
}, 1000);
});
};
const generateFetchTableData = (getCurrentStatus: () => eStatus) => {
return ({ page, page_size }: { page: number; page_size: number }) => {
return fetchTableData({
page,
page_size,
currentStatus: getCurrentStatus(),
});
};
};
const {
fetchNextPage: fetchNextPageForGoing,
tableData: tableDataForGoing,
refetch: refetchForGoing,
loading: loadingForGoing,
} = useTableData({
fetchData: generateFetchTableData(() => currentStatusForGoing.value),
});
const {
fetchNextPage: fetchNextPageForEnd,
tableData: tableDataForEnd,
loading: loadingForEnd,
refetch: refetchForEnd,
} = useTableData({
fetchData: generateFetchTableData(() => eStatus.approved),
});
const refetchDebounce = debounce(() => {
refetchForGoing();
refetchForEnd();
}, 500);
watch(searchValue, () => {
refetchDebounce();
});
</script>
<style lang="scss" scoped></style>
import { eStatus } from "./../../components/ApproveStatus/status";
import { eOperate } from "./types";
export const mappingFromStatusToOperate = {
[eStatus.platformVerification]: [eOperate.withdraw],
[eStatus.withdrawn]: [eOperate.edit, eOperate.delete],
[eStatus.platformDismissed]: [eOperate.edit, eOperate.delete],
[eStatus.submitReview]: [eOperate.seeDetails],
[eStatus.platformNotSubmitted]: [eOperate.seeDetails],
[eStatus.pendingReview]: [eOperate.seeDetails],
[eStatus.agree]: [eOperate.seeDetails],
[eStatus.rejected]: [eOperate.edit, eOperate.delete],
[eStatus.submitted]: [eOperate.seeDetails],
[eStatus.pendingFinalReview]: [eOperate.seeDetails],
[eStatus.approved]: [eOperate.viewCertificates, eOperate.seeDetails],
};
import { iTableColumn } from "./../../components/Table/types";
export const tableColumns = [
{
label: "版权名称",
prop: "name",
minWidth: "340",
},
{
label: "流水号",
prop: "address",
width: "310",
},
{
label: "操作日期",
prop: "date",
width: "270",
},
{
label: "当前状态",
slotName: "currentStatusCell",
headerSlotName: "currentStatusHeader",
width: "200",
},
{
label: "操作",
slotName: "operate",
width: "100",
},
] as iTableColumn[];
export enum eTableTab {
going = "going",
end = "end",
}
export enum eOperate {
withdraw = "撤销", // 撤销
edit = "编辑", // 编辑
delete = "删除", // 删除
seeDetails = "查看详情", // 查看详情
viewCertificates = "查看证书", // 查看证书
}
<template>
<Table
ref="tableRef"
:columns="tableColumns"
:data="data"
v-loading="loading"
height="100%"
element-loading-text="加载中..."
>
<template #operate="slotProps">
<syMoreOperate
:teleport="true"
:list="getOperateList(slotProps)"
@click-item="(value) => handleClickItem(value, slotProps)"
:margin-left="-30"
>
<Icon
icon-name="iconbianzu7"
style="font-size: 40px"
class="cursor-pointer"
></Icon>
</syMoreOperate>
</template>
</Table>
</template>
<script setup lang="ts">
import Table from "@/components/Table/index.vue";
import { tableColumns } from "./table";
import Icon from "@/components/Icon/index.vue";
import { onMounted, ref } from "vue";
import { throttle } from "lodash";
import { syMoreOperate } from "cqk-sy-ui";
const emit = defineEmits(["scrollToEnd"]);
const tableRef = ref<InstanceType<typeof Table>>();
onMounted(() => {
listener();
});
function listener() {
const tableEl = tableRef.value?.getEl();
const wrap = tableEl.querySelector(".el-scrollbar__wrap") as HTMLDivElement;
if (wrap.offsetHeight + wrap.scrollTop >= wrap.scrollHeight) {
emit("scrollToEnd");
}
wrap.onresize = () => {
console.log("resize");
};
wrap.onscroll = throttle(() => {
if (wrap.offsetHeight + wrap.scrollTop >= wrap.scrollHeight) {
emit("scrollToEnd");
}
}, 100);
}
defineProps<{
data: any[];
loading: boolean;
}>();
const getOperateList = (slotProps: any) => {
return [
{ name: "编辑", value: "编辑" },
{ name: "删除", value: "删除" },
];
};
const handleClickItem = (value: any, slotProps: any) => {
};
</script>
<style></style>
<template>
<LayoutVue>
<div class="flex flex-col w-full h-full">
<div class="flex items-center">
<Search v-model="searchValue" placeholder="搜索草稿"></Search>
<Avatar
class="ml-7"
@click="() => $router.push('/userCenter')"
></Avatar>
</div>
<div class="flex items-center justify-between" style="margin-top: 26px">
<Title>草稿箱</Title>
<div class="tip flex-grow">草稿将在7日后删除,请尽快完成版权登记</div>
<div class="flex items-center">
<syButton
style="width: 113px"
mode="elementBtn"
size="large"
@click="
() => {
$router.push('/copyrightManagement');
}
"
type="default"
>
<Icon icon-name="iconbanquan" style="margin-right: 3px"></Icon>
版权列表</syButton
>
<syButton
style="width: 113px"
mode="elementBtn"
size="large"
@click="copyRightNotifyVisible = true"
type="primary"
>添加版权</syButton
>
</div>
</div>
<div class="flex-grow overflow-hidden" style="padding-top: 60px">
<DraftBoxTable
:loading="loading"
:data="tableData"
@scrollToEnd="fetchNextPage"
></DraftBoxTable>
</div>
</div>
<CopyRightNotify v-model:visible="copyRightNotifyVisible"></CopyRightNotify>
</LayoutVue>
</template>
<script setup lang="ts">
import LayoutVue from "@/components/Layout.vue";
import Avatar from "@/components/Avatar/index.vue";
import Title from "@/components/Title.vue";
import Search from "@/components/Search/index.vue";
import Icon from "@/components/Icon/index.vue";
import { syButton } from "cqk-sy-ui";
import { ref, watch } from "vue";
import DraftBoxTable from "./draftBoxTable.vue";
import { useTableData } from "@/components/Table/hooks";
import { debounce } from "lodash";
import CopyRightNotify from "@/components/Dialogs/CopyRightNotify/index.vue";
const copyRightNotifyVisible = ref(false);
const searchValue = ref("");
const fetchTableData = ({
page,
page_size,
}: {
page: number;
page_size: number;
}): Promise<any> => {
return new Promise<any>((r) => {
setTimeout(() => {
r({
total: 100,
data: "1"
.repeat(page_size)
.split("")
.map((i, index) => ({
name: index + (page - 1) * page_size,
id: searchValue.value,
})),
});
}, 1000);
});
};
const { fetchNextPage, tableData, loading, refetch } = useTableData({
fetchData: fetchTableData,
});
const refetchDebounce = debounce(refetch, 500);
watch(searchValue, () => {
refetchDebounce();
});
</script>
<style scoped lang="scss">
.tip {
margin-left: 9px;
font-size: 13px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #717171;
}
</style>
import { iTableColumn } from "@/components/Table/types";
export const tableColumns = [
{
label: "版权名称",
prop: "name",
},
{
label: "流水号",
prop: "id",
},
{
label: "操作日期",
prop: "date",
},
{
label: "操作",
slotName: "operate",
width: 60,
},
] as iTableColumn[];
......@@ -2,7 +2,12 @@
<div class="h-full flex flex-col">
<Search v-model:query="query" :showCreateAsset="true"></Search>
<div class="flex-grow overflow-hidden list-table">
<div class="h-full" v-if="loading" v-loading="loading"></div>
<div
class="h-full"
v-if="loading"
v-loading="loading"
element-loading-text="加载中..."
></div>
<pass-list-table
v-if="!loading"
:pass-list="passList"
......@@ -20,7 +25,6 @@ import { defineComponent } from "vue";
import Search from "./Search.vue";
import PassListTable from "./PassListTable.vue";
export default defineComponent({
components: {
PassListTable,
......
......@@ -6,7 +6,12 @@
:show-create-asset="false"
></search>
<div class="flex-grow overflow-hidden list-table">
<div class="h-full" v-if="loading" v-loading="loading"></div>
<div
class="h-full"
v-if="loading"
v-loading="loading"
element-loading-text="加载中..."
></div>
<transfer-record-list
v-if="!loading"
@nextPage="nextPage"
......
......@@ -74,7 +74,7 @@ export default defineComponent({
}
.step-msg p {
font-size: 12px;
color: #797d84;
color: var(--text-gray);
line-height: 28px;
}
.step-msg h3 {
......
......@@ -259,7 +259,7 @@ export default defineComponent({
font-size: 12px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #797d84;
color: var(--text-gray);
margin-top: 9px;
margin-bottom: 19px;
line-height: 17px;
......
......@@ -514,7 +514,7 @@ export default defineComponent({
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #797d84;
color: var(--text-gray);
margin-right: 44px;
}
}
......@@ -600,7 +600,7 @@ export default defineComponent({
font-size: 12px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #797d84;
color: var(--text-gray);
span {
color: #462f2e;
}
......@@ -655,7 +655,7 @@ export default defineComponent({
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #797d84;
color: var(--text-gray);
line-height: 20px;
}
}
......@@ -915,7 +915,7 @@ export default defineComponent({
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #797d84;
color: var(--text-gray);
line-height: 20px;
}
.amount-payable {
......
......@@ -221,7 +221,7 @@ p {
margin-top: 10px;
}
span {
color: #797d84ff;
color: var(--text-gray)ff;
font-size: 14px;
}
</style>
......@@ -295,7 +295,7 @@ export default defineComponent({
}
.center-left__tip {
text-align: center;
color: #797d84;
color: var(--text-gray);
margin: 0;
font-size: 12px;
line-height: 1;
......
......@@ -24,6 +24,12 @@ export default defineConfig({
// target: "https://sy.8n.cn/api",
changeOrigin: true,
},
"^/proxyPdf": {
target:
"https://zbzb.s3.ap-northeast-1.amazonaws.com/yuan.org/ycc/white-paper/zh.pdf",
changeOrigin: true,
rewrite: (path) => path.replace(/^\/proxyPdf/, ""),
},
},
},
});
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment