编辑单元格和多选的功能
首先是编辑单元格的功能,点击编辑按钮,可以直接在表格中队内容进行编辑,点击保存以后能够同步到数据库。
其次是多选的功能,点击每行前面的多选框按钮,我们可以选中多行。
完整后端代码:
import api
import upload
import time
import amcomment
import env
import mcrud
import amuserdetailsave_dir = "uploads"
env.load(".env")
db = mcrud.new_env()app = api.Api(routes=[*amcomment.get_routes(db),*amuserdetail.get_routes(db),upload.download("/download/{filename}", save_dir),],middleware=[api.middleware.cors()]
)if __name__ == "__main__":app.run(port=8889)
完整前端代码:
<script setup>
import {cloneDeep} from 'lodash-es';
import {computed, onMounted, reactive, ref} from 'vue';
import axios from "axios";const columns = [{name: '姓名',dataIndex: 'name',id: 'name',},{name: '性别',dataIndex: 'gender',id: 'gender',},{title: '年龄',dataIndex: 'age',id: 'age',},{title: '电话',dataIndex: 'phone',id: 'phone',},{title: '邮箱',id: 'email',dataIndex: 'email',},{title: '薪资',id: 'salary',dataIndex: 'salary',},{title: '操作',id: 'action',},
];const dataSource = ref([]);const editableData = reactive({});const edit = id => {editableData[id] = cloneDeep(dataSource.value.filter(item => id === item.id)[0]);
};const save = id => {// backend updateaxios({method: "put",url: "http://127.0.0.1:8889/zdppy_amuserdetail/" + id,contentType: "application/json",data: editableData[id],}).then(resp => {console.log("update", resp.data);})// frontend updateObject.assign(dataSource.value.filter(item => id === item.id)[0], editableData[id]);delete editableData[id];
};const cancel = id => {delete editableData[id];
};// handle multi selected
const state = reactive({selectedRowKeys: [],// Check here to configure the default columnloading: false,
});const hasSelected = computed(() => state.selectedRowKeys.length > 0);
const start = () => {state.loading = true;// ajax request after empty completingsetTimeout(() => {state.loading = false;state.selectedRowKeys = [];}, 1000);
};const onSelectChange = selectedRowKeys => {console.log('selectedRowKeys changed: ', selectedRowKeys);state.selectedRowKeys = selectedRowKeys;
};onMounted(() => {axios({method: "get",url: "http://127.0.0.1:8889/zdppy_amuserdetail",}).then((response) => {console.log("response.data", response.data);const responseData = response.data.dataconsole.log("responseData=", responseData)dataSource.value = responseData.results;})
})
</script><template><div style="margin-bottom: 16px"><a-button type="primary" :disabled="!hasSelected" :loading="state.loading" @click="start">Reload</a-button><span style="margin-left: 8px"><template v-if="hasSelected">{{ `Selected ${state.selectedRowKeys.length} items` }}</template></span></div><a-table:columns="columns":data-source="dataSource":row-selection="{ selectedRowKeys: state.selectedRowKeys, onChange: onSelectChange }":row-key="record => record.id"bordered><template #headerCell="{ column }"><template v-if="column.id === 'name'"><span>{{ column.name }}</span></template><template v-else-if="column.id === 'gender'"><span>{{ column.name }}</span></template></template><template #bodyCell="{ column, text, record }"><template v-if="['name', 'age', 'address'].includes(column.dataIndex)"><div><a-inputv-if="editableData[record.id]"v-model:value="editableData[record.id][column.dataIndex]"style="margin: -5px 0"/><template v-else>{{ text }}</template></div></template><template v-else-if="column.id === 'action'"><div class="editable-row-operations"><span v-if="editableData[record.id]"><a-typography-link @click="save(record.id)">保存</a-typography-link><a-popconfirm title="Sure to cancel?" @confirm="cancel(record.id)"><a>取消</a></a-popconfirm></span><span v-else><a @click="edit(record.id)">编辑</a></span></div></template></template></a-table>
</template><style scoped>
.editable-row-operations a {margin-right: 8px;
}
</style>
不过目前有个问题,那就是没有实现批量删除的功能。我们可以在多选以后,点击批量删除按钮,同时删除被选中的数据。
实现前端批量删除的功能
如图:
选中任意两条数据以后,点击批量删除按钮,这时会弹出确认信息。
点击确认以后会触发一个方法,会在控制台输出需要被删除的数据的ID,是一个数组,用于执行批量删除的操作。
此时的完整前端代码如下:
<script setup>
import {cloneDeep} from 'lodash-es';
import {computed, onMounted, reactive, ref} from 'vue';
import axios from "axios";const columns = [{name: '姓名',dataIndex: 'name',id: 'name',},{name: '性别',dataIndex: 'gender',id: 'gender',},{title: '年龄',dataIndex: 'age',id: 'age',},{title: '电话',dataIndex: 'phone',id: 'phone',},{title: '邮箱',id: 'email',dataIndex: 'email',},{title: '薪资',id: 'salary',dataIndex: 'salary',},{title: '操作',id: 'action',},
];const dataSource = ref([]);const editableData = reactive({});const edit = id => {editableData[id] = cloneDeep(dataSource.value.filter(item => id === item.id)[0]);
};const save = id => {// backend updateaxios({method: "put",url: "http://127.0.0.1:8889/zdppy_amuserdetail/" + id,contentType: "application/json",data: editableData[id],}).then(resp => {console.log("update", resp.data);})// frontend updateObject.assign(dataSource.value.filter(item => id === item.id)[0], editableData[id]);delete editableData[id];
};const cancel = id => {delete editableData[id];
};// handle multi selected
const state = reactive({selectedRowKeys: [],// Check here to configure the default columnloading: false,
});const hasSelected = computed(() => state.selectedRowKeys.length > 0);
const start = () => {state.loading = true;// ajax request after empty completingsetTimeout(() => {state.loading = false;state.selectedRowKeys = [];}, 1000);
};const onSelectChange = selectedRowKeys => {console.log('selectedRowKeys changed: ', selectedRowKeys);state.selectedRowKeys = selectedRowKeys;
};// delete selected data
const onDeleteSelectedClick = () => {console.log("onDeleteSelectedClick", state.selectedRowKeys);
}
onMounted(() => {axios({method: "get",url: "http://127.0.0.1:8889/zdppy_amuserdetail",}).then((response) => {console.log("response.data", response.data);const responseData = response.data.dataconsole.log("responseData=", responseData)dataSource.value = responseData.results;})
})
</script><template><div class="flex space-x-3 py-3"><a-button type="primary" :disabled="!hasSelected" :loading="state.loading" @click="start">Reload</a-button><a-popconfirm title="您确认要删除选中的数据吗?" @confirm="onDeleteSelectedClick"><a-button type="primary" :disabled="!hasSelected" danger>批量删除</a-button></a-popconfirm></div><a-table:columns="columns":data-source="dataSource":row-selection="{ selectedRowKeys: state.selectedRowKeys, onChange: onSelectChange }":row-key="record => record.id"bordered><template #headerCell="{ column }"><template v-if="column.id === 'name'"><span>{{ column.name }}</span></template><template v-else-if="column.id === 'gender'"><span>{{ column.name }}</span></template></template><template #bodyCell="{ column, text, record }"><template v-if="['name', 'age', 'address'].includes(column.dataIndex)"><div><a-inputv-if="editableData[record.id]"v-model:value="editableData[record.id][column.dataIndex]"style="margin: -5px 0"/><template v-else>{{ text }}</template></div></template><template v-else-if="column.id === 'action'"><div class="editable-row-operations"><span v-if="editableData[record.id]"><a-typography-link @click="save(record.id)">保存</a-typography-link><a-popconfirm title="Sure to cancel?" @confirm="cancel(record.id)"><a>取消</a></a-popconfirm></span><span v-else><a @click="edit(record.id)">编辑</a></span></div></template></template></a-table>
</template><style scoped>
.editable-row-operations a {margin-right: 8px;
}
</style>
修改确认提示文本
修改之前:是OK和Cancel
修改之后:是确认和取消
核心代码如下:
<a-popconfirmtitle="您确认要删除选中的数据吗?"ok-text="确认"cancel-text="取消"@confirm="onDeleteSelectedClick"><a-button type="primary" :disabled="!hasSelected" danger>批量删除</a-button></a-popconfirm>
```此时前端的完整代码如下:
```html
<script setup>
import {cloneDeep} from 'lodash-es';
import {computed, onMounted, reactive, ref} from 'vue';
import axios from "axios";const columns = [{name: '姓名',dataIndex: 'name',id: 'name',},{name: '性别',dataIndex: 'gender',id: 'gender',},{title: '年龄',dataIndex: 'age',id: 'age',},{title: '电话',dataIndex: 'phone',id: 'phone',},{title: '邮箱',id: 'email',dataIndex: 'email',},{title: '薪资',id: 'salary',dataIndex: 'salary',},{title: '操作',id: 'action',},
];const dataSource = ref([]);const editableData = reactive({});const edit = id => {editableData[id] = cloneDeep(dataSource.value.filter(item => id === item.id)[0]);
};const save = id => {// backend updateaxios({method: "put",url: "http://127.0.0.1:8889/zdppy_amuserdetail/" + id,contentType: "application/json",data: editableData[id],}).then(resp => {console.log("update", resp.data);})// frontend updateObject.assign(dataSource.value.filter(item => id === item.id)[0], editableData[id]);delete editableData[id];
};const cancel = id => {delete editableData[id];
};// handle multi selected
const state = reactive({selectedRowKeys: [],// Check here to configure the default columnloading: false,
});const hasSelected = computed(() => state.selectedRowKeys.length > 0);
const start = () => {state.loading = true;// ajax request after empty completingsetTimeout(() => {state.loading = false;state.selectedRowKeys = [];}, 1000);
};const onSelectChange = selectedRowKeys => {console.log('selectedRowKeys changed: ', selectedRowKeys);state.selectedRowKeys = selectedRowKeys;
};// delete selected data
const onDeleteSelectedClick = () => {console.log("onDeleteSelectedClick", state.selectedRowKeys);
}
onMounted(() => {axios({method: "get",url: "http://127.0.0.1:8889/zdppy_amuserdetail",}).then((response) => {console.log("response.data", response.data);const responseData = response.data.dataconsole.log("responseData=", responseData)dataSource.value = responseData.results;})
})
</script><template><div class="flex space-x-3 py-3"><a-button type="primary" :disabled="!hasSelected" :loading="state.loading" @click="start">Reload</a-button><a-popconfirmtitle="您确认要删除选中的数据吗?"ok-text="确认"cancel-text="取消"@confirm="onDeleteSelectedClick"><a-button type="primary" :disabled="!hasSelected" danger>批量删除</a-button></a-popconfirm></div><a-table:columns="columns":data-source="dataSource":row-selection="{ selectedRowKeys: state.selectedRowKeys, onChange: onSelectChange }":row-key="record => record.id"bordered><template #headerCell="{ column }"><template v-if="column.id === 'name'"><span>{{ column.name }}</span></template><template v-else-if="column.id === 'gender'"><span>{{ column.name }}</span></template></template><template #bodyCell="{ column, text, record }"><template v-if="['name', 'age', 'address'].includes(column.dataIndex)"><div><a-inputv-if="editableData[record.id]"v-model:value="editableData[record.id][column.dataIndex]"style="margin: -5px 0"/><template v-else>{{ text }}</template></div></template><template v-else-if="column.id === 'action'"><div class="editable-row-operations"><span v-if="editableData[record.id]"><a-typography-link @click="save(record.id)">保存</a-typography-link><a-popconfirm title="Sure to cancel?" @confirm="cancel(record.id)"><a>取消</a></a-popconfirm></span><span v-else><a @click="edit(record.id)">编辑</a></span></div></template></template></a-table>
</template><style scoped>
.editable-row-operations a {margin-right: 8px;
}
</style>```## 实现批量删除的功能
后端本身已经有这个接口了,我们只需要在前端调用即可。核心代码如下:
```js// delete selected data
const onDeleteSelectedClick = () => {console.log("onDeleteSelectedClick", state.selectedRowKeys);state.loading = trueaxios({method: "delete",url: "http://127.0.0.1:8889/zdppy_amuserdetail_ids",contentType: "application/json",data: {ids: state.selectedRowKeys,}}).finally(() => {state.loading = false;loadTableData()})
}const loadTableData = () => {axios({method: "get",url: "http://127.0.0.1:8889/zdppy_amuserdetail",}).then((response) => {console.log("response.data", response.data);const responseData = response.data.dataconsole.log("responseData=", responseData)dataSource.value = responseData.results;})
}
onMounted(() => {loadTableData()
})
```此时完整的前端代码如下:
```html
<script setup>
import {cloneDeep} from 'lodash-es';
import {computed, onMounted, reactive, ref} from 'vue';
import axios from "axios";const columns = [{name: '姓名',dataIndex: 'name',id: 'name',},{name: '性别',dataIndex: 'gender',id: 'gender',},{title: '年龄',dataIndex: 'age',id: 'age',},{title: '电话',dataIndex: 'phone',id: 'phone',},{title: '邮箱',id: 'email',dataIndex: 'email',},{title: '薪资',id: 'salary',dataIndex: 'salary',},{title: '操作',id: 'action',},
];const dataSource = ref([]);const editableData = reactive({});const edit = id => {editableData[id] = cloneDeep(dataSource.value.filter(item => id === item.id)[0]);
};const save = id => {// backend updateaxios({method: "put",url: "http://127.0.0.1:8889/zdppy_amuserdetail/" + id,contentType: "application/json",data: editableData[id],}).then(resp => {console.log("update", resp.data);})// frontend updateObject.assign(dataSource.value.filter(item => id === item.id)[0], editableData[id]);delete editableData[id];
};const cancel = id => {delete editableData[id];
};// handle multi selected
const state = reactive({selectedRowKeys: [],// Check here to configure the default columnloading: false,
});const hasSelected = computed(() => state.selectedRowKeys.length > 0);
const start = () => {state.loading = true;// ajax request after empty completingsetTimeout(() => {state.loading = false;state.selectedRowKeys = [];}, 1000);
};const onSelectChange = selectedRowKeys => {console.log('selectedRowKeys changed: ', selectedRowKeys);state.selectedRowKeys = selectedRowKeys;
};// delete selected data
const onDeleteSelectedClick = () => {console.log("onDeleteSelectedClick", state.selectedRowKeys);state.loading = trueaxios({method: "delete",url: "http://127.0.0.1:8889/zdppy_amuserdetail_ids",contentType: "application/json",data: {ids: state.selectedRowKeys,}}).finally(() => {state.loading = false;loadTableData()})
}const loadTableData = () => {axios({method: "get",url: "http://127.0.0.1:8889/zdppy_amuserdetail",}).then((response) => {console.log("response.data", response.data);const responseData = response.data.dataconsole.log("responseData=", responseData)dataSource.value = responseData.results;})
}
onMounted(() => {loadTableData()
})
</script><template><div class="flex space-x-3 py-3"><a-button type="primary" :disabled="!hasSelected" :loading="state.loading" @click="start">Reload</a-button><a-popconfirmtitle="您确认要删除选中的数据吗?"ok-text="确认"cancel-text="取消"@confirm="onDeleteSelectedClick"><a-button type="primary" :disabled="!hasSelected" danger>批量删除</a-button></a-popconfirm></div><a-table:columns="columns":data-source="dataSource":row-selection="{ selectedRowKeys: state.selectedRowKeys, onChange: onSelectChange }":row-key="record => record.id"bordered><template #headerCell="{ column }"><template v-if="column.id === 'name'"><span>{{ column.name }}</span></template><template v-else-if="column.id === 'gender'"><span>{{ column.name }}</span></template></template><template #bodyCell="{ column, text, record }"><template v-if="['name', 'age', 'address'].includes(column.dataIndex)"><div><a-inputv-if="editableData[record.id]"v-model:value="editableData[record.id][column.dataIndex]"style="margin: -5px 0"/><template v-else>{{ text }}</template></div></template><template v-else-if="column.id === 'action'"><div class="editable-row-operations"><span v-if="editableData[record.id]"><a-typography-link @click="save(record.id)">保存</a-typography-link><a-popconfirm title="Sure to cancel?" @confirm="cancel(record.id)"><a>取消</a></a-popconfirm></span><span v-else><a @click="edit(record.id)">编辑</a></span></div></template></template></a-table>
</template><style scoped>
.editable-row-operations a {margin-right: 8px;
}
</style>```