Compare commits

...

12 Commits

Author SHA1 Message Date
xyc
3f715f361b 更新 2025-06-19 15:28:27 +08:00
xyc
827ff4994b Merge remote-tracking branch 'origin/master' 2025-06-19 09:28:20 +08:00
Lx
beeeb64328 Merge branch 'driver' 2025-06-18 17:56:39 +08:00
xyc
e5c6e235ae 更新 2025-06-18 17:49:21 +08:00
xyc
f3e72ea43c Merge branch 'driver' 2025-06-13 17:10:08 +08:00
xyc
8ebefd730e Merge branch 'insp' 2025-06-13 17:10:01 +08:00
xyc
6afa9dc6f4 更新 2025-06-13 17:08:45 +08:00
xyc
53aec3b076 Merge branch 'driver' 2025-06-06 17:40:18 +08:00
xyc
a791972a84 Merge branch 'driver' 2025-05-28 17:44:00 +08:00
xyc
a11039d4d1 更新 2025-05-27 17:55:21 +08:00
xyc
6d627d6908 Merge branch 'master' into insp 2025-05-19 13:34:04 +08:00
xyc
6a867c07e6 更新 2025-05-19 13:21:28 +08:00
10 changed files with 651 additions and 25 deletions

View File

@ -150,8 +150,10 @@ export class socialBindLogin {
export function getUserTenant(data) {
return request({
url: '/system/auth/getTenant',
method: 'post',
data: data
url: '/system/auth/getListByPhone',
method: 'get',
params: {
phone: data
}
})
}

View File

@ -0,0 +1,206 @@
<template>
<div class="tenant-selector">
<!-- 添加返回按钮 -->
<div class="back-button" @click="handleBack">
<i class="el-icon-arrow-left"></i> 返回
</div>
<div class="login-header">
<h2>选择租户登录</h2>
<p>请选择您要登录的租户</p>
</div>
<div class="tenant-list">
<div
v-for="tenant in tenants"
:key="tenant.id"
class="tenant-item"
:class="{ 'active': selectedTenant === tenant.id }"
@click="selectTenant(tenant)"
>
<div class="tenant-avatar">
{{ tenant.name.charAt(0).toUpperCase() }}
</div>
<div class="tenant-info">
<h3>{{ tenant.name }}</h3>
<p>{{ tenant.description || '暂无描述' }}</p>
</div>
</div>
</div>
<div class="login-actions">
<button
class="login-btn"
:disabled="!selectedTenant"
@click="confirmLogin"
>
确认登录
</button>
</div>
</div>
</template>
<script>
export default {
props: {
tenants: {
type: Array,
required: true,
default: () => []
}
},
data() {
return {
selectedTenant: null
}
},
methods: {
selectTenant(tenant) {
this.selectedTenant = tenant.id;
},
confirmLogin() {
if (this.selectedTenant) {
this.$emit('tenant-selected', this.selectedTenant);
}
},
handleBack() {
this.$emit('back');
}
}
}
</script>
<style scoped>
.tenant-selector {
max-width: 400px;
margin: 0 auto;
padding: 20px;
background: #fff;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
.login-header {
text-align: center;
margin-bottom: 24px;
}
.login-header h2 {
font-size: 20px;
color: #333;
margin-bottom: 8px;
}
.login-header p {
font-size: 14px;
color: #999;
}
.tenant-list {
margin-bottom: 24px;
}
.tenant-item {
display: flex;
align-items: center;
padding: 12px 16px;
border: 1px solid #eaeaea;
border-radius: 6px;
margin-bottom: 12px;
cursor: pointer;
transition: all 0.3s;
}
.tenant-item:hover {
border-color: #1890ff;
}
.tenant-item.active {
border-color: #1890ff;
background-color: #f0f7ff;
}
.tenant-avatar {
width: 40px;
height: 40px;
line-height: 40px;
text-align: center;
background-color: #1890ff;
color: white;
border-radius: 50%;
margin-right: 12px;
font-weight: bold;
}
.tenant-info h3 {
font-size: 16px;
color: #333;
margin-bottom: 4px;
}
.tenant-info p {
font-size: 12px;
color: #999;
}
.login-actions {
text-align: center;
}
.login-btn {
width: 100%;
height: 40px;
background-color: #1890ff;
color: white;
border: none;
border-radius: 4px;
font-size: 14px;
cursor: pointer;
transition: background-color 0.3s;
}
.login-btn:hover {
background-color: #40a9ff;
}
.login-btn:disabled {
background-color: #d9d9d9;
cursor: not-allowed;
}
.tenant-selector {
max-width: 500px;
margin: 0 auto;
padding: 20px;
background: #fff;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
position: relative;
}
.back-button {
position: absolute;
top: 20px;
left: 20px;
color: #1890ff;
cursor: pointer;
font-size: 14px;
display: flex;
align-items: center;
}
.back-button:hover {
color: #40a9ff;
}
.back-button i {
margin-right: 4px;
}
.login-header {
text-align: center;
margin-bottom: 24px;
padding-top: 10px; /* 为返回按钮留出空间 */
}
</style>

View File

@ -0,0 +1,52 @@
import request from '@/utils/request'
// 查询菜单列表
export function listBusiness(query) {
return request({
url: '/channel/tree',
method: 'get',
params: query
})
}
// 查询菜单(精简)列表
export function listSimpleMenus() {
return request({
url: '/system/menu/list-all-simple',
method: 'get'
})
}
// 查询菜单详细
export function getBusiness(id) {
return request({
url: '/channel/' + id,
method: 'get'
})
}
// 新增菜单
export function addBusiness(data) {
return request({
url: '/channel/add',
method: 'post',
data: data
})
}
// 修改菜单
export function updateBusiness(data) {
return request({
url: '/channel/update',
method: 'put',
data: data
})
}
// 删除菜单
export function delBusiness(id) {
return request({
url: '/channel/delete/' + id,
method: 'delete'
})
}

View File

@ -0,0 +1,303 @@
<template>
<div class="app-container">
<doc-alert title="功能权限" url="https://doc.iocoder.cn/resource-permission"/>
<doc-alert title="菜单路由" url="https://doc.iocoder.cn/vue2/route/"/>
<!-- 搜索工作栏 -->
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch">
<el-form-item label="菜单名称" prop="name">
<el-input v-model="queryParams.name" placeholder="请输入菜单名称" clearable @keyup.enter.native="handleQuery"/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd">新增
</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="info" plain icon="el-icon-sort" size="mini" @click="toggleExpandAll">展开/折叠</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-if="refreshTable" v-loading="loading" :data="menuList" row-key="id" :default-expand-all="isExpandAll"
:tree-props="{children: 'children', hasChildren: 'hasChildren'}">
<el-table-column prop="name" label="名称" :show-overflow-tooltip="true" width="250"></el-table-column>
<el-table-column prop="type" label="类型" width="100">
<template v-slot="scope">
<span>
{{ scope.row.type === 0 ? '业务渠道' : scope.row.type === 1 ? '客户来源' : '未知类型' }}
</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template v-slot="scope">
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)">修改
</el-button>
<el-button size="mini" v-if="scope.row.pid == 0" type="text" icon="el-icon-plus"
@click="handleAdd(scope.row)">新增
</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)">删除
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 添加或修改菜单对话框 -->
<el-dialog :title="title" :visible.sync="open" width="800px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="100px">
<el-row>
<!-- <el-col :span="24">-->
<!-- <el-form-item label="上级菜单">-->
<!-- <treeselect v-model="form.pid" :options="menuOptions" :normalizer="normalizer" :show-count="true"-->
<!-- placeholder="选择上级菜单"/>-->
<!-- </el-form-item>-->
<!-- </el-col>-->
<el-col :span="12">
<el-form-item label="名称" prop="name">
<el-input v-model="form.name" placeholder="请输入名称"/>
</el-form-item>
</el-col>
<el-col :span="12" v-if="form.pid != 0">
<el-form-item label="人员" prop="postId">
<el-select multiple filterable v-model="form.userIdList" placeholder="请选择人员">
<el-option v-for="item in staffList" :key="item.id" :label="item.nickname" :value="item.id"/>
</el-select>
</el-form-item>
</el-col>
</el-row>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import {listMenu, getMenu, delMenu, addMenu, updateMenu} from "@/api/system/menu";
import Treeselect from "@riophae/vue-treeselect";
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
import IconSelect from "@/components/IconSelect";
import {SystemMenuTypeEnum, CommonStatusEnum} from '@/utils/constants'
import {getDictDatas, DICT_TYPE} from '@/utils/dict'
import {isExternal} from "@/utils/validate";
import {
addBusiness,
delBusiness,
getBusiness,
listBusiness,
updateBusiness
} from "@/views/inspection/businessChannel/api";
import {listUser} from "@/views/inspection/staff/api/staff";
export default {
name: "BusinessChannel",
components: {Treeselect, IconSelect},
data() {
return {
//
loading: true,
//
showSearch: true,
//
menuList: [],
staffList: [],
//
menuOptions: [],
//
title: "",
//
open: false,
//
isExpandAll: false,
//
refreshTable: true,
//
queryParams: {
name: undefined,
visible: undefined
},
//
form: {},
//
rules: {
name: [
{required: true, message: "菜单名称不能为空", trigger: "blur"}
],
sort: [
{required: true, message: "菜单顺序不能为空", trigger: "blur"}
],
path: [
{required: true, message: "路由地址不能为空", trigger: "blur"}
],
status: [
{required: true, message: "状态不能为空", trigger: "blur"}
]
},
//
MenuTypeEnum: SystemMenuTypeEnum,
CommonStatusEnum: CommonStatusEnum,
//
menuTypeDictDatas: getDictDatas(DICT_TYPE.SYSTEM_MENU_TYPE),
statusDictDatas: getDictDatas("ins_business")
};
},
created() {
this.getList();
this.getStaff();
},
methods: {
//
selected(name) {
this.form.icon = name;
},
/** 查询菜单列表 */
getList() {
this.loading = true;
listBusiness(this.queryParams).then(response => {
this.menuList = this.handleTree(response.data, "id", "pid");
this.loading = false;
});
},
getStaff() {
const params = {
pageNo: 1,
pageSize: 99999
}
listUser(params).then(response => {
this.staffList = response.data.records;
});
},
/** 转换菜单数据结构 */
normalizer(node) {
if (node.children && !node.children.length) {
delete node.children;
}
return {
id: node.id,
label: node.name,
children: node.children
};
},
/** 查询菜单下拉树结构 */
getTreeselect() {
listBusiness().then(response => {
this.menuOptions = [];
const menu = {id: 0, name: '主类目', children: []};
if (!Array.isArray(response.data)) {
console.warn("handleTree error: data 不是数组", response.data);
return;
}
if (response.data.length === 0) {
console.warn("handleTree warning: data 是空数组");
return;
}
// data
debugger
menu.children = this.handleTree(response.data, "id", 'pid');
this.menuOptions.push(menu);
});
},
//
cancel() {
this.open = false;
this.reset();
},
//
reset() {
this.form = {
id: undefined,
pid: 0,
name: undefined,
type: undefined,
};
this.resetForm("form");
},
/** 搜索按钮操作 */
handleQuery() {
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm");
this.handleQuery();
},
/** 展开/折叠操作 */
toggleExpandAll() {
this.refreshTable = false;
this.isExpandAll = !this.isExpandAll;
this.$nextTick(() => {
this.refreshTable = true;
});
},
/** 新增按钮操作 */
handleAdd(row) {
this.reset();
this.getTreeselect();
if (row != null && row.id) {
this.form.pid = row.id;
this.form.type = 1;
this.title = "添加客户来源";
} else {
this.form.pid = 0;
this.form.type = 0;
this.title = "添加业务渠道";
}
this.open = true;
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset();
this.getTreeselect();
getBusiness(row.id).then(response => {
this.form = response.data;
this.open = true;
this.title = "修改";
});
},
/** 提交按钮 */
submitForm: function () {
this.$refs["form"].validate(valid => {
if (valid) {
//
if (this.form.id !== undefined) {
updateBusiness(this.form).then(response => {
this.$modal.msgSuccess("修改成功");
this.open = false;
this.getList();
});
} else {
addBusiness(this.form).then(response => {
this.$modal.msgSuccess("新增成功");
this.open = false;
this.getList();
});
}
}
});
},
/** 删除按钮操作 */
handleDelete(row) {
this.$modal.confirm('是否确认删除名称为"' + row.name + '"的数据项?').then(function () {
return delBusiness(row.id);
}).then(() => {
this.getList();
this.$modal.msgSuccess("删除成功");
}).catch(() => {
});
}
}
};
</script>

