Compare commits

...

2 Commits

Author SHA1 Message Date
Leo_Ding
1ee082eb90 添加修改密码的功能 2025-07-18 18:17:36 +08:00
Leo_Ding
d06f8005b0 修改文字 2025-07-16 18:04:58 +08:00
10 changed files with 124 additions and 42 deletions

View File

@ -13,6 +13,7 @@ VITE_ROUTER_HISTORY=hash
# api # api
VITE_API_BASIC=https://zh.shibeitong.com VITE_API_BASIC=https://zh.shibeitong.com
# VITE_API_BASIC=http://10.10.1.6:8070
VITE_API_HTTP=/api/v1/ VITE_API_HTTP=/api/v1/
# storage # storage
VITE_STORAGE_NAMESPACE = gin-admin_local_ VITE_STORAGE_NAMESPACE = gin-admin_local_

View File

@ -8,6 +8,6 @@ export const getUserDetail = () => request.basic.get('/api/v1/current/user')
export const updateUser = (_, params) => request.basic.put(`/api/v1/current/user`, params) export const updateUser = (_, params) => request.basic.put(`/api/v1/current/user`, params)
// 更新用户密码 // 更新用户密码
export const updatePassword = (_, params) => request.basic.put(`/api/v1/current/password`, params) export const updatePassword = (params) => request.basic.put(`/api/v1/current/password`, params)
// 用户权限菜单 // 用户权限菜单
export const getUserMenu = () => request.basic.get('/api/v1/current/menus') export const getUserMenu = () => request.basic.get('/api/v1/current/menus')

View File

