Commit c4aa0fbb by lijinqi

1.我的资源:算力资源分类筛选条件bug修复

2.算力资源列表 卡片布局切列表布局bug修复
3.我的订单:属性值为空时的异常处理
4.活动资讯页面,修复列表被导航栏遮挡bug
5.面包屑去掉
6.行业应用新增详情页,从详情页跳转到试用
parent c3c1c0ba
......@@ -25,6 +25,15 @@ export function assemblyList (query) {
})
}
// 获取组件服务详情
export function assemblyDetail (query) {
return request({
url: '/biz/industry-application/get',
method: 'get',
params: query
})
}
export function assemblyType (query) {
return request({
url: '/api/v1/assemblyType',
......
......@@ -18,11 +18,12 @@ export function getAppCategoryList(params) {
}
export function getAppInfoDetail(params) {
export function getAppInfoDetail(params, config) {
return request({
url: '/apihub/api/get',
method: 'get',
params: params
params: params,
...(config || {})
})
}
......@@ -59,4 +60,4 @@ export function createPay(query){
method: 'post',
data: query
})
}
\ No newline at end of file
}
......@@ -119,6 +119,15 @@ export function updateMobile(data) {
})
}
// 用户通过短信验证码修改密码
export function updateUserPwdByCode(data) {
return request({
url: '/member/user/update-password',
method: 'put',
data: data
})
}
// 用户头像上传
export function uploadAvatar(data) {
return request({
......
// cover some element-ui styles
.el-breadcrumb__inner,
.el-breadcrumb__inner a {
font-weight: 400 !important;
}
.el-upload {
input[type="file"] {
......
......@@ -103,23 +103,6 @@ aside {
box-sizing: border-box;
}
.com-breadcrumb{
background-color: #FFFFFF;
border-bottom: 1px solid #EBEDED;
padding: 30px;
margin-top:30px;
.el-breadcrumb{
font-size: 16px ;
}
.el-breadcrumb__inner{
color: #333!important;
}
.el-breadcrumb__item {
&:last-child .el-breadcrumb__inner {
color: #999!important;
}
}
}
.components-container {
margin: 30px 50px;
......@@ -314,21 +297,7 @@ aside {
.com-breadcrumb-1 {
font-size: 14px;
color: #fff;
background: var(--el-color-primary);
padding: 12px 24px;
padding: 30px;
.el-breadcrumb {
font-size: 16px;
}
.el-breadcrumb__inner,
.el-breadcrumb__separator,
.el-breadcrumb__item:last-child .el-breadcrumb__inner {
color: #fff !important;
}
}
// 控制台的全局样式
......
......@@ -16,6 +16,7 @@ const whiteList = [
'/industryApplications/index',
'/industryApplications/detail',
'/componentServices/componentServicesList',
'/componentServices/detail',
'/partnership/partnershipList',
'/information/informationDetail',
'/information/informationList',
......
......@@ -131,6 +131,12 @@ export const constantRoutes = [
component: () => import('@/views/componentServices/list.vue'),
name: 'ComponentServicesList',
meta: {title: '行业应用'}
},
{
path: 'detail',
component: () => import('@/views/componentServices/detail.vue'),
name: 'ComponentServicesDetail',
meta: {title: '行业应用详情'}
}
]
},
......
......@@ -110,6 +110,13 @@ service.interceptors.response.use(res => {
},
error => {
console.log('err' + error)
// 忽略被取消/中止的请求错误,避免无意义的报错提示
if (axios.isCancel && axios.isCancel(error)) {
return Promise.reject(error)
}
if (error && (error.code === 'ERR_CANCELED' || error.message === 'canceled' || error.name === 'CanceledError')) {
return Promise.reject(error)
}
let { message } = error;
if (message == "Network Error") {
message = "后端接口连接异常";
......
<template>
<div class="app-container custom-main-w ">
<div style="margin: 0 auto;padding: 0 84px;'">
<div style="margin: 0 auto; padding: 0 84px;">
<el-row :gutter="24">
<el-col v-for="(item,index) in assemblyData" :key="item.id" :span="6">
<div class="item flex">
......@@ -9,36 +9,22 @@
<div class="title">{{ item.title }}</div>
<p v-html="item.description"></p>
<el-button round @click="openPage(item,index)">点击试用</el-button>
<el-button round @click="openPage(item,index)">了解详情</el-button>
</div>
</div>
</el-col>
</el-row>
</div>
<el-dialog
v-model="dialogTableVisible"
style="width: 80% !important;"
:title="dialogTitle"
@close="handleDialogClose"
>
<div>
<iframe v-show="iframeShow" ref="iframe" :src="iframeSrc" width="100%" height="700px"></iframe>
</div>
</el-dialog>
</div>
</template>
<script setup name="ComponentServicesList">
import {ref} from 'vue'
import {assemblyList} from '@/api/home.js'
import {assemblyType} from "../../api/home.js";
import { useRouter } from 'vue-router'
const assemblyData = ref([])
const iframeSrc = ref('')
const iframeShow = ref(false)
const dialogTableVisible = ref(false)
const dialogTitle = ref('')
const indexNum = ref(0)
const router = useRouter()
function getAassemblyList() {
assemblyList().then(res => {
......@@ -47,22 +33,9 @@ function getAassemblyList() {
}
function openPage(data, index) {
indexNum.value = index
dialogTitle.value = data.title
iframeSrc.value = data.url
dialogTableVisible.value = true
iframeShow.value = true
// window.open(data.url)
}
function cancel() {
dialogTableVisible.value = false
iframeShow.value = false
}
// 关闭弹窗
function handleDialogClose() {
iframeSrc.value = null
if (data && data.id) {
router.push({ path: '/componentServices/detail', query: { id: data.id } })
}
}
getAassemblyList()
......@@ -123,45 +96,9 @@ getAassemblyList()
}
}
.iframe-container {
position: absolute;
top: 10%;
left: 6%;
}
.iframe-container iframe {
position: absolute;
top: 0;
left: 0;
}
:deep(.el-dialog__body) {
padding-top: unset !important;
}
.el-tabs {
--el-border-color-light: #2E77E3;
--el-tabs-header-height: 48px;
/* 旧iframe容器样式已移除 */
:deep(.el-tabs__content) {
overflow: visible
}
:deep(.el-tabs__active-bar) {
display: none;
}
:deep(.el-tabs__item) {
--el-font-size-base: 16px;
padding-left: 24px !important;
padding-right: 24px !important;
&.is-active {
color: #ffffff;
background-color: #2E77E3;
}
}
}
/* 清理过期的弹窗与Tab样式 */
.el-button {
height: 40px;
......
<template>
<div class="app-container confirm-order">
<div class="breadcrumb">
<div class="flex-justify-end">
<el-breadcrumb separator="/">
<el-breadcrumb-item>首页</el-breadcrumb-item>
<el-breadcrumb-item>计算资源</el-breadcrumb-item>
<el-breadcrumb-item>确认订单</el-breadcrumb-item>
</el-breadcrumb>
</div>
</div>
<div class="page-title">
<div>确认订单</div>
</div>
......@@ -136,24 +127,6 @@ function submit () {
min-height: 100%;
}
.breadcrumb {
background-color: #FFFFFF;
border-bottom: 1px solid #EBEDED;
padding-top: 12px;
padding-bottom: 12px;
> div {
width: 1280px;
margin: 0 auto;
}
:deep(.el-breadcrumb__item) {
&:last-child .el-breadcrumb__inner {
color: #222222;
}
}
}
.page-title {
font-weight: bold;
font-size: 24px;
......
<template>
<div class="app-container computing-resource">
<div class="breadcrumb">
<div class="flex-justify-end">
<el-breadcrumb separator="/">
<el-breadcrumb-item>首页</el-breadcrumb-item>
<el-breadcrumb-item>计算资源</el-breadcrumb-item>
</el-breadcrumb>
</div>
</div>
<div class="top-banner-list flex-justify-center">
<div class="banner-item flex-align-center">
......@@ -505,28 +497,11 @@ const clearProtocol = () => {
<style scoped lang="scss">
.app-container {
padding-top: 0;
padding-top: 20px;
padding-left: 0;
padding-right: 0;
}
.breadcrumb {
border-bottom: 1px solid #EBEDED;
padding-top: 12px;
padding-bottom: 12px;
> div {
width: 1280px;
margin: 0 auto;
}
:deep(.el-breadcrumb__item) {
&:last-child .el-breadcrumb__inner {
color: #222222;
}
}
}
.top-banner-list {
margin-top: 84px;
......
<template>
<div class="app-container shopping-cart">
<div class="breadcrumb">
<div class="flex-justify-end">
<el-breadcrumb separator="/">
<el-breadcrumb-item>首页</el-breadcrumb-item>
<el-breadcrumb-item>计算资源</el-breadcrumb-item>
<el-breadcrumb-item>购物车</el-breadcrumb-item>
</el-breadcrumb>
</div>
</div>
<div class="page-title">
<div>购物车 (总共{{ tableData.length }})</div>
</div>
......@@ -233,24 +224,6 @@ function submit() {
min-height: 100%;
}
.breadcrumb {
background-color: #FFFFFF;
border-bottom: 1px solid #EBEDED;
padding-top: 12px;
padding-bottom: 12px;
> div {
width: 1280px;
margin: 0 auto;
}
:deep(.el-breadcrumb__item) {
&:last-child .el-breadcrumb__inner {
color: #222222;
}
}
}
.page-title {
font-weight: bold;
font-size: 22px;
......
......@@ -113,13 +113,18 @@
</el-table-column>
<el-table-column label="资源类型" align="center" prop="categoryName"/>
<el-table-column
v-for="(item, index) in orderList[0]?.properties.length!==0?orderList[0]?.properties.slice(0,4):orderList[0]?.properties"
:key="index"
:label="item.propertyName"
>
<el-table-column label="商品属性" align="center" width="400">
<template #default="{ row }">
{{ row.properties?.[index]?.valueName || '-' }}
<div class="mt-1 properties-cell" v-if="row.properties && row.properties.length">
<el-tag
v-for="(property, i) in row.properties"
:key="property.propertyId ?? i"
class="mb-1 mr-1"
>
{{ property.propertyName }}: {{ property.valueName }}
</el-tag>
</div>
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column label="订单状态" align="center" prop="statusName"/>
......@@ -438,4 +443,14 @@ loadCategories()
color: #303233;
}
}
/* Limit properties column to 200px width and 2 lines */
.properties-cell {
width: 400px;
overflow: hidden;
display: -webkit-box;
-webkit-line: 2;
-webkit-box-orient: vertical;
white-space: normal;
}
</style>
......@@ -3,15 +3,19 @@
<el-table v-loading="loading" :data="resourcesList" :max-height="620">
<el-table-column label="订单编号" align="center" prop="tradeOrderNo"/>
<!-- <el-table-column label="商品类别" align="center" prop="categoryName"/>-->
<el-table-column
v-for="(item, index) in resourcesList[0]?.properties.length!==0?resourcesList[0]?.properties.slice(0,4):resourcesList[0]?.properties"
:key="index"
:label="item.propertyName"
>
<el-table-column label="资源属性" align="center" width="400">
<template #default="{ row }">
{{ row.properties?.[index]?.valueName || '-' }}
<div class="mt-1 properties-cell" v-if="row.properties && row.properties.length">
<el-tag
v-for="(property, i) in row.properties"
:key="property.propertyId ?? i"
class="mb-1 mr-1"
>
{{ property.propertyName }}: {{ property.valueName }}
</el-tag>
</div>
<span v-else>-</span>
</template>
</el-table-column>
<el-table-column label="申请时间" align="center" prop="createTime" width="180">
<template #default="scope">
......
......@@ -83,25 +83,7 @@ getDetail()
<style scoped lang="scss">
.app-container {
padding-top: 100px;
}
.breadcrumb {
background-color: #FFFFFF;
border-bottom: 1px solid #EBEDED;
padding-top: 12px;
padding-bottom: 12px;
> div {
width: 1280px;
margin: 0 auto;
}
:deep(.el-breadcrumb__item) {
&:last-child .el-breadcrumb__inner {
color: #222222;
}
}
padding-top: 90px;
}
.block-title {
......
......@@ -213,7 +213,7 @@ function handleSolution(id) {
}
.app-container {
padding-top: 100px;
padding-top: 90px;
flex-grow: 1;
flex-shrink: 1;
position: relative;
......
......@@ -33,23 +33,6 @@ getInformationDetail()
</script>
<style scoped lang="scss">
.breadcrumb {
background-color: #FFFFFF;
padding-top: 12px;
padding-bottom: 12px;
> div {
width: 1280px;
margin: 0 auto;
}
:deep(.el-breadcrumb__item) {
&:last-child .el-breadcrumb__inner {
color: #222222;
}
}
}
.app-container {
background-color: #F7F8F9;
padding: 0 0 90px;
......
......@@ -59,23 +59,6 @@ getInformation()
min-height: 100%;
}
.breadcrumb {
background-color: #FFFFFF;
padding-top: 12px;
padding-bottom: 12px;
> div {
width: 1280px;
margin: 0 auto;
}
:deep(.el-breadcrumb__item) {
&:last-child .el-breadcrumb__inner {
color: #222222;
}
}
}
.form {
width: 1280px;
margin: 24px auto 24px auto;
......
......@@ -298,4 +298,8 @@ export default {
margin-top: 30px;
margin-bottom: 50px;
}
.app-container {
padding-top: 90px;
}
</style>
<template>
<div class="custom-wrapper detail-container">
<div class="com-breadcrumb-1">
<div class="custom-main-w">
<el-breadcrumb separator=">">
<el-breadcrumb-item :to="{ path: '/' }">首页</el-breadcrumb-item>
<el-breadcrumb-item :to="{ path: '/marketplace/ai' }"
>API服务市场</el-breadcrumb-item
>
<el-breadcrumb-item v-if="categoryName">{{
categoryName
}}</el-breadcrumb-item>
</el-breadcrumb>
</div>
</div>
<div class="app-container">
<div class="custom-main-w detail-content">
<!-- 左侧内容区 -->
......@@ -32,19 +19,30 @@
<h1 class="product-title">
{{ productData.name || "应用详情" }}
</h1>
<el-tag size="small" type="warning" effect="dark"
>官方自营</el-tag>
<!-- <el-tag size="small" type="warning" effect="dark"-->
<!-- >官方自营</el-tag>-->
</div>
<p class="product-desc">{{ productData.description }}</p>
<div class="product-tags">
<el-tag effect="plain" v-if="categoryName">{{
categoryName
<el-tag effect="plain" v-if="productData.categoryName">{{
productData.categoryName
}}</el-tag>
</div>
<div class="vendor-card">
<div class="vendor-tags">
<div class="vendor">API供应商:{{productData.vendor}}</div>
<div class="vendorContact">供应商联系方式:{{productData.vendorContact}}</div>
<div class="vendor-left">
<el-icon class="vendor-icon"><OfficeBuilding /></el-icon>
<span class="vendor-label">API供应商</span>
<span class="vendor-name">{{ productData.vendor || '—' }}</span>
</div>
<div class="vendor-right" v-if="productData.vendorContact">
<el-icon class="vendor-icon"><Phone /></el-icon>
<span class="vendor-label">联系方式</span>
<el-link class="vendor-contact-link" :underline="false" @click="handleContactClick(productData.vendorContact)">
{{ productData.vendorContact }}
</el-link>
<el-button link class="copy-btn" @click="copyContact(productData.vendorContact)">
复制
</el-button>
</div>
</div>
<div class="main-price-card">
......@@ -255,7 +253,7 @@
</template>
<script setup>
import { ref, computed, onMounted, watch } from "vue";
import { ref, computed, onMounted, onUnmounted, watch } from "vue";
import { useRouter, useRoute } from "vue-router";
import {
//getMerchantInfo,
......@@ -264,6 +262,7 @@ import {
getAppInfoDetail, createApiOrderSubmit,createPay
} from "../../api/marketplace";
import {ElMessage, ElMessageBox} from "element-plus";
import { OfficeBuilding, Phone } from '@element-plus/icons-vue'
import QRCode from "qrcode";
import {PayOrderStatusEnum} from "@/utils/constants.js";
import request from "@/utils/request.js";
......@@ -333,32 +332,37 @@ const productData = ref({
});
// 获取详情
const detailAbort = ref(null)
const fetchDetail = async () => {
const id = route.query.id || route.params?.id;
if (!id) return;
const res = await getAppInfoDetail({ id });
const d = res?.data;
if (!d) return;
productData.value = { ...productData.value, ...d };
//productData.value.appImage = withBaseUrl(productData.value.appImage);
specs.value = Array.isArray(d.apiPackages)
? d.apiPackages.map((p) => ({
id: p.id,
name: p.name,
price: p.price/100,
times: `${p.times}次`,
validDays: p.validDays,
unitPrice:
p.price && p.times ? (p.price/100 / p.times).toFixed(4) : "-",
}))
: [];
selectedSpec.value = specs.value.length ? 0 : -1;
try {
// 取消上一次未完成的请求,避免离开页面后回调运行
if (detailAbort.value) {
try { detailAbort.value.abort() } catch (e) {}
}
detailAbort.value = new AbortController()
const res = await getAppInfoDetail({ id }, { signal: detailAbort.value.signal });
const d = res?.data;
if (!d) return;
productData.value = { ...productData.value, ...d };
specs.value = Array.isArray(d.apiPackages)
? d.apiPackages.map((p) => ({
id: p.id,
name: p.name,
price: p.price/100,
times: `${p.times}次`,
validDays: p.validDays,
unitPrice: p.price && p.times ? (p.price/100 / p.times).toFixed(4) : "-",
}))
: [];
selectedSpec.value = specs.value.length ? 0 : -1;
} catch (e) {
// 静默捕获,避免控制台未捕获或噪声
}
//fetchRelatedApis();
};
......@@ -385,16 +389,19 @@ const fetchCategories = async () => {
const relatedApis = ref([]);
const fetchRelatedApis = async () => {
if (!productData.value.categoryId) return;
const res = await getAppRecommendList({
categoryId: productData.value.categoryId,
});
const list = Array.isArray(res?.data) ? res.data : [];
relatedApis.value = list.map((item) => ({
id: item.appId,
name: item.appName,
description: item.appIntro,
image: withBaseUrl(item.appImage),
}));
try {
const res = await getAppRecommendList({
categoryId: productData.value.categoryId,
});
const list = Array.isArray(res?.data) ? res.data : [];
relatedApis.value = list.map((item) => ({
id: item.appId,
name: item.appName,
description: item.appIntro,
image: withBaseUrl(item.appImage),
}));
} catch (e) {
}
};
onMounted(() => {
......@@ -403,6 +410,12 @@ onMounted(() => {
//fetchCategories();
});
onUnmounted(() => {
// 防止离开页面后仍在轮询导致未捕获异常
try { clearQueryInterval() } catch (e) {}
try { detailAbort.value && detailAbort.value.abort() } catch (e) {}
})
// 监听路由变化
watch(
() => route.query.id,
......@@ -455,6 +468,50 @@ const currentHtml = computed(() => {
});
// 联系方式点击与复制
function isUrl(v) {
return /^https?:\/\//i.test(v)
}
function isEmail(v) {
return /^[\w.+-]+@[\w.-]+\.[A-Za-z]{2,}$/i.test(v)
}
function isPhone(v) {
return /^\+?[\d\s-]{6,}$/.test(v)
}
function handleContactClick(v) {
const c = (v || '').trim()
if (!c) return
if (isUrl(c)) {
window.open(c, '_blank')
return
}
if (isEmail(c)) {
window.location.href = `mailto:${c}`
return
}
if (isPhone(c)) {
const tel = c.replace(/\s+/g, '')
window.location.href = `tel:${tel}`
return
}
copyContact(c)
ElMessage.success('已复制联系方式')
}
async function copyContact(text) {
try {
await navigator.clipboard.writeText(text)
ElMessage.success('已复制')
} catch (e) {
const ta = document.createElement('textarea')
ta.value = text
document.body.appendChild(ta)
ta.select()
document.execCommand('copy')
document.body.removeChild(ta)
ElMessage.success('已复制')
}
}
async function handleCheckProtocol() {
console.log('点击')
protocol.value = true
......@@ -548,27 +605,29 @@ const createQueryInterval = (id) => {
return
}
interval.value = setInterval(async () => {
const res = await getOrder(id)
console.log(res, 'res')
// 已支付
if (res.data.status === PayOrderStatusEnum.SUCCESS.status) {
clearQueryInterval()
// ElMessage.success('支付成功!')
ElMessageBox.confirm(
'支付成功',
'请前往控制台-我的订单查看',
{
confirmButtonText: '确认',
showCancelButton: false,
type: 'success'
}
).then(() => {
})
}
// 已取消
if (res.data.status === PayOrderStatusEnum.CLOSED.status) {
clearQueryInterval()
ElMessage.error('支付已关闭!')
try {
const res = await getOrder(id)
console.log(res, 'res')
// 已支付
if (res.data.status === PayOrderStatusEnum.SUCCESS.status) {
clearQueryInterval()
ElMessageBox.confirm(
'支付成功',
'请前往控制台-我的订单查看',
{
confirmButtonText: '确认',
showCancelButton: false,
type: 'success'
}
).then(() => {})
}
// 已取消
if (res.data.status === PayOrderStatusEnum.CLOSED.status) {
clearQueryInterval()
ElMessage.error('支付已关闭!')
}
} catch (e) {
// 静默捕获轮询异常
}
}, 1000 * 2)
}
......@@ -702,25 +761,49 @@ defineExpose({ goOrderConfirm });
.vendor-card {
display: flex;
align-items: baseline;
gap: 16px;
background: rgba(100, 255, 227, 0.1);
border-radius: 8px;
padding: 14px 24px;
font-weight: bold;
.vendor-tags{
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
gap: 12px 16px;
border: 1px solid #e9eef5;
background: #f8fbff;
border-radius: 10px;
padding: 12px 16px;
margin: 10px 0 16px;
.vendor-left,
.vendor-right {
display: flex;
flex-direction: column;
line-height: 1.2;
align-items: center;
gap: 8px;
}
.vendor {
font-size: 16px;
.vendor-icon {
color: var(--el-color-primary);
}
.vendor-label {
color: #666;
}
.vendorContact {
color: #666
.vendor-name {
font-weight: 600;
color: #303233;
}
.vendor-contact-link {
color: var(--el-color-primary);
max-width: 360px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.copy-btn {
margin-left: 4px;
}
@media (max-width: 768px) {
.vendor-left,
.vendor-right {
width: 100%;
justify-content: flex-start;
}
}
}
.main-price-card {
......@@ -1114,5 +1197,8 @@ defineExpose({ goOrderConfirm });
}
.app-container {
padding-top: 90px;
}
</style>
<template>
<div class="custom-wrapper order-confirm-container">
<div class="com-breadcrumb-1">
<div class="custom-main-w">
<el-breadcrumb separator=">">
</el-breadcrumb>
</div>
</div>
<div class="custom-main-w order-main">
<h2 class="order-title">确认订单</h2>
<div class="order-info-list">
......
......@@ -16,12 +16,12 @@
<li class="list-group-item">
<svg-icon icon-class="user"/>
用户名称
<div class="pull-right">{{ state.userName }}</div>
<div class="pull-right">{{ state.user.nickname }}</div>
</li>
<li class="list-group-item">
<svg-icon icon-class="phone"/>
手机号码
<div class="pull-right">{{ state.mobile}}</div>
<div class="pull-right">{{ state.user.mobile}}</div>
</li>
</ul>
</div>
......
<template>
<el-form ref="pwdRef" :model="user" :rules="rules" label-width="80px" style="width: 400px;height: 260px;">
<el-form-item label="旧密码" prop="oldPassword">
<el-input v-model="user.oldPassword" placeholder="请输入旧密码" type="password" show-password />
</el-form-item>
<el-form-item label="新密码" prop="newPassword">
<el-input v-model="user.newPassword" placeholder="请输入新密码" type="password" show-password />
</el-form-item>
<el-form-item label="确认密码" prop="confirmPassword">
<el-input v-model="user.confirmPassword" placeholder="请确认新密码" type="password" show-password/>
</el-form-item>
<el-form-item>
<el-form ref="pwdRef" :model="user" :rules="rules" label-width="140px" style="width: 500px;height: 260px;">
<el-form-item label="手机号码">
<el-input :model-value="props.user?.mobile" placeholder="请输入手机号码" type="text" disabled />
</el-form-item>
<el-form-item label="验证码" prop="code">
<el-input
v-model="user.code"
type="text"
size="large"
auto-complete="off"
placeholder="请输入短信验证码"
>
<template #append>
<el-button @click="startCountdown" :disabled="isCounting">
{{ isCounting ? `重新发送(${countdown})` : '发送验证码' }}
</el-button>
</template>
</el-input>
</el-form-item>
<el-form-item label="新密码" prop="newPassword">
<el-input v-model="user.newPassword" placeholder="请输入新密码" type="password" show-password />
</el-form-item>
<el-form-item label="确认密码" prop="confirmPassword">
<el-input v-model="user.confirmPassword" placeholder="请确认新密码" type="password" show-password />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submit">保存</el-button>
<!-- <el-button type="danger" @click="close">关闭</el-button>-->
</el-form-item>
</el-form>
<!-- <el-button type="danger" @click="close">关闭</el-button>-->
</el-form-item>
</el-form>
</template>
<script setup>
import { updateUserPwd } from "@/api/system/user";
import { updateUserPwdByCode } from "@/api/system/user";
import { sendCode } from "@/api/login.js";
import { ElMessage, ElMessageBox } from "element-plus";
import useUserStore from "@/store/modules/user.js";
const userStore = useUserStore();
const { proxy } = getCurrentInstance();
const props = defineProps({
user: {
type: Object
}
});
const user = reactive({
oldPassword: undefined,
code: "",
newPassword: undefined,
confirmPassword: undefined
});
const countdown = ref(60);
const isCounting = ref(false);
const pwdRef = ref(null);
const equalToPassword = (rule, value, callback) => {
if (user.newPassword !== value) {
callback(new Error("两次输入的密码不一致"));
......@@ -34,24 +63,74 @@ const equalToPassword = (rule, value, callback) => {
callback();
}
};
const rules = ref({
oldPassword: [{ required: true, message: "旧密码不能为空", trigger: "blur" }],
newPassword: [{ required: true, message: "新密码不能为空", trigger: "blur" }, { min: 6, max: 20, message: "长度在 6 到 20 个字符", trigger: "blur" }, { pattern: /^[^<>"'|\\]+$/, message: "不能包含非法字符:< > \" ' \\\ |", trigger: "blur" }],
confirmPassword: [{ required: true, message: "确认密码不能为空", trigger: "blur" }, { required: true, validator: equalToPassword, trigger: "blur" }]
code: [{ required: true, message: "验证码不能为空", trigger: "blur" }],
newPassword: [
{ required: true, message: "新密码不能为空", trigger: "blur" },
{ min: 6, max: 20, message: "长度在 6 到 20 个字符", trigger: "blur" },
{ pattern: /^[^<>\"'|\\\\]+$/, message: "不能包含非法字符:< > \\\" ' \\\\ |", trigger: "blur" }
],
confirmPassword: [
{ required: true, message: "确认密码不能为空", trigger: "blur" },
{ required: true, validator: equalToPassword, trigger: "blur" }
]
});
function getCode() {
const mobile = props.user?.mobile;
if (!mobile) {
ElMessage({ message: "未获取到手机号", type: "warning" });
return;
}
// 场景: 会员用户 - 修改密码 -> scene = 3
sendCode({ mobile, scene: 3 }).then((res) => {
if (res.data === true) {
ElMessage({ message: "短信已发送请注意查收", type: "success" });
}
});
}
const startCountdown = () => {
if (isCounting.value) return;
getCode();
isCounting.value = true;
const timer = setInterval(() => {
if (countdown.value > 0) {
countdown.value--;
} else {
clearInterval(timer);
isCounting.value = false;
countdown.value = 60;
}
}, 1000);
};
/** 提交按钮 */
function submit() {
proxy.$refs.pwdRef.validate(valid => {
proxy.$refs.pwdRef.validate((valid) => {
if (valid) {
updateUserPwd(user.oldPassword, user.newPassword).then(response => {
proxy.$modal.msgSuccess("修改成功");
updateUserPwdByCode({ code: user.code, password: user.newPassword }).then((res) => {
if (res.code === 0 && res.data) {
ElMessageBox.confirm("修改成功,请重新登录", "提示", {
confirmButtonText: "确认",
showCancelButton: false,
showClose: false,
type: "warning"
}).then(() => {
userStore.logOut().then(() => {
location.href = "/index";
});
});
}
});
}
});
};
}
/** 关闭按钮 */
function close() {
proxy.$tab.closePage();
};
}
</script>
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 sign in to comment