接入反馈凭证原生拍摄
反馈页在移动壳声明拍摄能力时展示拍摄凭证入口 拍摄图片复用现有凭证校验、预览和提交链路 同步原生壳测试、文档和共享记忆
This commit is contained in:
@@ -37,6 +37,7 @@ test('PlatformFeedbackView renders reference feedback fields', () => {
|
||||
expect(screen.getByText('0/200')).toBeTruthy();
|
||||
expect(screen.getByText('上传凭证(提供问题截图)')).toBeTruthy();
|
||||
expect(screen.getByText('上传凭证')).toBeTruthy();
|
||||
expect(screen.queryByText('拍摄凭证')).toBeNull();
|
||||
const contactPhoneField = screen.getByLabelText('联系电话');
|
||||
expect(contactPhoneField).toBeTruthy();
|
||||
expect(contactPhoneField.tagName).toBe('INPUT');
|
||||
@@ -189,6 +190,57 @@ test('PlatformFeedbackView imports evidence image through native HostBridge', as
|
||||
}
|
||||
});
|
||||
|
||||
test('PlatformFeedbackView captures evidence image through native HostBridge', async () => {
|
||||
const inputClickSpy = vi
|
||||
.spyOn(HTMLInputElement.prototype, 'click')
|
||||
.mockImplementation(() => undefined);
|
||||
vi.spyOn(hostBridgeServices, 'canUseNativeHostCapability').mockImplementation(
|
||||
(capability) => capability === 'file.captureImage',
|
||||
);
|
||||
vi.spyOn(hostBridgeServices, 'captureHostImageFile').mockResolvedValue({
|
||||
action: 'captured',
|
||||
fileName: 'feedback-camera.png',
|
||||
base64Data: 'Y2FtZXJhLWZlZWRiYWNr',
|
||||
mimeType: 'image/png',
|
||||
bytes: 15,
|
||||
});
|
||||
const onSubmit = vi.fn();
|
||||
|
||||
try {
|
||||
render(<PlatformFeedbackView onBack={vi.fn()} onSubmit={onSubmit} />);
|
||||
|
||||
expect(screen.getByText('拍摄凭证')).toBeTruthy();
|
||||
fireEvent.click(screen.getByText('拍摄凭证'));
|
||||
|
||||
const preview = await screen.findByAltText('反馈凭证预览');
|
||||
expect(preview.getAttribute('src')).toBe(
|
||||
'data:image/png;base64,ZmVlZGJhY2s=',
|
||||
);
|
||||
expect(inputClickSpy).not.toHaveBeenCalled();
|
||||
|
||||
fireEvent.change(screen.getByLabelText('问题描述'), {
|
||||
target: { value: '拍摄凭证后应该可以直接提交' },
|
||||
});
|
||||
fireEvent.click(screen.getByRole('button', { name: '提交' }));
|
||||
|
||||
await waitFor(() => expect(onSubmit).toHaveBeenCalledTimes(1));
|
||||
expect(onSubmit).toHaveBeenCalledWith({
|
||||
description: '拍摄凭证后应该可以直接提交',
|
||||
contactPhone: null,
|
||||
evidenceItems: [
|
||||
{
|
||||
fileName: 'feedback-camera.png',
|
||||
contentType: 'image/png',
|
||||
sizeBytes: 15,
|
||||
dataUrl: 'data:image/png;base64,ZmVlZGJhY2s=',
|
||||
},
|
||||
],
|
||||
});
|
||||
} finally {
|
||||
inputClickSpy.mockRestore();
|
||||
}
|
||||
});
|
||||
|
||||
test('PlatformFeedbackView calls back from header home button', () => {
|
||||
const onBack = vi.fn();
|
||||
render(<PlatformFeedbackView onBack={onBack} />);
|
||||
|
||||
@@ -4,6 +4,7 @@ import { useRef, useState } from 'react';
|
||||
import type { ProfileFeedbackEvidenceItemInput } from '../../../packages/shared/src/contracts/runtime';
|
||||
import {
|
||||
canUseNativeHostCapability,
|
||||
captureHostImageFile,
|
||||
type HostFileImportImageResult,
|
||||
importHostImageFile,
|
||||
} from '../../services/host-bridge/hostBridge';
|
||||
@@ -86,6 +87,8 @@ export function PlatformFeedbackView({
|
||||
const [submitted, setSubmitted] = useState(false);
|
||||
|
||||
const descriptionLength = description.length;
|
||||
const canCaptureHostEvidenceImage =
|
||||
canUseNativeHostCapability('file.captureImage');
|
||||
|
||||
const showTemporaryNotice = (message: string) => {
|
||||
setNotice(message);
|
||||
@@ -104,6 +107,10 @@ export function PlatformFeedbackView({
|
||||
setSubmitted(false);
|
||||
};
|
||||
|
||||
const addHostEvidenceImage = (imageFile: HostFileImportImageResult) => {
|
||||
addEvidenceFiles([hostEvidenceImageResultToFile(imageFile)]);
|
||||
};
|
||||
|
||||
const openEvidencePicker = () => {
|
||||
if (canUseNativeHostCapability('file.importImage')) {
|
||||
void (async () => {
|
||||
@@ -112,7 +119,7 @@ export function PlatformFeedbackView({
|
||||
return;
|
||||
}
|
||||
|
||||
addEvidenceFiles([hostEvidenceImageResultToFile(importedImageFile)]);
|
||||
addHostEvidenceImage(importedImageFile);
|
||||
})();
|
||||
return;
|
||||
}
|
||||
@@ -120,6 +127,21 @@ export function PlatformFeedbackView({
|
||||
evidenceInputRef.current?.click();
|
||||
};
|
||||
|
||||
const captureEvidenceImage = () => {
|
||||
if (!canCaptureHostEvidenceImage) {
|
||||
return;
|
||||
}
|
||||
|
||||
void (async () => {
|
||||
const capturedImageFile = await captureHostImageFile();
|
||||
if (!capturedImageFile) {
|
||||
return;
|
||||
}
|
||||
|
||||
addHostEvidenceImage(capturedImageFile);
|
||||
})();
|
||||
};
|
||||
|
||||
const addEvidenceFiles = (files: FileList | File[] | null) => {
|
||||
const selectedFiles = files ? Array.from(files) : [];
|
||||
if (evidenceInputRef.current) {
|
||||
@@ -312,11 +334,20 @@ export function PlatformFeedbackView({
|
||||
/>
|
||||
))}
|
||||
{evidencePreviews.length < MAX_FEEDBACK_EVIDENCE_COUNT ? (
|
||||
<PlatformUploadTile
|
||||
onClick={openEvidencePicker}
|
||||
label="上传凭证"
|
||||
hint="(最多四张)"
|
||||
/>
|
||||
<>
|
||||
<PlatformUploadTile
|
||||
onClick={openEvidencePicker}
|
||||
label="上传凭证"
|
||||
hint="(最多四张)"
|
||||
/>
|
||||
{canCaptureHostEvidenceImage ? (
|
||||
<PlatformUploadTile
|
||||
onClick={captureEvidenceImage}
|
||||
label="拍摄凭证"
|
||||
hint="(最多四张)"
|
||||
/>
|
||||
) : null}
|
||||
</>
|
||||
) : null}
|
||||
</div>
|
||||
<input
|
||||
|
||||
Reference in New Issue
Block a user