贾宇博 4 hete%!(EXTRA string=óta)
szülő
commit
2b0e9710d4

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 4316 - 0
pnpm-lock.yaml


+ 9 - 0
src/api/order/manage.js

@@ -0,0 +1,9 @@
+import request from '@/utils/request'
+
+export function list(query) {
+  return request({
+    url: '/core/users/orders/web/mainOrderList',
+    method: 'get',
+    params: query
+  })
+}

+ 49 - 0
src/api/staff/price.js

@@ -0,0 +1,49 @@
+import request from '@/utils/request'
+
+//新增业务价格
+export function add(data) {
+  return request({
+    url: '/core/business/price',
+    method: 'post',
+    data: data
+  })
+}
+//修改业务价格
+export function update(data) {
+  return request({
+    url: '/core/business/price',
+    method: 'put',
+    data: data
+  })
+}
+//查询业务价格列表
+export function list(query) {
+  return request({
+    url: '/core/business/price/list',
+    method: 'get',
+    params: query
+  })
+}
+// 删除用户账户
+export function delPrice(businessPriceIds) {
+  return request({
+    url: '/core/business/price/' + businessPriceIds,
+    method: 'delete'
+  })
+}
+// 查询用户账户详细
+export function details(businessPriceId) {
+  return request({
+    url: '/core/business/price/' + businessPriceId,
+    method: 'get'
+  })
+}
+
+//查询所有业务列表(树形结构)
+export function getTreeList(query) {
+    return request({
+      url: '/core/business/management/getTreeList',
+      method: 'get',
+      params: query
+    })
+  }

+ 136 - 0
src/api/staff/user.js

