Skip to content

Commit

Permalink
feat: add upload gift card page (#510)
Browse files Browse the repository at this point in the history
* feat: add upload gift card page

新增了一个上传giftcard的页面

* chore: change deleteMany to drop

change deletemany to drop when overRide giftcards DB
  • Loading branch information
ccjaread committed Apr 17, 2024
1 parent 5899b04 commit 50665f6
Show file tree
Hide file tree
Showing 10 changed files with 218 additions and 2 deletions.
15 changes: 14 additions & 1 deletion service/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import type { ChatMessage } from './chatgpt'
import { abortChatProcess, chatConfig, chatReplyProcess, containsSensitiveWords, initAuditService } from './chatgpt'
import { auth, getUserId } from './middleware/auth'
import { clearApiKeyCache, clearConfigCache, getApiKeys, getCacheApiKeys, getCacheConfig, getOriginConfig } from './storage/config'
import type { AnnounceConfig, AuditConfig, ChatInfo, ChatOptions, Config, KeyConfig, MailConfig, SiteConfig, UserConfig, UserInfo } from './storage/model'
import type { AnnounceConfig, AuditConfig, ChatInfo, ChatOptions, Config, GiftCard, KeyConfig, MailConfig, SiteConfig, UserConfig, UserInfo } from './storage/model'
import { AdvancedConfig, Status, UsageResponse, UserRole } from './storage/model'
import {
clearChat,
Expand Down Expand Up @@ -39,6 +39,7 @@ import {
updateChat,
updateConfig,
updateGiftCard,
updateGiftCards,
updateRoomChatModel,
updateRoomPrompt,
updateRoomUsingContext,
Expand Down Expand Up @@ -888,6 +889,18 @@ router.post('/redeem-card', auth, async (req, res) => {
}
})

// update giftcard database
router.post('/giftcard-update', rootAuth, async (req, res) => {
try {
const { data, overRideSwitch } = req.body as { data: GiftCard[];overRideSwitch: boolean }
await updateGiftCards(data, overRideSwitch)
res.send({ status: 'Success', message: '更新成功 | Update successfully' })
}
catch (error) {
res.send({ status: 'Fail', message: error.message, data: null })
}
})

router.post('/user-chat-model', auth, async (req, res) => {
try {
const { chatModel } = req.body as { chatModel: string }
Expand Down
11 changes: 11 additions & 0 deletions service/src/storage/mongo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,17 @@ export async function updateAmountMinusOne(userId: string) {
return result.modifiedCount > 0
}

// update giftcards database
export async function updateGiftCards(data: GiftCard[], overRide = true) {
if (overRide) {
// i am not sure is there a drop option for the node driver reference https://mongodb.github.io/node-mongodb-native/6.4/
// await redeemCol.deleteMany({})
await redeemCol.drop()
}
const insertResult = await redeemCol.insertMany(data)
return insertResult
}

export async function insertChat(uuid: number, text: string, images: string[], roomId: number, options?: ChatOptions) {
const chatInfo = new ChatInfo(roomId, uuid, text, images, options)
await chatCol.insertOne(chatInfo)
Expand Down
9 changes: 8 additions & 1 deletion src/api/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { AxiosProgressEvent, GenericAbortSignal } from 'axios'
import { get, post } from '@/utils/request'
import type { AnnounceConfig, AuditConfig, ConfigState, KeyConfig, MailConfig, SiteConfig, Status, UserInfo, UserPassword } from '@/components/common/Setting/model'
import type { AnnounceConfig, AuditConfig, ConfigState, GiftCard, KeyConfig, MailConfig, SiteConfig, Status, UserInfo, UserPassword } from '@/components/common/Setting/model'
import { useAuthStore, useUserStore } from '@/store'
import type { SettingsState } from '@/store/modules/user/helper'

Expand Down Expand Up @@ -153,6 +153,13 @@ export function decode_redeemcard<T = any>(redeemCardNo: string) {
})
}

export function fetchUpdateGiftCards<T = any>(data: GiftCard[], overRideSwitch: boolean) {
return post<T>({
url: '/giftcard-update',
data: { data, overRideSwitch },
})
}

export function fetchUpdateUserChatModel<T = any>(chatModel: string) {
return post<T>({
url: '/user-chat-model',
Expand Down
163 changes: 163 additions & 0 deletions src/components/common/Setting/Gift.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
<script setup lang='ts'>
import { ref } from 'vue'
import type { UploadFileInfo } from 'naive-ui'
import { NButton, NDataTable, NDivider, NIcon, NP, NSpace, NSwitch, NText, NUpload, NUploadDragger, useMessage } from 'naive-ui'
import type { GiftCard } from './model'
import { SvgIcon } from '@/components/common'
import { fetchUpdateGiftCards } from '@/api'
import { t } from '@/locales'
const ms = useMessage()
const loading = ref(false)
const overRideSwitch = ref(true)
const fileListRef = ref<UploadFileInfo[]>([])
const handleSaving = ref(false)
const columns = [
{
title: 'cardno',
key: 'cardno',
resizable: true,
width: 100,
minWidth: 100,
maxWidth: 200,
},
{
title: 'amount',
key: 'amount',
width: 80,
},
{
title: 'redeemed',
key: 'redeemed',
width: 100,
},
]
const csvData = ref<Array<GiftCard>>([])
// const csvData: giftcard[] = [
// {
// cardno: 'dfsdfasf',
// amount: 10,
// redeemed: 0,
// },
// {
// cardno: 'ooioioo',
// amount: 20,
// redeemed: 0,
// },
// {
// cardno: '765653',
// amount: 30,
// redeemed: 1,
// },
// ]
function readfile(file: Blob) {
try {
// const file = event.target.files[0]
if (file) {
ms.info('生成预览中 | Generating Preview')
const reader = new FileReader()
reader.onload = (e) => {
const contents = e.target?.result as string
csvData.value = parseCSV(contents)
}
reader.readAsText(file)
}
else {
ms.info('没有读取到文件 | No file find')
}
}
catch (error: any) {
ms.info(`读取文件出错 | Error reading file | ${error.message}`)
}
}
function parseCSV(content: string) {
const rows = content.trim().split(/\r?\n/)
// const headers = rows[0].split(',')
const giftCards: GiftCard[] = rows.slice(1).map(row => row.split(',')).map(row => ({
cardno: row[0],
amount: Number(row[1].trim()),
redeemed: Number(row[2].trim()),
}))
return giftCards
}
function handleUploadChange(data: { file: UploadFileInfo, fileList: Array<UploadFileInfo>, event?: Event }) {
fileListRef.value = data.fileList
csvData.value = []
if (data.event) {
const file_bolb = data.fileList[0].file
if (file_bolb)
readfile(file_bolb)
}
}
async function uploadGiftCards() {
handleSaving.value = true
try {
if (csvData.value.length > 0)
await fetchUpdateGiftCards(csvData.value, overRideSwitch.value)
ms.success(`${t('common.success')}`)
}
catch (error: any) {
ms.error(`Failed update DB ${error.message}`)
}
handleSaving.value = false
}
</script>

<template>
<div class="p-4 space-y-5 min-h-[300px]">
<div class="space-y-6">
<NUpload
:max="1"
accept=".csv"
:on-change="handleUploadChange"
>
<NUploadDragger>
<div style="margin-bottom: 12px">
<NIcon size="48" :depth="3">
<SvgIcon icon="mage:box-upload" />
</NIcon>
</div>
<NText style="font-size: 16px">
点击或者拖动文件到该区域来上传|Upload CSV
</NText>
<NP depth="3" style="margin: 8px 0 0 0">
请不要上传敏感数据,文件仅限csv(2k行内),表头为cardno,amount,redeemed<br>
warning: duplicated cardno will not be detected in this process
</NP>
</NUploadDragger>
</NUpload>

<NSpace vertical :size="12">
<span class="flex-shrink-0 w-[100px]">Data Preview(Top 30) & Due to body-parser limits csv files >2k rows not supported </span>
<NDataTable
remote
:loading="loading"
:row-key="(rowData:GiftCard) => rowData.cardno"
:columns="columns"
:data="csvData.slice(0, 30)"
:max-height="200"
/>
</NSpace>
</div>
<NDivider />
<div class="flex items-center space-x-4">
<span class="flex-shrink-0 w-[100px]">{{ $t('setting.overRide') }}</span>
<div class="flex-1">
<NSwitch v-model:value="overRideSwitch" />
</div>
<div class="flex-1">
<NButton type="primary" :loading="handleSaving" size="large" @click="uploadGiftCards()">
{{ $t('setting.uploadgifts') }}
</NButton>
</div>
</div>
</div>
</template>
8 changes: 8 additions & 0 deletions src/components/common/Setting/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import About from './About.vue'
import Site from './Site.vue'
import Mail from './Mail.vue'
import Audit from './Audit.vue'
import Gift from './Gift.vue'
import User from './User.vue'
import Key from './Keys.vue'
import Password from './Password.vue'
Expand Down Expand Up @@ -141,6 +142,13 @@ const show = computed({
</template>
<Key />
</NTabPane>
<NTabPane v-if="userStore.userInfo.root" name="GiftCardConfig" tab="GiftCardConfig">
<template #tab>
<SvgIcon class="text-lg" icon="mdi-gift" />
<span class="ml-2">{{ $t('setting.uploadgifts') }}</span>
</template>
<Gift />
</NTabPane>
</NTabs>
</div>
</NModal>
Expand Down
6 changes: 6 additions & 0 deletions src/components/common/Setting/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,3 +162,9 @@ export class TwoFAConfig {
this.testCode = ''
}
}

export interface GiftCard {
cardno: string
amount: number
redeemed: number
}
2 changes: 2 additions & 0 deletions src/locales/en-US.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ export default {
disable2FAConfirm: 'Are you sure to disable 2FA for this user?',
},
setting: {
overRide: 'Enable Override',
uploadgifts: 'Upload Redemption Code',
announceConfig: 'Announcement',
announceEnabled: 'Open Announcement',
announceWords: 'Announcement Content',
Expand Down
2 changes: 2 additions & 0 deletions src/locales/ko-KR.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ export default {
disable2FAConfirm: 'Are you sure to disable 2FA for this user?',
},
setting: {
overRide: '덮어쓰기 활성화',
uploadgifts: '교환 코드 업로드',
announceConfig: '网站公告',
announceEnabled: 'Open Announcement',
announceWords: 'Announcement Content',
Expand Down
2 changes: 2 additions & 0 deletions src/locales/zh-CN.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ export default {
disable2FAConfirm: '您确定要为此用户禁用两步验证吗??',
},
setting: {
overRide: '开启覆写',
uploadgifts: '上传兑换码',
announceConfig: '网站公告',
announceEnabled: '公告开关',
announceWords: '公告内容',
Expand Down
2 changes: 2 additions & 0 deletions src/locales/zh-TW.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ export default {
disable2FAConfirm: '您确定要为此用户禁用两步验证吗??',
},
setting: {
overRide: '開啟覆寫',
uploadgifts: '上傳兌換碼',
announceConfig: '网站公告',
announceEnabled: '打开公告',
announceWords: '公告内容',
Expand Down

0 comments on commit 50665f6

Please sign in to comment.