Commit 06e2b1f1 authored by 郭铭瑶's avatar 郭铭瑶 🤘

添加ali-oss & 组织架构多加一级菜单

parent e0f535d9
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -14,6 +14,7 @@
"@vicons/ionicons5": "^0.11.0",
"@yzfe/svgicon": "^1.1.0",
"@yzfe/vue3-svgicon": "^1.0.1",
"ali-oss": "^6.16.0",
"animate.css": "^4.1.1",
"axios": "^0.21.1",
"countup.js": "^2.0.8",
......@@ -21,6 +22,7 @@
"docx": "^6.0.3",
"echarts": "^5.1.2",
"file-saver": "^2.0.5",
"md5": "^2.3.0",
"normalize.css": "^8.0.1",
"qs": "^6.10.1",
"vite-plugin-svgicon": "^1.0.0",
......@@ -29,6 +31,7 @@
},
"devDependencies": {
"@types/file-saver": "^2.0.3",
"@types/md5": "^2.3.1",
"@types/node": "^16.3.2",
"@types/qs": "^6.9.7",
"@typescript-eslint/eslint-plugin": "^4.28.1",
......@@ -41,7 +44,7 @@
"eslint-plugin-import": "^2.23.4",
"eslint-plugin-prettier": "^3.4.0",
"eslint-plugin-vue": "^7.14.0",
"naive-ui": "^2.18.0",
"naive-ui": "^2.18.1",
"prettier": "^2.3.2",
"stylus": "^0.54.8",
"typescript": "^4.3.5",
......
......@@ -36,4 +36,5 @@ export default {
ROOM: '24b5403c-9b6e-4882-b049-51ef197e3aa7',
ATTACHMENT: '988fc63e-fa55-4729-851d-24c4355213f2',
TAG: '54344e11-c0d3-40d5-8f99-771066249328',
GET_AUTH: '988fc63e-fa55-4729-851d-24c4355213f2/storage/grant',
}
import OSS from 'ali-oss'
import { useFetchAuth } from '@/hooks/useFetch'
import md5 from 'md5'
import { api } from '@/ajax'
const auth = (await useFetchAuth())?.token
export default async function useAliOss(file: any) {
const client = new OSS({
region: auth.region,
accessKeyId: auth.access_key_id,
accessKeySecret: auth.access_key_secret,
bucket: auth.bucket,
stsToken: auth.security_token,
})
const fr = new FileReader()
const filename = file.name
return new Promise((resolve: any) => {
fr.readAsArrayBuffer(file)
fr.onload = async (e) => {
const buffer = new OSS.Buffer(e.target && e.target.result)
const key = `${api.BASE_URL}/huamu_${md5(buffer)}_${filename}`
const res = await client.put(key, buffer)
resolve(res.url)
}
})
}
......@@ -85,3 +85,9 @@ export async function useFetchTag(params: QueryProps) {
})
return res && res.data && res.data.result
}
export async function useFetchAuth() {
const res = await ajax.get({
url: api.GET_AUTH,
})
return res && res.data && res.data.result
}
......@@ -6,6 +6,7 @@ declare module '*.vue' {
}
declare module 'animate.css'
declare module 'ali-oss'
declare module '*.css'
declare module '*.styl'
......
......@@ -24,13 +24,24 @@
<p>起始日期</p>
<p>截止日期</p>
</div>
<n-date-picker
start-placeholder="请选择日期"
end-placeholder="请选择日期"
size="small"
separator="至"
type="daterange"
/>
<div class="date-wrapper">
<n-date-picker
v-model:value="dateRange[0]"
class="date-picker"
type="date"
clearable
size="small"
:is-date-disabled="disableDateStart"
/>
<n-date-picker
v-model:value="dateRange[1]"
class="date-picker"
type="date"
clearable
size="small"
:is-date-disabled="disableDateEnd"
/>
</div>
</div>
<div class="list">
<div v-for="(item, i) in list" :key="i">
......@@ -76,15 +87,18 @@
<script lang="ts" setup>
import store from '@/store'
import { computed, ref } from 'vue'
import { computed, ref, watch } from 'vue'
import { Checkmark, Close } from '@vicons/ionicons5'
import ActivityListModal from './activity-list-modal.vue'
import dayjs from '@/util/dayjs'
const show = computed(() => store.state.showActivityDrawer)
const closeDrawer = () => {
store.commit('SET_ACTIVITY_DRAWER', false)
store.commit('SET_SHOW_BASIC_INFO', true)
}
const dateRange = ref<number[]>([])
const list = ref([
{ title: '支部党员大会', count: 35, people: 890, ratio: 50, onMap: false },
{ title: '支部委员会', count: 35, people: 890, ratio: 50, onMap: false },
......@@ -103,6 +117,35 @@ const showModal = () => {
store.commit('SET_SHOW_BASIC_INFO', false)
store.commit('SET_ACTIVITY_LIST_MODAL', true)
}
watch(
() => dateRange.value,
([start, end]) => {
console.log('起始-截止日期:', start, end)
// TODO 发请求获取数据
},
{ deep: true },
)
const disableDateStart = (ts: number) => {
const cur = dayjs(ts)
// TODO 日期起始具体是哪年?
const start = dayjs('1949-01-04')
let end = dayjs()
if (dateRange.value[1]) {
end = dayjs(dateRange.value[1])
}
return !cur.isAfter(start) || !cur.isBefore(end)
}
const disableDateEnd = (ts: number) => {
const cur = dayjs(ts)
// TODO 日期起始具体是哪年?
let start = dayjs('1949-01-04')
const end = dayjs()
if (dateRange.value[0]) {
start = dayjs(dateRange.value[0])
}
return !cur.isAfter(start) || !cur.isBefore(end)
}
</script>
<style lang="stylus" scoped>
......@@ -115,7 +158,7 @@ const showModal = () => {
$flex-align()
justify-content space-between
font-family $font-ping-medium
margin .1rem 0
margin .05rem 0
.date
padding 0 .1rem .1rem
border-bottom .01rem solid $light-gray
......@@ -125,6 +168,11 @@ const showModal = () => {
flex 1
color $font
padding-left .02rem
.date-wrapper
display flex
justify-content space-between
>.date-picker
width 48%
.list
flex 1
background #f7f7f7
......@@ -133,9 +181,9 @@ const showModal = () => {
border-radius .04rem
background #fff
box-shadow 0 .02rem .06rem 0 rgba(0,0,0,0.1)
padding .05rem .08rem
padding .05rem .07rem
box-sizing border-box
margin-bottom .1rem
margin-bottom .07rem
.title
$flex-align()
justify-content space-between
......
......@@ -16,14 +16,24 @@
size="small"
inline
>
<n-form-item label="活动日期区间" path="dateRange">
<n-form-item label="活动日期区间" path="dateStart">
<n-date-picker
v-model:value="model.dateRange"
start-placeholder="请选择日期"
end-placeholder="请选择日期"
v-model:value="model.dateStart"
class="date-picker"
type="date"
clearable
size="small"
separator="至"
type="daterange"
:is-date-disabled="disableDateStart"
/>
</n-form-item>
<n-form-item path="dateEne">
<n-date-picker
v-model:value="model.dateEne"
class="date-picker"
type="date"
clearable
size="small"
:is-date-disabled="disableDateEnd"
/>
</n-form-item>
<n-form-item label="出席率区间" path="rateStart">
......@@ -31,8 +41,7 @@
v-model:value="model.rateStart"
:show-button="false"
size="small"
:min="0"
:max="model.rateEnd || 100"
:validator="checkRateStart"
>
<template #suffix>%</template>
</n-input-number>
......@@ -43,8 +52,7 @@
v-model:value="model.rateEnd"
size="small"
:show-button="false"
:min="model.rateStart || 0"
:max="100"
:validator="checkRateEnd"
>
<template #suffix>%</template>
</n-input-number>
......@@ -54,6 +62,7 @@
v-model:value="model.type"
size="small"
:options="typeOptions"
clearable
/>
</n-form-item>
<n-form-item>
......@@ -162,7 +171,6 @@ const mockData = {
}
const activityData = ref<any>(null)
const openNewDrawer = (data: any = null) => {
console.log(model.value)
activityData.value = data
store.commit('SET_NEW_ACTIVITY_DRAWER', true)
}
......@@ -267,6 +275,43 @@ const sureToDelete = () => {
console.log(curRow.value)
message.success('删除成功')
}
const disableDateStart = (ts: number) => {
const cur = dayjs(ts)
// TODO 日期起始具体是哪年?
const start = dayjs('1949-01-04')
let end = dayjs()
if (model.value.dateEnd) {
end = dayjs(model.value.dateEnd)
}
return !cur.isAfter(start) || !cur.isBefore(end)
}
const disableDateEnd = (ts: number) => {
const cur = dayjs(ts)
// TODO 日期起始具体是哪年?
let start = dayjs('1949-01-04')
const end = dayjs()
if (model.value.dateStart) {
start = dayjs(model.value.dateStart)
}
return !cur.isAfter(start) || !cur.isBefore(end)
}
const checkRateStart = (val: number) => {
const start = 0
let end = 100
if (model.value.rateEnd) {
end = model.value.rateEnd
}
return val >= start && val <= end
}
const checkRateEnd = (val: number) => {
let start = 0
const end = 100
if (model.value.rateStart) {
start = model.value.rateStart
}
return val >= start && val <= end
}
</script>
<style lang="stylus" scoped>
......@@ -313,7 +358,7 @@ const sureToDelete = () => {
padding 0
#activity-filter
.n-select
width 1rem
width 1.4rem
.n-input-number
width 1rem
.n-input-wrapper
......@@ -326,7 +371,7 @@ const sureToDelete = () => {
font-size .1rem
color $font
.n-date-picker
width 2rem
width 1.2rem
.n-input
background #fff
.activity-table
......
......@@ -119,6 +119,8 @@
:span="12"
label="不计入参与活动党员人数"
path="excludeCount"
:min="0"
:max="memberData.count"
>
<p v-if="mode === 'view'">{{ memberData.excludeCount }}</p>
<n-input-number
......@@ -185,32 +187,36 @@
<n-grid :cols="24" :x-gap="12">
<n-form-item-gi
:span="24"
label="活动内容描述或照片(大小20M以内)"
path="fileType"
label="活动内容描述或描述照片(大小20M以内)"
path="describeType"
>
<p v-if="mode === 'view'">
{{
fileOptions.find((e) => e.value === memberData.fileType)
?.label
describeOptions.find(
(e) => e.value === detailData.describeType,
)?.label
}}
</p>
<n-select
v-else
v-model:value="detailData.fileType"
:options="fileOptions"
v-model:value="detailData.describeType"
:options="describeOptions"
placeholder="请选择上传类型"
/>
</n-form-item-gi>
<n-form-item-gi v-if="detailData.fileType === 'file'" :span="24">
<n-upload
style="width: 100%"
action="http://www.mocky.io/v2/5e4bafc63100007100d8b70f"
accept=".docx,.doc,.xlsx,.xls,.csv,.txt"
>
<n-button> 上传附件 </n-button>
</n-upload>
<n-form-item-gi
v-if="detailData.describeType === 'text'"
:span="24"
>
<n-input
v-model:value="detailData.attachment"
type="textarea"
/>
</n-form-item-gi>
<n-form-item-gi v-if="detailData.fileType === 'photo'" :span="24">
<n-form-item-gi
v-if="detailData.describeType === 'photo'"
:span="24"
>
<n-upload
style="width: 100%"
action="http://www.mocky.io/v2/5e4bafc63100007100d8b70f"
......@@ -261,6 +267,7 @@ import { NForm } from 'naive-ui'
import exportIcon from '@images/export.svg'
import { activity } from '@/util/tags'
import { useFetchOrg } from '@/hooks/useFetch'
import dayjs from '@/util/dayjs'
const props = defineProps({
data: {
......@@ -284,7 +291,13 @@ onMounted(async () => {
})
const show = computed(() => store.state.showNewActivityDrawer)
const closeDrawer = () => store.commit('SET_NEW_ACTIVITY_DRAWER', false)
const closeDrawer = () => {
basicData.value = {}
memberData.value = {}
detailData.value = {}
mode.value = null
store.commit('SET_NEW_ACTIVITY_DRAWER', false)
}
const typeOptions = computed(() => {
return activity.map((item) => ({
......@@ -294,6 +307,10 @@ const typeOptions = computed(() => {
})
const fileOptions = [
{ label: '电子表格(docx、doc、xlsx、xls、csv、txt)', value: 'file' },
{ label: '签到照片(jpg、jpeg、png、img)', value: 'photo' },
]
const describeOptions = [
{ label: '活动内容描述', value: 'text' },
{ label: '描述照片(jpg、jpeg、png、img)', value: 'photo' },
]
......@@ -314,19 +331,39 @@ watch(
return
}
basicData.value = {
name: data.name,
type: data.type,
orgName: data.orgName,
date: data.date,
address: data.address,
name: data['活动名称'],
type: data['标签类别'],
orgName: data['党组织名称'],
date: data['活动日期'] && dayjs(data['活动日期']).format('ll'),
address: data['活动地址'],
}
const isFile = data['签到表文件'] && data['签到表文件'].length > 0
const isPhoto = data['签到表照片'] && data['签到表照片'].length > 0
const fileType = isFile ? 'file' : isPhoto ? 'photo' : null
memberData.value = {
count: data.count,
excludeCount: data.excludeCount,
fileType: data.fileType,
count: data['实际参与人数'],
excludeCount: data['不计入参与活动党员人数'],
fileType,
attachment:
fileType === 'file'
? data['签到表文件']
: fileType === 'photo'
? data['签到表照片']
: [],
}
const isText = data['活动内容']
const isImage = data['台账记录照片'] && data['台账记录照片'].length > 0
const describeType = isText ? 'text' : isImage ? 'photo' : null
detailData.value = {
fileType: data.fileType,
describeType,
attachment:
describeType === 'text'
? data['活动内容描述']
: describeType === 'photo'
? data['台账记录照片']
: [],
photoList: data['活动照片'] || [],
}
mode.value = data._mode || null
},
......@@ -377,6 +414,11 @@ const rules = {
trigger: ['blur', 'change'],
message: '请选择上传类型',
},
describeType: {
required: true,
trigger: ['blur', 'change'],
message: '请选择描述类型',
},
}
const submit = () => {
......
......@@ -33,13 +33,13 @@
</n-layout-sider>
<n-layout has-sider>
<n-layout-sider
width="23%"
width="25%"
:collapsed="!showSubordinates"
:collapsed-width="0"
collapsed-mode="width"
class="sub"
>
<p
<!-- <p
v-for="item in subList"
:key="item.key"
:class="{ on: subKey === item.key }"
......@@ -47,7 +47,15 @@
@click.prevent="setSub(item)"
>
{{ item.label }}
</p>
</p> -->
<n-menu
:on-update:value="(_, item) => setSub(item)"
class="sub-menu"
:value="subKey"
:options="subList"
:expanded-keys="subExpandedKeys"
:on-update:expanded-keys="onSubExpand"
/>
</n-layout-sider>
<n-layout class="wrapper">
<n-layout-header class="head">
......@@ -282,7 +290,7 @@
</div>
</div>
</div>
<div class="card">
<div v-if="curMenu['等级'] == '党支部'" class="card">
<div class="title">
<p>党员详表</p>
<n-button type="primary" size="tiny" @click="exportList">
......@@ -485,6 +493,7 @@ const handleExpand = (val: string[]) => {
console.log('expandedKeys', expandedKeys.value)
if (expandedKeys.value.length === 1 && expandedKeys.value[0].includes('-')) {
expandedKeys.value = []
subExpandedKeys.value = []
subKey.value = null
curMenu.value = { label: '中共浦东新区花木街道工作委员会', key: 'default' }
curKey.value = 'default'
......@@ -496,6 +505,8 @@ const handleExpand = (val: string[]) => {
subKey.value = null
if (cur) {
curMenu.value = cur
subExpandedKeys.value = []
subKey.value = null
}
}
......@@ -517,7 +528,30 @@ watch(
async (data) => {
console.log('cur-menu: ', data, menus.value)
if (data && data._hasSub) {
subList.value = data.subList
if (data.subList && data.subList.length > 0) {
await Promise.all(
data.subList.map(async (item: any) => {
const children =
(
await useFetchOrg({
q: `paths @ "上级党组织名称" && string @ "${item['党组织名称']}"`,
})
)?.map((e: any, i: number) => ({
...e.extra,
key: item.key + '-' + (i + 1),
label: e.extra['党组织名称']
.replace('浦东新区花木街道', '')
.replace('中共', ''),
})) || []
if (children && children.length > 0) {
item.children = children
}
}),
)
subList.value = data.subList
} else {
subList.value = []
}
curSubMenu.value = data
}
tableList.value =
......@@ -530,10 +564,31 @@ watch(
)
const showSubordinates = computed(() => curMenu.value._hasSub || !!subKey.value)
const subExpandedKeys = ref<string[]>([])
function setSub(data: any) {
if (!data) {
subKey.value = null
curMenu.value = null
return
}
console.log('set-sub: ', data)
subKey.value = data && data.key
curMenu.value = data
}
function onSubExpand(keys: string[]) {
console.log('sub-expand: ', keys)
if (subExpandedKeys.value.length === 0 || keys.length === 0) {
subExpandedKeys.value = keys
} else if (keys[keys.length - 1].startsWith(subExpandedKeys.value[0])) {
subExpandedKeys.value = keys
} else {
subExpandedKeys.value = [keys[keys.length - 1]]
}
// console.log('222', subExpandedKeys.value)
if (subExpandedKeys.value.length === 0) return
const cur = subList.value.find((e) => e.key === subExpandedKeys.value[0])
setSub(cur)
}
const columns = [
{ title: '姓名', key: '姓名' },
......@@ -629,15 +684,15 @@ const exportList = () => {
z-index 3
box-sizing border-box
padding .1rem 0
p
padding .1rem
font-size .09rem
color $font
cursor pointer
$text-overflow()
&:hover
&.on
color $red
// p
// padding .1rem
// font-size .09rem
// color $font
// cursor pointer
// $text-overflow()
// &:hover
// &.on
// color $red
</style>
<style lang="stylus">
@import '../../components/MyComponent/main.styl'
......@@ -658,6 +713,14 @@ const exportList = () => {
.n-submenu-children
.n-menu-item-content-header
font-size .09rem
&.sub-menu
.n-menu-item-content
padding .1rem .2rem !important
.n-menu-item-content-header
font-size .09rem
.n-submenu-children
.n-menu-item-content
padding-left .35rem !important
.n-menu-item-content--child-active
&:before
content ""
......
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