This commit is contained in:
那些花儿
2025-09-05 15:15:11 +08:00
parent 23885590c5
commit a72c01358a
13 changed files with 1719 additions and 60 deletions
@@ -0,0 +1,331 @@
const apps = {
template: /*language=HTML*/ `
<div class="apps-container">
<van-nav-bar title="代表阅览" placeholder fixed></van-nav-bar>
<!-- 搜索栏 -->
<van-sticky offset-top="46px">
<van-search
v-model="searchKeyword"
placeholder="搜索应用"
show-action
@search="onSearch"
@cancel="onCancel"
></van-search>
</van-sticky>
<!-- 使用TreeSelect组件 -->
<van-tree-select
:items="treeSelectItems"
:main-active-index.sync="activeTab"
@click-nav="onClickNav"
>
<template #content>
<!-- 应用列表 -->
<div class="app-list" v-if="applications.length > 0">
<div
v-for="app in applications"
:key="app.id"
class="app-item"
@click="openApp(app)"
>
<div class="app-icon">
<van-image
v-if="app.picIcon"
:src="app.picIcon"
fit="cover"
width="40"
height="40"
radius="4"
></van-image>
<van-icon v-else-if="app.icon" :name="app.icon" size="24"></van-icon>
<van-icon v-else name="apps-o" size="24"></van-icon>
</div>
<div class="app-info">
<div class="app-title">{{ app.name }}</div>
<div class="app-desc" v-if="app.department">{{ app.department }}</div>
</div>
<div class="app-action">
<van-icon
:name="app.isFavorite ? 'star' : 'star-o'"
:class="['favorite-icon', app.isFavorite ? 'active' : '']"
@click.stop="toggleFavorite(app.id)"
/>
</div>
</div>
</div>
<!-- 空状态 -->
<van-empty v-else description="暂无应用"></van-empty>
</template>
</van-tree-select>
</div>
`,
data() {
return {
// 应用列表
applications: [],
// 固定分类列表
categories: [
{id: "all", name: "全部应用", icon: "apps-o"},
{id: "favorites", name: "我的收藏", icon: "star-o"},
{id: "recommended", name: "推荐应用", icon: "like-o"}
],
// 动态加载的分类
dynamicCategories: [],
// 当前选中的分类索引
activeTab: 0,
// 搜索关键词
searchKeyword: "",
// 列表相关
loading: true
}
},
computed: {
// 所有分类(固定分类 + 动态分类)
allCategories() {
return [...this.categories, ...this.dynamicCategories]
},
// 当前选中的分类ID
currentCategoryId() {
return this.allCategories[this.activeTab]?.id || "all"
},
// TreeSelect组件所需的数据格式
treeSelectItems() {
return this.allCategories.map(category => ({
text: category.name,
className: 'category-item'
}))
}
},
mounted() {
// 页面加载时获取分类和应用数据
this.loadCategories()
this.loadApps()
},
methods: {
// 加载分类数据
loadCategories() {
$.get("/platform/v4/apps/categories", {platform: "H5"})
.then((result) => {
if (result.code === 0) {
this.dynamicCategories = result.data || []
} else {
console.error("获取应用分类失败:", result.msg)
}
})
.fail((error) => {
console.error("获取应用分类异常:", error)
})
},
// 加载应用数据
loadApps() {
this.loading = true
// 构建请求参数
const params = {
categoryId:
this.currentCategoryId === "all"
? ""
: this.currentCategoryId,
keyword: this.searchKeyword,
platform: "H5"
}
// 将参数转换为URL查询参数
const queryString = Object.keys(params)
.filter((key) => params[key] !== null && params[key] !== undefined && params[key] !== "")
.map((key) => encodeURIComponent(key) + "=" + encodeURIComponent(params[key]))
.join("&")
// 如果是"我的收藏"分类
if (this.currentCategoryId === "favorites") {
this.loadFavorites()
return
}
// 如果是"推荐应用"分类
if (this.currentCategoryId === "recommended") {
$.get("/platform/v4/apps/recommended")
.then((result) => {
if (result.code === 0) {
this.applications = result.data.list || []
} else {
console.error("获取推荐应用失败:", result.msg)
}
this.loading = false
})
.fail((error) => {
console.error("获取推荐应用异常:", error)
this.loading = false
})
return
}
// 发送请求获取普通应用列表
$.get("/platform/v4/apps/list?" + queryString)
.then((result) => {
if (result.code === 0) {
this.applications = result.data || []
} else {
console.error("获取应用列表失败:", result.msg)
}
this.loading = false
})
.fail((error) => {
console.error("获取应用列表异常:", error)
this.loading = false
})
},
// 加载收藏的应用
loadFavorites() {
$.get("/platform/v4/apps/favorite")
.then((result) => {
if (result.code === 0) {
this.applications = result.data || []
} else {
console.error("获取收藏应用失败:", result.msg)
}
this.loading = false
})
.fail((error) => {
console.error("获取收藏应用异常:", error)
this.loading = false
})
},
// 切换应用收藏状态
toggleFavorite(appId) {
const app = this.applications.find((a) => a.id === appId)
if (!app) return
const url = app.isFavorite ? "/platform/v4/apps/removeFavorite" : "/platform/v4/apps/addFavorite"
const params = {appId: appId}
$.post(url, params)
.then((result) => {
if (result.code === 0) {
app.isFavorite = !app.isFavorite
this.$toast(app.isFavorite ? "收藏成功" : "取消收藏成功")
} else {
console.error(app.isFavorite ? "取消收藏失败:" : "收藏失败:", result.msg)
}
})
.fail((error) => {
console.error(app.isFavorite ? "取消收藏异常:" : "收藏异常:", error)
})
},
// 搜索
onSearch() {
this.applications = []
this.loadApps()
},
// 取消搜索
onCancel() {
this.searchKeyword = ""
this.onSearch()
},
// 切换标签页 - TreeSelect导航点击事件
onClickNav(index) {
this.activeTab = index
this.applications = []
this.loadApps()
},
// 打开应用
openApp(app) {
// 储存到缓存
window.sessionStorage.setItem("zhgh_sub_app", JSON.stringify(app))
// 新标签页打开
window.open("/platform/v4/subApp?appId=" + app.id, "_blank")
}
},
style: /*language=CSS*/ `
.apps-container {
display: flex;
flex-direction: column;
height: 100%;
}
.van-tree-select {
height: calc(100vh - 150px) !important;
}
.van-tree-select__nav {
flex: 0 0 90px;
}
.van-tree-select__content {
padding: 0;
}
.category-item {
font-size: 14px;
}
.app-list {
flex: 1;
overflow-y: auto;
}
.app-item {
display: flex;
align-items: center;
padding: 12px 16px;
background-color: #fff;
margin-bottom: 1px;
position: relative;
}
.app-icon {
width: 40px;
height: 40px;
border-radius: 4px;
background-color: #f2f3f5;
display: flex;
align-items: center;
justify-content: center;
margin-right: 12px;
overflow: hidden;
}
.app-info {
flex: 1;
}
.app-title {
font-size: 16px;
font-weight: 500;
margin-bottom: 4px;
color: #323233;
}
.app-desc {
font-size: 12px;
color: #969799;
}
.app-action {
padding: 0 8px;
}
.favorite-icon {
font-size: 20px;
color: #c8c9cc;
}
.favorite-icon.active {
color: #ff9800;
}
.loading-container {
padding: 20px 0;
text-align: center;
}
`
}
@@ -6,14 +6,18 @@ layout("/layouts/platform_h5.html"){
<div>
<div>
<home v-if="homeTabbarActive === 'home'" @module-click="moduleClick"></home>
<todo v-if="homeTabbarActive === 'todo'"></todo>
<work v-if="homeTabbarActive === 'work'"></work>
<mine v-if="homeTabbarActive === 'mine'"></mine>
<apps v-if="homeTabbarActive === 'apps'"></apps>
</div>
<div id="page-tarbar" class="page-tarbar">
<van-tabbar v-model="homeTabbarActive" @change="homeTabbarChange">
<van-tabbar-item name="home" icon="wap-home-o">首页</van-tabbar-item>
<van-tabbar-item name="apps" icon="gem">应用</van-tabbar-item>
<van-tabbar-item name="work" icon="gem">工作台</van-tabbar-item>
<van-tabbar-item name="todo" icon="gem">待办</van-tabbar-item>
<van-tabbar-item name="mine" icon="user-o">我的</van-tabbar-item>
</van-tabbar>
</div>
@@ -24,13 +28,17 @@ layout("/layouts/platform_h5.html"){
<!--#include("home.js"){}#-->
<!--#include("work.js"){}#-->
<!--#include("mine.js"){}#-->
<!--#include("todo.js"){}#-->
<!--#include("apps.js"){}#-->
new Vue({
el: "#app",
store,
components: {
home,
mine,
work
work,
todo,
apps
},
data() {
return {
@@ -0,0 +1,359 @@
const todo = {
template: /*language=HTML*/ `
<div class="task-center">
<van-nav-bar title="待办中心" placeholder fixed></van-nav-bar>
<!-- 标签页 -->
<van-sticky offset-top="46px">
<van-tabs v-model="activeTab" @change="handleTabChange" animated swipeable>
<van-tab title="待办" name="todo"></van-tab>
<van-tab title="已办" name="done"></van-tab>
<van-tab title="我发起的" name="started"></van-tab>
</van-tabs>
<!-- 搜索筛选区域 -->
<div class="filter-section">
<div>
<div class="search-form">
<van-search v-model="pageForm.searchKeyword" placeholder="请输入搜索关键词"></van-search>
</div>
<!-- <van-field-->
<!-- readonly-->
<!-- clickable-->
<!-- :value="categoryLabel"-->
<!-- placeholder="选择流程分类"-->
<!-- class="category-select"-->
<!-- @click="showCategoryPicker = true"-->
<!-- ></van-field>-->
</div>
<van-popup v-model="showCategoryPicker" round position="bottom">
<van-picker
show-toolbar
:columns="categoryOptions"
value-key="name"
@confirm="onCategoryConfirm"
@cancel="showCategoryPicker = false"
></van-picker>
</van-popup>
</div>
</van-sticky>
<!-- 任务列表区域 -->
<van-pull-refresh v-model="refreshing" @refresh="onRefresh">
<van-list
v-model="loading"
:finished="finished"
finished-text="没有更多了"
@load="getTasks"
>
<div v-if="tasks.length > 0" class="task-list">
<div
v-for="task in tasks"
:key="task.taskId"
class="task-item"
>
<div class="task-content">
<div class="task-title">{{task.variable?.instanceName || '无标题流程'}}</div>
<div class="task-info">
<span class="task-info-label">任务节点:</span>
<span class="task-info-value">{{task.taskName}}</span>
</div>
<div class="task-info">
<span class="task-info-label">流程分类:</span>
<span class="task-info-value">
{{categoryOptions.find(item => item.id === task.category)?.name || '未知分类'}}
</span>
</div>
<div class="task-info">
<span class="task-info-label">申请人:</span>
<span class="task-info-value">{{task.variable?.initiatorName || '未知'}}</span>
</div>
<div class="task-info" v-if="activeTab === 'started'">
<span class="task-info-label">状态:</span>
<span class="task-info-value">
{{processStatusMap[task.state]?.text || '未知状态'}}
</span>
</div>
<div class="task-footer">
<van-button
type="primary"
size="mini"
@click="openView(task)"
>查看
</van-button>
</div>
</div>
</div>
</div>
<div v-else class="empty-section">
<van-empty :description="getEmptyText()"/>
</div>
</van-list>
</van-pull-refresh>
</div>
`,
data() {
return {
// 统计数据
todoCount: 0,
doneCount: 0,
startedCount: 0,
// 查询表单
pageForm: {
pageNumber: 1,
pageSize: 10,
totalCount: 0,
searchKeyword: "",
category: ""
},
// 流程类型选项
categoryOptions: [],
showCategoryPicker: false,
categoryLabel: "",
// 任务列表
tasks: [],
loading: false,
finished: false,
refreshing: false,
// 标签页
activeTab: "todo",
processStatusMap: {
10: {text: "进行中", class: "doing"},
20: {text: "已完成", class: "finished"},
30: {text: "已撤回", class: "withdraw"},
40: {text: "强行终止", class: "interrupt"},
45: {text: "已拒绝", class: "reject"},
50: {text: "挂起", class: "pending"},
99: {text: "已废弃", class: "abandon"}
}
}
},
created() {
this.initData();
},
methods: {
// 初始化数据
async initData() {
await Promise.all([this.getStatistics(), this.listCategory()]);
// 初始加载任务
// this.getTasks();
},
// 获取统计数据
async getStatistics() {
try {
const {code, data, msg} = await this.$axios.post("/flow/todoCenter/statistics");
if (code === 0) {
const {todoCount, doneCount, startedCount} = data
this.todoCount = todoCount;
this.doneCount = doneCount;
this.startedCount = startedCount;
}
} catch (error) {
this.$toast("获取统计数据失败");
console.error("获取统计数据失败:", error);
}
},
// 获取流程类型
async listCategory() {
try {
// 这里使用模拟数据,实际项目中替换为API调用
const res = await axios.post("/flow/category/list");
if (res.data.code === 0) {
this.categoryOptions = res.data.data;
}
} catch (error) {
this.$toast("获取流程分类失败");
console.error("获取流程分类失败:", error);
}
},
// 获取任务列表
async getTasks() {
if (this.refreshing) {
this.tasks = [];
this.refreshing = false;
}
this.loading = true;
try {
const {code,data,msg} = await this.$axios.post("/flow/todoCenter/" + this.activeTab, this.pageForm);
if (code === 0) {
this.tasks = this.tasks.concat(data.list || []);
this.pageForm.totalCount = data.totalCount;
this.loading = false;
// 数据全部加载完成
if (this.tasks.length >= this.pageForm.totalCount) {
this.finished = true;
} else {
this.pageForm.pageNumber++;
}
}
} catch (error) {
this.$toast("获取任务列表失败");
console.error("获取任务列表失败:", error);
this.loading = false;
this.refreshing = false;
}
},
// 下拉刷新
onRefresh() {
this.pageForm.pageNumber = 1;
this.finished = false;
this.getTasks();
},
// 处理标签页变化
handleTabChange(name) {
this.activeTab = name;
this.pageForm.pageNumber = 1;
this.tasks = [];
this.finished = false;
this.getTasks();
this.getStatistics();
},
// 搜索
search() {
this.pageForm.pageNumber = 1;
this.tasks = [];
this.finished = false;
this.getTasks();
this.getStatistics();
},
// 重置搜索
reset() {
this.pageForm.searchKeyword = "";
this.pageForm.category = "";
this.categoryLabel = "";
this.search();
},
// 分类选择确认
onCategoryConfirm(value) {
this.pageForm.category = value.id;
this.categoryLabel = value.name;
this.showCategoryPicker = false;
},
// 处理任务
openView(task) {
const {taskId, taskKey, instanceId, businessNo, formKey} = task;
if (!formKey) {
this.$toast("当前流程没有配置地址");
return;
}
},
// 获取空状态文本
getEmptyText() {
switch (this.activeTab) {
case "todo":
return "您当前没有需要办理的任务,辛苦了";
case "done":
return "您当前没有已办理的任务记录";
case "started":
return "您当前没有发起的流程";
default:
return "暂无数据";
}
}
},
style: /*language=CSS*/ `
.task-center {
margin: 0 auto;
}
::v-deep .filter-section {
margin-bottom: 16px;
}
.search-form {
display: flex;
background: #fff;
padding: 12px 16px;
border-radius: 8px;
align-items: center;
}
.search-form .van-search{
width: 100%;
}
.search-input {
flex: 1;
margin-right: 12px;
}
.task-list {
margin-top: 16px;
}
::v-deep .task-item {
margin-bottom: 12px;
overflow: hidden;
background-color: #ffffff;
}
::v-deep .task-content {
padding: 16px;
}
::v-deep .task-title {
font-weight: 500;
font-size: 16px;
margin-bottom: 8px;
color: #323233;
}
::v-deep .task-info {
display: flex;
font-size: 14px;
color: #969799;
margin-bottom: 4px;
}
::v-deep .task-info-label {
width: 70px;
flex-shrink: 0;
}
::v-deep .task-info-value {
flex: 1;
}
::v-deep .task-footer {
display: flex;
justify-content: flex-end;
margin-top: 12px;
}
::v-deep .empty-section {
padding: 40px 0;
text-align: center;
color: #969799;
}
.category-select {
margin: 0 12px 12px 0;
}
`
}