@@ -0,0 +1,136 @@
+import request from '@/utils/request'
+import { parseStrEmpty } from "@/utils/ruoyi";
+
+// 查询用户列表
+export function listUser(query) {
+  return request({
+    url: '/system/user/userList',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询用户详细
+export function getUser(userId) {
+  return request({
+    url: '/system/user/' + parseStrEmpty(userId),
+    method: 'get'
+  })
+}
+
+// 新增用户
+export function addUser(data) {
+  return request({
+    url: '/system/user',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改用户
+export function updateUser(data) {
+  return request({
+    url: '/system/user',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除用户
+export function delUser(userId) {
+  return request({
+    url: '/system/user/' + userId,
+    method: 'delete'
+  })
+}
+
+// 用户密码重置
+export function resetUserPwd(userId, password) {
+  const data = {
+    userId,
+    password
+  }
+  return request({
+    url: '/system/user/resetPwd',
+    method: 'put',
+    data: data
+  })
+}
+
+// 用户状态修改
+export function changeUserStatus(userId, status) {
+  const data = {
+    userId,
+    status
+  }
+  return request({
+    url: '/system/user/changeStatus',
+    method: 'put',
+    data: data
+  })
+}
+
+// 查询用户个人信息
+export function getUserProfile() {
+  return request({
+    url: '/system/user/profile',
+    method: 'get'
+  })
+}
+
+// 修改用户个人信息
+export function updateUserProfile(data) {
+  return request({
+    url: '/system/user/profile',
+    method: 'put',
+    data: data
+  })
+}
+
+// 用户密码重置
+export function updateUserPwd(oldPassword, newPassword) {
+  const data = {
+    oldPassword,
+    newPassword
+  }
+  return request({
+    url: '/system/user/profile/updatePwd',
+    method: 'put',
+    data: data
+  })
+}
+
+// 用户头像上传
+export function uploadAvatar(data) {
+  return request({
+    url: '/system/user/profile/avatar',
+    method: 'post',
+    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
+    data: data
+  })
+}
+
+// 查询授权角色
+export function getAuthRole(userId) {
+  return request({
+    url: '/system/user/authRole/' + userId,
+    method: 'get'
+  })
+}
+
+// 保存授权角色
+export function updateAuthRole(data) {
+  return request({
+    url: '/system/user/authRole',
+    method: 'put',
+    params: data
+  })
+}
+
+// 查询部门下拉树结构
+export function deptTreeSelect() {
+  return request({
+    url: '/system/user/deptTree',
+    method: 'get'
+  })
+}

+ 28 - 0
src/api/staff/volunteer.js

@@ -0,0 +1,28 @@
+import request from '@/utils/request'
+
+//(后台)查询志愿者信息列表
+export function list(query) {
+  return request({
+    url: '/core/volunteer/info/web/list',
+    method: 'get',
+    params: query
+  })
+}
+
+//志愿者审批
+export function approval(data) {
+  return request({
+    url: '/core/volunteer/info/web/approval',
+    method: 'post',
+    data: data
+  })
+}
+
+//获取志愿者信息详细信息
+export function getDetails(data) {
+  return request({
+    url: '/core/volunteer/info/getDetails',
+    method: 'post',
+    data: data
+  })
+}

+ 173 - 0
src/views/components/DialogForm/index.vue

@@ -0,0 +1,173 @@
+<template>
+    <el-dialog :title="title" v-model="open" width="700px" append-to-body>
+        <el-form ref="dialogFormRef" :model="form" label-width="100px">
+            <template v-for="item in column" :key="item.prop">
+                <!-- 输入框 -->
+                <el-form-item :label="item.label" v-if="item.type === 'input'" :prop="item.prop" :rules="item.rules">
+                    <el-input v-model="form[item.prop]" :placeholder="'请输入' + item.label" clearable  :disabled="disables[item.prop]"/>
+                </el-form-item>
+                <!-- 文本域 -->
+                <el-form-item :label="item.label" v-if="item.type === 'textarea'" :prop="item.prop" :rules="item.rules">
+                    <el-input v-model="form[item.prop]" type="textarea"
+                    :autosize="{ minRows: 2, maxRows: 4 }"
+                     :placeholder="'请输入' + item.label" clearable  :disabled="disables[item.prop]"/>
+                </el-form-item>
+
+                <el-form-item :label="item.label" v-if="item.type === 'radio'" :prop="item.prop" :rules="item.rules">
+                    <el-radio-group v-model="form[item.prop]"  :disabled="disables[item.prop]">
+                        <el-radio v-for="dict in item.options" :key="dict.value" :value="dict.value">{{ dict.label }}</el-radio>
+                    </el-radio-group>
+                </el-form-item>
+
+                <!-- 时间选择 -->
+                <el-form-item :label="item.label" v-if="item.type === 'date'" :prop="item.prop" :rules="item.rules">
+                    <el-date-picker v-model="form[item.prop]" value-format="YYYY-MM-DD" type="daterange"
+                        range-separator="-" start-placeholder="开始日期" clearable end-placeholder="结束日期"  :disabled="disables[item.prop]"></el-date-picker>
+                </el-form-item>
+
+                <!-- 下拉框选择 -->
+                <el-form-item :label="item.label" v-if="item.type === 'select' && item.dictionary" :prop="item.prop" :rules="item.rules">
+                    <el-select v-model="form[item.prop]" :placeholder="'请选择' + item.label" clearable  :disabled="disables[item.prop]">
+                        <el-option v-for="dict in dictionaryOptions[item.dictionary]" :key="dict.value"
+                            :label="dict.label" :value="dict.value"></el-option>
+                    </el-select>
+                </el-form-item>
+
+                <el-form-item :label="item.label" v-if="item.type === 'select' && item.options" :prop="item.prop" :rules="item.rules">
+                    <el-select v-model="form[item.prop]" :placeholder="'请选择' + item.label" clearable  :disabled="disables[item.prop]">
+                        <el-option v-for="dict in item.options" :key="dict.value"
+                            :label="dict.label" :value="dict.value"></el-option>
+                    </el-select>
+                </el-form-item>
+
+                 <!-- 联动选择框 -->
+                <el-form-item :label="item.label" v-if="item.type === 'cascader' " :prop="item.prop">
+                    <el-cascader v-model="form[item.prop]" :options="item.options || []" style="width: 100%;"
+                        :props="item.props"  :disabled="disables[item.prop]"/>
+                </el-form-item>
+
+                 <!-- 图片预览 -->
+                 <el-form-item :label="item.label" v-if="item.type === 'img' " :prop="item.prop">
+                    <el-space wrap>
+                        <div v-for="(imgItem,imgIndex) in getImages(item.prop)" :key="imgIndex">
+                            <img  :src="imgItem" alt="" srcset="" style="width: 180px;" />
+                        </div>
+                    </el-space>
+                </el-form-item>
+            </template>
+
+
+            <el-form-item v-if="form.appStatus === '3'" label="驳回原因" prop="rejectReason" :rules="{ required: true, message: '请输入驳回原因', trigger: 'blur' }">
+                    <el-input v-model="form.rejectReason" type="textarea"
+                    :autosize="{ minRows: 2, maxRows: 4 }"
+                     placeholder="请输入驳回原因" clearable  :disabled="disables.appStatus"/>
+                </el-form-item>
+        </el-form>
+        <template #footer>
+            <div class="dialog-footer">
+                <el-button type="primary" @click="submitForm">确 定</el-button>
+                <el-button @click="cancel">取 消</el-button>
+            </div>
+        </template>
+    </el-dialog>
+</template>
+
+<script setup>
+import { computed, reactive } from 'vue';
+const { proxy } = getCurrentInstance();
+
+const props = defineProps({
+    title: {
+        type: String,
+        default: '新增',
+    },
+    column: {
+        type: Object,
+        default: [],
+        required: true
+    },
+})
+
+const open = ref(false);
+const form = ref({});
+const dictionaryOptions = reactive({})
+const emit = defineEmits(['submit']);
+
+const dialogFormRef = ref(null);
+
+const disables = ref({});
+
+
+const getImages = (key) => {
+    const imgs = form.value[key];
+    console.log(233,imgs,key);
+    
+    if(!imgs){
+        return [];
+    }
+    return imgs.split(',')
+}
+
+const handleInit = () => {
+    try {
+        const keys = props.column.map(item => {
+            if (item.type === 'select' && item.dictionary) {
+                return item.dictionary;
+            }
+        }).filter(Boolean);
+        if(keys && keys.length > 0){
+            const res = proxy.useDict(keys);
+            Object.assign(dictionaryOptions, res)
+        }
+    } catch (error) {
+        console.log('error', error);
+
+    }
+}
+
+
+onMounted(() => {
+    handleInit();
+})
+
+const handleDialog = (status,data) => {
+    console.log('status',status);
+    if(data){
+        form.value = data;
+    }
+    open.value = status;
+}
+
+
+const submitForm = () => {
+    proxy.$refs["dialogFormRef"].validate(valid => {
+        if (valid) {
+            console.log('form', form.value);
+            emit('submit',form.value)
+        }
+    });
+}
+const cancel = () => {
+    open.value = false;
+    disables.value = {};
+    dialogFormRef.value.resetFields();
+    console.log('cancel');
+}
+
+
+const initForm = (data,disableData) => {
+    console.log('initForm',data);
+    form.value = data;
+    if(disableData){
+        disables.value = disableData;
+    }
+}
+
+
+defineExpose({
+    handleDialog,
+    initForm
+})
+</script>
+
+<style lang='scss' scoped></style>

+ 144 - 0
src/views/components/ListPage/Search.vue

@@ -0,0 +1,144 @@
+<template>
+    <div>
+        <el-form :inline="true" ref="searchRef" :model="formInline" class="demo-form-inline">
+            <template v-for="item in column" :key="item.prop">
+                <!-- 输入框 -->
+                <el-form-item :label="item.label" v-if="item.type === 'input'" :prop="item.prop">
+                    <el-input v-model="formInline[item.prop]" :placeholder="'请输入' + item.label" clearable />
+                </el-form-item>
+
+                <!-- 时间选择 -->
+                <el-form-item :label="item.label" v-if="item.type === 'date'" :prop="item.prop">
+                    <el-date-picker v-model="formInline[item.prop]" value-format="YYYY-MM-DD" type="daterange"
+                        range-separator="-" start-placeholder="开始日期" clearable end-placeholder="结束日期"></el-date-picker>
+                </el-form-item>
+
+                <!-- 下拉框选择 -->
+                <el-form-item :label="item.label" v-if="item.type === 'select'" :prop="item.prop">
+                    <el-select v-model="formInline[item.prop]" :placeholder="'请选择' + item.label" clearable>
+                        <el-option v-for="dict in dictionaryOptions[item.dictionary]" :key="dict.value"
+                            :label="dict.label" :value="dict.value"></el-option>
+                    </el-select>
+                </el-form-item>
+                <!-- 联动选择框 -->
+                <el-form-item :label="item.label" v-if="item.type === 'cascader' " :prop="item.prop">
+                    <el-cascader v-model="formInline[item.prop]" :options="item.options || []" style="width: 100%;"
+                        :props="item.props" />
+                </el-form-item>
+
+               
+            </template>
+            <el-form-item>
+                <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+                <el-button @click="resetForm">重置</el-button>
+            </el-form-item>
+        </el-form>
+        <el-row :gutter="10" class="mb8">
+            <el-col :span="1.5" v-for="item in searchBtns" :key="item.key">
+                <el-button :type="item.type || 'primary'" plain :icon="item.icon" @click="item.func"
+                    v-hasPermi="item.hasPermi">{{ item.label }}</el-button>
+            </el-col>
+        </el-row>
+    </div>
+</template>
+
+<script setup>
+import { ref, onMounted, reactive } from 'vue'
+const { proxy } = getCurrentInstance();
+
+const props = defineProps({
+    column: {
+        type: Object,
+        default: [],
+        required: true
+    },
+    searchBtns: {
+        type: Array,
+        default: [],
+    }
+})
+
+const emit = defineEmits(['submit', 'reset'])
+
+const formInline = reactive({
+    user: '',
+    region: '',
+    date: '',
+})
+
+const searchRef = ref(null);
+
+const dictionaryOptions = reactive({})
+
+const handlerFormData = () => {
+    const array = props.column;
+    const parmas = {}
+    for (let i = 0; i < array.length; i++) {
+        const element = array[i];
+        if (element.type === 'date' && formInline[element.prop].length>0) {
+            parmas[element.keys[0]] = formInline[element.prop][0];
+            parmas[element.keys[1]] = formInline[element.prop][1];
+        } else if (formInline[element.prop]) {
+            if(element.prop === 'businessManagementId'){
+                console.log('formInline[element.prop]',formInline[element.prop]);
+                parmas[element.prop] = formInline[element.prop][formInline[element.prop].length-1];
+            }else{
+            parmas[element.prop] = formInline[element.prop];
+         }
+
+        }
+    }
+    return parmas
+}
+const handleQuery = () => {
+    const parmas = handlerFormData();
+    console.log('parmas',parmas);    
+    emit('submit', parmas)
+}
+const resetForm = () => {
+    if (!searchRef.value) return
+    searchRef.value.resetFields();
+    const parmas = handlerFormData();
+    emit('reset', parmas)
+}
+
+const handleInit = () => {
+    try {
+        const keys = props.column.map(item => {
+            if (item.type === 'select' && item.dictionary) {
+                return item.dictionary;
+            }
+        }).filter(Boolean);
+        
+        
+        if(keys && keys.length > 0){
+            const res = proxy.useDict(keys);
+            Object.assign(dictionaryOptions, res)
+        }
+
+    } catch (error) {
+        console.log('error', error);
+
+    }
+}
+
+
+
+
+onMounted(() => {
+    handleInit();
+})
+
+
+</script>
+
+<style>
+.demo-form-inline .el-input {
+    --el-input-width: 220px;
+}
+
+.demo-form-inline .el-select {
+    --el-select-width: 220px;
+}
+
+</style>

+ 140 - 0
src/views/components/ListPage/Table.vue

@@ -0,0 +1,140 @@
+<template>
+    <div class="app-container">
+        <!-- 表格数据 -->
+        <el-table v-loading="loading" :data="data" @selection-change="handleSelectionChange">
+            <el-table-column type="selection" width="55" align="center" v-if="isSelect"/>
+            <template v-for="item in column" :key="item.prop">
+
+                <el-table-column v-if="item.type === 'img'" :label="item.label" :prop="item.tableProp || item.prop"
+                    :width="item.width">
+                    <template #default="scope">
+                        <el-button type="primary" link @click="onClick(scope.row,item.tableProp || item.prop)">
+                            查看
+                        </el-button>
+                    </template>
+                </el-table-column>
+                <el-table-column v-else-if="item.type === 'dict'" :label="item.label" :prop="item.tableProp || item.prop"
+                    :width="item.width">
+                    <template #default="scope">
+                        <dict-tag :options="item.dict" :value="scope.row[item.tableProp || item.prop]" />
+                    </template>
+                </el-table-column>
+                <el-table-column v-else-if="item.type === 'render'" :label="item.label" :prop="item.prop"
+                    :width="item.width">
+                    <template #default="scope">
+                        <span>{{ item.render(scope.row) }}</span>
+                    </template>
+                </el-table-column>
+
+                <el-table-column v-else :label="item.label" :prop="item.tableProp || item.prop"
+                    :width="item.width"></el-table-column>
+            </template>
+            <el-table-column label="操作"  class-name="small-padding fixed-width">
+                <template #default="scope">
+                    <el-space wrap>
+                        <div v-for="item in scopeBtns" :key="item.key">
+                           <template v-if="item.show?item.show(scope.row) :true">
+                                <el-button  link :type="item.type"
+                                @click="item.func(scope.row)" v-hasPermi="item.hasPermi"> {{ item.label }}</el-button>
+                           </template>
+                        </div>
+                       
+                    </el-space>
+                </template>
+            </el-table-column>
+        </el-table>
+
+        <el-dialog v-model="dialogVisible" title="图片查看"  :before-close="handleClose">
+            <div class="img-box">
+                <el-space wrap>
+                    <div v-for="(imgItem, imgIndex) in images" :key="imgIndex">
+                        <el-image  :src="imgItem"  />
+                    </div>
+                </el-space>
+            </div>
+            <template #footer>
+                <div class="dialog-footer">
+                    <el-button @click="dialogVisible = false">取消</el-button>
+                    <el-button type="primary" @click="dialogVisible = false">
+                        确定
+                    </el-button>
+                </div>
+            </template>
+        </el-dialog>
+    </div>
+</template>
+<script setup>
+import { ref } from 'vue'
+
+const props = defineProps({
+    column: {
+        type: Object,
+        default: [],
+        required: true
+    },
+    loading: {
+        type: Boolean,
+        default: false,
+        required: false
+    },
+    data: {
+        type: Array,
+        default: [],
+        required: true
+    },
+    scopeBtns: {
+        type: Array,
+        default: [],
+    },
+    tableKey: {
+        type: String,
+        default: 'id',
+    },
+    isSelect:{
+        type: Boolean,
+        default: true
+    }
+})
+
+const ids = ref([])
+const dialogVisible = ref(false)
+const images = ref([]);
+/** 多选框选中数据 */
+const handleSelectionChange = (selection) => {
+    console.log('selection', selection);
+
+    ids.value = selection.map(item => item[props.tableKey]);
+    console.log('ids', ids);
+
+}
+
+const resetIds = () => {
+    ids.value = []
+}
+
+const onClick = (row,pro) => {
+    console.log('row', row,pro);
+    dialogVisible.value = true;
+    if (row[pro]) {
+        images.value = row[pro].split(',');
+
+    }
+}
+
+
+defineExpose({
+    ids,
+    resetIds
+})
+</script>
+
+<style lang='scss' scoped>
+.img-box {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    min-height: 300px;
+    width: 100%;
+    height: 100%;
+}
+</style>

+ 163 - 0
src/views/components/ListPage/index.vue

@@ -0,0 +1,163 @@
+<template>
+    <div class="list-page">
+        <el-tabs v-model="tabsValue" type="card" class="demo-tabs"  @tab-change="changeTab" v-if="tabList && tabList.length > 0">
+            <el-tab-pane v-for="item in tabList" :key="item.name" :label="item.title" :name="item.name"></el-tab-pane>
+        </el-tabs>
+        <div class="search-div">
+            <Search :column="searchColumn" @submit="searchSubmit" @reset="resetForm" :searchBtns="searchBtns"/>
+        </div>
+        <div class="table-div">
+            <Table :tableKey="tableKey" ref="tableRef" :column="tableColumn" :data="tableData.list" :loading="loading" :scopeBtns="scopeBtns" :isSelect="isSelect" />
+        </div>
+        <div class="pagination-div">
+            <pagination v-show="tableData.total > 0" :total="tableData.total" v-model:page="queryParams.pageNum"
+                v-model:limit="queryParams.pageSize" @pagination="getList" />
+        </div>
+    </div>
+</template>
+
+<script setup>
+import { computed, onMounted, reactive, watch } from 'vue';
+import Search from './Search.vue';
+import Table from './Table.vue';
+import { ElMessage } from 'element-plus'
+import { ref } from 'vue';
+const props = defineProps({
+    column: {
+        type: Object,
+        default: [],
+        required: true
+    },
+    scopeBtns: {
+        type: Array,
+        default: [],
+    },
+    tableApi: {
+        type: Function,
+        default: () => { },
+        required: true
+    },
+    searchBtns: {
+        type: Array,
+        default: [],
+    },
+    tableKey:{
+        type: String,
+        default: 'id',
+    },
+    tabList:{
+        type: Array,
+        default:[]
+    },
+    tabsearchKey:{
+        type: String,
+        default: ''
+    },
+    isSelect:{
+        type: Boolean,
+        default: true
+    }
+})
+const tabsValue = ref('2')
+
+const queryParams = reactive({
+    pageNum: 1,
+    pageSize: 10
+})
+
+const tableData = ref({
+    total: 0,
+    list: []
+})
+
+const loading = ref(false)
+const tableRef = ref(null)
+
+const searchColumn = computed(() => {
+    return props.column.filter(item => item.isSearch);
+})
+
+const tableColumn = computed(() => {
+    return props.column
+})
+
+//表单提交
+const searchSubmit = (parmas) => {
+    getList(parmas)
+}
+//表单重置
+const resetForm = () => {
+    Object.assign(queryParams, {
+        pageNum: 1,
+        pageSize: 10
+    })
+
+    //清除选中的row
+    tableRef.value.resetIds();
+    getList({})
+}
+
+const changeTab = (tab) => {
+    console.log('tab', tab);
+
+    resetForm();
+}
+
+watch(() =>tabsValue.value,()=>{
+    sessionStorage.setItem('tabsValue',tabsValue.value)
+} )
+
+const getList = async (parmas) => {
+    try {
+        loading.value = true;
+        const searchData = {...queryParams, ...parmas}
+        if(props.tabsearchKey){
+            searchData[props.tabsearchKey] = tabsValue.value;
+        }
+        console.log('查询条件',queryParams,parmas);
+        const response = await props.tableApi(searchData);
+        tableData.value = {
+            total: response.total,
+            list: response.rows
+        }
+    } catch (error) {
+        console.error('error', error);
+    } finally {
+        loading.value = false;
+    }
+}
+
+
+
+const ids = computed(() =>{
+    const _d = tableRef.value.ids;
+    if(_d && _d.length <= 0){
+        ElMessage({
+            message: '请选择需要操作的数据!',
+            type: 'warning',
+        })
+        return []
+    }
+    return tableRef.value.ids
+})
+
+onMounted(() => {
+  const tabs =   sessionStorage.getItem('tabsValue');  
+  if(tabs){
+    tabsValue.value = tabs;
+  }
+  getList();
+})
+
+
+defineExpose({
+    ids,
+    resetForm
+})
+</script>
+
+<style lang='scss' scoped>
+.list-page {
+    padding: 20px;
+}
+</style>

+ 76 - 0
src/views/order/details/index.vue

@@ -0,0 +1,76 @@
+<template>
+    <div class="details-main">
+        <div class="details-main-box">
+            <div class="details-dr">1</div>
+            <div class="details-list">
+                <div class="details-list-item">
+                    <el-image style="width: 100px; height: 100px"
+                        src="https://cube.elemecdn.com/0/88/03b0d39583f48206768a7534e55bcpng.png" />
+                    <div>
+                        <div>姓名:xxx</div>
+                        <div>评分:xxx</div>
+                        <div> 类别:xxx</div>
+                        <div> 技能简介:xxx</div>
+                    </div>
+
+                </div>
+                <el-divider />
+            </div>
+        </div>
+        <div class="details-main-footer">
+            <el-descriptions title="订单信息" border>
+                <el-descriptions-item label="姓名">kooriookami</el-descriptions-item>
+                <el-descriptions-item label="项目类别">18100000000</el-descriptions-item>
+                <el-descriptions-item label="被服务人员">18100000000</el-descriptions-item>
+                <el-descriptions-item label="是否有疾病">18100000000</el-descriptions-item>
+                <el-descriptions-item label="手机号">18100000000</el-descriptions-item>
+                <el-descriptions-item label="科目">18100000000</el-descriptions-item>
+                <el-descriptions-item label="性别">18100000000</el-descriptions-item>
+                <el-descriptions-item label="服务项目">18100000000</el-descriptions-item>
+                <el-descriptions-item label="订单状态">18100000000</el-descriptions-item>
+                <el-descriptions-item label="电话">18100000000</el-descriptions-item>
+                <el-descriptions-item label="住址">18100000000</el-descriptions-item>
+            </el-descriptions>
+        </div>
+
+    </div>
+</template>
+
+<script setup>
+
+const list = [
+    {
+        lable: ''
+    }
+]
+</script>
+
+<style lang="scss" scoped>
+.details-main {
+    height: calc(100vh - 84px);
+    display: flex;
+    flex-direction: column;
+    padding: 24px;
+
+    .details-main-box {
+        display: flex;
+        flex: 1;
+
+        .details-dr {
+            flex: 1;
+        }
+
+        .details-list {
+            display: flex;
+            flex-direction: column;
+            overflow-y: auto;
+
+            .details-list-item {
+                display: flex;
+            }
+        }
+    }
+
+    .details-main-footer {}
+}
+</style>

+ 270 - 0
src/views/order/examine/index.vue

@@ -0,0 +1,270 @@
+<template>
+    <div>
+        <ListPage :column="listPageData.tableColumn" :tableApi="listPageData.tableApi" :isSelect="listPageData.isSelect"
+            :scopeBtns="listPageData.scopeBtns" :searchBtns="listPageData.searchBtns" ref="userTableRef"
+            v-if="options && options.length > 0" tabsearchKey="appStatus" />
+        <DialogForm ref="dialogFormRef" :title="title" :column="dialogData.column" @submit="submitForm" />
+    </div>
+</template>
+
+<script setup>
+import { ref } from 'vue';
+import ListPage from '@/views/components/ListPage/index.vue';
+import { list, approval } from "@/api/staff/volunteer.js";
+import { getTreeList } from "@/api/staff/price.js";
+
+import DialogForm from '@/views/components/DialogForm/index.vue';
+const { proxy } = getCurrentInstance();
+const { volunteer_app_status } = proxy.useDict("volunteer_app_status");
+
+const options = ref([]);
+const userTableRef = ref();
+const dialogFormRef = ref(null);
+const listPageData = reactive({
+    tableColumn: [
+        {
+            label: '时间',
+            prop: 'createTime',
+            type: 'date',
+            isSearch: false,
+            width: '180px'
+        },
+        {
+            label: '姓名',
+            prop: 'name',
+            type: 'input',
+            isSearch: true,
+        },
+        {
+            label: '服务项目',
+            prop: 'businessManagementId',
+            type: 'cascader',
+            isSearch: true,
+            tableProp: 'projectName',
+            options: options,
+            props: { label: 'businessName', value: 'id', checkStrictly:true },
+        },
+        {
+            label: '项目类别',
+            prop: 'projectTypeName',
+        },
+        {
+            label: '科目',
+            prop: 'serviceSubjectName',
+        },
+        {
+            label: '被服务人员',
+            prop: 'name',
+        },
+        {
+            label: '已服务',
+            prop: 'address',
+        },
+        {
+            label: '为服务',
+            prop: 'address',
+        },
+        {
+            label: '退单状态',
+            prop: 'idCardPicture',
+            type: 'dict',
+            dict: volunteer_app_status
+        },
+        {
+            label: '退款金额',
+            prop: 'volunteerPicture',
+            type: 'img',
+        },
+        {
+            label: '备注',
+            prop: 'address',
+        },
+    ],
+    searchBtns: [],
+    tableApi: list,//接口地址
+    isSelect: false,//是否勾选
+    scopeBtns: [
+        {
+            label: '审核',
+            type: 'primary',
+            hasPermi: ['manage:examine'],
+            key: 'examine',
+            func: (row) => {
+                console.log(row)
+                openDialog(row, 'examine')
+            },
+            // show: (row) => {
+            //     return row.appStatus == 1
+            // }
+        },
+    ]
+})
+const dialogData = reactive({
+    title: '',
+    column: [
+        {
+            label: '时间',
+            prop: 'name',
+            type: 'input',
+
+        },
+        {
+            label: '姓名',
+            prop: 'name',
+            type: 'input',
+
+        },
+        {
+            label: '电话',
+            prop: 'phonenumber',
+            type: 'input',
+
+        },
+        {
+            label: '服务项目/类别',
+            prop: 'businessManagementId',
+            type: 'cascader',
+            isSearch: true,
+            options: options,
+            props: { label: 'businessName', value: 'id', checkStrictly:true },
+        },
+        {
+            label: '科目',
+            prop: 'age',
+            type: 'input',
+
+        },
+        {
+            label: '被服务人员',
+            prop: 'address',
+            type: 'input',
+        },
+       
+        {
+            label: '手机号',
+            prop: 'idCardPicture',
+            type: 'img',
+
+        },
+        {
+            label: '退款金额',
+            prop: 'certificationPicture',
+            type: 'img',
+
+        },
+        {
+            label: '照片上传',
+            prop: 'certificationPicture',
+            type: 'img',
+        },
+        {
+            label: '备注',
+            prop: 'skillDescribe',
+            type: 'textarea',
+        },
+        {
+            label: '审核状态',
+            prop: 'appStatus',
+            type: 'radio',
+            rules: [
+                { required: true, message: '请选择审核状态', trigger: 'blur' }
+            ],
+            options: [
+                {
+                    label: '通过',
+                    value: '2'
+                },
+                {
+                    label: '不通过',
+                    value: '3'
+                }
+            ]
+        },
+    ]
+})
+const { title } = toRefs(dialogData);
+const parentId = ref(0);
+
+const openDialog = (row, type) => {
+    console.log('row', row);
+    try {
+        const disabledData = {
+            name: true,
+            age: true,
+            phonenumber: true,
+            address: true,
+            skillDescribe: true,
+            businessManagementId: true,
+        }
+
+        if (type) {
+            //审核
+            title.value = '审核'
+
+        } else {
+            disabledData['appStatus'] = true;
+            //查看详情
+            title.value = '查看详情'
+        }
+
+        dialogFormRef.value.initForm(row, disabledData)
+
+    } catch (error) {
+        console.log('error', error);
+    } finally {
+        console.log('dialogFormRef.value', dialogFormRef.value);
+
+        dialogFormRef.value.handleDialog(true);
+    }
+}
+const handleDelete = (ids) => {
+    proxy.$modal.confirm('是否确认删除角色编号为"' + ids + '"的数据项?').then(function () {
+        return true
+    }).then(() => {
+        userTableRef.value.resetForm();
+        proxy.$modal.msgSuccess("删除成功");
+    }).catch(() => { });
+}
+
+const submitForm = async (parmas) => {
+
+    try {
+        console.log('submit', parmas);
+        if (title.value === '审核') {
+            const res = await approval({
+                volunteerInfoId: parmas.volunteerInfoId,
+                appStatus: parmas.appStatus,
+                rejectReason: parmas.rejectReason
+            })
+            if (up_res.code === 200) {
+                proxy.$modal.msgSuccess("审核成功");
+                return;
+            }
+            proxy.$modal.msgSuccess(res.msg);
+        }
+    } catch (error) {
+        console.log('error', error);
+
+    } finally {
+        userTableRef.value.resetForm();
+        dialogFormRef.value.handleDialog(false);
+    }
+
+}
+
+
+const getTreeListData = async () => {
+    try {
+        const res = await getTreeList({ parentId: parentId.value });
+        console.log('res', res);
+        options.value = res.data;
+    } catch (error) {
+
+    }
+}
+
+getTreeListData();
+
+</script>
+
+<style lang='scss' scoped></style>

+ 286 - 0
src/views/order/manage/index.vue

@@ -0,0 +1,286 @@
+<template>
+    <div>
+        <ListPage :column="listPageData.tableColumn" :tableApi="listPageData.tableApi" :isSelect="listPageData.isSelect"
+            :scopeBtns="listPageData.scopeBtns" :searchBtns="listPageData.searchBtns" ref="userTableRef"
+            v-if="options && options.length > 0"  />
+        <DialogForm ref="dialogFormRef" :title="title" :column="dialogData.column" @submit="submitForm" />
+    </div>
+</template>
+
+<script setup>
+import { ref } from 'vue';
+import ListPage from '@/views/components/ListPage/index.vue';
+import { list } from "@/api/order/manage.js";
+import { getTreeList } from "@/api/staff/price.js";
+
+import DialogForm from '@/views/components/DialogForm/index.vue';
+const { proxy } = getCurrentInstance();
+const { lrr_service_status } = proxy.useDict("lrr_service_status");
+
+const options = ref([]);
+const userTableRef = ref();
+const dialogFormRef = ref(null);
+const listPageData = reactive({
+    tableColumn: [
+        {
+            label: '订单ID',
+            prop: 'mainOrderId',
+             width: '180px'
+        },
+        {
+            label: '时间',
+            prop: 'createTime',
+            type: 'date',
+            isSearch: false,
+            width: '180px'
+        },
+        {
+            label: '姓名',
+            prop: 'name',
+            type: 'input',
+            isSearch: true,
+        },
+        {
+            label: '手机号',
+            prop: 'phonenumber',
+            type: 'input',
+            isSearch: true
+        },
+        {
+            label: '服务项目',
+            prop: 'businessManagementId',
+            type: 'cascader',
+            isSearch: true,
+            tableProp: 'projectName',
+            options: options,
+            props: { label: 'businessName', value: 'id', checkStrictly:true },
+        },
+        {
+            label: '项目类别',
+            prop: 'projectTypeName',
+        },
+        {
+            label: '科目',
+            prop: 'projectTypeName',
+        },
+        {
+            label: '评分',
+            prop: 'address',
+        },
+        {
+            label: '订单状态',
+            prop: 'orderStatus',
+            type: 'dict',
+            dict: lrr_service_status
+        },
+        {
+            label: '订单单价',
+            prop: 'serviceOnePrice',
+        },
+        {
+            label: '订单金额',
+            prop: 'serviceTotalPrice',
+        },
+        {
+            label: '平台提成',
+            prop: 'skillDescribe',
+        }
+    ],
+    searchBtns: [],
+    tableApi: list,//接口地址
+    isSelect: false,//是否勾选
+    scopeBtns: [
+        // {
+        //     label: '审核',
+        //     type: 'primary',
+        //     hasPermi: ['manage:examine'],
+        //     key: 'examine',
+        //     func: (row) => {
+        //         console.log(row)
+        //         openDialog(row, 'examine')
+        //     },
+        //     show: (row) => {
+        //         return row.appStatus == 1
+        //     }
+        // },
+        // {
+        //     label: '查看',
+        //     type: 'primary',
+        //     hasPermi: ['manage:details'],
+        //     key: 'details',
+        //     func: (row) => {
+        //         console.log(row)
+        //         openDialog(row)
+        //     }
+        // },
+        // {
+        //     label: '删除',
+        //     type: 'danger',
+        //     hasPermi: ['manage:delete'],
+        //     key: 'delete',
+        //     func: (row) => {
+        //         console.log(row)
+        //         handleDelete([row.id])
+        //     }
+        // }
+    ]
+})
+const dialogData = reactive({
+    title: '',
+    column: [
+        {
+            label: '姓名',
+            prop: 'name',
+            type: 'input',
+
+        },
+        {
+            label: '年龄',
+            prop: 'age',
+            type: 'input',
+
+        },
+        {
+            label: '电话',
+            prop: 'phonenumber',
+            type: 'input',
+
+        },
+        {
+            label: '家庭地址',
+            prop: 'address',
+            type: 'input',
+
+        },
+        {
+            label: '服务项目/类别',
+            prop: 'businessManagementId',
+            type: 'cascader',
+            isSearch: true,
+            options: options,
+            props: { label: 'businessName', value: 'id', checkStrictly:true },
+
+        },
+        {
+            label: '身份证件',
+            prop: 'idCardPicture',
+            type: 'img',
+
+        },
+        {
+            label: '职业证书',
+            prop: 'certificationPicture',
+            type: 'img',
+
+        },
+        {
+            label: '技能简介',
+            prop: 'skillDescribe',
+            type: 'textarea',
+        },
+        {
+            label: '审核状态',
+            prop: 'appStatus',
+            type: 'radio',
+            rules: [
+                { required: true, message: '请选择审核状态', trigger: 'blur' }
+            ],
+            options: [
+                {
+                    label: '通过',
+                    value: '2'
+                },
+                {
+                    label: '不通过',
+                    value: '3'
+                }
+            ]
+        },
+    ]
+})
+const { title } = toRefs(dialogData);
+const parentId = ref(0);
+
+const openDialog = (row, type) => {
+    console.log('row', row);
+    try {
+        const disabledData = {
+            name: true,
+            age: true,
+            phonenumber: true,
+            address: true,
+            skillDescribe: true,
+            businessManagementId: true,
+        }
+
+        if (type) {
+            //审核
+            title.value = '审核'
+
+        } else {
+            disabledData['appStatus'] = true;
+            //查看详情
+            title.value = '查看详情'
+        }
+
+        dialogFormRef.value.initForm(row, disabledData)
+
+    } catch (error) {
+        console.log('error', error);
+    } finally {
+        console.log('dialogFormRef.value', dialogFormRef.value);
+
+        dialogFormRef.value.handleDialog(true);
+    }
+}
+const handleDelete = (ids) => {
+    proxy.$modal.confirm('是否确认删除角色编号为"' + ids + '"的数据项?').then(function () {
+        return true
+    }).then(() => {
+        userTableRef.value.resetForm();
+        proxy.$modal.msgSuccess("删除成功");
+    }).catch(() => { });
+}
+
+const submitForm = async (parmas) => {
+
+    try {
+        console.log('submit', parmas);
+        // if (title.value === '审核') {
+        //     const res = await approval({
+        //         volunteerInfoId: parmas.volunteerInfoId,
+        //         appStatus: parmas.appStatus,
+        //         rejectReason: parmas.rejectReason
+        //     })
+        //     if (up_res.code === 200) {
+        //         proxy.$modal.msgSuccess("审核成功");
+        //         return;
+        //     }
+        //     proxy.$modal.msgSuccess(res.msg);
+        // }
+    } catch (error) {
+        console.log('error', error);
+
+    } finally {
+        userTableRef.value.resetForm();
+        dialogFormRef.value.handleDialog(false);
+    }
+
+}
+
+
+const getTreeListData = async () => {
+    try {
+        const res = await getTreeList({ parentId: parentId.value });
+        console.log('res', res);
+        options.value = res.data;
+    } catch (error) {
+
+    }
+}
+
+getTreeListData();
+
+</script>
+
+<style lang='scss' scoped></style>

+ 161 - 0
src/views/staff/demo.vue

@@ -0,0 +1,161 @@
+<template>
+    <div>
+        <ListPage :column="listPageData.tableColumn" :tableApi="listPageData.tableApi" :isSelect="listPageData.isSelect"
+            :scopeBtns="listPageData.scopeBtns" :searchBtns="listPageData.searchBtns" ref="userTableRef" />
+        <DialogForm ref="dialogFormRef" :title="title" :column="dialogData.column" @submit="submitForm" />
+    </div>
+</template>
+
+<script setup>
+import { ref } from 'vue';
+import ListPage from '@/views/components/ListPage/index.vue';
+import { listUser } from "@/api/staff/user";
+
+import DialogForm from '@/views/components/DialogForm/index.vue';
+
+const userTableRef = ref();
+const listPageData = reactive({
+    tableColumn: [
+        {
+            label: '姓名',
+            prop: 'name',
+            type: 'input',
+            isSearch: true
+        },
+        {
+            label: '时间',
+            prop: 'date',
+            type: 'date',
+            isSearch: true,
+            keys: ['start', 'end']
+        },
+        {
+            label: '性别',
+            prop: 'sex',
+            type: 'select',
+            dictionary: 'sys_user_sex',
+            isSearch: true
+        },
+    ],
+    searchBtns: [
+        {
+            label: '新增',
+            func: () => {
+                console.log('新增')
+                openDialog();
+            },
+            key: 'add',
+            hasPermi: ['system:role:query'],
+            icon: 'Plus',
+            type: 'primary'
+        },
+        {
+            label: '批量删除',
+            func: () => {
+                const ids = userTableRef.value.ids;
+                console.log('批量删除', ids)
+                handleDelete(ids);
+            },
+            key: 'deletes',
+            hasPermi: ['system:role:query'],
+            type: 'danger'
+        },
+    ],
+    tableApi: listUser,//接口地址
+    isSelect: true,//是否勾选
+    scopeBtns: [
+        {
+            label: '编辑',
+            type: 'primary',
+            hasPermi: ['system:role:edit'],
+            key: 'edit',
+            func: (row) => {
+                console.log(row)
+                openDialog(row)
+            }
+        },
+        {
+            label: '删除',
+            type: 'danger',
+            hasPermi: ['price:edit'],
+            key: 'edit',
+            func: (row) => {
+                console.log(row)
+                handleDelete([row.id])
+            }
+        }
+    ]
+})
+const dialogFormRef = ref(null);
+const dialogData = reactive({
+    title: '',
+    column:[
+        {
+            label: '姓名',
+            prop: 'name',
+            type: 'input',
+            rules: [
+                { required: true, message: '请输入姓名', trigger: 'blur' }
+            ]
+        },
+        {
+            label: '时间',
+            prop: 'date',
+            type: 'date',
+            keys: ['start', 'end'],
+            rules: [
+                { required: true, message: '请选择时间', trigger: 'blur' }
+            ]
+        },
+        {
+            label: '性别',
+            prop: 'sex',
+            type: 'select',
+            dictionary: 'sys_user_sex',
+            rules: [
+                { required: true, message: '请选择性别', trigger: 'blur' }
+            ]
+        },
+    ]
+})
+const { title } = toRefs(dialogData);
+const openDialog = (row) => {
+    console.log('row', row);
+    try {
+        if (row) {
+            //修改
+            title.value = '价格修改'
+            form.value = row;
+        } else {
+            //新增
+            title.value = '价格新增'
+        }
+
+    } catch (error) {
+        console.log('error', error);
+    } finally {
+        console.log('dialogFormRef.value',dialogFormRef.value);
+        
+        dialogFormRef.value.handleDialog(true);
+    }
+}
+const handleDelete = (ids) => {
+    proxy.$modal.confirm('是否确认删除角色编号为"' + ids + '"的数据项?').then(function () {
+        return true
+    }).then(() => {
+        userTableRef.value.resetForm();
+        proxy.$modal.msgSuccess("删除成功");
+    }).catch(() => { });
+}
+
+
+const submitForm = (parmas) => {
+
+    console.log('submit',parmas);
+    
+}
+
+
+</script>
+
+<style lang='scss' scoped></style>

+ 267 - 0
src/views/staff/user/index.vue

@@ -0,0 +1,267 @@
+<template>
+    <div>
+        <ListPage :column="listPageData.tableColumn" :tableApi="listPageData.tableApi" :isSelect="listPageData.isSelect"
+            :scopeBtns="listPageData.scopeBtns" :searchBtns="listPageData.searchBtns" ref="userTableRef"
+            v-if="options && options.length > 0"  />
+        <DialogForm ref="dialogFormRef" :title="title" :column="dialogData.column" @submit="submitForm" />
+    </div>
+</template>
+
+<script setup>
+import { ref } from 'vue';
+import ListPage from '@/views/components/ListPage/index.vue';
+import { listUser } from "@/api/staff/user";
+import { getTreeList } from "@/api/staff/price.js";
+
+import DialogForm from '@/views/components/DialogForm/index.vue';
+const { proxy } = getCurrentInstance();
+const { volunteer_app_status } = proxy.useDict("volunteer_app_status");
+
+const options = ref([]);
+const userTableRef = ref();
+const dialogFormRef = ref(null);
+const listPageData = reactive({
+    tableColumn: [
+        {
+            label: '用户ID',
+            prop: 'roleId',
+             width: '180px'
+        },
+        {
+            label: '注册时间',
+            prop: 'createTime',
+            type: 'date',
+            isSearch: false,
+            width: '180px'
+        },
+        {
+            label: '姓名',
+            prop: 'nickName',
+            type: 'input',
+            isSearch: true,
+        },
+        {
+            label: '用户名',
+            prop: 'userName',
+        },
+        {
+            label: '性别',
+            prop: 'sex',
+            type: 'render',
+            render:(row) => {
+                return row.sex === '0' ? '男' : '女'
+            }
+        },
+        {
+            label: '电话',
+            prop: 'phonenumber',
+            type: 'input',
+            isSearch: true
+        },
+        {
+            label: '是否有疾病',
+            prop: 'isContagion',
+        },
+        {
+            label: '住址',
+            prop: 'adress',
+        },
+    ],
+    searchBtns: [],
+    tableApi: listUser,//接口地址
+    isSelect: false,//是否勾选
+    scopeBtns: [
+        // {
+        //     label: '审核',
+        //     type: 'primary',
+        //     hasPermi: ['manage:examine'],
+        //     key: 'examine',
+        //     func: (row) => {
+        //         console.log(row)
+        //         openDialog(row, 'examine')
+        //     },
+        //     show: (row) => {
+        //         return row.appStatus == 1
+        //     }
+        // },
+        // {
+        //     label: '查看',
+        //     type: 'primary',
+        //     hasPermi: ['manage:details'],
+        //     key: 'details',
+        //     func: (row) => {
+        //         console.log(row)
+        //         openDialog(row)
+        //     }
+        // },
+        // {
+        //     label: '删除',
+        //     type: 'danger',
+        //     hasPermi: ['manage:delete'],
+        //     key: 'delete',
+        //     func: (row) => {
+        //         console.log(row)
+        //         handleDelete([row.id])
+        //     }
+        // }
+    ]
+})
+const dialogData = reactive({
+    title: '',
+    column: [
+        {
+            label: '姓名',
+            prop: 'name',
+            type: 'input',
+
+        },
+        {
+            label: '年龄',
+            prop: 'age',
+            type: 'input',
+
+        },
+        {
+            label: '电话',
+            prop: 'phonenumber',
+            type: 'input',
+
+        },
+        {
+            label: '家庭地址',
+            prop: 'address',
+            type: 'input',
+
+        },
+        {
+            label: '服务项目/类别',
+            prop: 'businessManagementId',
+            type: 'cascader',
+            isSearch: true,
+            options: options,
+            props: { label: 'businessName', value: 'id', checkStrictly:true },
+
+        },
+        {
+            label: '身份证件',
+            prop: 'idCardPicture',
+            type: 'img',
+
+        },
+        {
+            label: '职业证书',
+            prop: 'certificationPicture',
+            type: 'img',
+
+        },
+        {
+            label: '技能简介',
+            prop: 'skillDescribe',
+            type: 'textarea',
+        },
+        {
+            label: '审核状态',
+            prop: 'appStatus',
+            type: 'radio',
+            rules: [
+                { required: true, message: '请选择审核状态', trigger: 'blur' }
+            ],
+            options: [
+                {
+                    label: '通过',
+                    value: '2'
+                },
+                {
+                    label: '不通过',
+                    value: '3'
+                }
+            ]
+        },
+    ]
+})
+const { title } = toRefs(dialogData);
+const parentId = ref(0);
+
+const openDialog = (row, type) => {
+    console.log('row', row);
+    try {
+        const disabledData = {
+            name: true,
+            age: true,
+            phonenumber: true,
+            address: true,
+            skillDescribe: true,
+            businessManagementId: true,
+        }
+
+        if (type) {
+            //审核
+            title.value = '审核'
+
+        } else {
+            disabledData['appStatus'] = true;
+            //查看详情
+            title.value = '查看详情'
+        }
+
+        dialogFormRef.value.initForm(row, disabledData)
+
+    } catch (error) {
+        console.log('error', error);
+    } finally {
+        console.log('dialogFormRef.value', dialogFormRef.value);
+
+        dialogFormRef.value.handleDialog(true);
+    }
+}
+const handleDelete = (ids) => {
+    proxy.$modal.confirm('是否确认删除角色编号为"' + ids + '"的数据项?').then(function () {
+        return true
+    }).then(() => {
+        userTableRef.value.resetForm();
+        proxy.$modal.msgSuccess("删除成功");
+    }).catch(() => { });
+}
+
+const submitForm = async (parmas) => {
+
+    try {
+        console.log('submit', parmas);
+        // if (title.value === '审核') {
+        //     const res = await approval({
+        //         volunteerInfoId: parmas.volunteerInfoId,
+        //         appStatus: parmas.appStatus,
+        //         rejectReason: parmas.rejectReason
+        //     })
+        //     if (up_res.code === 200) {
+        //         proxy.$modal.msgSuccess("审核成功");
+        //         return;
+        //     }
+        //     proxy.$modal.msgSuccess(res.msg);
+        // }
+    } catch (error) {
+        console.log('error', error);
+
+    } finally {
+        userTableRef.value.resetForm();
+        dialogFormRef.value.handleDialog(false);
+    }
+
+}
+
+
+const getTreeListData = async () => {
+    try {
+        const res = await getTreeList({ parentId: parentId.value });
+        console.log('res', res);
+        options.value = res.data;
+    } catch (error) {
+
+    }
+}
+
+getTreeListData();
+
+</script>
+
+<style lang='scss' scoped></style>

+ 307 - 0
src/views/staff/volunteer/manage/index.vue

@@ -0,0 +1,307 @@
+<template>
+    <div>
+        <ListPage :column="listPageData.tableColumn" :tableApi="listPageData.tableApi" :isSelect="listPageData.isSelect"
+            :scopeBtns="listPageData.scopeBtns" :searchBtns="listPageData.searchBtns" ref="userTableRef"
+            v-if="options && options.length > 0" :tabList="tabList" tabsearchKey="appStatus" />
+        <DialogForm ref="dialogFormRef" :title="title" :column="dialogData.column" @submit="submitForm" />
+    </div>
+</template>
+
+<script setup>
+import { ref } from 'vue';
+import ListPage from '@/views/components/ListPage/index.vue';
+import { list, approval } from "@/api/staff/volunteer.js";
+import { getTreeList } from "@/api/staff/price.js";
+
+import DialogForm from '@/views/components/DialogForm/index.vue';
+const { proxy } = getCurrentInstance();
+const { volunteer_app_status } = proxy.useDict("volunteer_app_status");
+
+const options = ref([]);
+const userTableRef = ref();
+const dialogFormRef = ref(null);
+const listPageData = reactive({
+    tableColumn: [
+        {
+            label: '注册时间',
+            prop: 'createTime',
+            type: 'date',
+            isSearch: false,
+            keys: ['start', 'end'],
+            width: '180px'
+        },
+        {
+            label: '姓名',
+            prop: 'name',
+        },
+
+        {
+            label: '服务项目',
+            prop: 'businessManagementId',
+            type: 'cascader',
+            isSearch: true,
+            tableProp: 'projectName',
+            options: options,
+            props: { label: 'businessName', value: 'id', checkStrictly:true },
+
+
+        },
+        {
+            label: '项目类别',
+            prop: 'projectTypeName',
+        },
+        // {
+        //     label: '科目',
+        //     prop: 'projectTypeName',
+        // },
+
+        {
+            label: '手机号',
+            prop: 'phonenumber',
+            type: 'input',
+            isSearch: true
+        },
+        {
+            label: '家庭地址',
+            prop: 'address',
+        },
+        {
+            label: '身份证件',
+            prop: 'idCardPicture',
+            type: 'img',
+        },
+        {
+            label: '职业证书',
+            prop: 'volunteerPicture',
+            type: 'img',
+        },
+        {
+            label: '技能简介',
+            prop: 'skillDescribe',
+        },
+        {
+            label: '审核状态',
+            prop: 'appStatus',
+            type:'dict',
+            dict: volunteer_app_status
+        },
+    ],
+    searchBtns: [
+        // {
+        //     label: '批量删除',
+        //     func: () => {
+        //         const ids = userTableRef.value.ids;
+        //         console.log('批量删除', ids)
+        //         handleDelete(ids);
+        //     },
+        //     key: 'deletes',
+        //     hasPermi: ['manage:delete'],
+        //     type: 'danger'
+        // },
+    ],
+    tableApi: list,//接口地址
+    isSelect: false,//是否勾选
+    scopeBtns: [
+        {
+            label: '审核',
+            type: 'primary',
+            hasPermi: ['manage:examine'],
+            key: 'examine',
+            func: (row) => {
+                console.log(row)
+                openDialog(row, 'examine')
+            },
+            show: (row) => {
+                return row.appStatus == 1
+            }
+        },
+        {
+            label: '查看详情',
+            type: 'primary',
+            hasPermi: ['manage:details'],
+            key: 'details',
+            func: (row) => {
+                console.log(row)
+                openDialog(row)
+            }
+        },
+        // {
+        //     label: '删除',
+        //     type: 'danger',
+        //     hasPermi: ['manage:delete'],
+        //     key: 'delete',
+        //     func: (row) => {
+        //         console.log(row)
+        //         handleDelete([row.id])
+        //     }
+        // }
+    ]
+})
+const dialogData = reactive({
+    title: '',
+    column: [
+        {
+            label: '姓名',
+            prop: 'name',
+            type: 'input',
+
+        },
+        {
+            label: '年龄',
+            prop: 'age',
+            type: 'input',
+
+        },
+        {
+            label: '电话',
+            prop: 'phonenumber',
+            type: 'input',
+
+        },
+        {
+            label: '家庭地址',
+            prop: 'address',
+            type: 'input',
+
+        },
+        {
+            label: '服务项目/类别',
+            prop: 'businessManagementId',
+            type: 'cascader',
+            isSearch: true,
+            options: options,
+            props: { label: 'businessName', value: 'id', checkStrictly:true },
+
+        },
+        {
+            label: '身份证件',
+            prop: 'idCardPicture',
+            type: 'img',
+
+        },
+        {
+            label: '职业证书',
+            prop: 'certificationPicture',
+            type: 'img',
+
+        },
+        {
+            label: '技能简介',
+            prop: 'skillDescribe',
+            type: 'textarea',
+        },
+        {
+            label: '审核状态',
+            prop: 'appStatus',
+            type: 'radio',
+            rules: [
+                { required: true, message: '请选择审核状态', trigger: 'blur' }
+            ],
+            options: [
+                {
+                    label: '通过',
+                    value: '2'
+                },
+                {
+                    label: '不通过',
+                    value: '3'
+                }
+            ]
+        },
+    ]
+})
+const { title } = toRefs(dialogData);
+const parentId = ref(0);
+const tabList = [
+    {
+        title: '已通过',
+        name: '2',
+    },
+    {
+        title: '待审核',
+        name: '1',
+    },
+]
+const openDialog = (row, type) => {
+    console.log('row', row);
+    try {
+        const disabledData = {
+            name: true,
+            age: true,
+            phonenumber: true,
+            address: true,
+            skillDescribe: true,
+            businessManagementId: true,
+        }
+
+        if (type) {
+            //审核
+            title.value = '审核'
+
+        } else {
+            disabledData['appStatus'] = true;
+            //查看详情
+            title.value = '查看详情'
+        }
+
+        dialogFormRef.value.initForm(row, disabledData)
+
+    } catch (error) {
+        console.log('error', error);
+    } finally {
+        console.log('dialogFormRef.value', dialogFormRef.value);
+
+        dialogFormRef.value.handleDialog(true);
+    }
+}
+const handleDelete = (ids) => {
+    proxy.$modal.confirm('是否确认删除角色编号为"' + ids + '"的数据项?').then(function () {
+        return true
+    }).then(() => {
+        userTableRef.value.resetForm();
+        proxy.$modal.msgSuccess("删除成功");
+    }).catch(() => { });
+}
+
+const submitForm = async (parmas) => {
+
+    try {
+        console.log('submit', parmas);
+        if (title.value === '审核') {
+            const res = await approval({
+                volunteerInfoId: parmas.volunteerInfoId,
+                appStatus: parmas.appStatus,
+                rejectReason: parmas.rejectReason
+            })
+            if (up_res.code === 200) {
+                proxy.$modal.msgSuccess("审核成功");
+                return;
+            }
+            proxy.$modal.msgSuccess(res.msg);
+        }
+    } catch (error) {
+        console.log('error', error);
+
+    } finally {
+        userTableRef.value.resetForm();
+        dialogFormRef.value.handleDialog(false);
+    }
+
+}
+
+
+const getTreeListData = async () => {
+    try {
+        const res = await getTreeList({ parentId: parentId.value });
+        console.log('res', res);
+        options.value = res.data;
+    } catch (error) {
+
+    }
+}
+
+getTreeListData();
+
+</script>
+
+<style lang='scss' scoped></style>

+ 330 - 0
src/views/staff/volunteer/price/index.vue

@@ -0,0 +1,330 @@
+<template>
+    <div>
+        <ListPage tableKey="businessPriceId" :column="listPageData.tableColumn" :tableApi="listPageData.tableApi" :isSelect="listPageData.isSelect"
+            :scopeBtns="listPageData.scopeBtns" :searchBtns="listPageData.searchBtns" ref="userTableRef" v-if="options && options.length>0"/>
+
+        <el-dialog :title="title" v-model="open" width="500" :before-close="cancel">
+            <div style="padding: 20px;">
+                <el-form ref="dialogFormsRef" :model="form" :rules="rules" label-width="80px">
+                    <el-form-item label="服务项目" prop="businessManagementId">
+                        <el-cascader v-model="form.businessManagementId" :options="options" style="width: 100%;"
+                            :props="{ label: 'businessName', value: 'id',checkStrictly:true }" />
+                    </el-form-item>
+                    <el-form-item label="服务时长" prop="businessDuration">
+                        <el-input v-model="form.businessDuration" placeholder="请输入服务时长" >
+                            <template #append>分钟</template>
+                        </el-input>
+                        
+                    </el-form-item>
+                    <el-form-item label="服务价格" prop="businessPrice">
+                        <el-input v-model="form.businessPrice" placeholder="请输入服务价格" />
+                    </el-form-item>
+                </el-form>
+            </div>
+            <template #footer>
+                <div class="dialog-footer">
+                    <el-button type="primary" @click="submitForm">确 定</el-button>
+                    <el-button @click="cancel">取 消</el-button>
+                </div>
+            </template>
+        </el-dialog>
+    </div>
+</template>
+
+<script setup>
+import { onMounted, ref, render } from 'vue';
+import ListPage from '@/views/components/ListPage/index.vue';
+import { add, update, list, delPrice, details, getTreeList } from "@/api/staff/price.js";
+
+const { proxy } = getCurrentInstance();
+
+const userTableRef = ref();
+const options = ref([]);
+const listPageData = reactive({
+    tableColumn: [
+        {
+            label: '服务层级名称',
+            prop: 'businessManagementId',
+            type: 'cascader',
+            isSearch: true,
+            tableProp:'businessTierName',
+            options:options,
+            props: { label: 'businessName', value: 'id', checkStrictly:true },
+
+
+        },
+        // {
+        //     label: '项目类别',
+        //     prop: 'projectTypeName',
+        // },
+        {
+            label: '服务时长',
+            prop: 'businessDuration',
+            type:'render',
+            render: (row) => {
+                return row.businessDuration + '分钟'
+            }
+        },
+        {
+            label: '服务价格',
+            prop: 'businessPrice',
+            type:'render',
+            render: (row) => {
+                return '¥'+row.businessPrice
+            }
+           
+        },
+        
+    ],
+    searchBtns: [
+        {
+            label: '新增',
+            func: () => {
+                console.log('新增')
+                openDialog();
+            },
+            key: 'add',
+            hasPermi: ['price:add'],
+            icon: 'Plus',
+            type: 'primary'
+        },
+        {
+            label: '批量删除',
+            func: () => {
+                const ids = userTableRef.value.ids;
+                console.log('批量删除', ids)
+                handleDelete(ids)
+            },
+            key: 'deletes',
+            hasPermi: ['price:delete'],
+            type: 'danger'
+        },
+    ],
+    tableApi: list,//接口地址
+    isSelect: true,//是否勾选
+    scopeBtns: [
+        {
+            label: '编辑',
+            type: 'primary',
+            hasPermi: ['price:edit'],
+            key: 'edit',
+            func: (row) => {
+                console.log(row)
+                openDialog(row);
+
+            }
+        },
+        {
+            label: '删除',
+            type: 'danger',
+            hasPermi: ['price:delete'],
+            key: 'edit',
+            func: (row) => {
+                console.log(row)
+                handleDelete([row.businessPriceId])
+            }
+        }
+    ]
+})
+// const options = [
+//     {
+//         value: 'guide',
+//         label: 'Guide',
+//         children: [
+//             {
+//                 value: 'disciplines',
+//                 label: 'Disciplines',
+//                 children: [
+//                     {
+//                         value: 'consistency',
+//                         label: 'Consistency',
+//                     },
+//                     {
+//                         value: 'feedback',
+//                         label: 'Feedback',
+//                     },
+//                     {
+//                         value: 'efficiency',
+//                         label: 'Efficiency',
+//                     },
+//                     {
+//                         value: 'controllability',
+//                         label: 'Controllability',
+//                     },
+//                 ],
+//             },
+//             {
+//                 value: 'navigation',
+//                 label: 'Navigation',
+//                 children: [
+//                     {
+//                         value: 'side nav',
+//                         label: 'Side Navigation',
+//                     },
+//                     {
+//                         value: 'top nav',
+//                         label: 'Top Navigation',
+//                     },
+//                 ],
+//             },
+//         ],
+//     },
+//     {
+//         value: 'resource',
+//         label: 'Resource',
+//         children: [
+//             {
+//                 value: 'axure',
+//                 label: 'Axure Components',
+//             },
+//             {
+//                 value: 'sketch',
+//                 label: 'Sketch Templates',
+//             },
+//             {
+//                 value: 'docs',
+//                 label: 'Design Documentation',
+//             },
+//         ],
+//     },
+// ]
+
+const open = ref(false);
+const dialogFormsRef = ref(null);
+const data = reactive({
+    title: '',
+    form: {
+        businessManagementId: "",
+        businessPrice: '',
+        businessDuration: null
+    },
+    rules: {
+        businessManagementId: [{ required: true, message: "请选择服务项目", trigger: "blur" }],
+        businessDuration: [{ required: true, message: "请填入服务时间", trigger: "blur" }],
+        businessPrice: [{ required: true, message: "请填入服务价格", trigger: "blur" }],
+    }
+
+});
+const { title, rules, form } = toRefs(data);
+
+function getParentPathById(data, targetId) {
+    const path = [];
+
+    function traverse(node, id) {
+        if (node.id === id) {
+            path.unshift(node.id);
+            return true;
+        }
+
+        if (node.children) {
+            for (const child of node.children) {
+                if (traverse(child, id)) {
+                    path.unshift(node.id);
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
+
+    for (const item of data) {
+        if (traverse(item, targetId)) {
+            break;
+        }
+    }
+
+    return path;
+}
+const openDialog = async (row) => {
+
+    try {
+   
+        if (row) {
+            //修改
+            title.value = '价格修改'
+            const result = getParentPathById(options.value, row.businessManagementId+'');
+            console.log(result,row.businessManagementId); 
+            form.value = {
+                ...row,
+                businessManagementId: result
+            };
+        } else {
+            //新增
+            title.value = '价格新增'
+        }
+
+
+    } catch (error) {
+
+
+
+    } finally {
+        open.value = true;
+    }
+}
+
+const handleDelete = (ids) => {
+    console.log('ids',ids);
+    
+    proxy.$modal.confirm('是否确认删除编号为"' + ids + '"的数据项?').then(function () {
+        return delPrice(ids)
+    }).then(() => {
+        userTableRef.value.resetForm();
+        proxy.$modal.msgSuccess("删除成功");
+    }).catch(() => { });
+}
+const submitForm = () => {
+    console.log('submit');
+    proxy.$refs["dialogFormsRef"].validate(async (valid) => {
+        if (valid) {
+            console.log('form', form.value);
+            const businessManagementId = form.value.businessManagementId[form.value.businessManagementId.length -1];
+            const parmas = {...form.value, businessManagementId}
+            if (form.value.businessPriceId) {
+                const up_res = await update(parmas);
+                if (up_res.code === 200) {
+                    proxy.$modal.msgSuccess("修改成功");
+                    cancel()
+                    return;
+                }
+                proxy.$modal.msgSuccess(res.msg);
+                return
+            }
+            const res = await add(parmas);
+            if (res.code === 200) {
+                proxy.$modal.msgSuccess("新增成功");
+                cancel()
+                return;
+            }
+            proxy.$modal.msgSuccess(res.msg);
+        }
+    });
+}
+const cancel = () => {
+    open.value = false;
+    userTableRef.value.resetForm();
+    // dialogFormsRef.value.resetFields();
+    form.value = {
+        businessManagementId: "",
+        businessPrice: '',
+        businessDuration: null
+    }
+    console.log('cancel');
+}
+const parentId = ref(0);
+
+const getTreeListData = async () => {
+    try {
+        const res = await getTreeList({ parentId: parentId.value });
+        console.log('res', res);
+        options.value = res.data;
+    } catch (error) {
+
+    }
+}
+
+getTreeListData();
+</script>
+
+<style lang='scss' scoped></style>

+ 1 - 1
vite.config.js

@@ -32,7 +32,7 @@ export default defineConfig(({ mode, command }) => {
         // https://cn.vitejs.dev/config/#server-proxy
         '/dev-api': {
           // target: 'http://localhost:9527',
-        target: 'http://192.168.121.121:9527',
+        target: 'http://192.168.100.121:9527',
           changeOrigin: true,
           rewrite: (p) => p.replace(/^\/dev-api/, '')
         }