View File

@ -70,7 +70,7 @@ export function updateUser(data) {
// 删除用户
export function delUser(userId) {
return request({
url: '/system/user/delete?id=' + userId,
url: '/inspectionStaff/delete?id=' + userId,
method: 'delete'
})
}

View File

@ -571,10 +571,10 @@ export default {
if (!this.form.folderId) {
addFolder(this.form.id).then(response => {
this.form.folderId = response.data
this.$router.push({path: '/jc/shop/partner/file/file', query: {"folderId": this.form.folderId}})
this.$router.push({path: '/jc/shop/nbgl/partner/file/file', query: {"folderId": this.form.folderId}})
})
} else {
this.$router.push({path: '/jc/shop/partner/file/file', query: {"folderId": this.form.folderId}})
this.$router.push({path: '/jc/shop/nbgl/partner/file/file', query: {"folderId": this.form.folderId}})
}
},
//

View File

@ -2,7 +2,7 @@
<div class="container">
<!-- <div class="logo"></div>-->
<!-- 登录区域 -->
<div class="content">
<div class="content" v-show="!showTenantList">
<!-- 配图 -->
<div class="pic"></div>
<!-- 表单 -->
@ -13,7 +13,7 @@
</h2>
<!-- 表单 -->
<div class="form-cont">
<div class="form-cont" >
<el-tabs class="form" v-model="loginForm.loginType" style=" float:none;">
<el-tab-pane label="账号密码登录" name="uname">
</el-tab-pane>
@ -94,13 +94,35 @@
</el-form>
</div>
</div>
</div>
</div>
<div v-if="showTenantList" style="width: 500px; position: relative;">
<tenant-select
:tenants="tenantList"
@tenant-selected="selectTenant"
@back="showTenantList = false"
></tenant-select>
</div>
<!-- <el-dialog-->
<!-- title="提示"-->
<!-- :visible.sync="showTenantList"-->
<!-- width="30%">-->
<!-- <el-radio-group v-model="tenant">-->
<!-- <el-radio-button :label="item" v-for="item in tenantList">{{item.name}}</el-radio-button>-->
<!-- </el-radio-group>-->
<!-- <span slot="footer" class="dialog-footer">-->
<!-- <el-button @click="showTenantList = false"> </el-button>-->
<!-- <el-button type="primary" @click="selectTenant"> </el-button>-->
<!-- </span>-->
<!-- </el-dialog>-->
<!-- 图形验证码 -->
<Verify ref="verify" :captcha-type="'blockPuzzle'" :img-size="{width:'400px',height:'200px'}"
@success="handleLogin" />
<!-- footer -->
<div class="footer">
<!-- Copyright © 2020-2022 iocoder.cn All Rights Reserved.-->
@ -124,18 +146,22 @@ import {
} from "@/utils/auth";
import Verify from '@/components/Verifition/Verify';
import TenantSelect from "@/components/tenantSelect/tenantSelect.vue";
import {resetUserPwd} from "@/api/system/user";
export default {
name: "Login",
components: {
Verify
Verify,
TenantSelect
},
data() {
return {
// tenantCode:"lighting",
tenantCode:"lanan",
codeUrl: "",
showTenantList:false,
tenant:undefined,
//
captchaEnable: false,
tenantEnable: true,
@ -150,6 +176,7 @@ export default {
rememberMe: false,
tenantName: "租户管理员",
},
tenantList:[],
scene: 21,
LoginRules: {
@ -221,7 +248,8 @@ export default {
getCode() {
//
if (!this.captchaEnable) {
this.handleLogin({})
// this.handleLogin({})
this.getTenantList()
return;
}
@ -242,7 +270,17 @@ export default {
tenantName: tenantName ? tenantName : this.loginForm.tenantName,
};
},
selectTenant(tenant){
this.tenant = tenant
if (!this.tenant) {
this.$message.error("请选择租户")
}
console.log('当前租户',this.tenant)
setTenantId(this.tenant)
this.handleLogin()
},
handleLogin(captchaParams) {
//
this.$refs.loginForm.validate(async valid => {
console.log("登录", this.loginForm)
if (valid) {
@ -259,12 +297,11 @@ export default {
removeRememberMe()
removeTenantName()
}
this.loginForm.captchaVerification = captchaParams.captchaVerification
if (captchaParams){
this.loginForm.captchaVerification = captchaParams.captchaVerification
}
//
await getUserTenant(this.loginForm).then(res => {
console.log('当前登陆人信息', res)
setTenantId(res.data.tenant_id)
});
//
// console.log("", this.loginForm);
this.$store.dispatch(this.loginForm.loginType === "sms" ? "SmsLogin" : "Login", this.loginForm).then(() => {
@ -272,10 +309,19 @@ export default {
});
}).catch(() => {
this.loading = false;
this.showTenantList = false
});
}
});
},
async getTenantList(){
await getUserTenant(this.loginForm.username).then(res => {
console.log('当前登陆人信息', res)
// setTenantId(res.data.tenant_id)
this.tenantList = res.data
});
this.showTenantList = true
},
async doSocialLogin(socialTypeEnum) {
//
this.loading = true;

View File

@ -409,7 +409,7 @@
this.$set(this.dict.type,this.$options.dicts[i],res.data)
})
}
this.getpid()
this.getList();
this.customerSource();
},
methods: {

View File

@ -76,7 +76,7 @@
</div>
<div class="bjandshanchu">
<div class="one" @click="handleE(item)">编辑</div>
<!-- <div class="two" v-if="item.type == '2'" @click="downloadFile(item)">下载</div>-->
<div class="two" v-if="item.type == '2'" @click="downloadFile(item)">下载</div>
<div class="two" v-if="item.type == '2'" @click="preview(item)">预览</div>
<div class="two" @click="clickStaff(item.id)" v-hasPermi="['inspectionFile:inspectionFilePermis:edit']">
分配权限
@ -175,6 +175,7 @@
<template #description>
<div class="step-content">
<div class="step-file-name">文件名称{{ item.fileName }}</div>
<div class="step-time">修改人{{ item.nickname }}</div>
<div class="step-time">修改时间{{ formatDate(item.createTime) }}</div>
<div class="step-time">提醒时间{{ formatDate(item.warnTime) }}</div>
<div class="step-download" @click="downloadFile(item)" v-if="item.type == '2'">📂 下载历史文件</div>
@ -337,18 +338,23 @@ export default {
number: 0,
uploadList: [],
totalUploadCount: 0,
servicePackageId: "jiance",
dictType:"ins_file_role",
//
queryParams: {
pageNum: 1,
pageSize: 10,
servicePackageId: "jiance",
type: null,
fatherId: null,
dictType: 'ins_file_role'
},
fatherId: '',
oldFatherId: '',
//
form: {},
form: {servicePackageId: this.servicePackageId},
isShowFile: false,
//
rules: {
fileList: [
@ -421,6 +427,8 @@ export default {
this.queryParams.pageNum = 1
const data = {
fatherId: this.fatherId,
servicePackageId: this.servicePackageId,
dictType: this.dictType,
fileName: this.fatherId === '' || this.fatherId == null || this.fatherId === undefined ? this.queryParams.fileName : ''
}
this.getFolderList(data)
@ -451,7 +459,10 @@ export default {
handleFileClick(row) {
if (row.type === '2') {
// this.fileUrl = 'https://view.xdocin.com/view?src=' + this.imageUrl + row.filePath
this.fileUrl = 'https://view.officeapps.live.com/op/view.aspx?src=' + this.imageUrl + row.filePath
this.fileUrl = 'https://view.officeapps.live.com/op/view.aspx?src=' +
(row.filePath.includes('http')
? this.inspectionFileUrl + row.filePath.replace(/^.*?uploads\//, 'uploads/')
: this.previewUrl + row.filePath);
this.$nextTick(() => {
// this.$refs.filePreview.show()
this.selectFile = row
@ -530,7 +541,9 @@ export default {
const data = {
pageNum: 1,
pageSize: 10,
fatherId: id
fatherId: id,
servicePackageId: this.servicePackageId,
dictType: this.dictType
}
this.getFolderList(data)
},
@ -592,7 +605,8 @@ export default {
createTime: null,
createBy: null,
updateTime: null,
updateBy: null
updateBy: null,
servicePackageId: this.servicePackageId
};
this.resetForm("form");
},
@ -650,14 +664,14 @@ export default {
this.title = "修改";
console.log(item)
//itemiditemid
this.folderList = this.disableIfExistsInTree(this.folderList, item.id)
this.folderList = this.disableIfExistsInTree(this.folderList, item.id)
},
disableIfExistsInTree(treeData, targetId) {
console.log(treeData, targetId, '执行');
function traverse(nodes, parentDisabled = false) {
return nodes.map(node => {
let newNode = { ...node };
let newNode = {...node};
//
if (newNode.children && newNode.children.length > 0) {
@ -723,6 +737,7 @@ export default {
item.fileName = this.getFileNameWithoutExtension(item.name)
item.filePath = item.url
item.warnTime = this.form.warnTime
item.servicePackageId = "jiance"
})
addBatchInspectionFile(this.fileList).then(res => {
this.$modal.msgSuccess("新增成功");

View File

@ -26,7 +26,7 @@
</el-form-item>
<el-form-item label="角色" prop="status">
<el-select v-model="queryParams.roleId" placeholder="角色" clearable style="width: 240px">
<el-option v-for="dict in dict.type.inspection_use_role.slice(0, 3)" :key="dict.value" :label="dict.label"
<el-option v-for="dict in dict.type.inspection_use_role" :key="dict.value" :label="dict.label"
:value="dict.value" />
</el-select>
</el-form-item>
@ -463,7 +463,8 @@ export default {
this.$set(this.dict.type, this.$options.dicts[i], res.data)
})
}
this.getpid()
// this.getpid()
this.getList();
this.customerSource();
},
methods: {
@ -640,6 +641,7 @@ export default {
this.BankAccountList.push(temp)
})
})
this.loading = false;
},
//
cancel() {