陈薪名 12 months ago
parent
commit
57ee2936fc
  1. 3
      src/components/Annex/index.ts
  2. 119
      src/components/Annex/src/Annex.vue
  3. 3
      src/components/ChangeRecord/index.ts
  4. 111
      src/components/ChangeRecord/src/ChangeRecord.vue
  5. 3
      src/components/ImportForm/index.ts
  6. 222
      src/components/ImportForm/src/ImportForm.vue
  7. 3
      src/components/Remarks/index.ts
  8. 108
      src/components/Remarks/src/Remarks.vue
  9. 136
      src/views/detail/detail/index.vue

3
src/components/Annex/index.ts

@ -0,0 +1,3 @@
import Annex from './src/Annex.vue'
export { Annex }

119
src/components/Annex/src/Annex.vue

@ -0,0 +1,119 @@
<!-- 附件组件 -->
<template>
<div class="annex">
<div class="title flex items-center">
<div class="title-txt">附件</div>
<el-button type="primary" @click="handleImport">
<Icon icon="ep:upload" />
添加附件
</el-button>
</div>
<div class="list">
<div class="item flex items-start" v-for="(item, index) in data.annexList" :key="index">
<Icon icon="fa:file-text-o" color="#409eff" size="40" class="mt-4px" />
<div class="item-center">
<div class="item-title">{{ item.title}}</div>
<div class="info mt-6px">
<div class="info-txt">
<div>{{ item.size }}</div>
<div>来自 {{ item.people }}</div>
</div>
<Icon icon="ep:delete" class="cursor-pointer" size="20" @click="deleteAnnex(item)"/>
</div>
<div class="time mt-6px ">{{ item.time }}</div>
</div>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
const message = useMessage() //
const { t } = useI18n() //
defineComponent({
name: 'Annex'
})
//
const { data } = defineProps({
data: {
type: Object,
required: true
}
})
// emit
const emit = defineEmits(['handleImport','deleteAnnexSuccess'])
//
const handleImport =()=>{
emit('handleImport')
}
//
const deleteAnnex =async (item) => {
try {
//
await message.delConfirm()
//
// await RoleApi.deleteRole(id)
message.success(t('common.delSuccess'))
emit('deleteAnnexSuccess')
} catch { }
}
</script>
<style scoped lang="scss">
.title {
border-bottom: 1px solid #dedede;
justify-content: space-between;
.title-txt {
width: 80px;
text-align: center;
color: rgb(63, 158, 255);
border-bottom: 2px solid rgb(63, 158, 255);
height: 30px;
}
}
.item {
border-bottom: 1px dashed #dedede;
padding: 20px 0px 10px;
.item-center {
flex: 1;
margin-left: 16px;
overflow: hidden;
.item-title {
font-size: 18px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.info {
display: flex;
align-items: center;
.info-txt {
flex: 1;
display: flex;
align-items: center;
div {
color: #b6b6b6;
margin-right: 20px;
font-size: 14px;
}
}
}
.time {
color: #b6b6b6;
font-size: 14px;
}
}
}
</style>

3
src/components/ChangeRecord/index.ts

@ -0,0 +1,3 @@
import ChangeRecord from './src/ChangeRecord.vue'
export { ChangeRecord }

111
src/components/ChangeRecord/src/ChangeRecord.vue

@ -0,0 +1,111 @@
<!-- 变更记录组件 -->
<template>
<div class="annex">
<div class="title flex items-center">
<div class="title-txt">变更记录</div>
</div>
<div class="list">
<el-steps direction="vertical" class="mt-16px" :space="90">
<el-step v-for="(item, index) in data.changeRecordList" :key="index">
<template #icon>
<slot>
<Icon color="#9e9e9e"
:icon="item.type == 1 ? 'ep:document-add' : item.type == 2 ? 'ep:edit' : item.type == 3 ? 'ep:document' : ''"
class="cursor-pointer" size="20" />
</slot>
</template>
<template #title>
<slot>
<span class="color-#9e9e9e font-size-16px time">{{ item.time }}</span>
</slot>
</template>
<template #description>
<slot>
<div class="dic color-#303133" v-if="item.type == 1">
{{ item.name }} <span>创建了</span> 记录
</div>
<div class="dic color-#303133" v-else-if="item.type == 2">
{{ item.name }} <span>修改了</span> 状态
</div>
<div class="dic color-#303133" v-else-if="item.type == 3">
{{ item.name }} <span>添加了</span> 附件
</div>
<div class="tips" v-if="item.type == 2">
<span class="color-#f56c6c" style="text-decoration:line-through">原值</span>><span
class="color-#67c23a">新值</span>
</div>
<div class="file" v-if="item.type == 3">
<div class="flex mt-8px items-center" v-for="(cur, key) in item.file" :key="key" @click="downFile(cur)">
<Icon color="#70b6ff" icon="ep:document" size="20" style="display:bloc"/>
<div class="file-text" type="primary">{{cur.name}}</div>
</div>
</div>
</slot>
</template>
</el-step>
</el-steps>
</div>
</div>
</template>
<script lang="ts" setup>
import download from '@/utils/download'
defineComponent({
name: 'Annex'
})
//
const { data } = defineProps({
data: {
type: Object,
required: true
}
})
//
const downFile = (cur)=>{
download.excel(cur.url, cur.name)
}
</script>
<style scoped lang="scss">
.title {
border-bottom: 1px solid #dedede;
justify-content: space-between;
.title-txt {
width: 80px;
text-align: center;
color: rgb(63, 158, 255);
border-bottom: 2px solid rgb(63, 158, 255);
height: 30px;
}
}
.time {
font-weight: normal !important;
;
}
.dic {
font-size: 16px;
span {
color: #9e9e9e;
}
}
.tips {
font-size: 16px;
margin-top: 6px;
}
.file{
.file-text{
margin-left: 6px;
color: #70b6ff;
text-decoration: underline;
cursor: pointer;
font-size: 14px;
}
}
</style>

3
src/components/ImportForm/index.ts

@ -0,0 +1,3 @@
import ImportForm from './src/ImportForm.vue'
export { ImportForm }

222
src/components/ImportForm/src/ImportForm.vue

@ -0,0 +1,222 @@
<!-- 导入组件 -->
<template>
<Dialog v-model="dialogVisible" title="导入" width="600">
<el-upload ref="uploadRef" v-model:file-list="fileList" :action="importUrl + '?updateSupport=' + updateSupport"
:auto-upload="false" :disabled="formLoading" :headers="uploadHeaders" :limit="1" :on-error="submitFormError"
:on-exceed="handleExceed" :on-success="submitFormSuccess" :accept="accept" drag
style="width:300px;margin:0 auto">
<Icon icon="ep:upload-filled" color="#c0c4cc" size="60" />
<div class="el-upload__text">将文件拖到此处<em>点击上传</em></div>
<template #tip>
<div class="el-upload__tip ml--80px mr--80px">
<div class="flex">
<div class="label h-32px mr-26px color-#acaeb3 font-size-14px" style="line-height:32px">导入模式</div>
<div class="">
<div class="radio">
<el-radio-group v-model="updateSupport">
<el-radio :label="1" :disabled="updateIsDisable">更新</el-radio>
<el-radio :label="2" :disabled="appendIsDisable">追加</el-radio>
<el-radio :label="3" :disabled="coverIsDisable">覆盖</el-radio>
</el-radio-group>
</div>
<div class="tips color-#acaeb3 font-size-14px">
<div class="mt-2">更新新增并修改</div>
<div class="mt-2">追加只新增不修改</div>
<div class="mt-2">覆盖只修改不新增</div>
</div>
</div>
</div>
<div class="flex mt-16px">
<div class="label h-32px mr-26px color-#acaeb3 font-size-14px" style="line-height:32px">部分保存</div>
<div class="">
<div class="switch">
<el-switch v-model="isSaveAll" />
</div>
<div class="tips color-#acaeb3 font-size-14px">
<div class="mt-2">部分保存如存在错误数据正确数据正常导入</div>
<div class="mt-2">全部保存全部数据正确才能导入</div>
</div>
</div>
</div>
</div>
</template>
</el-upload>
<template #footer>
<div class="flex items-center">
<div class="flex-1 text-left">
<el-button type="primary" plain @click="importTemplate">
<Icon icon="ep:download" />
下载模板
</el-button>
</div>
<el-button :disabled="formLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="dialogVisible = false"> </el-button>
</div>
</template>
</Dialog>
</template>
<script lang="ts" setup>
// import * as UserApi from '@/api/system/user'
import { getAccessToken, getTenantId } from '@/utils/auth'
import download from '@/utils/download'
defineOptions({ name: 'ImportForm' })
const message = useMessage() //
const dialogVisible = ref(false) //
const formLoading = ref(false) //
const uploadRef = ref()
const importUrl =
import.meta.env.VITE_BASE_URL + import.meta.env.VITE_API_URL + '/system/user/import'
const uploadHeaders = ref() // Header
const fileList = ref([]) //
const props = defineProps({
importTemplateData: {
type: Object,
required: true
},
//
accept: {
type: String,
required: false,
default:'.xlsx,.xls'
},
// .1
updateSupport: {
type: Number,
required: false,
default: 1
},
// ,
updateIsDisable: {
type: Boolean,
required: false,
default: false
},
// ,
appendIsDisable: {
type: Boolean,
required: false,
default: false
},
// ,
coverIsDisable: {
type: Boolean,
required: false,
default: false
},
// ,
isSaveAll: {
type: Boolean,
required: false,
default: true
},
})
const { importTemplateData, accept } = toRefs(props)
const updateSupport = ref(props.updateSupport)//.1
const updateIsDisable = ref(props.updateIsDisable)//,
const appendIsDisable = ref(props.appendIsDisable)//,
const coverIsDisable = ref(props.coverIsDisable)//,
const isSaveAll = ref(props.isSaveAll)//
/** 打开弹窗 */
const open = () => {
dialogVisible.value = true
resetForm()
}
defineExpose({ open }) // open
/** 提交表单 */
const submitForm = async () => {
if (fileList.value.length == 0) {
message.error('请上传文件')
return
}
//
uploadHeaders.value = {
Authorization: 'Bearer ' + getAccessToken(),
'tenant-id': getTenantId()
}
formLoading.value = true
uploadRef.value!.submit()
}
/** 文件上传成功 */
const emits = defineEmits(['success'])
const submitFormSuccess = (response: any) => {
if (response.code !== 0) {
message.error(response.msg)
formLoading.value = false
return
}
//
const data = response.data
let text = '上传成功数量:' + data.createUsernames.length + ';'
for (let username of data.createUsernames) {
text += '< ' + username + ' >'
}
text += '更新成功数量:' + data.updateUsernames.length + ';'
for (const username of data.updateUsernames) {
text += '< ' + username + ' >'
}
text += '更新失败数量:' + Object.keys(data.failureUsernames).length + ';'
for (const username in data.failureUsernames) {
text += '< ' + username + ': ' + data.failureUsernames[username] + ' >'
}
message.alert(text)
//
emits('success')
}
/** 上传错误提示 */
const submitFormError = (): void => {
message.error('上传失败,请您重新上传!')
formLoading.value = false
}
/** 重置表单 */
const resetForm = () => {
//
formLoading.value = false
uploadRef.value?.clearFiles()
}
/** 文件数超出提示 */
const handleExceed = (): void => {
message.error('最多只能上传一个文件!')
}
/** 下载模板操作 */
const importTemplate = () => {
const res = importTemplateData.templateUrl
download.excel(res, importTemplateData.templateTitle)
}
</script>
<style scoped lang="scss">
.tips {
div {
position: relative;
padding-left: 22px;
&::before {
width: 4px;
height: 4px;
border-radius: 50%;
content: '';
background: #c2c2c2;
position: absolute;
top: 50%;
margin-top: -2px;
left: 4px;
}
}
}
</style>

3
src/components/Remarks/index.ts

@ -0,0 +1,3 @@
import Remarks from './src/Remarks.vue'
export { Remarks }

108
src/components/Remarks/src/Remarks.vue

@ -0,0 +1,108 @@
<!-- 备注组件 -->
<template>
<div class="annex">
<div class="title flex items-center">
<div class="title-txt">备注</div>
</div>
<div class="list">
<div class="item flex items-start" v-for="(item, index) in data.remarksList" :key="index">
<div class="user-icon mt-4px">
<Icon icon="fa-solid:user" color="#fff" size="20" />
</div>
<div class="item-center">
<div class="item-title">
<div class="item-title-txt">{{ item.name }}</div>
<div class="time">{{ item.time }}</div>
</div>
<div class="mt-8px color-#303133 font-size-16px">{{ item.text }}</div>
</div>
</div>
</div>
<div class="add-remarks flex items-center mt-20px">
<el-input v-model="remark" placeholder="请输入备注" :input-style="{height:'40px'}"/>
<el-button class="ml-16px" type="primary" @click="handleSubmit" size="large">
确定
</el-button>
</div>
</div>
</template>
<script lang="ts" setup>
import { getCurrentInstance } from 'vue'
const message = useMessage() //
const { proxy } = getCurrentInstance()
defineComponent({
name: 'Annex'
})
const remark = ref('')
//
const { data } = defineProps({
data: {
type: Object,
required: true
}
})
// emit
const emit = defineEmits(['remarksSubmitSucss'])
//
const handleSubmit = ()=>{
if(!remark.value){
message.error('请填写备注')
}
emit('remarksSubmitSucss') //
}
</script>
<style scoped lang="scss">
.title {
border-bottom: 1px solid #dedede;
justify-content: space-between;
.title-txt {
width: 80px;
text-align: center;
color: rgb(63, 158, 255);
border-bottom: 2px solid rgb(63, 158, 255);
height: 30px;
}
}
.item {
border-bottom: 1px dashed #dedede;
padding: 20px 0px 10px;
.user-icon {
width: 40px;
height: 40px;
background: #dedfe0;
border-radius: 4px;
display: flex;
align-items: center;
justify-content: center;
}
.item-center {
flex: 1;
margin-left: 16px;
overflow: hidden;
.item-title {
display: flex;
align-items: flex-end;
.item-title-txt {
font-size: 20px;
color: #9e9e9e;
}
.time {
color: #9e9e9e;
margin-left: 10px;
}
}
}
}</style>

136
src/views/detail/detail/index.vue

@ -0,0 +1,136 @@
<template>
<!-- 搜索工作栏 -->
<ContentWrap>
<el-form class="-mb-15px" :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
<el-form-item label="部门名称" prop="title">
<el-input v-model="queryParams.name" placeholder="请输入部门名称" clearable class="!w-240px" />
</el-form-item>
<el-form-item>
<el-button type="info" plain @click="handleQuery">
<Icon icon="ep:search" class="mr-5px" /> 搜索
</el-button>
<el-button type="info" plain @click="resetQuery">
<Icon icon="ep:refresh" class="mr-5px" /> 重置
</el-button>
</el-form-item>
</el-form>
</ContentWrap>
<div class="flex">
<!-- 详情 -->
<ContentWrap class="w-[73%]">
1
</ContentWrap>
<ContentWrap class="w-[27%] ml-16px">
<!-- 附件组件 -->
<Annex :data="annexData" @handleImport="handleImport" @deleteAnnex="deleteAnnexSuccess" />
<!-- 备注组件 -->
<Remarks :data="remarksData" class="mt-20px" @submitSucss="remarksSubmitSucss"/>
<!-- 变更记录组件 -->
<ChangeRecord :data="changeRecordData" class="mt-20px" />
</ContentWrap>
<!-- 用户导入对话框 -->
<ImportForm ref="importFormRef" :importTemplateData="importTemplateData" @success="importSuccess" />
</div>
</template>
<script lang="ts" setup>
defineOptions({ name: 'Detail' })
import Annex from '@/components/Annex/src/Annex.vue'
import Remarks from '@/components/Remarks/src/Remarks.vue'
import ImportForm from '@/components/ImportForm/src/ImportForm.vue'
import ChangeRecord from '@/components/ChangeRecord/src/ChangeRecord.vue'
import * as UserApi from '@/api/system/user'
//
const queryParams = reactive({
title: '',
name: undefined,
status: undefined,
pageNo: 1,
pageSize: 100
})
const queryFormRef = ref() //
//
const annexData = reactive({
annexList: [{
title: '文件名文件名2023-12-12.docx',
size: '150.02KB',
people: '贾先生',
time: '2023年5月6日 17:16:00',
}, {
title: '文件名文件名2023-12-15.docx',
size: '242KB',
people: '张张',
time: '2022年12月12日 17:16:00',
}]
})
//
const remarksData = reactive({
remarksList: [{
name: '诸葛亮',
text: '转朱阁,低绮户,照无眠。不应有恨,何事长向别时圆?人有悲欢离合,月有阴晴圆缺,此事古难全。但愿人长久,千里共婵娟。',
time: '2023年5月6日 17:16:00',
}, {
name: '刘备',
text: '转朱阁,低绮户,照无眠。不应有恨,何事长向别时圆?人有悲欢离合,月有阴晴圆缺,此事古难全。但愿人长久,千里共婵娟。',
time: '2022年12月12日 17:16:00',
}]
})
//
const changeRecordData = reactive({
changeRecordList: [{
name: '诸葛亮',
type: 1,
time: '2023年5月6日 17:16:00',
}, {
name: '刘备',
type: 2,
time: '2023年5月6日 17:16:00',
}, {
name: '曹操',
type: 3,
time: '2023年5月6日 17:16:00',
file: [{
name: '这是个附件的名字.docx',
url: 'http://localhost:12080/admin-api/system/user/get-import-template'
}, {
name: '这是个附件的名字.docx',
url: 'http://localhost:12080/admin-api/system/user/get-import-template'
}]
}]
})
//
const importTemplateData = reactive({
templateUrl: UserApi.importUserTemplate(),
templateTitle: '导入模版99.xls'
})
//
const importSuccess = () => {
}
/** 搜索按钮操作 */
const handleQuery = () => {
}
/** 重置按钮操作 */
const resetQuery = () => {
queryParams.pageNo = 1
queryFormRef.value.resetFields()
}
/** 用户导入 */
const importFormRef = ref()
const handleImport = () => {
importFormRef.value.open()
}
//
const deleteAnnexSuccess = async () => {
console.log('删除成功');
}
//
const remarksSubmitSucss=()=>{
console.log('提交陈工');
}
</script>
Loading…
Cancel
Save