@ -1,18 +1,11 @@
<template> <template>
<a-layout-header <a-layout-header class="basic-header" :class="cpClassNames" :style="cpStyles">
class="basic-header"
:class="cpClassNames"
:style="cpStyles">
<!-- 左侧 --> <!-- 左侧 -->
<div <div v-if="cpShowLeftSlot" class="basic-header__left">
v-if="cpShowLeftSlot"
class="basic-header__left">
<slot name="left"></slot> <slot name="left"></slot>
</div> </div>
<!-- 中间 --> <!-- 中间 -->
<div <div v-if="cpShowDefaultSlot" class="basic-header__center">
v-if="cpShowDefaultSlot"
class="basic-header__center">
<slot></slot> <slot></slot>
</div> </div>
<!-- 右侧 --> <!-- 右侧 -->
@ -28,10 +21,7 @@
<a-spin /> <a-spin />
<template #overlay> <template #overlay>
<a-menu v-model:selectedKeys="current"> <a-menu v-model:selectedKeys="current">
<a-menu-item <a-menu-item v-for="(item, key) in langData" :key="key" @click="handleLang(key)">
v-for="(item, key) in langData"
:key="key"
@click="handleLang(key)">
{{ item.icon }} {{ item.label }} {{ item.icon }} {{ item.label }}
</a-menu-item> </a-menu-item>
</a-menu> </a-menu>
@ -40,9 +30,7 @@
<a-dropdown :trigger="['click']"> <a-dropdown :trigger="['click']">
<action-button :style="{ height: '44px' }"> <action-button :style="{ height: '44px' }">
<a-avatar <a-avatar class="mr-8-1 display-inline-flex justify-content-center" :size="24"
class="mr-8-1 display-inline-flex justify-content-center"
:size="24"
:src="userInfo?.avatar"> :src="userInfo?.avatar">
</a-avatar> </a-avatar>
<span>{{ userInfo?.name }}</span> <span>{{ userInfo?.name }}</span>
@ -50,15 +38,11 @@
<a-spin /> <a-spin />
<template #overlay> <template #overlay>
<a-menu> <a-menu>
<a-menu-item <a-menu-item key="edit" @click="handleOpen">
key="edit"
@click="handleOpen">
<edit-outlined /> <edit-outlined />
{{ $t('component.RightContent.profile') }} 修改密码
</a-menu-item> </a-menu-item>
<a-menu-item <a-menu-item key="logout" @click="handleLogout">
key="logout"
@click="handleLogout">
<login-outlined></login-outlined> <login-outlined></login-outlined>
{{ $t('component.RightContent.logout') }} {{ $t('component.RightContent.logout') }}
</a-menu-item> </a-menu-item>
@ -68,10 +52,36 @@
</a-space> </a-space>
</div> </div>
</a-layout-header> </a-layout-header>
<a-modal v-model:open="open" title="修改密码" @ok="handleOk">
<a-form ref="formRef" :model="pwdFormData" :rules="pwdFormRules">
<a-card class="mb-8-2">
<a-row :gutter="12">
<a-col :span="24">
<a-form-item :label="'原密码'" name="oldPwd">
<a-input-password :placeholder="'请输入原密码'"
v-model:value="pwdFormData.oldPwd"></a-input-password>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item :label="'新密码'" name="newPwd">
<a-input-password :placeholder="'请输入新密码'"
v-model:value="pwdFormData.newPwd"></a-input-password>
</a-form-item>
</a-col>
<a-col :span="24">
<a-form-item :label="'确认密码'" name="confirmPwd">
<a-input-password :placeholder="'确认密码'"
v-model:value="pwdFormData.confirmPwd"></a-input-password>
</a-form-item>
</a-col>
</a-row>
</a-card>
</a-form>
</a-modal>
</template> </template>
<script setup> <script setup>
import { Modal } from 'ant-design-vue' import { message, Modal } from 'ant-design-vue'
import { storeToRefs } from 'pinia' import { storeToRefs } from 'pinia'
import { computed, useSlots, ref } from 'vue' import { computed, useSlots, ref } from 'vue'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
@ -82,7 +92,10 @@ import { theme as antTheme } from 'ant-design-vue'
import { config as conf } from '@/config' import { config as conf } from '@/config'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import storage from '@/utils/storage' import storage from '@/utils/storage'
import apis from '@/apis'
import { useForm, useModal, useSpining } from '@/hooks'
const { modal, showModal, hideModal, showLoading, hideLoading } = useModal()
const { locale, t } = useI18n() const { locale, t } = useI18n()
defineOptions({ defineOptions({
name: 'BasicHeader', name: 'BasicHeader',
@ -99,7 +112,7 @@ const props = defineProps({
const emit = defineEmits(['config']) const emit = defineEmits(['config'])
const slots = useSlots(['default', 'left', 'right']) const slots = useSlots(['default', 'left', 'right'])
const formRef = ref(null)
const userStore = useUserStore() const userStore = useUserStore()
const appStore = useAppStore() const appStore = useAppStore()
@ -107,7 +120,13 @@ const router = useRouter()
const { config } = storeToRefs(appStore) const { config } = storeToRefs(appStore)
const { userInfo } = storeToRefs(userStore) const { userInfo } = storeToRefs(userStore)
const { token } = antTheme.useToken() const { token } = antTheme.useToken()
const pwdFormData = ref({})
const pwdFormRules = {
oldPwd: [{ required: true, message: '请输原密码' }],
newPwd: [{ required: true, message: '请输入新密码' }],
confirmPwd: [{ required: true, message: '请确认新密码' }],
}
const open = ref(false)
const cpClassNames = computed(() => ({ const cpClassNames = computed(() => ({
[`basic-header--${props.theme}`]: true, [`basic-header--${props.theme}`]: true,
})) }))
@ -164,9 +183,7 @@ function handleLogout() {
*/ */
function handleOpen() { function handleOpen() {
router.push({ open.value = true
name: 'setting',
})
} }
/** /**
@ -185,6 +202,35 @@ function handleLang(lang) {
function handleConfig() { function handleConfig() {
emit('config') emit('config')
} }
function handleOk() {
formRef.value.validateFields().then(async (values) => {
console.log(pwdFormData.value)
if (pwdFormData.value.newPwd !== pwdFormData.value.confirmPwd) {
return message.error('两次密码不一致')
}
try {
console.log(pwdFormData.value)
showLoading()
const params = {
new_password: pwdFormData.value.newPwd,
old_password: pwdFormData.value.oldPwd
}
const result = await apis.user.updatePassword(params)
if (conf('http.code.success') === result?.success) {
hideModal()
hideLoading()
userStore.logout().then(() => {
router.push({
name: 'login',
})
})
}
} catch (error) {
message.error({ content: error.message })
hideLoading()
}
})
}
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>

View File

@ -84,7 +84,7 @@ export default {
fangchan: '南通景点年卡', fangchan: '南通景点年卡',
birth: '生日礼遇', birth: '生日礼遇',
quanwu: '全屋纱窗', quanwu: '全屋纱窗',
aiya: '爱牙抵用', aiya: '爱牙抵用',
yllvs: '医疗绿色', yllvs: '医疗绿色',
ycequite: '盐城权益兑换', ycequite: '盐城权益兑换',

View File

@ -1,4 +1,3 @@
import { active } from "sortablejs";
export default [ export default [
{ {

View File

@ -4,7 +4,7 @@ import list from './list'
import profile from './profile' import profile from './profile'
import result from './result' import result from './result'
import exception from './exception' import exception from './exception'
// import admin from './admin' import admin from './admin'
import system from './system' import system from './system'
import link from './link' import link from './link'
import iframe from './iframe' import iframe from './iframe'
@ -27,7 +27,7 @@ export default [
...profile, ...profile,
...result, ...result,
...exception, ...exception,
// ...admin, ...admin,
...system, ...system,
...link, ...link,
...iframe, ...iframe,

View File

@ -94,8 +94,9 @@ const imgList = ref([])
const type = ref(1) const type = ref(1)
const columns = [ const columns = [
{ title: '客户名称', dataIndex: 'customerName' },
{ title: '活动名称', dataIndex: 'activityName' }, { title: '活动名称', dataIndex: 'activityName' },
{ title: '客户姓名', dataIndex: 'customerName' },
{ title: '联系方式', dataIndex: 'customerPhone' },
{ title: '报名时间', dataIndex: 'createdAt', width: 150, align: 'center' }, { title: '报名时间', dataIndex: 'createdAt', width: 150, align: 'center' },
// { title: t('button.action'), key: 'action', fixed: 'right', width: 150, align: 'center' }, // { title: t('button.action'), key: 'action', fixed: 'right', width: 150, align: 'center' },

View File

@ -0,0 +1,14 @@
<template>
<a-row :gutter="8" :wrap="false">
<a-col flex="auto">
<a-card type="flex">
</a-card>
</a-col>
</a-row>
</template>
<script setup>
import { message, Modal } from 'ant-design-vue'
import { ref } from 'vue'
</script>

View File

@ -51,7 +51,7 @@
<template v-if="column.dataIndex === 'startAt'"> <template v-if="column.dataIndex === 'startAt'">
<span>{{ dayjs(record.startAt).format('YYYY-MM-DD HH:mm:ss') }}</span> <span>{{ dayjs(record.startAt).format('YYYY-MM-DD HH:mm:ss') }}</span>
</template> </template>
<template v-if="column.dataIndex === 'endAt'"> <template v-if="column.dataIndex === 'endAt'">
<span>{{ dayjs(record.endAt).format('YYYY-MM-DD HH:mm:ss') }}</span> <span>{{ dayjs(record.endAt).format('YYYY-MM-DD HH:mm:ss') }}</span>
</template> </template>
<template v-if="'isDaily' === column.dataIndex"> <template v-if="'isDaily' === column.dataIndex">
@ -63,6 +63,11 @@
<a-tooltip> <a-tooltip>
<template #title> {{ $t('pages.system.user.edit') }}</template> <template #title> {{ $t('pages.system.user.edit') }}</template>
<edit-outlined /> </a-tooltip></x-action-button> <edit-outlined /> </a-tooltip></x-action-button>
<x-action-button @click="createQrcode(record)">
<a-tooltip>
<template #title>二维码</template>
<QrcodeOutlined />
</a-tooltip></x-action-button>
<x-action-button @click="handleDelete(record.id)"> <x-action-button @click="handleDelete(record.id)">
<a-tooltip> <a-tooltip>
<template #title>{{ $t('pages.system.delete') }}</template> <template #title>{{ $t('pages.system.delete') }}</template>
@ -73,6 +78,12 @@
</a-card> </a-card>
</a-col> </a-col>
</a-row> </a-row>
<a-modal v-model:open="qropen" :title="'生成二维码'" @ok="qropen = false" :footer="null">
<a-card class="mb-8-2"
style="display: flex;align-items: center;flex-direction: column;justify-content: center;">
<x-qrCode :value="qrValue" :icon="qrlogo" :iconBackgroundColor="'#ffffff'" :size="180"></x-qrCode>
</a-card>
</a-modal>
<edit-dialog ref="editDialogRef" @ok="onOk"></edit-dialog> <edit-dialog ref="editDialogRef" @ok="onOk"></edit-dialog>
</template> </template>
@ -101,9 +112,9 @@ const columns = [
{ title: '案场名称', dataIndex: 'companyName' }, { title: '案场名称', dataIndex: 'companyName' },
{ title: '礼品名称', dataIndex: 'name' }, { title: '礼品名称', dataIndex: 'name' },
{ title: '兑换数量', dataIndex: 'maxNum' }, { title: '兑换数量', dataIndex: 'maxNum' },
{ title: '开始时间', dataIndex: 'startAt',width:180,align:'center' }, { title: '开始时间', dataIndex: 'startAt', width: 180, align: 'center' },
{ title: '结束时间', dataIndex: 'endAt',width:180,align:'center' }, { title: '结束时间', dataIndex: 'endAt', width: 180, align: 'center' },
{ title: '是否每天', dataIndex: 'isDaily',width:120,align:'center' }, { title: '是否每天', dataIndex: 'isDaily', width: 120, align: 'center' },
// { title: '', dataIndex: 'status', key: 'introduce', width: 100, align: 'center' }, // { title: '', dataIndex: 'status', key: 'introduce', width: 100, align: 'center' },
{ title: t('button.action'), key: 'action', fixed: 'right', width: 150, align: 'center' }, { title: t('button.action'), key: 'action', fixed: 'right', width: 150, align: 'center' },
] ]
@ -139,7 +150,18 @@ async function getPageList() {
hideLoading() hideLoading()
} }
} }
const createQrcode = (params) => {
const { name, id,img } = params
const item = {
title: name,
typer: 'product',
pathUrl: '/pages/product/index.vue',
relationId: id,
kvalue1: img,
}
qrValue.value = JSON.stringify(item)
qropen.value = true
}
/** /**
* 删除 * 删除
*/ */

View File

@ -226,7 +226,6 @@ function handleResetSearch() {
* 编辑完成 * 编辑完成
*/ */
async function onOk() { async function onOk() {
message.success(t('component.message.success.delete'))
await getPageList() await getPageList()
} }
</script> </script>